def action(self, document, keys, params=None, action=None, encoding=None, transform=None): if isinstance(keys, string_types): keys = [keys] # Validate the keys and link parameters. link, link_ancestors = _lookup_link(document, keys) if (action is not None) or (encoding is not None) or (transform is not None): # Handle any explicit overrides. action = link.action if (action is None) else action encoding = link.encoding if (encoding is None) else encoding transform = link.transform if (transform is None) else transform link = Link(link.url, action=action, encoding=encoding, transform=transform, fields=link.fields) # Perform the action, and return a new document. transport = determine_transport(self.transports, link.url) return transport.transition(link, self.decoders, params=params, link_ancestors=link_ancestors)
def reload(self, document): url = _make_absolute(document.url) link = Link(url, action='get') # Perform the action, and return a new document. transport = determine_transport(link.url, transports=self.transports) return transport.transition(link, decoders=self.decoders)
def get(self, url, force_codec=False): link = Link(url, action='get') # Perform the action, and return a new document. transport = determine_transport(self.transports, link.url) return transport.transition(link, self.decoders, force_codec=force_codec)
def _primative_to_document(data, base_url=None): """ Take Python primatives as returned from parsing JSON content, and return a Core API document. """ if isinstance(data, dict) and data.get('_type') == 'document': # Document meta = _get_dict(data, '_meta') url = _get_string(meta, 'url') url = urlparse.urljoin(base_url, url) title = _get_string(meta, 'title') content = _get_content(data, base_url=url) return Document(url=url, title=title, content=content) if isinstance(data, dict) and data.get('_type') == 'error': # Error meta = _get_dict(data, '_meta') title = _get_string(meta, 'title') content = _get_content(data, base_url=base_url) return Error(title=title, content=content) elif isinstance(data, dict) and data.get('_type') == 'link': # Link url = _get_string(data, 'url') url = urlparse.urljoin(base_url, url) action = _get_string(data, 'action') encoding = _get_string(data, 'encoding') transform = _get_string(data, 'transform') description = _get_string(data, 'description') fields = _get_list(data, 'fields') fields = [ Field(name=_get_string(item, 'name'), required=_get_bool(item, 'required'), location=_get_string(item, 'location'), type=_get_string(item, 'type'), description=_get_string(item, 'description')) for item in fields if isinstance(item, dict) ] return Link(url=url, action=action, encoding=encoding, transform=transform, description=description, fields=fields) elif isinstance(data, dict): # Map content = _get_content(data, base_url=base_url) return Object(content) elif isinstance(data, list): # Array content = [_primative_to_document(item, base_url) for item in data] return Array(content) # String, Integer, Number, Boolean, null. return data
def action( self, document, keys, params=None, validate=True, overrides=None, action=None, encoding=None, transform=None, ): if (action is not None) or (encoding is not None) or (transform is not None): # Fallback for v1.x overrides. # Will be removed at some point, most likely in a 2.1 release. if overrides is None: overrides = {} if action is not None: overrides["action"] = action if encoding is not None: overrides["encoding"] = encoding if transform is not None: overrides["transform"] = transform if isinstance(keys, string_types): keys = [keys] if params is None: params = {} # Validate the keys and link parameters. link, link_ancestors = _lookup_link(document, keys) if validate: _validate_parameters(link, params) if overrides: # Handle any explicit overrides. url = overrides.get("url", link.url) action = overrides.get("action", link.action) encoding = overrides.get("encoding", link.encoding) transform = overrides.get("transform", link.transform) fields = overrides.get("fields", link.fields) link = Link( url, action=action, encoding=encoding, transform=transform, fields=fields, ) # Perform the action, and return a new document. transport = determine_transport(self.transports, link.url) return transport.transition(link, self.decoders, params=params, link_ancestors=link_ancestors)
def doc(): return Document(url='http://example.org/', title='Example', content={ 'integer': 123, 'dict': { 'key': 'value' }, 'list': [1, 2, 3], 'link': Link(url='http://example.org/', fields=[Field(name='example')]), 'nested': { 'child': Link(url='http://example.org/123') }, '_type': 'needs escaping' })
def _parse_link(data, base_url=None): url = _get_string(data, 'href') url = urlparse.urljoin(base_url, url) if _get_bool(data, 'templated'): fields = [ Field(name, location='path') for name in uritemplate.variables(url) ] else: fields = None return Link(url=url, fields=fields)
def get(self, url, format=None, force_codec=False): link = Link(url, action='get') decoders = self.decoders if format: decoders = [decoder for decoder in self.decoders if decoder.format == format] if not decoders: raise ValueError("No decoder available with format='%s'" % format) # Perform the action, and return a new document. transport = determine_transport(self.transports, link.url) return transport.transition(link, decoders, force_codec=force_codec)
def _get_content(data, base_url, ref): content = {} links = _get_list(data, 'links') properties = _get_dict(data, 'properties') if properties: for key, value in properties.items(): if not isinstance(value, dict): continue if list(value.keys()) == ['$ref']: value = _dereference(value['$ref'], ref) sub_content = _get_content(value, base_url, ref) if sub_content: content[key] = sub_content if links: for link in get_dicts(links): rel = _get_string(link, 'rel') if rel: href = _get_string(link, 'href') method = _get_string(link, 'method') schema = _get_dict(link, 'schema') schema_type = _get_list(schema, 'type') schema_properties = _get_dict(schema, 'properties') schema_required = _get_list(schema, 'required') fields = [] url = urlparse.urljoin(base_url, href) templated = uritemplate.variables(url) for item in templated: orig = item if item.startswith('(') and item.endswith(')'): item = unquote(item.strip('(').rstrip(')')) if item.startswith('#/'): components = [ component for component in item.strip('#/').split('/') if component != 'definitions' ] item = '_'.join(components).replace('-', '_') url = url.replace(orig, item) fields.append( Field(name=item, location='path', required=True)) if schema_type == ['object'] and schema_properties: fields += [ Field(name=key, required=(key in schema_required)) for key in schema_properties.keys() ] if rel == 'self': rel = 'read' content[rel] = Link(url=url, action=method, fields=fields) return content
def test_link_encodings(json_codec): doc = Document( content={ 'link': Link(action='post', transform='inplace', fields=[ 'optional', Field('required', required=True, location='path') ]) }) bytes = json_codec.encode(doc, indent=True) assert bytes == b"""{
def doc(): return Document(url='http://example.org/', title='Example', content={ 'integer': 123, 'dict': { 'key': 'value' }, 'list': [1, 2, 3], 'link': Link(url='http://example.org/', fields=[ Field(name='noschema'), Field(name='string_example', schema=String()), Field(name='enum_example', schema=Enum(['a', 'b', 'c'])), ]), 'nested': { 'child': Link(url='http://example.org/123') }, '_type': 'needs escaping' })
def get(self, url, format=None, force_codec=False): link = Link(url, action="get") decoders = self.decoders if format: force_codec = True decoders = [ decoder for decoder in self.decoders if decoder.format == format ] if not decoders: installed_codecs = get_installed_codecs() if format in installed_codecs: decoders = [installed_codecs[format]] else: raise ValueError("No decoder available with format='%s'" % format) # Perform the action, and return a new document. transport = determine_transport(self.transports, link.url) return transport.transition(link, decoders, force_codec=force_codec)
def test_invalid_link_fields_ignored(json_codec): doc = json_codec.decode( b'{"_type": "document", "link": {"_type": "link", "fields": 1}}') assert doc == Document(content={"link": Link()})
def _primitive_to_document(data, base_url=None): """ Take Python primitives as returned from parsing JSON content, and return a Core API document. """ if isinstance(data, dict) and data.get("_type") == "document": # Document meta = _get_dict(data, "_meta") url = _get_string(meta, "url") url = urlparse.urljoin(base_url, url) title = _get_string(meta, "title") description = _get_string(meta, "description") content = _get_content(data, base_url=url) return Document( url=url, title=title, description=description, media_type="application/coreapi+json", content=content, ) if isinstance(data, dict) and data.get("_type") == "error": # Error meta = _get_dict(data, "_meta") title = _get_string(meta, "title") content = _get_content(data, base_url=base_url) return Error(title=title, content=content) elif isinstance(data, dict) and data.get("_type") == "link": # Link url = _get_string(data, "url") url = urlparse.urljoin(base_url, url) action = _get_string(data, "action") encoding = _get_string(data, "encoding") transform = _get_string(data, "transform") title = _get_string(data, "title") description = _get_string(data, "description") fields = _get_list(data, "fields") fields = [ Field( name=_get_string(item, "name"), required=_get_bool(item, "required"), location=_get_string(item, "location"), schema=_get_schema(item, "schema"), ) for item in fields if isinstance(item, dict) ] return Link( url=url, action=action, encoding=encoding, transform=transform, title=title, description=description, fields=fields, ) elif isinstance(data, dict): # Map content = _get_content(data, base_url=base_url) return Object(content) elif isinstance(data, list): # Array content = [_primitive_to_document(item, base_url) for item in data] return Array(content) # String, Integer, Number, Boolean, null. return data
def test_invalid_link_url_ignored(json_codec): doc = json_codec.load( b'{"_type": "document", "link": {"_type": "link", "url": 1}}') assert doc == Document(content={"link": Link()})