-
-
Notifications
You must be signed in to change notification settings - Fork 2k
/
_utils.py
118 lines (93 loc) · 3.14 KB
/
_utils.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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import uuid
import collections
import six
def interpolate_str(template, **data):
s = template
for k, v in data.items():
key = '{%' + k + '%}'
s = s.replace(key, v)
return s
def format_tag(tag_name, attributes, inner='', closed=False, opened=False):
tag = '<{tag} {attributes}'
if closed:
tag += '/>'
elif opened:
tag += '>'
else:
tag += '>' + inner + '</{tag}>'
return tag.format(
tag=tag_name,
attributes=' '.join([
'{}="{}"'.format(k, v) for k, v in attributes.items()]))
def generate_hash():
return str(uuid.uuid4().hex).strip('-')
def get_asset_path(
requests_pathname,
asset_path,
asset_url_path):
return '/'.join([
# Only take the first part of the pathname
requests_pathname.rstrip('/'),
asset_url_path,
asset_path
])
# pylint: disable=no-member
def patch_collections_abc(member):
if six.PY2:
return getattr(collections, member)
return getattr(collections.abc, member)
class AttributeDict(dict):
"""
Dictionary subclass enabling attribute lookup/assignment of keys/values.
For example::
>>> m = AttributeDict({'foo': 'bar'})
>>> m.foo
'bar'
>>> m.foo = 'not bar'
>>> m['foo']
'not bar'
``AttributeDict`` objects also provide ``.first()`` which acts like
``.get()`` but accepts multiple keys as arguments, and returns the value of
the first hit, e.g.::
>>> m = AttributeDict({'foo': 'bar', 'biz': 'baz'})
>>> m.first('wrong', 'incorrect', 'foo', 'biz')
'bar'
"""
def __setattr__(self, key, value):
self[key] = value
def __getattr__(self, key):
try:
return self[key]
except KeyError:
pass
# to conform with __getattr__ spec
# but get out of the except block so it doesn't look like a nested err
raise AttributeError(key)
def set_read_only(self, names, msg='Attribute is read-only'):
object.__setattr__(self, '_read_only', names)
object.__setattr__(self, '_read_only_msg', msg)
def finalize(self, msg='Object is final: No new keys may be added.'):
"""Prevent any new keys being set"""
object.__setattr__(self, '_final', msg)
def __setitem__(self, key, val):
if key in self.__dict__.get('_read_only', []):
raise AttributeError(self._read_only_msg, key)
final_msg = self.__dict__.get('_final')
if final_msg and key not in self:
raise AttributeError(final_msg, key)
return super(AttributeDict, self).__setitem__(key, val)
# pylint: disable=inconsistent-return-statements
def first(self, *names):
for name in names:
value = self.get(name)
if value:
return value
def create_callback_id(output):
if isinstance(output, (list, tuple)):
return '..{}..'.format('...'.join(
'{}.{}'.format(x.component_id, x.component_property)
for x in output
))
return '{}.{}'.format(
output.component_id, output.component_property
)