-
Notifications
You must be signed in to change notification settings - Fork 15
/
_util.py
87 lines (68 loc) · 2.36 KB
/
_util.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
"""Various utility functions to support physt implementation.
These functions are mostly general Python functions, not specific
for numerical computing, histogramming, etc.
"""
from __future__ import annotations
import warnings
from functools import wraps
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from typing import Any, Callable, Dict, Tuple
def all_subclasses(cls: type) -> Tuple[type, ...]:
"""All subclasses of a class.
From: http://stackoverflow.com/a/17246726/2692780
"""
subclasses = []
for subclass in cls.__subclasses__():
subclasses.append(subclass)
subclasses.extend(all_subclasses(subclass))
return tuple(subclasses)
def find_subclass(base: type, name: str) -> type:
"""Find a named subclass of a base class.
Uses only the class name without namespace.
"""
class_candidates = [
klass for klass in all_subclasses(base) if klass.__name__ == name
]
if not class_candidates:
raise TypeError(f"No '{base.__name__}' subclass of '{name}'.")
if len(class_candidates) > 1:
raise TypeError(f"Multiple '{base.__name__}' subclasses of '{name}'.")
return class_candidates[0]
def pop_many(a_dict: Dict[str, Any], *args: str, **kwargs) -> Dict[str, Any]:
"""Pop multiple items from a dictionary.
Parameters
----------
a_dict : Dictionary from which the items will popped
args: Keys which will be popped (and not included if not present)
kwargs: Keys + default value pairs (if key not found, this default is included)
Returns
-------
A dictionary of collected items.
"""
result = {}
for arg in args:
if arg in a_dict:
result[arg] = a_dict.pop(arg)
for key, value in kwargs.items():
result[key] = a_dict.pop(key, value)
return result
def deprecation_alias(f: Callable, deprecated_name: str) -> Callable:
"""Provide a deprecated copy of a function.
Parameters
----------
f : The correct function
deprecated_name : The name the function will be given
Examples
--------
>>> def new(x): return 1
>>> old = deprecation_alias(new, "old")
"""
@wraps(f)
def inner(*args, **kwargs):
warnings.warn(
f"{deprecated_name} is deprecated, use {f.__name__} instead",
FutureWarning,
)
return f(*args, **kwargs)
return inner