From 016c2f729265dcc12fc66b287aa030912541e77b Mon Sep 17 00:00:00 2001 From: Kelsey Morris Date: Wed, 15 Jun 2016 10:12:50 -0700 Subject: [PATCH 01/14] Add Event class --- boxsdk/object/base_object.py | 1 + boxsdk/object/event.py | 21 +++++++++++++++++++++ boxsdk/object/events.py | 9 ++++++--- developer_setup.py | 20 ++++++++++++++++++++ test/functional/test_events.py | 2 ++ test/unit/object/test_event.py | 23 +++++++++++++++++++++++ test/unit/object/test_events.py | 24 ++++++++++++++++++++++-- 7 files changed, 95 insertions(+), 5 deletions(-) create mode 100644 boxsdk/object/event.py create mode 100644 developer_setup.py create mode 100644 test/unit/object/test_event.py diff --git a/boxsdk/object/base_object.py b/boxsdk/object/base_object.py index 3fe1d8b6b..88002be0d 100644 --- a/boxsdk/object/base_object.py +++ b/boxsdk/object/base_object.py @@ -21,6 +21,7 @@ def __init__(cls, name, bases, attrs): super(ObjectMeta, cls).__init__(name, bases, attrs) item_type = attrs.get('_item_type', None) if item_type is not None: + print "registering " + item_type Translator().register(item_type, cls) diff --git a/boxsdk/object/event.py b/boxsdk/object/event.py new file mode 100644 index 000000000..145117e67 --- /dev/null +++ b/boxsdk/object/event.py @@ -0,0 +1,21 @@ +# coding: utf-8 + +from __future__ import unicode_literals + +from boxsdk.object.base_object import BaseObject + + +class Event(BaseObject): + """Represents a single Box event""" + + _item_type = 'event' + + @property + def get_url(self, *args): + """ + Base class override. + Disallow this method for this subclass, should not access Event by event_id. + """ + raise AttributeError("'Event' class has no method 'get_url'") + + diff --git a/boxsdk/object/events.py b/boxsdk/object/events.py index dbb321f76..61b016e68 100644 --- a/boxsdk/object/events.py +++ b/boxsdk/object/events.py @@ -9,6 +9,7 @@ from boxsdk.util.enum import ExtendableEnumMeta from boxsdk.util.lru_cache import LRUCache from boxsdk.util.text_enum import TextEnum +from boxsdk.util.translator import Translator # pylint:disable=too-many-ancestors @@ -79,8 +80,7 @@ def get_events(self, limit=100, stream_position=0, stream_type=UserEventsStreamT :type stream_type: :enum:`EventsStreamType` :returns: - JSON response from the Box /events endpoint. Contains the next stream position to use for the next call, - along with some number of events. + Dictionary containing the next stream position along with a list of some number of events. :rtype: `dict` """ @@ -91,7 +91,10 @@ def get_events(self, limit=100, stream_position=0, stream_type=UserEventsStreamT 'stream_type': stream_type, } box_response = self._session.get(url, params=params) - return box_response.json() + response = box_response.json().copy() + if 'entries' in response: + response['entries'] = [Translator().translate(item['type'])(self._session, item['event_id'], item) for item in response['entries']] + return response def get_latest_stream_position(self, stream_type=UserEventsStreamType.ALL): """ diff --git a/developer_setup.py b/developer_setup.py new file mode 100644 index 000000000..67abb8bae --- /dev/null +++ b/developer_setup.py @@ -0,0 +1,20 @@ +from boxsdk.auth.developer_token_auth import DeveloperTokenAuth + +from boxsdk.client.development_client import DevelopmentClient +from boxsdk.client.developer_token_client import DeveloperTokenClient +from boxsdk.client.logging_client import LoggingClient + +from boxsdk.session.box_session import BoxSession +from boxsdk.network.default_network import DefaultNetwork +from boxsdk.object.events import Events + +oauth = DeveloperTokenAuth() + +# Input developer token here + +client = DevelopmentClient() + +# Input developer token here + +box_session = BoxSession(oauth, DefaultNetwork()) +events = Events(box_session) diff --git a/test/functional/test_events.py b/test/functional/test_events.py index b0ccd4989..590682de1 100644 --- a/test/functional/test_events.py +++ b/test/functional/test_events.py @@ -8,6 +8,7 @@ import requests from boxsdk.object.folder import FolderSyncState +from boxsdk.object.event import Event as BoxEvent @pytest.fixture @@ -36,6 +37,7 @@ def helper(get_item, event_type, stream_position=0): assert event['event_type'] == event_type assert event['source']['name'] == item.name assert event['source']['id'] == item.id + assert isinstance(event, BoxEvent) return helper diff --git a/test/unit/object/test_event.py b/test/unit/object/test_event.py new file mode 100644 index 000000000..9a978a4ea --- /dev/null +++ b/test/unit/object/test_event.py @@ -0,0 +1,23 @@ +# coding: utf-8 + +from __future__ import unicode_literals + +from mock import Mock +import pytest + +from boxsdk.object.event import Event + + +def test_init_event(mock_box_session): + event = Event(mock_box_session, "f82c3ba03e41f7e8a7608363cc6c0390183c3f83", { + "type": "event", + "event_id": "f82c3ba03e41f7e8a7608363cc6c0390183c3f83", + "source": { + "type": "folder", + "id": "11446498", + } + }) + assert event['type'] == 'event' + assert event._item_type == 'event' + with pytest.raises(AttributeError): + event.get_url() diff --git a/test/unit/object/test_events.py b/test/unit/object/test_events.py index bf456876e..41b3ecad4 100644 --- a/test/unit/object/test_events.py +++ b/test/unit/object/test_events.py @@ -13,6 +13,7 @@ from boxsdk.network.default_network import DefaultNetworkResponse from boxsdk.object.events import Events, EventsStreamType, UserEventsStreamType +from boxsdk.object.event import Event from boxsdk.session.box_session import BoxResponse from boxsdk.util.ordered_dict import OrderedDict @@ -180,6 +181,18 @@ def mock_event(): } +@pytest.fixture() +def mock_event_object(mock_box_session): + return Event(mock_box_session, "f82c3ba03e41f7e8a7608363cc6c0390183c3f83", { + "type": "event", + "event_id": "f82c3ba03e41f7e8a7608363cc6c0390183c3f83", + "source": { + "type": "folder", + "id": "11446498", + } + }) + + @pytest.fixture() def events_response(initial_stream_position, mock_event, make_mock_box_request): # pylint:disable=redefined-outer-name @@ -195,6 +208,7 @@ def test_get_events( events_response, stream_type_kwargs, expected_stream_type_params, + mock_event_object ): # pylint:disable=redefined-outer-name expected_url = test_events.get_url() @@ -205,6 +219,12 @@ def test_get_events( expected_url, params=dict(limit=100, stream_position=0, **expected_stream_type_params), ) + event_entries = events['entries'] + assert len(event_entries) == len(events_response.json.return_value['entries']) + if len(event_entries): + event = event_entries[0] + assert isinstance(event, Event) + assert event.event_id == mock_event_object['event_id'] def test_get_long_poll_options( @@ -234,7 +254,7 @@ def test_generate_events_with_long_polling( new_change_long_poll_response, reconnect_long_poll_response, max_retries_long_poll_response, - mock_event, + mock_event_object, stream_type_kwargs, expected_stream_type, expected_stream_type_params, @@ -253,7 +273,7 @@ def test_generate_events_with_long_polling( empty_events_response, ] events = test_events.generate_events_with_long_polling(**stream_type_kwargs) - assert next(events) == mock_event + assert next(events) == mock_event_object with pytest.raises(StopIteration): next(events) events.close() From 64d04f9567f4aede1be68b2aacff6b0f50715b45 Mon Sep 17 00:00:00 2001 From: Kelsey Morris Date: Wed, 15 Jun 2016 10:13:52 -0700 Subject: [PATCH 02/14] Add Event class --- developer_setup.py | 20 -------------------- 1 file changed, 20 deletions(-) delete mode 100644 developer_setup.py diff --git a/developer_setup.py b/developer_setup.py deleted file mode 100644 index 67abb8bae..000000000 --- a/developer_setup.py +++ /dev/null @@ -1,20 +0,0 @@ -from boxsdk.auth.developer_token_auth import DeveloperTokenAuth - -from boxsdk.client.development_client import DevelopmentClient -from boxsdk.client.developer_token_client import DeveloperTokenClient -from boxsdk.client.logging_client import LoggingClient - -from boxsdk.session.box_session import BoxSession -from boxsdk.network.default_network import DefaultNetwork -from boxsdk.object.events import Events - -oauth = DeveloperTokenAuth() - -# Input developer token here - -client = DevelopmentClient() - -# Input developer token here - -box_session = BoxSession(oauth, DefaultNetwork()) -events = Events(box_session) From f834121b933216dc12f46938d05ae692258dce44 Mon Sep 17 00:00:00 2001 From: Kelsey Morris Date: Thu, 16 Jun 2016 08:44:35 -0700 Subject: [PATCH 03/14] Remove print statement --- boxsdk/object/base_object.py | 1 - 1 file changed, 1 deletion(-) diff --git a/boxsdk/object/base_object.py b/boxsdk/object/base_object.py index 88002be0d..3fe1d8b6b 100644 --- a/boxsdk/object/base_object.py +++ b/boxsdk/object/base_object.py @@ -21,7 +21,6 @@ def __init__(cls, name, bases, attrs): super(ObjectMeta, cls).__init__(name, bases, attrs) item_type = attrs.get('_item_type', None) if item_type is not None: - print "registering " + item_type Translator().register(item_type, cls) From 7f87500235a32ade61b13419a2bc8f0733bd5d06 Mon Sep 17 00:00:00 2001 From: Kelsey Morris Date: Thu, 16 Jun 2016 09:04:07 -0700 Subject: [PATCH 04/14] Conform to pep8 rules --- boxsdk/object/event.py | 2 -- test/unit/object/test_event.py | 4 +--- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/boxsdk/object/event.py b/boxsdk/object/event.py index 145117e67..e98936aa8 100644 --- a/boxsdk/object/event.py +++ b/boxsdk/object/event.py @@ -17,5 +17,3 @@ def get_url(self, *args): Disallow this method for this subclass, should not access Event by event_id. """ raise AttributeError("'Event' class has no method 'get_url'") - - diff --git a/test/unit/object/test_event.py b/test/unit/object/test_event.py index 9a978a4ea..275d4e159 100644 --- a/test/unit/object/test_event.py +++ b/test/unit/object/test_event.py @@ -2,7 +2,6 @@ from __future__ import unicode_literals -from mock import Mock import pytest from boxsdk.object.event import Event @@ -10,7 +9,7 @@ def test_init_event(mock_box_session): event = Event(mock_box_session, "f82c3ba03e41f7e8a7608363cc6c0390183c3f83", { - "type": "event", + "type": "event", "event_id": "f82c3ba03e41f7e8a7608363cc6c0390183c3f83", "source": { "type": "folder", @@ -18,6 +17,5 @@ def test_init_event(mock_box_session): } }) assert event['type'] == 'event' - assert event._item_type == 'event' with pytest.raises(AttributeError): event.get_url() From d3dcd714df56cc99857e0bca176267a26f3b8e5c Mon Sep 17 00:00:00 2001 From: Kelsey Morris Date: Thu, 16 Jun 2016 09:28:51 -0700 Subject: [PATCH 05/14] Add trailing commas, fix constructor formatting --- test/unit/object/test_event.py | 24 ++++++++++++------------ test/unit/object/test_events.py | 22 +++++++++++++--------- 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/test/unit/object/test_event.py b/test/unit/object/test_event.py index 275d4e159..843f62ac0 100644 --- a/test/unit/object/test_event.py +++ b/test/unit/object/test_event.py @@ -2,20 +2,20 @@ from __future__ import unicode_literals -import pytest - from boxsdk.object.event import Event def test_init_event(mock_box_session): - event = Event(mock_box_session, "f82c3ba03e41f7e8a7608363cc6c0390183c3f83", { - "type": "event", - "event_id": "f82c3ba03e41f7e8a7608363cc6c0390183c3f83", - "source": { - "type": "folder", - "id": "11446498", - } - }) + event = Event( + mock_box_session, + "f82c3ba03e41f7e8a7608363cc6c0390183c3f83", + { + "type": "event", + "event_id": "f82c3ba03e41f7e8a7608363cc6c0390183c3f83", + "source": + { + "type": "folder", + "id": "11446498", + }, + },) assert event['type'] == 'event' - with pytest.raises(AttributeError): - event.get_url() diff --git a/test/unit/object/test_events.py b/test/unit/object/test_events.py index 41b3ecad4..147dcbf2e 100644 --- a/test/unit/object/test_events.py +++ b/test/unit/object/test_events.py @@ -177,20 +177,24 @@ def mock_event(): "source": { "type": "folder", "id": "11446498", - } + }, } @pytest.fixture() def mock_event_object(mock_box_session): - return Event(mock_box_session, "f82c3ba03e41f7e8a7608363cc6c0390183c3f83", { - "type": "event", - "event_id": "f82c3ba03e41f7e8a7608363cc6c0390183c3f83", - "source": { - "type": "folder", - "id": "11446498", - } - }) + return Event( + mock_box_session, + "f82c3ba03e41f7e8a7608363cc6c0390183c3f83", + { + "type": "event", + "event_id": "f82c3ba03e41f7e8a7608363cc6c0390183c3f83", + "source": + { + "type": "folder", + "id": "11446498", + }, + },) @pytest.fixture() From 379aa4cedb0e9c417b29a469e538a5f424b5c439 Mon Sep 17 00:00:00 2001 From: Kelsey Morris Date: Thu, 16 Jun 2016 10:56:41 -0700 Subject: [PATCH 06/14] Improve Event unit tests --- test/unit/object/test_event.py | 1 + test/unit/object/test_events.py | 31 ++++++------------------------- 2 files changed, 7 insertions(+), 25 deletions(-) diff --git a/test/unit/object/test_event.py b/test/unit/object/test_event.py index 843f62ac0..a27c9ba13 100644 --- a/test/unit/object/test_event.py +++ b/test/unit/object/test_event.py @@ -19,3 +19,4 @@ def test_init_event(mock_box_session): }, },) assert event['type'] == 'event' + assert event['event_id'] == 'f82c3ba03e41f7e8a7608363cc6c0390183c3f83' diff --git a/test/unit/object/test_events.py b/test/unit/object/test_events.py index 147dcbf2e..946eea881 100644 --- a/test/unit/object/test_events.py +++ b/test/unit/object/test_events.py @@ -170,7 +170,7 @@ def max_retries_long_poll_response(make_mock_box_request): @pytest.fixture() -def mock_event(): +def mock_event_json(): return { "type": "event", "event_id": "f82c3ba03e41f7e8a7608363cc6c0390183c3f83", @@ -182,26 +182,10 @@ def mock_event(): @pytest.fixture() -def mock_event_object(mock_box_session): - return Event( - mock_box_session, - "f82c3ba03e41f7e8a7608363cc6c0390183c3f83", - { - "type": "event", - "event_id": "f82c3ba03e41f7e8a7608363cc6c0390183c3f83", - "source": - { - "type": "folder", - "id": "11446498", - }, - },) - - -@pytest.fixture() -def events_response(initial_stream_position, mock_event, make_mock_box_request): +def events_response(initial_stream_position, mock_event_json, make_mock_box_request): # pylint:disable=redefined-outer-name mock_box_response, _ = make_mock_box_request( - response={"next_stream_position": initial_stream_position, "entries": [mock_event]}, + response={"next_stream_position": initial_stream_position, "entries": [mock_event_json]}, ) return mock_box_response @@ -212,7 +196,6 @@ def test_get_events( events_response, stream_type_kwargs, expected_stream_type_params, - mock_event_object ): # pylint:disable=redefined-outer-name expected_url = test_events.get_url() @@ -225,10 +208,8 @@ def test_get_events( ) event_entries = events['entries'] assert len(event_entries) == len(events_response.json.return_value['entries']) - if len(event_entries): - event = event_entries[0] + for event in event_entries: assert isinstance(event, Event) - assert event.event_id == mock_event_object['event_id'] def test_get_long_poll_options( @@ -258,7 +239,7 @@ def test_generate_events_with_long_polling( new_change_long_poll_response, reconnect_long_poll_response, max_retries_long_poll_response, - mock_event_object, + mock_event_json, stream_type_kwargs, expected_stream_type, expected_stream_type_params, @@ -277,7 +258,7 @@ def test_generate_events_with_long_polling( empty_events_response, ] events = test_events.generate_events_with_long_polling(**stream_type_kwargs) - assert next(events) == mock_event_object + assert next(events) == Event(mock_box_session, "f82c3ba03e41f7e8a7608363cc6c0390183c3f83", mock_event_json) with pytest.raises(StopIteration): next(events) events.close() From 6b4f791b05b953498ce29538eef9b3d5cfaf9712 Mon Sep 17 00:00:00 2001 From: Kelsey Morris Date: Thu, 16 Jun 2016 16:46:29 -0700 Subject: [PATCH 07/14] Begin to separate REST behavior from other behavior --- boxsdk/object/api_json_object.py | 9 ++ boxsdk/object/base_api_json_object.py | 85 +++++++++++++++ boxsdk/object/base_endpoint.py | 8 +- boxsdk/object/base_object.py | 145 +++++++++++++------------- 4 files changed, 173 insertions(+), 74 deletions(-) create mode 100644 boxsdk/object/api_json_object.py create mode 100644 boxsdk/object/base_api_json_object.py diff --git a/boxsdk/object/api_json_object.py b/boxsdk/object/api_json_object.py new file mode 100644 index 000000000..b716c0288 --- /dev/null +++ b/boxsdk/object/api_json_object.py @@ -0,0 +1,9 @@ +# coding: utf-8 + +from __future__ import unicode_literals + +from boxsdk.object.base_api_json_object import BaseAPIJSONObject + + +class APIJSONObject(BaseAPIJSONObject): + pass diff --git a/boxsdk/object/base_api_json_object.py b/boxsdk/object/base_api_json_object.py new file mode 100644 index 000000000..fd54568c5 --- /dev/null +++ b/boxsdk/object/base_api_json_object.py @@ -0,0 +1,85 @@ +# coding: utf-8 + +from __future__ import unicode_literals +from abc import ABCMeta + +import six + +from boxsdk.util.translator import Translator + + +class BaseAPIJSONObjectMeta(ABCMeta): + """ + Metaclass for Box API objects. Registers classes so that API responses can be translated to the correct type. + Relies on the _item_type field defined on the classes to match the type property of the response json. + But the type-class mapping will only be registered if the module of the class is imported. + So it's also important to add the module name to __all__ in object/__init__.py. + """ + def __init__(cls, name, bases, attrs): + super(BaseAPIJSONObjectMeta, cls).__init__(name, bases, attrs) + item_type = attrs.get('_item_type', None) + if item_type is not None: + Translator().register(item_type, cls) + + +@six.add_metaclass(BaseAPIJSONObjectMeta) +class BaseAPIJSONObject(object): + # pass + def __init__(self, object_id=None, response_object=None): + self._object_id = object_id or '' + self._response_object = response_object or {} + self.__dict__.update(self._response_object) + + def __getitem__(self, item): + """Base class override. Try to get the attribute from the API response object.""" + return self._response_object[item] + + def __repr__(self): + """Base class override. Return a human-readable representation using the Box ID or name of the object.""" + description = ''.format(self.__class__.__name__, self._description) + if six.PY2: + return description.encode('utf-8') + else: + return description + + @property + def _description(self): + if 'name' in self._response_object: + return '{0} ({1})'.format(self._object_id, self.name) # pylint:disable=no-member + else: + return '{0}'.format(self._object_id) + + @property + def object_id(self): + """Return the Box ID for the object. + + :rtype: + `unicode` + """ + return self._object_id + + def __eq__(self, other): + """Base class override. Equality is determined by object id.""" + return self._object_id == other.object_id + + def get(self, fields=None, headers=None): + """ + Get information about the object, specified by fields. If fields is None, return the default fields. + + :param fields: + List of fields to request. + :type fields: + `Iterable` of `unicode` + :param headers: + Additional headers to send with the request. + :type headers: + `dict` + :return: + An object of the same type that has the requested information. + :rtype: + :class:`BaseObject` + """ + url = self.get_url() + params = {'fields': ','.join(fields)} if fields else None + box_response = self._session.get(url, params=params, headers=headers) + return self.__class__(self._session, self._object_id, box_response.json()) diff --git a/boxsdk/object/base_endpoint.py b/boxsdk/object/base_endpoint.py index 76b0ffe6a..6935ee9ee 100644 --- a/boxsdk/object/base_endpoint.py +++ b/boxsdk/object/base_endpoint.py @@ -2,11 +2,14 @@ from __future__ import unicode_literals +from boxsdk.object.base_api_json_object import BaseAPIJSONObject -class BaseEndpoint(object): + +class BaseEndpoint(BaseAPIJSONObject): """A Box API endpoint.""" - def __init__(self, session): + def __init__(self, session, object_id=None, response_object=None): + # def __init__(self, session): """ :param session: @@ -15,6 +18,7 @@ def __init__(self, session): :class:`BoxSession` """ self._session = session + super(BaseEndpoint, self).__init__(object_id, response_object) def get_url(self, endpoint, *args): """ diff --git a/boxsdk/object/base_object.py b/boxsdk/object/base_object.py index 3fe1d8b6b..bb12e32e6 100644 --- a/boxsdk/object/base_object.py +++ b/boxsdk/object/base_object.py @@ -1,7 +1,7 @@ # coding: utf-8 from __future__ import unicode_literals -from abc import ABCMeta +# from abc import ABCMeta import json import six @@ -10,21 +10,21 @@ from boxsdk.util.translator import Translator -class ObjectMeta(ABCMeta): - """ - Metaclass for Box API objects. Registers classes so that API responses can be translated to the correct type. - Relies on the _item_type field defined on the classes to match the type property of the response json. - But the type-class mapping will only be registered if the module of the class is imported. - So it's also important to add the module name to __all__ in object/__init__.py. - """ - def __init__(cls, name, bases, attrs): - super(ObjectMeta, cls).__init__(name, bases, attrs) - item_type = attrs.get('_item_type', None) - if item_type is not None: - Translator().register(item_type, cls) - - -@six.add_metaclass(ObjectMeta) +# class ObjectMeta(ABCMeta): +# """ +# Metaclass for Box API objects. Registers classes so that API responses can be translated to the correct type. +# Relies on the _item_type field defined on the classes to match the type property of the response json. +# But the type-class mapping will only be registered if the module of the class is imported. +# So it's also important to add the module name to __all__ in object/__init__.py. +# """ +# def __init__(cls, name, bases, attrs): +# super(ObjectMeta, cls).__init__(name, bases, attrs) +# item_type = attrs.get('_item_type', None) +# if item_type is not None: +# Translator().register(item_type, cls) +# +# +# @six.add_metaclass(ObjectMeta) class BaseObject(BaseEndpoint): """ A Box API endpoint for interacting with a Box object. @@ -46,29 +46,30 @@ def __init__(self, session, object_id, response_object=None): :type response_object: :class:`BoxResponse` """ - super(BaseObject, self).__init__(session) - self._object_id = object_id - self._response_object = response_object or {} - self.__dict__.update(self._response_object) - - def __getitem__(self, item): - """Base class override. Try to get the attribute from the API response object.""" - return self._response_object[item] - - def __repr__(self): - """Base class override. Return a human-readable representation using the Box ID or name of the object.""" - description = ''.format(self.__class__.__name__, self._description) - if six.PY2: - return description.encode('utf-8') - else: - return description - - @property - def _description(self): - if 'name' in self._response_object: - return '{0} ({1})'.format(self._object_id, self.name) # pylint:disable=no-member - else: - return '{0}'.format(self._object_id) + super(BaseObject, self).__init__(session, object_id, response_object) + # super(BaseObject, self).__init__(session) + # self._object_id = object_id + # self._response_object = response_object or {} + # self.__dict__.update(self._response_object) + + # def __getitem__(self, item): + # """Base class override. Try to get the attribute from the API response object.""" + # return self._response_object[item] + + # def __repr__(self): + # """Base class override. Return a human-readable representation using the Box ID or name of the object.""" + # description = ''.format(self.__class__.__name__, self._description) + # if six.PY2: + # return description.encode('utf-8') + # else: + # return description + + # @property + # def _description(self): + # if 'name' in self._response_object: + # return '{0} ({1})'.format(self._object_id, self.name) # pylint:disable=no-member + # else: + # return '{0}'.format(self._object_id) def get_url(self, *args): """ @@ -86,36 +87,36 @@ def get_type_url(self): """ return super(BaseObject, self).get_url('{0}s'.format(self._item_type)) - @property - def object_id(self): - """Return the Box ID for the object. - - :rtype: - `unicode` - """ - return self._object_id - - def get(self, fields=None, headers=None): - """ - Get information about the object, specified by fields. If fields is None, return the default fields. - - :param fields: - List of fields to request. - :type fields: - `Iterable` of `unicode` - :param headers: - Additional headers to send with the request. - :type headers: - `dict` - :return: - An object of the same type that has the requested information. - :rtype: - :class:`BaseObject` - """ - url = self.get_url() - params = {'fields': ','.join(fields)} if fields else None - box_response = self._session.get(url, params=params, headers=headers) - return self.__class__(self._session, self._object_id, box_response.json()) + # @property + # def object_id(self): + # """Return the Box ID for the object. + # + # :rtype: + # `unicode` + # """ + # return self._object_id + + # def get(self, fields=None, headers=None): + # """ + # Get information about the object, specified by fields. If fields is None, return the default fields. + # + # :param fields: + # List of fields to request. + # :type fields: + # `Iterable` of `unicode` + # :param headers: + # Additional headers to send with the request. + # :type headers: + # `dict` + # :return: + # An object of the same type that has the requested information. + # :rtype: + # :class:`BaseObject` + # """ + # url = self.get_url() + # params = {'fields': ','.join(fields)} if fields else None + # box_response = self._session.get(url, params=params, headers=headers) + # return self.__class__(self._session, self._object_id, box_response.json()) def update_info(self, data, params=None, headers=None, **kwargs): """Update information about this object. @@ -184,9 +185,9 @@ def delete(self, params=None, headers=None): box_response = self._session.delete(url, expect_json_response=False, params=params or {}, headers=headers) return box_response.ok - def __eq__(self, other): - """Base class override. Equality is determined by object id.""" - return self._object_id == other.object_id + # def __eq__(self, other): + # """Base class override. Equality is determined by object id.""" + # return self._object_id == other.object_id def _paging_wrapper(self, url, starting_index, limit, factory=None): """ From 66ebc917663da95698b52b4f6078093192cd5399 Mon Sep 17 00:00:00 2001 From: Kelsey Morris Date: Thu, 16 Jun 2016 17:34:22 -0700 Subject: [PATCH 08/14] Remove Event class from REST object hierarchy --- boxsdk/object/api_json_object.py | 5 +- boxsdk/object/base_api_json_object.py | 25 +------ boxsdk/object/base_endpoint.py | 1 - boxsdk/object/base_object.py | 94 ++++++--------------------- boxsdk/object/event.py | 12 +--- boxsdk/object/events.py | 2 +- test/unit/object/test_event.py | 1 - test/unit/object/test_events.py | 2 +- 8 files changed, 30 insertions(+), 112 deletions(-) diff --git a/boxsdk/object/api_json_object.py b/boxsdk/object/api_json_object.py index b716c0288..8a4fbe2e7 100644 --- a/boxsdk/object/api_json_object.py +++ b/boxsdk/object/api_json_object.py @@ -1,9 +1,12 @@ # coding: utf-8 from __future__ import unicode_literals +from collections import Mapping from boxsdk.object.base_api_json_object import BaseAPIJSONObject -class APIJSONObject(BaseAPIJSONObject): +class APIJSONObject(BaseAPIJSONObject, Mapping): + """Class representing objects that are not part of the REST API""" + pass diff --git a/boxsdk/object/base_api_json_object.py b/boxsdk/object/base_api_json_object.py index fd54568c5..7393fa068 100644 --- a/boxsdk/object/base_api_json_object.py +++ b/boxsdk/object/base_api_json_object.py @@ -24,7 +24,8 @@ def __init__(cls, name, bases, attrs): @six.add_metaclass(BaseAPIJSONObjectMeta) class BaseAPIJSONObject(object): - # pass + """Base class containing basic logic shared between true REST objects and other objects (such as an Event)""" + def __init__(self, object_id=None, response_object=None): self._object_id = object_id or '' self._response_object = response_object or {} @@ -61,25 +62,3 @@ def object_id(self): def __eq__(self, other): """Base class override. Equality is determined by object id.""" return self._object_id == other.object_id - - def get(self, fields=None, headers=None): - """ - Get information about the object, specified by fields. If fields is None, return the default fields. - - :param fields: - List of fields to request. - :type fields: - `Iterable` of `unicode` - :param headers: - Additional headers to send with the request. - :type headers: - `dict` - :return: - An object of the same type that has the requested information. - :rtype: - :class:`BaseObject` - """ - url = self.get_url() - params = {'fields': ','.join(fields)} if fields else None - box_response = self._session.get(url, params=params, headers=headers) - return self.__class__(self._session, self._object_id, box_response.json()) diff --git a/boxsdk/object/base_endpoint.py b/boxsdk/object/base_endpoint.py index 6935ee9ee..4c277a093 100644 --- a/boxsdk/object/base_endpoint.py +++ b/boxsdk/object/base_endpoint.py @@ -9,7 +9,6 @@ class BaseEndpoint(BaseAPIJSONObject): """A Box API endpoint.""" def __init__(self, session, object_id=None, response_object=None): - # def __init__(self, session): """ :param session: diff --git a/boxsdk/object/base_object.py b/boxsdk/object/base_object.py index bb12e32e6..ff37b9f28 100644 --- a/boxsdk/object/base_object.py +++ b/boxsdk/object/base_object.py @@ -1,30 +1,12 @@ # coding: utf-8 from __future__ import unicode_literals -# from abc import ABCMeta import json -import six - from boxsdk.object.base_endpoint import BaseEndpoint from boxsdk.util.translator import Translator -# class ObjectMeta(ABCMeta): -# """ -# Metaclass for Box API objects. Registers classes so that API responses can be translated to the correct type. -# Relies on the _item_type field defined on the classes to match the type property of the response json. -# But the type-class mapping will only be registered if the module of the class is imported. -# So it's also important to add the module name to __all__ in object/__init__.py. -# """ -# def __init__(cls, name, bases, attrs): -# super(ObjectMeta, cls).__init__(name, bases, attrs) -# item_type = attrs.get('_item_type', None) -# if item_type is not None: -# Translator().register(item_type, cls) -# -# -# @six.add_metaclass(ObjectMeta) class BaseObject(BaseEndpoint): """ A Box API endpoint for interacting with a Box object. @@ -47,29 +29,28 @@ def __init__(self, session, object_id, response_object=None): :class:`BoxResponse` """ super(BaseObject, self).__init__(session, object_id, response_object) - # super(BaseObject, self).__init__(session) - # self._object_id = object_id - # self._response_object = response_object or {} - # self.__dict__.update(self._response_object) - - # def __getitem__(self, item): - # """Base class override. Try to get the attribute from the API response object.""" - # return self._response_object[item] - # def __repr__(self): - # """Base class override. Return a human-readable representation using the Box ID or name of the object.""" - # description = ''.format(self.__class__.__name__, self._description) - # if six.PY2: - # return description.encode('utf-8') - # else: - # return description + def get(self, fields=None, headers=None): + """ + Get information about the object, specified by fields. If fields is None, return the default fields. - # @property - # def _description(self): - # if 'name' in self._response_object: - # return '{0} ({1})'.format(self._object_id, self.name) # pylint:disable=no-member - # else: - # return '{0}'.format(self._object_id) + :param fields: + List of fields to request. + :type fields: + `Iterable` of `unicode` + :param headers: + Additional headers to send with the request. + :type headers: + `dict` + :return: + An object of the same type that has the requested information. + :rtype: + :class:`BaseObject` + """ + url = self.get_url() + params = {'fields': ','.join(fields)} if fields else None + box_response = self._session.get(url, params=params, headers=headers) + return self.__class__(self._session, self._object_id, box_response.json()) def get_url(self, *args): """ @@ -87,37 +68,6 @@ def get_type_url(self): """ return super(BaseObject, self).get_url('{0}s'.format(self._item_type)) - # @property - # def object_id(self): - # """Return the Box ID for the object. - # - # :rtype: - # `unicode` - # """ - # return self._object_id - - # def get(self, fields=None, headers=None): - # """ - # Get information about the object, specified by fields. If fields is None, return the default fields. - # - # :param fields: - # List of fields to request. - # :type fields: - # `Iterable` of `unicode` - # :param headers: - # Additional headers to send with the request. - # :type headers: - # `dict` - # :return: - # An object of the same type that has the requested information. - # :rtype: - # :class:`BaseObject` - # """ - # url = self.get_url() - # params = {'fields': ','.join(fields)} if fields else None - # box_response = self._session.get(url, params=params, headers=headers) - # return self.__class__(self._session, self._object_id, box_response.json()) - def update_info(self, data, params=None, headers=None, **kwargs): """Update information about this object. @@ -185,10 +135,6 @@ def delete(self, params=None, headers=None): box_response = self._session.delete(url, expect_json_response=False, params=params or {}, headers=headers) return box_response.ok - # def __eq__(self, other): - # """Base class override. Equality is determined by object id.""" - # return self._object_id == other.object_id - def _paging_wrapper(self, url, starting_index, limit, factory=None): """ Helper function that turns any paging API into a generator that transparently implements the paging for diff --git a/boxsdk/object/event.py b/boxsdk/object/event.py index e98936aa8..90860fd22 100644 --- a/boxsdk/object/event.py +++ b/boxsdk/object/event.py @@ -2,18 +2,10 @@ from __future__ import unicode_literals -from boxsdk.object.base_object import BaseObject +from boxsdk.object.base_api_json_object import BaseAPIJSONObject -class Event(BaseObject): +class Event(BaseAPIJSONObject): """Represents a single Box event""" _item_type = 'event' - - @property - def get_url(self, *args): - """ - Base class override. - Disallow this method for this subclass, should not access Event by event_id. - """ - raise AttributeError("'Event' class has no method 'get_url'") diff --git a/boxsdk/object/events.py b/boxsdk/object/events.py index 61b016e68..343053147 100644 --- a/boxsdk/object/events.py +++ b/boxsdk/object/events.py @@ -93,7 +93,7 @@ def get_events(self, limit=100, stream_position=0, stream_type=UserEventsStreamT box_response = self._session.get(url, params=params) response = box_response.json().copy() if 'entries' in response: - response['entries'] = [Translator().translate(item['type'])(self._session, item['event_id'], item) for item in response['entries']] + response['entries'] = [Translator().translate(item['type'])(item['event_id'], item) for item in response['entries']] return response def get_latest_stream_position(self, stream_type=UserEventsStreamType.ALL): diff --git a/test/unit/object/test_event.py b/test/unit/object/test_event.py index a27c9ba13..3cfb66e9a 100644 --- a/test/unit/object/test_event.py +++ b/test/unit/object/test_event.py @@ -7,7 +7,6 @@ def test_init_event(mock_box_session): event = Event( - mock_box_session, "f82c3ba03e41f7e8a7608363cc6c0390183c3f83", { "type": "event", diff --git a/test/unit/object/test_events.py b/test/unit/object/test_events.py index 946eea881..1bafca501 100644 --- a/test/unit/object/test_events.py +++ b/test/unit/object/test_events.py @@ -258,7 +258,7 @@ def test_generate_events_with_long_polling( empty_events_response, ] events = test_events.generate_events_with_long_polling(**stream_type_kwargs) - assert next(events) == Event(mock_box_session, "f82c3ba03e41f7e8a7608363cc6c0390183c3f83", mock_event_json) + assert next(events) == Event("f82c3ba03e41f7e8a7608363cc6c0390183c3f83", mock_event_json) with pytest.raises(StopIteration): next(events) events.close() From 10a41c86f148f61e4df1bb1f8951f6c6a7eae20a Mon Sep 17 00:00:00 2001 From: Kelsey Morris Date: Mon, 20 Jun 2016 13:03:58 -0700 Subject: [PATCH 09/14] Update base_endpoint class hierarchy --- boxsdk/object/api_json_object.py | 23 ++++++++++++--- boxsdk/object/base_api_json_object.py | 37 +++++++++--------------- boxsdk/object/base_endpoint.py | 14 ++++----- boxsdk/object/base_object.py | 41 +++++++++++++++++++++------ boxsdk/object/event.py | 8 +++--- boxsdk/object/events.py | 15 +++++----- boxsdk/object/folder.py | 1 + boxsdk/object/item.py | 6 +++- boxsdk/object/metadata.py | 2 +- test/unit/object/test_event.py | 5 ++-- test/unit/object/test_events.py | 4 +-- 11 files changed, 95 insertions(+), 61 deletions(-) diff --git a/boxsdk/object/api_json_object.py b/boxsdk/object/api_json_object.py index 8a4fbe2e7..67e481062 100644 --- a/boxsdk/object/api_json_object.py +++ b/boxsdk/object/api_json_object.py @@ -1,12 +1,27 @@ # coding: utf-8 -from __future__ import unicode_literals +from __future__ import unicode_literals, absolute_import from collections import Mapping -from boxsdk.object.base_api_json_object import BaseAPIJSONObject +# import six +from .base_api_json_object import BaseAPIJSONObject, BaseAPIJSONObjectMeta -class APIJSONObject(BaseAPIJSONObject, Mapping): - """Class representing objects that are not part of the REST API""" +class APIJSONObjectMeta(BaseAPIJSONObjectMeta, Mapping.__metaclass__): + """Avoid conflicting metaclass definitions for APIJSONObject""" pass + + +# @six.add_metaclass(APIJSONObjectMeta) +# class APIJSONObject(APIJSONObjectMeta, BaseAPIJSONObject, Mapping): +class APIJSONObject(BaseAPIJSONObject, Mapping): + """Class representing objects that are not part of the REST API.""" + + __metaclass__ = APIJSONObjectMeta + + def __len__(self): + return len(self._response_object) + + def __iter__(self): + return self._response_object.__iter__() diff --git a/boxsdk/object/base_api_json_object.py b/boxsdk/object/base_api_json_object.py index 7393fa068..93f2e61f1 100644 --- a/boxsdk/object/base_api_json_object.py +++ b/boxsdk/object/base_api_json_object.py @@ -1,14 +1,13 @@ # coding: utf-8 -from __future__ import unicode_literals -from abc import ABCMeta +from __future__ import unicode_literals, absolute_import import six -from boxsdk.util.translator import Translator +from ..util.translator import Translator -class BaseAPIJSONObjectMeta(ABCMeta): +class BaseAPIJSONObjectMeta(type): """ Metaclass for Box API objects. Registers classes so that API responses can be translated to the correct type. Relies on the _item_type field defined on the classes to match the type property of the response json. @@ -26,8 +25,13 @@ def __init__(cls, name, bases, attrs): class BaseAPIJSONObject(object): """Base class containing basic logic shared between true REST objects and other objects (such as an Event)""" - def __init__(self, object_id=None, response_object=None): - self._object_id = object_id or '' + def __init__(self, response_object=None): + """ + :param response_object: + The Box API response representing the object. + :type response_object: + :class:`BoxResponse` + """ self._response_object = response_object or {} self.__dict__.update(self._response_object) @@ -37,7 +41,8 @@ def __getitem__(self, item): def __repr__(self): """Base class override. Return a human-readable representation using the Box ID or name of the object.""" - description = ''.format(self.__class__.__name__, self._description) + extra_description = ' - {0}'.format(self._description) if self._description else '' + description = ' Date: Mon, 20 Jun 2016 13:15:03 -0700 Subject: [PATCH 10/14] Remove print statement --- boxsdk/object/events.py | 1 - 1 file changed, 1 deletion(-) diff --git a/boxsdk/object/events.py b/boxsdk/object/events.py index 6c2bd2339..636ade92a 100644 --- a/boxsdk/object/events.py +++ b/boxsdk/object/events.py @@ -93,7 +93,6 @@ def get_events(self, limit=100, stream_position=0, stream_type=UserEventsStreamT box_response = self._session.get(url, params=params) response = box_response.json().copy() if 'entries' in response: - print [Translator().translate(item['type']) for item in response['entries']] response['entries'] = [Translator().translate(item['type'])(item) for item in response['entries']] return response From 4545a7f12c787fecb6ce2495db81b66213ffadbb Mon Sep 17 00:00:00 2001 From: Kelsey Morris Date: Tue, 21 Jun 2016 09:15:49 -0700 Subject: [PATCH 11/14] Clean up code, adhere to Python 3 compatibility --- boxsdk/object/__init__.py | 2 +- boxsdk/object/api_json_object.py | 14 +++---- boxsdk/object/base_api_json_object.py | 27 ++++++++++--- boxsdk/object/base_endpoint.py | 11 +++--- boxsdk/object/base_object.py | 55 ++++++++++++--------------- boxsdk/object/events.py | 1 - boxsdk/object/item.py | 1 - 7 files changed, 58 insertions(+), 53 deletions(-) diff --git a/boxsdk/object/__init__.py b/boxsdk/object/__init__.py index ffd3611b4..e4fdb61ea 100644 --- a/boxsdk/object/__init__.py +++ b/boxsdk/object/__init__.py @@ -5,4 +5,4 @@ from six.moves import map # pylint:disable=redefined-builtin -__all__ = list(map(str, ['collaboration', 'events', 'file', 'folder', 'group', 'group_membership', 'search', 'user'])) +__all__ = list(map(str, ['collaboration', 'events', 'event', 'file', 'folder', 'group', 'group_membership', 'search', 'user'])) diff --git a/boxsdk/object/api_json_object.py b/boxsdk/object/api_json_object.py index 67e481062..da22aa054 100644 --- a/boxsdk/object/api_json_object.py +++ b/boxsdk/object/api_json_object.py @@ -2,26 +2,22 @@ from __future__ import unicode_literals, absolute_import from collections import Mapping - -# import six +from abc import ABCMeta +import six from .base_api_json_object import BaseAPIJSONObject, BaseAPIJSONObjectMeta -class APIJSONObjectMeta(BaseAPIJSONObjectMeta, Mapping.__metaclass__): +class APIJSONObjectMeta(BaseAPIJSONObjectMeta, ABCMeta): """Avoid conflicting metaclass definitions for APIJSONObject""" pass -# @six.add_metaclass(APIJSONObjectMeta) -# class APIJSONObject(APIJSONObjectMeta, BaseAPIJSONObject, Mapping): -class APIJSONObject(BaseAPIJSONObject, Mapping): +class APIJSONObject(six.with_metaclass(APIJSONObjectMeta, BaseAPIJSONObject, Mapping)): """Class representing objects that are not part of the REST API.""" - __metaclass__ = APIJSONObjectMeta - def __len__(self): return len(self._response_object) def __iter__(self): - return self._response_object.__iter__() + return iter(self._response_object) diff --git a/boxsdk/object/base_api_json_object.py b/boxsdk/object/base_api_json_object.py index 93f2e61f1..6da618310 100644 --- a/boxsdk/object/base_api_json_object.py +++ b/boxsdk/object/base_api_json_object.py @@ -1,7 +1,6 @@ # coding: utf-8 from __future__ import unicode_literals, absolute_import - import six from ..util.translator import Translator @@ -25,24 +24,39 @@ def __init__(cls, name, bases, attrs): class BaseAPIJSONObject(object): """Base class containing basic logic shared between true REST objects and other objects (such as an Event)""" - def __init__(self, response_object=None): + _item_type = None + + def __init__(self, response_object=None, **kwargs): """ :param response_object: - The Box API response representing the object. + A JSON object representing the object returned from a Box API request. :type response_object: - :class:`BoxResponse` + :`dict` + :param kwargs: + Keyword arguments for base class constructors. + :type kwargs: + :`dict` """ self._response_object = response_object or {} self.__dict__.update(self._response_object) + super(BaseAPIJSONObject, self).__init__(**kwargs) def __getitem__(self, item): - """Base class override. Try to get the attribute from the API response object.""" + """ + Try to get the attribute from the API response object. + :param item: + The attribute to retrieve from the API response object. + :type item: + `unicode` + :rtype: + `unicode` + """ return self._response_object[item] def __repr__(self): """Base class override. Return a human-readable representation using the Box ID or name of the object.""" extra_description = ' - {0}'.format(self._description) if self._description else '' - description = ' Date: Tue, 21 Jun 2016 11:11:43 -0700 Subject: [PATCH 12/14] Add unit tests for new classes --- test/unit/object/test_api_json_object.py | 3 +++ test/unit/object/test_base_api_json_object.py | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 test/unit/object/test_api_json_object.py create mode 100644 test/unit/object/test_base_api_json_object.py diff --git a/test/unit/object/test_api_json_object.py b/test/unit/object/test_api_json_object.py new file mode 100644 index 000000000..51a557999 --- /dev/null +++ b/test/unit/object/test_api_json_object.py @@ -0,0 +1,3 @@ +# coding: utf-8 + +from __future__ import unicode_literals, absolute_import diff --git a/test/unit/object/test_base_api_json_object.py b/test/unit/object/test_base_api_json_object.py new file mode 100644 index 000000000..a1c909ff7 --- /dev/null +++ b/test/unit/object/test_base_api_json_object.py @@ -0,0 +1,18 @@ +# coding: utf-8 + +from __future__ import unicode_literals, absolute_import +import pytest + +from boxsdk.object.base_api_json_object import BaseAPIJSONObject + + +@pytest.fixture(params=[{'foo': 'bar'}, {'a': {'b': 'c'}}]) +def base_api_json_object(request): + return request.param, BaseAPIJSONObject(request.param) + + +def test_getitem(base_api_json_object): + dictionary, test_object = base_api_json_object + assert isinstance(test_object, BaseAPIJSONObject) + for key in dictionary: + assert test_object[key] == dictionary[key] From e590817e0822b694a1b70db999c8c67226d089a5 Mon Sep 17 00:00:00 2001 From: Kelsey Morris Date: Tue, 21 Jun 2016 14:32:00 -0700 Subject: [PATCH 13/14] Improve unit tests --- boxsdk/object/api_json_object.py | 5 ++++- boxsdk/object/base_api_json_object.py | 11 +++-------- boxsdk/object/base_endpoint.py | 4 ++-- boxsdk/object/base_object.py | 4 ++-- test/unit/object/test_api_json_object.py | 18 ++++++++++++++++++ test/unit/object/test_base_api_json_object.py | 16 +++++++++++----- 6 files changed, 40 insertions(+), 18 deletions(-) diff --git a/boxsdk/object/api_json_object.py b/boxsdk/object/api_json_object.py index da22aa054..e407b1c9c 100644 --- a/boxsdk/object/api_json_object.py +++ b/boxsdk/object/api_json_object.py @@ -9,7 +9,10 @@ class APIJSONObjectMeta(BaseAPIJSONObjectMeta, ABCMeta): - """Avoid conflicting metaclass definitions for APIJSONObject""" + """ + Avoid conflicting metaclass definitions for APIJSONObject. + http://code.activestate.com/recipes/204197-solving-the-metaclass-conflict/ + """ pass diff --git a/boxsdk/object/base_api_json_object.py b/boxsdk/object/base_api_json_object.py index 6da618310..5bee4aa53 100644 --- a/boxsdk/object/base_api_json_object.py +++ b/boxsdk/object/base_api_json_object.py @@ -32,24 +32,19 @@ def __init__(self, response_object=None, **kwargs): A JSON object representing the object returned from a Box API request. :type response_object: :`dict` - :param kwargs: - Keyword arguments for base class constructors. - :type kwargs: - :`dict` """ + super(BaseAPIJSONObject, self).__init__(**kwargs) self._response_object = response_object or {} self.__dict__.update(self._response_object) - super(BaseAPIJSONObject, self).__init__(**kwargs) def __getitem__(self, item): """ Try to get the attribute from the API response object. + :param item: The attribute to retrieve from the API response object. :type item: `unicode` - :rtype: - `unicode` """ return self._response_object[item] @@ -64,5 +59,5 @@ def __repr__(self): @property def _description(self): - """Return a description if the object if one exists.""" + """Return a description of the object if one exists.""" return "" diff --git a/boxsdk/object/base_endpoint.py b/boxsdk/object/base_endpoint.py index 775cf4135..d24d8ca41 100644 --- a/boxsdk/object/base_endpoint.py +++ b/boxsdk/object/base_endpoint.py @@ -15,10 +15,10 @@ def __init__(self, session, **kwargs): :param kwargs: Keyword arguments for base class constructors. :type kwargs: - :`dict` + `dict` """ - self._session = session super(BaseEndpoint, self).__init__(**kwargs) + self._session = session def get_url(self, endpoint, *args): """ diff --git a/boxsdk/object/base_object.py b/boxsdk/object/base_object.py index febbcaa1b..582322293 100644 --- a/boxsdk/object/base_object.py +++ b/boxsdk/object/base_object.py @@ -24,10 +24,10 @@ def __init__(self, session, object_id, response_object=None): :param response_object: A JSON object representing the object returned from a Box API request. :type response_object: - :`dict` + `dict` """ - self._object_id = object_id super(BaseObject, self).__init__(session=session, response_object=response_object) + self._object_id = object_id @property def _description(self): diff --git a/test/unit/object/test_api_json_object.py b/test/unit/object/test_api_json_object.py index 51a557999..1be04ef62 100644 --- a/test/unit/object/test_api_json_object.py +++ b/test/unit/object/test_api_json_object.py @@ -1,3 +1,21 @@ # coding: utf-8 from __future__ import unicode_literals, absolute_import +import pytest + +from boxsdk.object.api_json_object import APIJSONObject + + +@pytest.fixture(params=[{'foo': 'bar'}, {'a': {'b': 'c'}}]) +def api_json_object(request): + return request.param, APIJSONObject(request.param) + + +def test_len(api_json_object): + dictionary, test_object = api_json_object + assert len(dictionary) == len(test_object) + + +def test_api_json_object_dict(api_json_object): + dictionary, test_object = api_json_object + assert dictionary == test_object diff --git a/test/unit/object/test_base_api_json_object.py b/test/unit/object/test_base_api_json_object.py index a1c909ff7..3032f1147 100644 --- a/test/unit/object/test_base_api_json_object.py +++ b/test/unit/object/test_base_api_json_object.py @@ -7,12 +7,18 @@ @pytest.fixture(params=[{'foo': 'bar'}, {'a': {'b': 'c'}}]) -def base_api_json_object(request): - return request.param, BaseAPIJSONObject(request.param) +def response(request): + return request.param + + +@pytest.fixture() +def base_api_json_object(response): + dictionary_response = response + return dictionary_response, BaseAPIJSONObject(dictionary_response) def test_getitem(base_api_json_object): - dictionary, test_object = base_api_json_object + dictionary_response, test_object = base_api_json_object assert isinstance(test_object, BaseAPIJSONObject) - for key in dictionary: - assert test_object[key] == dictionary[key] + for key in dictionary_response: + assert test_object[key] == dictionary_response[key] From c8057a0d3c4b33a64077f06ee034b97601f9b48c Mon Sep 17 00:00:00 2001 From: Kelsey Morris Date: Tue, 21 Jun 2016 15:30:55 -0700 Subject: [PATCH 14/14] Fix unit test --- boxsdk/object/base_api_json_object.py | 2 +- test/unit/object/test_events.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/boxsdk/object/base_api_json_object.py b/boxsdk/object/base_api_json_object.py index 5bee4aa53..8dbacde50 100644 --- a/boxsdk/object/base_api_json_object.py +++ b/boxsdk/object/base_api_json_object.py @@ -31,7 +31,7 @@ def __init__(self, response_object=None, **kwargs): :param response_object: A JSON object representing the object returned from a Box API request. :type response_object: - :`dict` + `dict` """ super(BaseAPIJSONObject, self).__init__(**kwargs) self._response_object = response_object or {} diff --git a/test/unit/object/test_events.py b/test/unit/object/test_events.py index 29fd0a6f4..ff6c88e24 100644 --- a/test/unit/object/test_events.py +++ b/test/unit/object/test_events.py @@ -207,7 +207,7 @@ def test_get_events( params=dict(limit=100, stream_position=0, **expected_stream_type_params), ) event_entries = events['entries'] - assert len(event_entries) == len(events_response.json.return_value['entries']) + assert event_entries == events_response.json.return_value['entries'] for event in event_entries: assert isinstance(event, Event)