def __init__(self, resource, backref=None, io="rw", attribute=None, **kwargs): self.reference = ResourceReference(resource) self.attribute = attribute self.backref = backref self.io = io
def __init__(self, resource, attribute=None): self.target_reference = ResourceReference(resource) super(ItemUri, self).__init__(lambda: { "type": "string", "pattern": "^{}\/[^/]+$".format(re.escape(self.target.route_prefix)) }, io="r", attribute=attribute)
def __init__(self, resource, **kwargs): self.target_reference = ResourceReference(resource) def schema(): key_converters = self.target.meta.key_converters response_schema = self.formatter_key.response if len(key_converters) > 1: request_schema = { # "type": [self.formatter_key.matcher_type()] + [nk.matcher_type() for nk in natural_keys], "anyOf": [nk.request for nk in key_converters] } else: request_schema = self.formatter_key.request return response_schema, request_schema super(ToOne, self).__init__(schema, **kwargs)
class Relation(RouteSet, ResourceBound): """ Used to define a relation to another :class:`ModelResource`. """ def __init__(self, resource, backref=None, io="rw", attribute=None, **kwargs): self.reference = ResourceReference(resource) self.attribute = attribute self.backref = backref self.io = io @cached_property def target(self): return self.reference.resolve(self.resource) # FIXME can only be loaded after target is added to API def routes(self): io = self.io rule = '/{}'.format(attribute_to_route_uri(self.attribute)) relation_route = ItemRoute(rule='{}/<{}:target_id>'.format(rule, self.target.meta.id_converter)) relations_route = ItemRoute(rule=rule) if "r" in io: @relations_route.GET def relation_instances(resource, item, page, per_page): return resource.manager.relation_instances(item, self.attribute, self.target, page, per_page) relations_route.request_schema = FieldSet({ "page": Integer(minimum=1, default=1), "per_page": Integer(minimum=1, default=20, # FIXME use API reference maximum=50) }) relations_route.response_schema = RelationInstances(self.target) if "w" in io: @relations_route.POST def relation_add(resource, item, target_item): resource.manager.relation_add(item, self.attribute, self.target, target_item) resource.manager.commit() return target_item relation_add.request_schema = ToOne(self.target) relation_add.response_schema = ToOne(self.target) @relation_route.DELETE def relation_remove(resource, item, target_id): target_item = self.target.manager.read(target_id) resource.manager.relation_remove(item, self.attribute, self.target, target_item) resource.manager.commit() return None, 204 yield relation_route if io: yield relations_route
def __init__(self, resource, patchable=False, **kwargs): self.target_reference = ResourceReference(resource) self.patchable = patchable def schema(): def _response_schema(): if self.resource == self.target: return {"$ref": "#"} return {"$ref": self.target.routes["describedBy"].rule_factory(self.target)} if not not self.patchable: return _response_schema() else: return _response_schema(), self.target.schema.patchable.update super(Inline, self).__init__(schema, **kwargs)
class ItemUri(Raw): """ A string field that formats the url of a resource item; read-only. """ def __init__(self, resource, attribute=None): self.target_reference = ResourceReference(resource) super(ItemUri, self).__init__(lambda: { "type": "string", "pattern": "^{}\/[^/]+$".format(re.escape(self.target.route_prefix)) }, io="r", attribute=attribute) @cached_property def target(self): return self.target_reference.resolve() def format(self, value): return '{}/{}'.format(self.target.route_prefix, value) def converter(self, value): try: endpoint, args = route_from(value, 'GET') except Exception as e: raise e return self.target.manager.id_field.convert(args['id'])
class Inline(Raw, ResourceBound): """ Formats and converts items in a :class:`ModelResource` using the resource's ``schema``. :param resource: a resource reference as in :class:`ToOne` :param bool patchable: whether to allow partial objects """ def __init__(self, resource, patchable=False, **kwargs): self.target_reference = ResourceReference(resource) self.patchable = patchable def schema(): def _response_schema(): if self.resource == self.target: return {"$ref": "#"} return { "$ref": self.target.routes["describedBy"].rule_factory(self.target) } if not self.patchable: return _response_schema() else: return _response_schema(), self.target.schema.patchable.update super(Inline, self).__init__(schema, **kwargs) def rebind(self, resource): if self.target_reference.value == 'self': return self.__class__( 'self', patchable=self.patchable, default=self.default, attribute=self.attribute, nullable=self.nullable, title=self.title, description=self.description, io=self.io, ).bind(resource) else: return self @cached_property def target(self): return self.target_reference.resolve(self.resource) def format(self, item): return self.target.schema.format(item) def convert(self, item, update=False, validate=True): if not validate: raise NotImplementedError() return self.target.schema.convert(item, update=update, patchable=self.patchable)
class Inline(Raw, ResourceBound): """ Formats and converts items in a :class:`ModelResource` using the resource's ``schema``. :param resource: a resource reference as in :class:`ToOne` :param bool patchable: whether to allow partial objects """ def __init__(self, resource, patchable=False, **kwargs): self.target_reference = ResourceReference(resource) self.patchable = patchable def schema(): def _response_schema(): if self.resource == self.target: return {"$ref": "#"} return {"$ref": self.target.routes["describedBy"].rule_factory(self.target)} if not self.patchable: return _response_schema() else: return _response_schema(), self.target.schema.patchable.update super(Inline, self).__init__(schema, **kwargs) def rebind(self, resource): if self.target_reference.value == 'self': return self.__class__( 'self', patchable=self.patchable, default=self.default, attribute=self.attribute, nullable=self.nullable, title=self.title, description=self.description, io=self.io ).bind(resource) else: return self @cached_property def target(self): return self.target_reference.resolve(self.resource) def format(self, item): return self.target.schema.format(item) def convert(self, item, update=False, validate=True): if not validate: raise NotImplementedError() return self.target.schema.convert(item, update=update, patchable=self.patchable)
def __init__(self, resource, patchable=False, **kwargs): self.target_reference = ResourceReference(resource) self.patchable = patchable def schema(): def _response_schema(): if self.resource == self.target: return {"$ref": "#"} return {"$ref": self.resource.routes["describedBy"].rule_factory(self.resource)} if not not self.patchable: return _response_schema() else: return _response_schema(), self.target.schema.patchable.update super(Inline, self).__init__(schema, **kwargs)
def __init__(self, resource, **kwargs): self.target_reference = ResourceReference(resource) def schema(): target = self.target key_converters = self.target.meta.key_converters response_schema = self.formatter_key.response if len(key_converters) > 1: request_schema = { # "type": [self.formatter_key.matcher_type()] + [nk.matcher_type() for nk in natural_keys], "anyOf": [nk.request for nk in key_converters] } else: request_schema = self.formatter_key.request return response_schema, request_schema super(ToOne, self).__init__(schema, **kwargs)
class ItemUri(Raw): """ A string field that formats the url of a resource item; read-only. """ def __init__(self, resource, attribute=None): self.target_reference = ResourceReference(resource) super(ItemUri, self).__init__(lambda: { "type": "string", "pattern": "^{}\/[^/]+$".format(re.escape(self.target.route_prefix)) }, io="r", attribute=attribute) @cached_property def target(self): return self.target_reference.resolve() def format(self, value): return '{}/{}'.format(self.target.route_prefix, value)
class Relation(RouteSet, ResourceBound): """ Used to define a relation to another :class:`ModelResource`. """ def __init__(self, resource, backref=None, io="rw", attribute=None, **kwargs): self.reference = ResourceReference(resource) self.attribute = attribute self.backref = backref self.io = io @cached_property def target(self): return self.reference.resolve(self.resource) # FIXME can only be loaded after target is added to API def routes(self): io = self.io rule = '/{}'.format(attribute_to_route_uri(self.attribute)) relation_route = ItemRoute(rule=rule) relations_route = ItemRoute(rule=rule) if "r" in io: def relation_instances(resource, item, page, per_page): return resource.manager.relation_instances(item, self.attribute, self.target, page, per_page) yield relations_route.for_method('GET', relation_instances, rel=self.attribute, response_schema=RelationInstances(self.target), schema=FieldSet({ "page": Integer(minimum=1, default=1), "per_page": Integer(minimum=1, default=20, # FIXME use API reference maximum=50) })) if "w" in io or "u" in io: def relation_add(resource, item, target_item): resource.manager.relation_add(item, self.attribute, self.target, target_item) resource.manager.commit() return target_item yield relations_route.for_method('POST', relation_add, rel=to_camel_case('add_{}'.format(self.attribute)), response_schema=ToOne(self.target), schema=ToOne(self.target)) def relation_remove(resource, item, target_item): resource.manager.relation_remove(item, self.attribute, self.target, target_item) resource.manager.commit() return None, 204 yield relation_route.for_method('DELETE', relation_remove, rel=to_camel_case('remove_{}'.format(self.attribute)), response_schema=ToOne(self.target), schema=ToOne(self.target))
class ToOne(Raw, ResourceBound): """ Represents references between resources as `json-ref` objects. Resource references can be one of the following: - :class:`Resource` class - a string with a resource name - a string with a module name and class name of a resource - ``"self"`` --- which resolves to the resource this field is bound to :param resource: a resource reference """ def __init__(self, resource, **kwargs): self.target_reference = ResourceReference(resource) def schema(): target = self.target key_converters = self.target.meta.key_converters response_schema = self.formatter_key.response if len(key_converters) > 1: request_schema = { # "type": [self.formatter_key.matcher_type()] + [nk.matcher_type() for nk in natural_keys], "anyOf": [nk.request for nk in key_converters] } else: request_schema = self.formatter_key.request return response_schema, request_schema super(ToOne, self).__init__(schema, **kwargs) def rebind(self, resource): if self.target_reference.value == 'self': return self.__class__( 'self', default=self.default, attribute=self.attribute, nullable=self.nullable, title=self.title, description=self.description, io=self.io ).bind(resource) else: return self @cached_property def target(self): return self.target_reference.resolve(self.resource) @cached_property def formatter_key(self): return self.target.meta.key_converters[0] def formatter(self, item): return self.formatter_key.format(item) def converter(self, value): for python_type, json_type in ( (dict, 'object'), (int, 'integer'), ((list, tuple), 'array'), (six.string_types, 'string')): if isinstance(value, python_type): return self.target.meta.key_converters_by_type[json_type].convert(value)
class ToOne(Raw, ResourceBound): """ Represents references between resources as `json-ref` objects. Resource references can be one of the following: - :class:`Resource` class - a string with a resource name - a string with a module name and class name of a resource - ``"self"`` --- which resolves to the resource this field is bound to :param resource: a resource reference """ def __init__(self, resource, **kwargs): self.target_reference = ResourceReference(resource) def schema(): target = self.target key_converters = self.target.meta.key_converters response_schema = self.formatter_key.response if len(key_converters) > 1: request_schema = { # "type": [self.formatter_key.matcher_type()] + [nk.matcher_type() for nk in natural_keys], "anyOf": [nk.request for nk in key_converters] } else: request_schema = self.formatter_key.request return response_schema, request_schema super(ToOne, self).__init__(schema, **kwargs) def rebind(self, resource): if self.target_reference.value == 'self': return self.__class__('self', default=self.default, attribute=self.attribute, nullable=self.nullable, title=self.title, description=self.description, io=self.io).bind(resource) else: return self @cached_property def target(self): return self.target_reference.resolve(self.resource) @cached_property def formatter_key(self): return self.target.meta.key_converters[0] def formatter(self, item): return self.formatter_key.format(item) def converter(self, value): for python_type, json_type in ((dict, 'object'), (int, 'integer'), ((list, tuple), 'array'), (six.string_types, 'string')): if isinstance(value, python_type): return self.target.meta.key_converters_by_type[ json_type].convert(value)