Skip to content

Commit 1ed86e7

Browse files
author
Emanuele Palazzetti
committed
[core] split util module in utils package; keeping backward compatibility
1 parent 7af26f1 commit 1ed86e7

File tree

3 files changed

+134
-119
lines changed

3 files changed

+134
-119
lines changed

ddtrace/util.py

Lines changed: 14 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -1,119 +1,14 @@
1-
import os
2-
import wrapt
3-
import inspect
4-
5-
6-
def deep_getattr(obj, attr_string, default=None):
7-
"""
8-
Returns the attribute of `obj` at the dotted path given by `attr_string`
9-
If no such attribute is reachable, returns `default`
10-
11-
>>> deep_getattr(cass, "cluster")
12-
<cassandra.cluster.Cluster object at 0xa20c350
13-
14-
>>> deep_getattr(cass, "cluster.metadata.partitioner")
15-
u'org.apache.cassandra.dht.Murmur3Partitioner'
16-
17-
>>> deep_getattr(cass, "i.dont.exist", default="default")
18-
'default'
19-
"""
20-
attrs = attr_string.split('.')
21-
for attr in attrs:
22-
try:
23-
obj = getattr(obj, attr)
24-
except AttributeError:
25-
return default
26-
27-
return obj
28-
29-
30-
def safe_patch(patchable, key, patch_func, service, meta, tracer):
31-
""" takes patch_func (signature: takes the orig_method that is
32-
wrapped in the monkey patch == UNBOUND + service and meta) and
33-
attach the patched result to patchable at patchable.key
34-
35-
36-
- if this is the module/class we can rely on methods being unbound, and just have to
37-
update the __dict__
38-
39-
- if this is an instance, we have to unbind the current and rebind our
40-
patched method
41-
42-
- If patchable is an instance and if we've already patched at the module/class level
43-
then patchable[key] contains an already patched command!
44-
To workaround this, check if patchable or patchable.__class__ are _dogtraced
45-
If is isn't, nothing to worry about, patch the key as usual
46-
But if it is, search for a "__dd_orig_{key}" method on the class, which is
47-
the original unpatched method we wish to trace.
48-
49-
"""
50-
def _get_original_method(thing, key):
51-
orig = None
52-
if hasattr(thing, '_dogtraced'):
53-
# Search for original method
54-
orig = getattr(thing, "__dd_orig_{}".format(key), None)
55-
else:
56-
orig = getattr(thing, key)
57-
# Set it for the next time we attempt to patch `thing`
58-
setattr(thing, "__dd_orig_{}".format(key), orig)
59-
60-
return orig
61-
62-
if inspect.isclass(patchable) or inspect.ismodule(patchable):
63-
orig = _get_original_method(patchable, key)
64-
if not orig:
65-
# Should never happen
66-
return
67-
elif hasattr(patchable, '__class__'):
68-
orig = _get_original_method(patchable.__class__, key)
69-
if not orig:
70-
# Should never happen
71-
return
72-
else:
73-
return
74-
75-
dest = patch_func(orig, service, meta, tracer)
76-
77-
if inspect.isclass(patchable) or inspect.ismodule(patchable):
78-
setattr(patchable, key, dest)
79-
elif hasattr(patchable, '__class__'):
80-
setattr(patchable, key, dest.__get__(patchable, patchable.__class__))
81-
82-
83-
def asbool(value):
84-
"""Convert the given String to a boolean object. Accepted
85-
values are `True` and `1`."""
86-
if value is None:
87-
return False
88-
89-
if isinstance(value, bool):
90-
return value
91-
92-
return value.lower() in ("true", "1")
93-
94-
95-
def get_env(integration, variable, default=None):
96-
"""Retrieves environment variables value for the given integration. It must be used
97-
for consistency between integrations. The implementation is backward compatible
98-
with legacy nomenclature:
99-
* `DATADOG_` is a legacy prefix with lower priority
100-
* `DD_` environment variables have the highest priority
101-
* the environment variable is built concatenating `integration` and `variable`
102-
arguments
103-
* return `default` otherwise
104-
"""
105-
key = '{}_{}'.format(integration, variable).upper()
106-
legacy_env = 'DATADOG_{}'.format(key)
107-
env = 'DD_{}'.format(key)
108-
109-
# [Backward compatibility]: `DATADOG_` variables should be supported;
110-
# add a deprecation warning later if it's used, so that we can drop the key
111-
# in newer releases.
112-
value = os.getenv(env) or os.getenv(legacy_env)
113-
return value if value else default
114-
115-
116-
def unwrap(obj, attr):
117-
f = getattr(obj, attr, None)
118-
if f and isinstance(f, wrapt.ObjectProxy) and hasattr(f, '__wrapped__'):
119-
setattr(obj, attr, f.__wrapped__)
1+
# [Backward compatibility]: keep importing modules functions
2+
from .utils.deprecation import deprecated
3+
from .utils.formats import asbool, deep_getattr, get_env
4+
from .utils.wrappers import safe_patch, unwrap
5+
6+
7+
__all__ = [
8+
'deprecated',
9+
'asbool',
10+
'deep_getattr',
11+
'get_env',
12+
'safe_patch',
13+
'unwrap',
14+
]

