ATLAS Offline Software
Toggle main menu visibility
Loading...
Searching...
No Matches
Tools
PyUtils
python
Decorators.py
Go to the documentation of this file.
1
# Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
2
3
"""
4
Some useful decorators.
5
"""
6
7
from
typing
import
Any, Callable
8
import
functools
9
import
inspect
10
import
logging
11
import
sys
12
13
log = logging.getLogger(__name__)
14
15
TFunc = Callable[..., Any]
16
17
def
_reraise_exception
(new_exc, exc_info=None):
18
if
exc_info
is
None
:
19
exc_info = sys.exc_info()
20
_exc_class, _exc, tb = exc_info
21
raise
new_exc.__class__ (new_exc, tb)
22
23
24
def
forking
(func):
25
"""
26
This decorator implements the forking patterns, i.e. it runs the function
27
in a forked process.
28
see:
29
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/511474
30
"""
31
@functools.wraps(func)
32
def
wrapper(*args, **kwargs):
33
import
os
34
import
pickle
35
36
# create a pipe which will be shared between parent and child
37
pread, pwrite = os.pipe()
38
39
# do fork
40
pid = os.fork()
41
42
43
if
pid > 0:
44
os.close(pwrite)
45
with
os.fdopen(pread,
'rb'
)
as
f:
46
status, result = pickle.load(f)
47
os.waitpid(pid, 0)
48
if
status == 0:
49
return
result
50
else
:
51
remote_exc = result[0]
52
_reraise_exception
(remote_exc)
53
54
55
else
:
56
os.close(pread)
57
try
:
58
result = func(*args, **kwargs)
59
status = 0
60
except
(Exception, KeyboardInterrupt)
as
exc:
61
import
traceback
62
exc_string = traceback.format_exc(limit=10)
63
for
l
in
exc_string.splitlines():
64
print
(
"[%d]"
%os.getpid(),l.rstrip())
65
sys.stdout.flush()
66
result = exc, exc_string
67
status = 1
68
with
os.fdopen(pwrite,
'wb'
)
as
f:
69
try
:
70
pickle.dump((status,result), f, pickle.HIGHEST_PROTOCOL)
71
except
pickle.PicklingError
as
exc:
72
pickle.dump((2,exc), f, pickle.HIGHEST_PROTOCOL)
73
os._exit(0)
74
return
result
75
76
return
wrapper
77
78
79
def
deprecate
(
80
reason: str, *, warn_once_per_call: bool =
True
, print_context: bool =
False
81
) -> Callable[[TFunc], TFunc]:
82
"""Decorator to indicate that a function should not be used
83
84
Parameters
85
----------
86
reason : str
87
A string explaining why the function should not be used
88
warn_once_per_call : bool
89
If True, only warn once per call location, default True
90
print_context: bool
91
If True, print the calling context as part of the warning, default False
92
"""
93
94
# Record when we've warned about a function+filename+line combination
95
warncache: set[tuple[int, str, int]] =
set
()
96
97
def
deprecate_decorator(f):
98
@functools.wraps(f)
99
def
call_deprecated(*args, **kwargs):
100
"""Call a deprecated function"""
101
# Figure out where we're calling from. The stack indices are as follows
102
# 0: this inspect.stack call
103
# 1: the actual call site we want to mark
104
frame_info = inspect.stack()[1]
105
cache_value = id(f), frame_info.filename, frame_info.lineno
106
if
not
warn_once_per_call
or
cache_value
not
in
warncache:
107
if
warn_once_per_call:
108
warncache.add(cache_value)
109
log.warning(f
"Calling deprecated function '{f.__qualname__}'"
)
110
log.warning(
111
f
"in function {frame_info.function}, file {frame_info.filename}, line {frame_info.lineno}"
112
)
113
if
print_context:
114
for
idx, line
in
enumerate(frame_info.code_context):
115
log.warning(f
"{frame_info.lineno + idx - frame_info.index}\t{line}"
)
116
log.warning(reason)
117
return
f(*args, **kwargs)
118
return
call_deprecated
119
return
deprecate_decorator
set
STL class.
python.Decorators._reraise_exception
_reraise_exception(new_exc, exc_info=None)
Definition
Decorators.py:17
python.Decorators.forking
forking(func)
Definition
Decorators.py:24
python.Decorators.deprecate
Callable[[TFunc], TFunc] deprecate(str reason, *, bool warn_once_per_call=True, bool print_context=False)
Definition
Decorators.py:81
Generated on
for ATLAS Offline Software by
1.17.0