1 from collections
import namedtuple
4 from .facade
import ReturnMapping
, Type
, TypeEncoder
6 from .import _definitions
22 """A single websocket delta.
24 :ivar entity: The entity name, e.g. 'unit', 'application'
27 :ivar type: The delta type, e.g. 'add', 'change', 'remove'
30 :ivar data: The raw delta data
33 NOTE: The 'data' variable above is being incorrectly cross-linked by a
34 Sphinx bug: https://github.com/sphinx-doc/sphinx/issues/2549
37 _toSchema
= {'deltas': 'deltas'}
38 _toPy
= {'deltas': 'deltas'}
40 def __init__(self
, deltas
=None):
42 :param deltas: [str, str, object]
47 Change
= namedtuple('Change', 'entity type data')
48 change
= Change(*self
.deltas
)
50 self
.entity
= change
.entity
51 self
.type = change
.type
52 self
.data
= change
.data
55 def from_json(cls
, data
):
56 return cls(deltas
=data
)
59 class ResourcesFacade(Type
):
60 """Patch parts of ResourcesFacade to make it work.
63 @ReturnMapping(_client
.AddPendingResourcesResult
)
64 async def AddPendingResources(self
, application_tag
, charm_url
, resources
):
65 """Fix the calling signature of AddPendingResources.
67 The ResourcesFacade doesn't conform to the standard facade pattern in
68 the Juju source, which leads to the schemagened code not matching up
69 properly with the actual calling convention in the API. There is work
70 planned to fix this in Juju, but we have to work around it for now.
74 resources : typing.Sequence<+T_co>[~CharmResource]<~CharmResource>
75 Returns -> typing.Union[_ForwardRef('ErrorResult'),
76 typing.Sequence<+T_co>[str]]
78 # map input types to rpc msg
80 msg
= dict(type='Resources',
81 request
='AddPendingResources',
84 _params
['tag'] = application_tag
85 _params
['url'] = charm_url
86 _params
['resources'] = resources
87 reply
= await self
.rpc(msg
)
91 class AllWatcherFacade(Type
):
93 Patch rpc method of allwatcher to add in 'id' stuff.
96 async def rpc(self
, msg
):
97 if not hasattr(self
, 'Id'):
98 client
= _client
.ClientFacade
.from_connection(self
.connection
)
100 result
= await client
.WatchAll()
101 self
.Id
= result
.watcher_id
104 result
= await self
.connection
.rpc(msg
, encoder
=TypeEncoder
)
108 class Number(_definitions
.Number
):
110 This type represents a semver string.
112 Because it is not standard JSON, the typical from_json parsing fails and
113 the parsing must be handled specially.
115 See https://github.com/juju/version for more info.
117 numberPat
= re
.compile(r
'^(\d{1,9})\.(\d{1,9})(?:\.|-([a-z]+))(\d{1,9})(\.\d{1,9})?$') # noqa
119 def __init__(self
, major
=None, minor
=None, patch
=None, tag
=None,
120 build
=None, **unknown_fields
):
128 self
.major
= int(major
or '0')
129 self
.minor
= int(minor
or '0')
130 self
.patch
= int(patch
or '0')
132 self
.build
= int(build
or '0')
135 return '<Number major={} minor={} patch={} tag={} build={}>'.format(
136 self
.major
, self
.minor
, self
.patch
, self
.tag
, self
.build
)
139 return self
.serialize()
141 def __eq__(self
, other
):
143 isinstance(other
, type(self
)) and
144 other
.major
== self
.major
and
145 other
.minor
== self
.minor
and
146 other
.tag
== self
.tag
and
147 other
.patch
== self
.patch
and
148 other
.build
== self
.build
)
151 def from_json(cls
, data
):
153 if isinstance(data
, cls
):
157 elif isinstance(data
, dict):
159 elif isinstance(data
, str):
160 match
= cls
.numberPat
.match(data
)
163 'major': match
.group(1),
164 'minor': match
.group(2),
165 'tag': match
.group(3),
166 'patch': match
.group(4),
167 'build': (match
.group(5)[1:] if match
.group(5)
171 raise TypeError('Unable to parse Number version string: '
174 for k
, v
in parsed
.items():
175 d
[cls
._toPy
.get(k
, k
)] = v
182 s
= "{}.{}.{}".format(self
.major
, self
.minor
, self
.patch
)
184 s
= "{}.{}-{}{}".format(self
.major
, self
.minor
, self
.tag
,
187 s
= "{}.{}".format(s
, self
.build
)
191 return self
.serialize()
194 class Binary(_definitions
.Binary
):
196 This type represents a semver string with additional series and arch info.
198 Because it is not standard JSON, the typical from_json parsing fails and
199 the parsing must be handled specially.
201 See https://github.com/juju/version for more info.
203 binaryPat
= re
.compile(r
'^(\d{1,9})\.(\d{1,9})(?:\.|-([a-z]+))(\d{1,9})(\.\d{1,9})?-([^-]+)-([^-]+)$') # noqa
205 def __init__(self
, number
=None, series
=None, arch
=None, **unknown_fields
):
211 self
.number
= Number
.from_json(number
)
216 return '<Binary number={} series={} arch={}>'.format(
217 self
.number
, self
.series
, self
.arch
)
220 return self
.serialize()
222 def __eq__(self
, other
):
224 isinstance(other
, type(self
)) and
225 other
.number
== self
.number
and
226 other
.series
== self
.series
and
227 other
.arch
== self
.arch
)
230 def from_json(cls
, data
):
232 if isinstance(data
, cls
):
236 elif isinstance(data
, dict):
238 elif isinstance(data
, str):
239 match
= cls
.binaryPat
.match(data
)
243 'major': match
.group(1),
244 'minor': match
.group(2),
245 'tag': match
.group(3),
246 'patch': match
.group(4),
247 'build': (match
.group(5)[1:] if match
.group(5)
250 'series': match
.group(6),
251 'arch': match
.group(7),
254 raise TypeError('Unable to parse Binary version string: '
257 for k
, v
in parsed
.items():
258 d
[cls
._toPy
.get(k
, k
)] = v
263 return "{}-{}-{}".format(self
.number
.serialize(),
264 self
.series
, self
.arch
)
267 return self
.serialize()