diff --git a/coreapi/client.py b/coreapi/client.py index 00b0057..b005eae 100644 --- a/coreapi/client.py +++ b/coreapi/client.py @@ -1,19 +1,15 @@ from coreapi import codecs, exceptions, transports from coreapi.compat import string_types -from coreapi.document import Document, Link +from coreapi.document import Link from coreapi.utils import determine_transport, get_installed_codecs -import collections import itypes -LinkAncestor = collections.namedtuple('LinkAncestor', ['document', 'keys']) - - def _lookup_link(document, keys): """ Validates that keys looking up a link are correct. - Returns a two-tuple of (link, link_ancestors). + Returns the Link. """ if not isinstance(keys, (list, tuple)): msg = "'keys' must be a list of strings or ints." @@ -28,7 +24,6 @@ def _lookup_link(document, keys): # 'node' is the link we're calling the action for. # 'document_keys' is the list of keys to the link's parent document. node = document - link_ancestors = [LinkAncestor(document=document, keys=[])] for idx, key in enumerate(keys): try: node = node[key] @@ -36,9 +31,6 @@ def _lookup_link(document, keys): index_string = ''.join('[%s]' % repr(key).strip('u') for key in keys) msg = 'Index %s did not reference a link. Key %s was not found.' raise exceptions.LinkLookupError(msg % (index_string, repr(key).strip('u'))) - if isinstance(node, Document): - ancestor = LinkAncestor(document=node, keys=keys[:idx + 1]) - link_ancestors.append(ancestor) # Ensure that we've correctly indexed into a link. if not isinstance(node, Link): @@ -48,7 +40,7 @@ def _lookup_link(document, keys): msg % (index_string, type(node).__name__) ) - return (node, link_ancestors) + return node def _validate_parameters(link, parameters): @@ -140,8 +132,8 @@ def reload(self, document, format=None, force_codec=False): return self.get(document.url, format=format, force_codec=force_codec) 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): + action=None, encoding=None): + if (action is not None) or (encoding 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: @@ -150,8 +142,6 @@ def action(self, document, keys, params=None, validate=True, overrides=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] @@ -160,7 +150,7 @@ def action(self, document, keys, params=None, validate=True, overrides=None, params = {} # Validate the keys and link parameters. - link, link_ancestors = _lookup_link(document, keys) + link = _lookup_link(document, keys) if validate: _validate_parameters(link, params) @@ -169,10 +159,9 @@ def action(self, document, keys, params=None, validate=True, overrides=None, 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) + link = Link(url, action=action, encoding=encoding, 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) + return transport.transition(link, self.decoders, params=params) diff --git a/coreapi/codecs/corejson.py b/coreapi/codecs/corejson.py index f025533..92facc4 100644 --- a/coreapi/codecs/corejson.py +++ b/coreapi/codecs/corejson.py @@ -196,8 +196,6 @@ def _document_to_primitive(node, base_url=None): ret['action'] = node.action if node.encoding: ret['encoding'] = node.encoding - if node.transform: - ret['transform'] = node.transform if node.title: ret['title'] = node.title if node.description: @@ -264,7 +262,6 @@ def _primitive_to_document(data, base_url=None): 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') @@ -278,7 +275,7 @@ def _primitive_to_document(data, base_url=None): for item in fields if isinstance(item, dict) ] return Link( - url=url, action=action, encoding=encoding, transform=transform, + url=url, action=action, encoding=encoding, title=title, description=description, fields=fields ) diff --git a/coreapi/codecs/python.py b/coreapi/codecs/python.py index 6265a28..6feec4e 100644 --- a/coreapi/codecs/python.py +++ b/coreapi/codecs/python.py @@ -42,8 +42,6 @@ def _to_repr(node): args += ", action=%s" % repr(node.action) if node.encoding: args += ", encoding=%s" % repr(node.encoding) - if node.transform: - args += ", transform=%s" % repr(node.transform) if node.description: args += ", description=%s" % repr(node.description) if node.fields: diff --git a/coreapi/document.py b/coreapi/document.py index c6c9ceb..dd498dc 100644 --- a/coreapi/document.py +++ b/coreapi/document.py @@ -187,15 +187,13 @@ class Link(itypes.Object): """ Links represent the actions that a client may perform. """ - def __init__(self, url=None, action=None, encoding=None, transform=None, title=None, description=None, fields=None): + def __init__(self, url=None, action=None, encoding=None, title=None, description=None, fields=None): if (url is not None) and (not isinstance(url, string_types)): raise TypeError("Argument 'url' must be a string.") if (action is not None) and (not isinstance(action, string_types)): raise TypeError("Argument 'action' must be a string.") if (encoding is not None) and (not isinstance(encoding, string_types)): raise TypeError("Argument 'encoding' must be a string.") - if (transform is not None) and (not isinstance(transform, string_types)): - raise TypeError("Argument 'transform' must be a string.") if (title is not None) and (not isinstance(title, string_types)): raise TypeError("Argument 'title' must be a string.") if (description is not None) and (not isinstance(description, string_types)): @@ -211,7 +209,6 @@ def __init__(self, url=None, action=None, encoding=None, transform=None, title=N self._url = '' if (url is None) else url self._action = '' if (action is None) else action self._encoding = '' if (encoding is None) else encoding - self._transform = '' if (transform is None) else transform self._title = '' if (title is None) else title self._description = '' if (description is None) else description self._fields = () if (fields is None) else tuple([ @@ -231,10 +228,6 @@ def action(self): def encoding(self): return self._encoding - @property - def transform(self): - return self._transform - @property def title(self): return self._title @@ -253,7 +246,6 @@ def __eq__(self, other): self.url == other.url and self.action == other.action and self.encoding == other.encoding and - self.transform == other.transform and self.description == other.description and sorted(self.fields, key=lambda f: f.name) == sorted(other.fields, key=lambda f: f.name) ) diff --git a/coreapi/transports/http.py b/coreapi/transports/http.py index 7338e61..5b78fc7 100644 --- a/coreapi/transports/http.py +++ b/coreapi/transports/http.py @@ -305,32 +305,6 @@ def _decode_result(response, decoders, force_codec=False): return result -def _handle_inplace_replacements(document, link, link_ancestors): - """ - Given a new document, and the link/ancestors it was created, - determine if we should: - - * Make an inline replacement and then return the modified document tree. - * Return the new document as-is. - """ - if not link.transform: - if link.action.lower() in ('put', 'patch', 'delete'): - transform = 'inplace' - else: - transform = 'new' - else: - transform = link.transform - - if transform == 'inplace': - root = link_ancestors[0].document - keys_to_link_parent = link_ancestors[-1].keys - if document is None: - return root.delete_in(keys_to_link_parent) - return root.set_in(keys_to_link_parent, document) - - return document - - class HTTPTransport(BaseTransport): schemes = ['http', 'https'] @@ -366,7 +340,7 @@ def __init__(self, credentials=None, headers=None, auth=None, session=None, requ def headers(self): return self._headers - def transition(self, link, decoders, params=None, link_ancestors=None, force_codec=False): + def transition(self, link, decoders, params=None, force_codec=False): session = self._session method = _get_method(link.action) encoding = _get_encoding(link.encoding) @@ -380,9 +354,6 @@ def transition(self, link, decoders, params=None, link_ancestors=None, force_cod response = session.send(request, **settings) result = _decode_result(response, decoders, force_codec) - if isinstance(result, Document) and link_ancestors: - result = _handle_inplace_replacements(result, link, link_ancestors) - if isinstance(result, Error): raise exceptions.ErrorMessage(result) diff --git a/tests/test_codecs.py b/tests/test_codecs.py index 32458cd..2475293 100644 --- a/tests/test_codecs.py +++ b/tests/test_codecs.py @@ -194,7 +194,6 @@ def test_link_encodings(json_codec): doc = Document(content={ 'link': Link( action='post', - transform='inplace', fields=['optional', Field('required', required=True, location='path')] ) }) @@ -204,7 +203,6 @@ def test_link_encodings(json_codec): "link": { "_type": "link", "action": "post", - "transform": "inplace", "fields": [ { "name": "optional" diff --git a/tests/test_document.py b/tests/test_document.py index 6b06de7..c985fa9 100644 --- a/tests/test_document.py +++ b/tests/test_document.py @@ -17,7 +17,6 @@ def doc(): 'link': Link( url='/', action='post', - transform='inplace', fields=['optional', Field('required', required=True, location='path')] ), 'nested': {'child': Link(url='/123')} @@ -224,7 +223,7 @@ def test_document_repr(doc): "'integer': 123, " "'list': [1, 2, 3], " "'nested': {'child': Link(url='/123')}, " - "'link': Link(url='/', action='post', transform='inplace', " + "'link': Link(url='/', action='post', " "fields=['optional', Field('required', required=True, location='path')])" "})" ) @@ -345,7 +344,6 @@ def test_document_equality(doc): 'link': Link( url='/', action='post', - transform='inplace', fields=['optional', Field('required', required=True, location='path')] ), 'nested': {'child': Link(url='/123')} @@ -424,11 +422,6 @@ def test_link_action_must_be_string(): Link(action=123) -def test_link_transform_must_be_string(): - with pytest.raises(TypeError): - Link(transform=123) - - def test_link_fields_must_be_list(): with pytest.raises(TypeError): Link(fields=123) diff --git a/tests/test_transitions.py b/tests/test_transitions.py index a31ba13..28e2ad0 100644 --- a/tests/test_transitions.py +++ b/tests/test_transitions.py @@ -1,24 +1,14 @@ # coding: utf-8 from coreapi import Document, Link, Client from coreapi.transports import HTTPTransport -from coreapi.transports.http import _handle_inplace_replacements import pytest class MockTransport(HTTPTransport): schemes = ['mock'] - def transition(self, link, decoders, params=None, link_ancestors=None): - if link.action == 'get': - document = Document(title='new', content={'new': 123}) - elif link.action in ('put', 'post'): - if params is None: - params = {} - document = Document(title='new', content={'new': 123, 'foo': params.get('foo')}) - else: - document = None - - return _handle_inplace_replacements(document, link, link_ancestors) + def transition(self, link, decoders, params=None): + return {'action': link.action, 'params': params} client = Client(transports=[MockTransport()]) @@ -29,7 +19,6 @@ def doc(): return Document(title='original', content={ 'nested': Document(content={ 'follow': Link(url='mock://example.com', action='get'), - 'action': Link(url='mock://example.com', action='post', transform='inplace', fields=['foo']), 'create': Link(url='mock://example.com', action='post', fields=['foo']), 'update': Link(url='mock://example.com', action='put', fields=['foo']), 'delete': Link(url='mock://example.com', action='delete') @@ -40,44 +29,27 @@ def doc(): # Test valid transitions. def test_get(doc): - new = client.action(doc, ['nested', 'follow']) - assert new == {'new': 123} - assert new.title == 'new' - - -def test_inline_post(doc): - new = client.action(doc, ['nested', 'action'], params={'foo': 123}) - assert new == {'nested': {'new': 123, 'foo': 123}} - assert new.title == 'original' + data = client.action(doc, ['nested', 'follow']) + assert data == {'action': 'get', 'params': {}} def test_post(doc): - new = client.action(doc, ['nested', 'create'], params={'foo': 456}) - assert new == {'new': 123, 'foo': 456} - assert new.title == 'new' + data = client.action(doc, ['nested', 'create'], params={'foo': 456}) + assert data == {'action': 'post', 'params': {'foo': 456}} def test_put(doc): - new = client.action(doc, ['nested', 'update'], params={'foo': 789}) - assert new == {'nested': {'new': 123, 'foo': 789}} - assert new.title == 'original' + data = client.action(doc, ['nested', 'update'], params={'foo': 789}) + assert data == {'action': 'put', 'params': {'foo': 789}} def test_delete(doc): - new = client.action(doc, ['nested', 'delete']) - assert new == {} - assert new.title == 'original' + data = client.action(doc, ['nested', 'delete']) + assert data == {'action': 'delete', 'params': {}} # Test overrides def test_override_action(doc): - new = client.action(doc, ['nested', 'follow'], overrides={'action': 'put'}) - assert new == {'nested': {'new': 123, 'foo': None}} - assert new.title == 'original' - - -def test_override_transform(doc): - new = client.action(doc, ['nested', 'update'], params={'foo': 456}, overrides={'transform': 'new'}) - assert new == {'new': 123, 'foo': 456} - assert new.title == 'new' + data = client.action(doc, ['nested', 'follow'], overrides={'action': 'put'}) + assert data == {'action': 'put', 'params': {}}