Commit 0b005a39 by Simon János

actually the whole code has been refactored

parent eed8e4b7
import copy
import json
import uuid
from enum import Enum
from voluptuous import Schema, Invalid, MultipleInvalid
from voluptuous import Schema, Invalid, MultipleInvalid, Any, ALLOW_EXTRA, PREVENT_EXTRA
class Resource(object):
DEFAULT_ID_LENGTH = 8
ADDITIONAL_SCHEMA = {}
def __new__(cls, *args, **kwargs):
attributes = cls.__attributes_from_dict(args[0] if len(args) else kwargs)
resource_type = attributes['type'].value
if resource_type is Resource:
raise InvalidResourceException('Resource class is abstract')
cls.__validate_attributes(attributes, cls.__schema(resource_type, extend=True))
instance = super(Resource, resource_type).__new__(resource_type)
instance._attributes = attributes # pylint: disable=protected-access
return instance
def __init__(self, *args, **kwargs):
if len(args):
resource = args[0]
if isinstance(resource, Resource):
self.__id = resource.id
self.__type = Resource.Type[resource.type]
else:
self.__attributes_from_dict(resource)
else:
self.__attributes_from_dict(kwargs)
def __attributes_from_dict(self, attributes):
schema = Schema({
'id': str,
'type': Resource.Type.validate
})
@classmethod
def __attributes_from_dict(cls, attributes):
cls.__validate_attributes(attributes, cls.__schema(extend=False))
attributes = copy.deepcopy(attributes)
attributes['id'] = attributes.get('id', Resource.__generate_random_id())
attributes['type'] = ResourceType.validate(attributes.get('type', cls))
return attributes
@classmethod
def __validate_attributes(cls, attributes, schema):
try:
schema(attributes)
self.__id = attributes.get('id', Resource._random_id())
self.__type = Resource.Type[attributes.get('type', 'null')]
except MultipleInvalid as invalid:
raise InvalidResourceException(invalid)
@property
def id(self):
return self.__id
@classmethod
def __schema(cls, resource_type=None, extend=False):
try:
string_validator = Any(str, unicode)
except NameError:
string_validator = Any(str)
schema = Schema(schema={'id': string_validator, 'type': ResourceType.validate}, extra=ALLOW_EXTRA)
if extend:
additional = resource_type.ADDITIONAL_SCHEMA if resource_type else cls.ADDITIONAL_SCHEMA
schema = schema.extend(additional, extra=PREVENT_EXTRA)
return schema
@property
def type(self):
return self.__type.name
return str(self._attributes['type'])
def __getattr__(self, item):
try:
return self._attributes[item]
except KeyError:
raise AttributeError('Attribute (%s) is not set on resource')
@staticmethod
def _random_id():
def __generate_random_id():
return uuid.uuid4().hex[:Resource.DEFAULT_ID_LENGTH]
def __eq__(self, other):
return isinstance(other, Resource) and \
self.id == other.id and \
self.type == other.type
try:
for attr, other_value in other.items():
value = self._attributes.get(attr)
if value is None or value != other_value:
return False
return True
except AttributeError:
return False
def __repr__(self):
return "%s(%s)" % (self.__class__.__name__, self.id)
return json.dumps(self, default=Resource.json_encoder)
def __hash__(self):
return hash(self.__repr__())
def __iter__(self):
return self._attributes.__iter__()
class Type(Enum):
null = 0
instance = 1
def keys(self):
return self._attributes.keys()
@classmethod
def validate(cls, value):
try:
cls[value]
except KeyError:
raise Invalid('The given resource type (%s) is not valid' % value)
return True
def values(self):
return self._attributes.values()
def items(self):
return self._attributes.items()
class Instance(Resource):
def __init__(self, *args, **kwargs):
kwargs['type'] = Resource.Type.instance.name
super(Instance, self).__init__(*args, **kwargs)
def __getitem__(self, item):
return self._attributes[item]
def __add__(self, other):
return ResourceGroup(resources=[self, other])
@staticmethod
def json_encoder(data):
if isinstance(data, ResourceType):
return str(data)
return dict(data)
class ResourceGroup(Resource):
ADDITIONAL_SCHEMA = {
'resources': Any(list, set, tuple)
}
def __init__(self, *_, **__):
self.__resources = {}
if 'resources' in self._attributes.keys():
for resource in self._attributes['resources']:
self.add(resource)
self._attributes['resources'] = self.resources
def add(self, resource):
if not isinstance(resource, Resource):
try:
resource = Resource(resource)
except InvalidResourceException:
raise InvalidResourceException('ResourceGroup can only store resources')
self.__resources[resource.id] = resource
class ResourceGroup(object):
def __init__(self, *args):
self.__resources = set()
if len(args):
for argument in args:
def remove(self, resource):
try:
self.__iadd__(argument)
del self.__resources[Resource(resource).id]
except InvalidResourceException:
for resource in argument:
self.__iadd__(resource)
del self.__resources[resource.id]
@property
def resources(self):
return list(self.__resources)
return list(self.__resources.values())
def __add__(self, other):
if isinstance(other, dict):
return ResourceGroup(Resource(other), *self.resources)
if isinstance(other, Resource):
return ResourceGroup(other, *self.resources)
if isinstance(other, ResourceGroup):
resources = other.resources + self.resources
return ResourceGroup(*resources)
raise InvalidResourceException()
def __iadd__(self, other):
if isinstance(other, dict):
self.__resources.add(Resource(other))
return self
if isinstance(other, Resource):
self.__resources.add(other)
return self
if isinstance(other, ResourceGroup):
self.__resources.union(other.resources)
return self
raise InvalidResourceException()
def __iter__(self):
return self.__resources.__iter__()
class Instance(Resource):
ADDITIONAL_SCHEMA = {
'number_of_cores': int
}
def __eq__(self, other):
return self.__resources == set(other.resources)
class ResourceType(Enum):
null = Resource
group = ResourceGroup
instance = Instance
@classmethod
def validate(cls, value):
if isinstance(value, cls):
return value
try:
return cls[value]
except KeyError:
return cls(value)
except ValueError:
raise Invalid('The given resource type (%s) is not valid' % value)
def __str__(self):
return str(self.name)
def __repr__(self):
return '%s(%s)' % (self.__class__.__name__, str(self))
class InvalidResourceException(Exception):
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment