-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathhal.py
More file actions
158 lines (131 loc) · 5.02 KB
/
hal.py
File metadata and controls
158 lines (131 loc) · 5.02 KB
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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
import logging
try:
import json
except ImportError:
import simplejson as json # NOQA
LOG = logging.getLogger(__name__)
class Link(object):
"""
Object to encapsulate HAL links.
If an attribute of the link is accessed and the document had not been
fetched before, a GET request is sent to the ``href`` of this Link.
:param rel: The relation name.
:type rel: basestring
:param obj: A dictionary representing the link, following the HAL spec for
links.
:type obj: dict
"""
def __init__(self, rel, obj):
self._data = obj
self._document = None
self.rel = rel
def __repr__(self):
return "Link(%r, %r)" % (self.rel, self._data)
def __getattribute__(self, attr):
if attr in ('_document', '_fetch_document', '_data', 'rel'):
return object.__getattribute__(self, attr)
if not self._document:
self._fetch_document()
LOG.warning('Links are not yet fully implemented')
return getattr(self._document, attr)
def _fetch_document(self):
"""
Send a GET request to the href of this link and stores the result
in a local variable.
"""
LOG.warning('Links are not yet fully implemented')
print 'fetching document (dummy)'
self._document = Document(u'/author/10')
self._document.name = u'John Doe'
def asdict(self):
"""
Returns a HAL style dict.
"""
return self._data
class Document(object):
"""
A HAL Document representation.
:param selfurl: The URL pointing to self.
:type selfurl: basestring
"""
@staticmethod
def makeDocument(obj):
"""
Factory method to construct Document instances from different sources.
The source (``obj``) can be any of the following:
* A ``dict`` -- This assumes that the dict follows the HAL spec and
implements all required keys.
* A file-like object (any object with a ``read`` method). This should
contain a JSON representation of the HAL document.
* A string. Again, this should be a valid JSON representation
following the HAL spec.
* A list. This assumes, that each item is a valid HAL Document
representation. The items are instantiated using
``Document.makeDocument``, so they can be of any of the above types.
"""
instance = Document()
if isinstance(obj, dict):
instance._data = obj
elif hasattr(obj, 'read'):
instance._data = json.load(obj)
elif isinstance(obj, basestring):
instance._data = json.loads(obj)
elif isinstance(obj, list):
instance = [Document.makeDocument(_) for _ in obj]
else:
raise NotImplementedError('Unable to instantiate a HAL Document '
'from %r' % obj)
return instance
def __init__(self, selfurl=u''):
self._data = {'_links': {'self': {'href': selfurl}}}
def __getattribute__(self, attr):
LOG.debug('Retrieving %r from %r' % (attr, self))
try:
return object.__getattribute__(self, attr)
except AttributeError:
pass
data = object.__getattribute__(self, '_data')
if attr in data:
return data[attr]
elif "_embedded" in data and attr in data['_embedded']:
return Document.makeDocument(data['_embedded'][attr])
elif "_links" in data and attr in data['_links']:
return Link(attr, data['_links'][attr])
raise AttributeError('%r has no attribute %r' % (self, attr))
def __repr__(self):
data = object.__getattribute__(self, '_data')
return "<Document %s>" % (data['_links']['self']['href'])
def __str__(self):
data = object.__getattribute__(self, '_data')
return json.dumps(data)
def __iter__(self):
data = object.__getattribute__(self, '_data')
for key in data:
if key == '_embedded':
for embedded_key in data[key]:
yield embedded_key
elif key == '_links':
# we'll ignore links when iterating over the keys. For now.
pass
else:
yield key
def __getitem__(self, key):
return getattr(self, key)
def __setattr__(self, name, value):
if name == '_data':
object.__setattr__(self, name, value)
else:
data = object.__getattribute__(self, '_data')
if isinstance(value, Document) or (
isinstance(value, list) and all([isinstance(_, Document) for _ in value])):
data['_embedded'][name] = value.asdict()
elif isinstance(value, Link):
data['_links'][name] = value.asdict()
else:
data[name] = value
def asdict(self):
"""
Returns a dictionary following the HAL spec.
"""
data = object.__getattribute__(self, '_data')
return data