+++ /dev/null
-import re
-from collections import namedtuple
-
-from . import _client, _definitions
-from .facade import ReturnMapping, Type, TypeEncoder
-
-__all__ = [
- 'Delta',
- 'Number',
- 'Binary',
- 'ConfigValue',
- 'Resource',
-]
-
-__patches__ = [
- 'ResourcesFacade',
- 'AllWatcherFacade',
- 'ActionFacade',
-]
-
-
-class Delta(Type):
- """A single websocket delta.
-
- :ivar entity: The entity name, e.g. 'unit', 'application'
- :vartype entity: str
-
- :ivar type: The delta type, e.g. 'add', 'change', 'remove'
- :vartype type: str
-
- :ivar data: The raw delta data
- :vartype data: dict
-
- NOTE: The 'data' variable above is being incorrectly cross-linked by a
- Sphinx bug: https://github.com/sphinx-doc/sphinx/issues/2549
-
- """
- _toSchema = {'deltas': 'deltas'}
- _toPy = {'deltas': 'deltas'}
-
- def __init__(self, deltas=None):
- """
- :param deltas: [str, str, object]
-
- """
- self.deltas = deltas
-
- Change = namedtuple('Change', 'entity type data')
- change = Change(*self.deltas)
-
- self.entity = change.entity
- self.type = change.type
- self.data = change.data
-
- @classmethod
- def from_json(cls, data):
- return cls(deltas=data)
-
-
-class ResourcesFacade(Type):
- """Patch parts of ResourcesFacade to make it work.
- """
-
- @ReturnMapping(_client.AddPendingResourcesResult)
- async def AddPendingResources(self, application_tag, charm_url, resources):
- """Fix the calling signature of AddPendingResources.
-
- The ResourcesFacade doesn't conform to the standard facade pattern in
- the Juju source, which leads to the schemagened code not matching up
- properly with the actual calling convention in the API. There is work
- planned to fix this in Juju, but we have to work around it for now.
-
- application_tag : str
- charm_url : str
- resources : typing.Sequence<+T_co>[~CharmResource]<~CharmResource>
- Returns -> typing.Union[_ForwardRef('ErrorResult'),
- typing.Sequence<+T_co>[str]]
- """
- # map input types to rpc msg
- _params = dict()
- msg = dict(type='Resources',
- request='AddPendingResources',
- version=1,
- params=_params)
- _params['tag'] = application_tag
- _params['url'] = charm_url
- _params['resources'] = resources
- reply = await self.rpc(msg)
- return reply
-
-
-class AllWatcherFacade(Type):
- """
- Patch rpc method of allwatcher to add in 'id' stuff.
-
- """
- async def rpc(self, msg):
- if not hasattr(self, 'Id'):
- client = _client.ClientFacade.from_connection(self.connection)
-
- result = await client.WatchAll()
- self.Id = result.watcher_id
-
- msg['Id'] = self.Id
- result = await self.connection.rpc(msg, encoder=TypeEncoder)
- return result
-
-
-class ActionFacade(Type):
-
- class _FindTagsResults(Type):
- _toSchema = {'matches': 'matches'}
- _toPy = {'matches': 'matches'}
-
- def __init__(self, matches=None, **unknown_fields):
- '''
- FindTagsResults wraps the mapping between the requested prefix and the
- matching tags for each requested prefix.
-
- Matches map[string][]Entity `json:"matches"`
- '''
- self.matches = {}
- matches = matches or {}
- for prefix, tags in matches.items():
- self.matches[prefix] = [_definitions.Entity.from_json(r)
- for r in tags]
-
- @ReturnMapping(_FindTagsResults)
- async def FindActionTagsByPrefix(self, prefixes):
- '''
- prefixes : typing.Sequence[str]
- Returns -> typing.Sequence[~Entity]
- '''
- # map input types to rpc msg
- _params = dict()
- msg = dict(type='Action',
- request='FindActionTagsByPrefix',
- version=2,
- params=_params)
- _params['prefixes'] = prefixes
- reply = await self.rpc(msg)
- return reply
-
-
-class Number(_definitions.Number):
- """
- This type represents a semver string.
-
- Because it is not standard JSON, the typical from_json parsing fails and
- the parsing must be handled specially.
-
- See https://github.com/juju/version for more info.
- """
- numberPat = re.compile(r'^(\d{1,9})\.(\d{1,9})(?:\.|-([a-z]+))(\d{1,9})(\.\d{1,9})?$') # noqa
-
- def __init__(self, major=None, minor=None, patch=None, tag=None,
- build=None, **unknown_fields):
- '''
- major : int
- minor : int
- patch : int
- tag : str
- build : int
- '''
- self.major = int(major or '0')
- self.minor = int(minor or '0')
- self.patch = int(patch or '0')
- self.tag = tag or ''
- self.build = int(build or '0')
-
- def __repr__(self):
- return '<Number major={} minor={} patch={} tag={} build={}>'.format(
- self.major, self.minor, self.patch, self.tag, self.build)
-
- def __str__(self):
- return self.serialize()
-
- @property
- def _cmp(self):
- return (self.major, self.minor, self.tag, self.patch, self.build)
-
- def __eq__(self, other):
- return isinstance(other, type(self)) and self._cmp == other._cmp
-
- def __lt__(self, other):
- return self._cmp < other._cmp
-
- def __le__(self, other):
- return self._cmp <= other._cmp
-
- def __gt__(self, other):
- return self._cmp > other._cmp
-
- def __ge__(self, other):
- return self._cmp >= other._cmp
-
- @classmethod
- def from_json(cls, data):
- parsed = None
- if isinstance(data, cls):
- return data
- elif data is None:
- return cls()
- elif isinstance(data, dict):
- parsed = data
- elif isinstance(data, str):
- match = cls.numberPat.match(data)
- if match:
- parsed = {
- 'major': match.group(1),
- 'minor': match.group(2),
- 'tag': match.group(3),
- 'patch': match.group(4),
- 'build': (match.group(5)[1:] if match.group(5)
- else 0),
- }
- if not parsed:
- raise TypeError('Unable to parse Number version string: '
- '{}'.format(data))
- d = {}
- for k, v in parsed.items():
- d[cls._toPy.get(k, k)] = v
-
- return cls(**d)
-
- def serialize(self):
- s = ""
- if not self.tag:
- s = "{}.{}.{}".format(self.major, self.minor, self.patch)
- else:
- s = "{}.{}-{}{}".format(self.major, self.minor, self.tag,
- self.patch)
- if self.build:
- s = "{}.{}".format(s, self.build)
- return s
-
- def to_json(self):
- return self.serialize()
-
-
-class Binary(_definitions.Binary):
- """
- This type represents a semver string with additional series and arch info.
-
- Because it is not standard JSON, the typical from_json parsing fails and
- the parsing must be handled specially.
-
- See https://github.com/juju/version for more info.
- """
- binaryPat = re.compile(r'^(\d{1,9})\.(\d{1,9})(?:\.|-([a-z]+))(\d{1,9})(\.\d{1,9})?-([^-]+)-([^-]+)$') # noqa
-
- def __init__(self, number=None, series=None, arch=None, **unknown_fields):
- '''
- number : Number
- series : str
- arch : str
- '''
- self.number = Number.from_json(number)
- self.series = series
- self.arch = arch
-
- def __repr__(self):
- return '<Binary number={} series={} arch={}>'.format(
- self.number, self.series, self.arch)
-
- def __str__(self):
- return self.serialize()
-
- def __eq__(self, other):
- return (
- isinstance(other, type(self)) and
- other.number == self.number and
- other.series == self.series and
- other.arch == self.arch)
-
- @classmethod
- def from_json(cls, data):
- parsed = None
- if isinstance(data, cls):
- return data
- elif data is None:
- return cls()
- elif isinstance(data, dict):
- parsed = data
- elif isinstance(data, str):
- match = cls.binaryPat.match(data)
- if match:
- parsed = {
- 'number': {
- 'major': match.group(1),
- 'minor': match.group(2),
- 'tag': match.group(3),
- 'patch': match.group(4),
- 'build': (match.group(5)[1:] if match.group(5)
- else 0),
- },
- 'series': match.group(6),
- 'arch': match.group(7),
- }
- if parsed is None:
- raise TypeError('Unable to parse Binary version string: '
- '{}'.format(data))
- d = {}
- for k, v in parsed.items():
- d[cls._toPy.get(k, k)] = v
-
- return cls(**d)
-
- def serialize(self):
- return "{}-{}-{}".format(self.number.serialize(),
- self.series, self.arch)
-
- def to_json(self):
- return self.serialize()
-
-
-class ConfigValue(_definitions.ConfigValue):
- def __repr__(self):
- return '<{} source={} value={}>'.format(type(self).__name__,
- repr(self.source),
- repr(self.value))
-
-
-class Resource(Type):
- _toSchema = {'application': 'application',
- 'charmresource': 'CharmResource',
- 'id_': 'id',
- 'pending_id': 'pending-id',
- 'timestamp': 'timestamp',
- 'username': 'username',
- 'name': 'name',
- 'origin': 'origin'}
- _toPy = {'CharmResource': 'charmresource',
- 'application': 'application',
- 'id': 'id_',
- 'pending-id': 'pending_id',
- 'timestamp': 'timestamp',
- 'username': 'username',
- 'name': 'name',
- 'origin': 'origin'}
-
- def __init__(self, charmresource=None, application=None, id_=None,
- pending_id=None, timestamp=None, username=None, name=None,
- origin=None, **unknown_fields):
- '''
- charmresource : CharmResource
- application : str
- id_ : str
- pending_id : str
- timestamp : str
- username : str
- name: str
- origin : str
- '''
- if charmresource:
- self.charmresource = _client.CharmResource.from_json(charmresource)
- else:
- self.charmresource = None
- self.application = application
- self.id_ = id_
- self.pending_id = pending_id
- self.timestamp = timestamp
- self.username = username
- self.name = name
- self.origin = origin