ddtrace/utils/formats.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import os
2+
3+
4+
def get_env(integration, variable, default=None):
5+
"""Retrieves environment variables value for the given integration. It must be used
6+
for consistency between integrations. The implementation is backward compatible
7+
with legacy nomenclature:
8+
* `DATADOG_` is a legacy prefix with lower priority
9+
* `DD_` environment variables have the highest priority
10+
* the environment variable is built concatenating `integration` and `variable`
11+
arguments
12+
* return `default` otherwise
13+
"""
14+
key = '{}_{}'.format(integration, variable).upper()
15+
legacy_env = 'DATADOG_{}'.format(key)
16+
env = 'DD_{}'.format(key)
17+
18+
# [Backward compatibility]: `DATADOG_` variables should be supported;
19+
# add a deprecation warning later if it's used, so that we can drop the key
20+
# in newer releases.
21+
value = os.getenv(env) or os.getenv(legacy_env)
22+
return value if value else default
23+
24+
25+
def deep_getattr(obj, attr_string, default=None):
26+
"""
27+
Returns the attribute of `obj` at the dotted path given by `attr_string`
28+
If no such attribute is reachable, returns `default`
29+
30+
>>> deep_getattr(cass, "cluster")
31+
<cassandra.cluster.Cluster object at 0xa20c350
32+
33+
>>> deep_getattr(cass, "cluster.metadata.partitioner")
34+
u'org.apache.cassandra.dht.Murmur3Partitioner'
35+
36+
>>> deep_getattr(cass, "i.dont.exist", default="default")
37+
'default'
38+
"""
39+
attrs = attr_string.split('.')
40+
for attr in attrs:
41+
try:
42+
obj = getattr(obj, attr)
43+
except AttributeError:
44+
return default
45+
46+
return obj
47+
48+
49+
def asbool(value):
50+
"""Convert the given String to a boolean object. Accepted
51+
values are `True` and `1`."""
52+
if value is None:
53+
return False
54+
55+
if isinstance(value, bool):
56+
return value
57+
58+
return value.lower() in ("true", "1")

ddtrace/utils/wrappers.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import wrapt
2+
import inspect
3+
4+
5+
def unwrap(obj, attr):
6+
f = getattr(obj, attr, None)
7+
if f and isinstance(f, wrapt.ObjectProxy) and hasattr(f, '__wrapped__'):
8+
setattr(obj, attr, f.__wrapped__)
9+
10+
11+
def safe_patch(patchable, key, patch_func, service, meta, tracer):
12+
""" takes patch_func (signature: takes the orig_method that is
13+
wrapped in the monkey patch == UNBOUND + service and meta) and
14+
attach the patched result to patchable at patchable.key
15+
16+
17+
- if this is the module/class we can rely on methods being unbound, and just have to
18+
update the __dict__
19+
20+
- if this is an instance, we have to unbind the current and rebind our
21+
patched method
22+
23+
- If patchable is an instance and if we've already patched at the module/class level
24+
then patchable[key] contains an already patched command!
25+
To workaround this, check if patchable or patchable.__class__ are _dogtraced
26+
If is isn't, nothing to worry about, patch the key as usual
27+
But if it is, search for a "__dd_orig_{key}" method on the class, which is
28+
the original unpatched method we wish to trace.
29+
30+
"""
31+
def _get_original_method(thing, key):
32+
orig = None
33+
if hasattr(thing, '_dogtraced'):
34+
# Search for original method
35+
orig = getattr(thing, "__dd_orig_{}".format(key), None)
36+
else:
37+
orig = getattr(thing, key)
38+
# Set it for the next time we attempt to patch `thing`
39+
setattr(thing, "__dd_orig_{}".format(key), orig)
40+
41+
return orig
42+
43+
if inspect.isclass(patchable) or inspect.ismodule(patchable):
44+
orig = _get_original_method(patchable, key)
45+
if not orig:
46+
# Should never happen
47+
return
48+
elif hasattr(patchable, '__class__'):
49+
orig = _get_original_method(patchable.__class__, key)
50+
if not orig:
51+
# Should never happen
52+
return
53+
else:
54+
return
55+
56+
dest = patch_func(orig, service, meta, tracer)
57+
58+
if inspect.isclass(patchable) or inspect.ismodule(patchable):
59+
setattr(patchable, key, dest)
60+
elif hasattr(patchable, '__class__'):
61+
setattr(patchable, key, dest.__get__(patchable, patchable.__class__))
62+

0 commit comments

Comments
 (0)