diff --git a/docs/source/conf.py b/docs/source/conf.py index b435b95..96c6570 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -11,7 +11,10 @@ # All configuration values have a default; values that are commented out # serve to show the default. -import sys, os +from __future__ import absolute_import, division, print_function, unicode_literals + +import os +import sys FILE_ROOT = os.path.abspath(os.path.dirname(__file__)) #add the apps dir to the python path. @@ -46,8 +49,8 @@ master_doc = 'index' # General information about the project. -project = u'Sunspear' -copyright = u'2013, Numan Sachwani' +project = 'Sunspear' +copyright = '2013, Numan Sachwani' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -189,8 +192,8 @@ # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ - ('index', 'Sunspear.tex', u'Sunspear Documentation', - u'Numan Sachwani', 'manual'), + ('index', 'Sunspear.tex', 'Sunspear Documentation', + 'Numan Sachwani', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of @@ -219,8 +222,8 @@ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - ('index', 'sunspear', u'Sunspear Documentation', - [u'Numan Sachwani'], 1) + ('index', 'sunspear', 'Sunspear Documentation', + ['Numan Sachwani'], 1) ] # If true, show URL addresses after external links. @@ -233,8 +236,8 @@ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - ('index', 'Sunspear', u'Sunspear Documentation', - u'Numan Sachwani', 'Sunspear', 'One line description of project.', + ('index', 'Sunspear', 'Sunspear Documentation', + 'Numan Sachwani', 'Sunspear', 'One line description of project.', 'Miscellaneous'), ] diff --git a/setup.cfg b/setup.cfg index ce26f6a..b6c1cfb 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,2 +1,23 @@ [nosetests] where=tests + +[isort] +line_length=120 +known_standard_library= +known_third_party= +known_first_party=sunspear +balanced_wrapping=true +combine_star=true +# 0: grid +# 1: vertical +# 2: hanging +# 3: vert-hanging +# 4: vert-grid +# 5: vert-grid-grouped +multi_line_output=4 +not_skip=__init__.py + +# Don't sort one-letter classes (like Q) first +order_by_type=false + +enforce_white_space=true diff --git a/setup.py b/setup.py index ad645f1..c38d4ac 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,8 @@ #!/usr/bin/python -from setuptools import setup, find_packages +from __future__ import absolute_import, division, print_function, unicode_literals + +from setuptools import find_packages, setup tests_require=[ 'nose', @@ -20,9 +22,9 @@ packages=find_packages(exclude=['tests']), test_suite='nose.collector', install_requires=[ - 'riak==2.5.4', - 'python-dateutil==1.5', - 'protobuf==2.6.1', + 'python-dateutil>=1.5, != 2.0', + 'riak', + 'six', ], options={'easy_install': {'allow_hosts': 'pypi.python.org'}}, tests_require=tests_require, diff --git a/sunspear/activitystreams/models.py b/sunspear/activitystreams/models.py index 02ca5e4..bdec8fc 100644 --- a/sunspear/activitystreams/models.py +++ b/sunspear/activitystreams/models.py @@ -1,10 +1,12 @@ -from sunspear.exceptions import SunspearValidationException +from __future__ import absolute_import, division, print_function, unicode_literals -from sunspear.lib.rfc3339 import rfc3339 +import datetime +import six from dateutil.parser import parse -import datetime +from sunspear.exceptions import SunspearValidationException +from sunspear.lib.rfc3339 import rfc3339 __all__ = ('Model', 'Activity', 'ReplyActivity', 'LikeActivity', 'Object', 'MediaLink', ) @@ -89,7 +91,7 @@ def parse_data(self, data, *args, **kwargs): _parsed_data[c] = _parsed_data[c].parse_data(_parsed_data[c].get_dict()) #parse anything that is a dictionary for things like datetime fields that are datetime objects - for k, v in _parsed_data.items(): + for k, v in list(_parsed_data.items()): if isinstance(v, dict) and k not in self._response_fields: _parsed_data[k] = self.parse_data(v) @@ -113,7 +115,7 @@ def get_dict(self): def _parse_date(self, date=None, utc=True, use_system_timezone=False): dt = None if date is None or not isinstance(date, datetime.datetime): - if isinstance(date, basestring): + if isinstance(date, six.string_types): try: dt = parse(date) except ValueError: diff --git a/sunspear/aggregators/base.py b/sunspear/aggregators/base.py index a2d8991..49b9b3d 100644 --- a/sunspear/aggregators/base.py +++ b/sunspear/aggregators/base.py @@ -1,3 +1,6 @@ +from __future__ import absolute_import, division, print_function, unicode_literals + + class BaseAggregator(object): def __init__(self, *args, **kwargs): pass diff --git a/sunspear/aggregators/property.py b/sunspear/aggregators/property.py index 277743f..fcc3389 100644 --- a/sunspear/aggregators/property.py +++ b/sunspear/aggregators/property.py @@ -1,10 +1,11 @@ -from sunspear.aggregators.base import BaseAggregator -from sunspear.lib.dotdict import dotdictify - -from itertools import groupby +from __future__ import absolute_import, division, print_function, unicode_literals import copy import re +from itertools import groupby + +from sunspear.aggregators.base import BaseAggregator +from sunspear.lib.dotdict import dotdictify class PropertyAggregator(BaseAggregator): @@ -48,12 +49,12 @@ def _listify_attributes(self, group_by_attributes=[], activity={}): nested_root, rest = attr.split('.', 1) #store a list of nested roots. We'll have to be careful not to listify these nested_root_attributes.append(nested_root) - for nested_dict_key, nested_dict_value in activity.get(nested_dict).items(): + for nested_dict_key, nested_dict_value in list(activity.get(nested_dict).items()): if nested_dict_key != deepest_attr: listified_dict['.'.join([nested_dict, nested_dict_key])] = [nested_dict_value] #now we listify all other non nested attributes - for key, val in activity.items(): + for key, val in list(activity.items()): if key not in group_by_attributes and key not in nested_root_attributes: listified_dict[key] = [val] @@ -96,7 +97,7 @@ def _aggregate_activities(self, group_by_attributes=[], grouped_activities=[]): #aggregate the rest of the activities into lists for activity in group_list[1:]: activity = dotdictify(activity) - for key in aggregated_activity.keys(): + for key in list(aggregated_activity.keys()): if key not in group_by_attributes and key not in nested_root_attributes: aggregated_activity[key].append(activity.get(key)) @@ -107,7 +108,7 @@ def _aggregate_activities(self, group_by_attributes=[], grouped_activities=[]): if nested_val is not None: nested_dict, deepest_attr = attr.rsplit('.', 1) - for nested_dict_key, nested_dict_value in activity.get(nested_dict).items(): + for nested_dict_key, nested_dict_value in list(activity.get(nested_dict).items()): if nested_dict_key != deepest_attr: aggregated_activity['.'.join([nested_dict, nested_dict_key])].append(nested_dict_value) diff --git a/sunspear/backends/base.py b/sunspear/backends/base.py index 3e415f9..9c30e97 100644 --- a/sunspear/backends/base.py +++ b/sunspear/backends/base.py @@ -1,9 +1,11 @@ -from sunspear.activitystreams.models import Activity, ReplyActivity, LikeActivity -from sunspear.exceptions import (SunspearDuplicateEntryException, SunspearInvalidActivityException, - SunspearInvalidObjectException) +from __future__ import absolute_import, division, print_function, unicode_literals -import uuid import copy +import uuid + +from sunspear.activitystreams.models import Activity, LikeActivity, ReplyActivity +from sunspear.exceptions import ( + SunspearDuplicateEntryException, SunspearInvalidActivityException, SunspearInvalidObjectException) __all__ = ('BaseBackend', 'SUB_ACTIVITY_MAP') @@ -75,7 +77,7 @@ def create_activity(self, activity, **kwargs): objs_created = [] objs_modified = [] - for key, value in activity_copy.items(): + for key, value in list(activity_copy.items()): if key in Activity._object_fields and isinstance(value, dict): if self.obj_exists(value): previous_value = self.get_obj([self._extract_id(value)])[0] diff --git a/sunspear/backends/riak.py b/sunspear/backends/riak.py index b3271f9..bda720b 100644 --- a/sunspear/backends/riak.py +++ b/sunspear/backends/riak.py @@ -15,18 +15,20 @@ specific language governing permissions and limitations under the License. """ -from __future__ import absolute_import +from __future__ import absolute_import, division, print_function, unicode_literals -from sunspear.activitystreams.models import Object, Activity, Model -from sunspear.exceptions import (SunspearValidationException) -from sunspear.backends.base import BaseBackend, SUB_ACTIVITY_MAP +import calendar +import copy +import datetime +import uuid +import six from riak import RiakClient -import uuid -import copy -import datetime -import calendar +from sunspear.activitystreams.models import Activity, Model, Object +from sunspear.backends.base import BaseBackend, SUB_ACTIVITY_MAP +from sunspear.compat import must_be_str +from sunspear.exceptions import SunspearValidationException __all__ = ('RiakBackend', ) @@ -149,38 +151,32 @@ class RiakBackend(BaseBackend): def __init__( self, protocol="pbc", nodes=[], objects_bucket_name="objects", - activities_bucket_name="activities", **kwargs): - - self._riak_backend = RiakClient(protocol=protocol, nodes=nodes) - - r_value = kwargs.get("r") - w_value = kwargs.get("w") - dw_value = kwargs.get("dw") - pr_value = kwargs.get("pr") - pw_value = kwargs.get("pw") + activities_bucket_name="activities", r=None, w=None, dw=None, + pr=None, pw=None, **kwargs): - self._objects = self._riak_backend.bucket(objects_bucket_name) - self._activities = self._riak_backend.bucket(activities_bucket_name) + self._riak_backend = RiakClient(protocol=protocol, nodes=nodes, **kwargs) + self._objects = self._riak_backend.bucket(must_be_str(objects_bucket_name)) + self._activities = self._riak_backend.bucket(must_be_str(activities_bucket_name)) - if r_value: - self._objects.r = r_value - self._activities.r = r_value + if r: + self._objects.r = r + self._activities.r = r - if w_value: - self._objects.w = w_value - self._activities.w = w_value + if w: + self._objects.w = w + self._activities.w = w - if dw_value: - self._objects.dw = dw_value - self._activities.dw = dw_value + if dw: + self._objects.dw = dw + self._activities.dw = dw - if pr_value: - self._objects.pr = pr_value - self._activities.pr = pr_value + if pr: + self._objects.pr = pr + self._activities.pr = pr - if pw_value: - self._objects.pw = pw_value - self._activities.pw = pw_value + if pw: + self._objects.pw = pw + self._activities.pw = pw def clear_all(self, **kwargs): """ @@ -237,11 +233,11 @@ def set_general_indexes(self, riak_object): :type riak_object: RiakObject :param riak_object: a RiakObject representing the model of the class """ - if not filter(lambda x: x[0] == "timestamp_int", riak_object.indexes): - riak_object.add_index("timestamp_int", self._get_timestamp()) + if not any(must_be_str(name) == must_be_str('timestamp_int') for name, value in riak_object.indexes): + riak_object.add_index(must_be_str("timestamp_int"), self._get_timestamp()) - riak_object.remove_index('modified_int') - riak_object.add_index("modified_int", self._get_timestamp()) + riak_object.remove_index(must_be_str('modified_int')) + riak_object.add_index(must_be_str("modified_int"), self._get_timestamp()) return riak_object def obj_update(self, obj, **kwargs): @@ -306,15 +302,15 @@ def set_activity_indexes(self, riak_object): """ _dict = riak_object.data - riak_object.remove_index('verb_bin') - riak_object.remove_index('actor_bin') - riak_object.remove_index('object_bin') - riak_object.add_index("verb_bin", self._extract_id(_dict['verb'])) - riak_object.add_index("actor_bin", self._extract_id(_dict['actor'])) - riak_object.add_index("object_bin", self._extract_id(_dict['object'])) + riak_object.remove_index(must_be_str('verb_bin')) + riak_object.remove_index(must_be_str('actor_bin')) + riak_object.remove_index(must_be_str('object_bin')) + riak_object.add_index(must_be_str("verb_bin"), self._extract_id(_dict['verb'])) + riak_object.add_index(must_be_str("actor_bin"), self._extract_id(_dict['actor'])) + riak_object.add_index(must_be_str("object_bin"), self._extract_id(_dict['object'])) if 'target' in _dict and _dict.get("target"): - riak_object.remove_index('target_bin') - riak_object.add_index("target_bin", self._extract_id(_dict['target'])) + riak_object.remove_index(must_be_str('target_bin')) + riak_object.add_index(must_be_str("target_bin"), self._extract_id(_dict['target'])) return riak_object @@ -360,7 +356,7 @@ def activity_get( :return: list -- a list of activities matching ``activity_ids``. If the activities is not found, it is not included in the result set. Activities are returned in the order of ids provided. """ - activity_ids = map(self._extract_id, activity_ids) + activity_ids = list(map(self._extract_id, activity_ids)) if not activity_ids: return [] @@ -429,13 +425,11 @@ def sub_activity_delete(self, sub_activity, sub_activity_verb, **kwargs): raise SunspearValidationException("Trying to delete something that is not a {}.".format(sub_activity_model.sub_item_verb)) #clean up the reference from the original activity - in_reply_to_key = filter(lambda x: x[0] == 'inreplyto_bin', sub_activity_riak_model.indexes)[0][1] + in_reply_to_key = [x for x in sub_activity_riak_model.indexes if x[0] == 'inreplyto_bin'][0][1] activity = self._activities.get(key=in_reply_to_key) activity_data = activity.data activity_data[sub_activity_model.sub_item_key]['totalItems'] -= 1 - activity_data[sub_activity_model.sub_item_key]['items'] = filter( - lambda x: x["id"] != sub_activity_id, - activity_data[sub_activity_model.sub_item_key]['items']) + activity_data[sub_activity_model.sub_item_key]['items'] = [x for x in activity_data[sub_activity_model.sub_item_key]['items'] if x["id"] != sub_activity_id] updated_activity = self.update_activity(activity_data, **kwargs) self.delete_activity(sub_activity_id) @@ -453,8 +447,8 @@ def set_sub_item_indexes(self, riak_object, **kwargs): original_activity_id = kwargs.get('activity_id') if not original_activity_id: raise SunspearValidationException() - riak_object.remove_index('inreplyto_bin') - riak_object.add_index("inreplyto_bin", str(original_activity_id)) + riak_object.remove_index(must_be_str('inreplyto_bin')) + riak_object.add_index(must_be_str("inreplyto_bin"), str(original_activity_id)) return riak_object @@ -570,7 +564,7 @@ def _dehydrate_sub_activity(self, sub_activity, obj_list, skip_sub_activities=Fa for i, item in enumerate(sub_activity[collection]['items']): try: dehydrated_sub_items.append(self._dehydrate_sub_activity(item, obj_list)) - except KeyError, e: + except KeyError as e: pass sub_activity[collection]['items'] = dehydrated_sub_items sub_activity[collection]['totalItems'] = len(dehydrated_sub_items) @@ -592,9 +586,9 @@ def _extract_object_keys(self, activity, skip_sub_activities=False): for in_reply_to_obj in objects['inReplyTo']] if isinstance(objects, list): for item in objects: - if isinstance(item, basestring): + if isinstance(item, six.string_types): keys.append(item) - if isinstance(objects, basestring): + if isinstance(objects, six.string_types): keys.append(objects) if not skip_sub_activities: @@ -620,9 +614,9 @@ def _dehydrate_object_keys(self, activity, objects_dict, skip_sub_activities=Fal objects_dict, skip_sub_activities=skip_sub_activities) if isinstance(activity_objects, list): for i, obj_id in enumerate(activity_objects): - if isinstance(activity[object_key][i], basestring): + if isinstance(activity[object_key][i], six.string_types): activity[object_key][i] = objects_dict.get(obj_id, {}) - if isinstance(activity_objects, basestring): + if isinstance(activity_objects, six.string_types): activity[object_key] = objects_dict.get(activity_objects, {}) if not skip_sub_activities: @@ -674,7 +668,7 @@ def _get_many_activities(self, activity_ids=[], raw_filter="", filters=None, inc #riak does not return the results in any particular order (unless we sort). So, #we have to put the objects returned by riak back in order - results_map = dict(map(lambda result: (result['id'], result,), results)) + results_map = dict([(result['id'], result,) for result in results]) reordered_results = [results_map[id] for id in activity_ids if id in results_map] return reordered_results @@ -684,7 +678,7 @@ def _extract_id(self, activity_or_id): Helper that returns an id if the activity has one. """ this_id = None - if isinstance(activity_or_id, basestring): + if isinstance(activity_or_id, six.string_types): this_id = activity_or_id elif isinstance(activity_or_id, dict): this_id = activity_or_id.get('id', None) @@ -704,7 +698,7 @@ def _get_timestamp(self): returns a unix timestamp representing the ``datetime`` object """ dt_obj = datetime.datetime.utcnow() - return long((calendar.timegm(dt_obj.utctimetuple()) * 1000)) + (dt_obj.microsecond / 1000) + return int((calendar.timegm(dt_obj.utctimetuple()) * 1000)) + (dt_obj.microsecond // 1000) def get_new_id(self): """ @@ -714,5 +708,3 @@ def get_new_id(self): :return: a new id """ return uuid.uuid1().hex - # now = datetime.datetime.utcnow() - # return str(long(calendar.timegm(now.utctimetuple()) - calendar.timegm(self.custom_epoch.utctimetuple())) + now.microsecond) diff --git a/sunspear/clients.py b/sunspear/clients.py index 491e4ac..88c56ff 100644 --- a/sunspear/clients.py +++ b/sunspear/clients.py @@ -1,3 +1,6 @@ +from __future__ import absolute_import, division, print_function, unicode_literals + + class SunspearClient(object): """ The class is used to create, delete, remove and update activity stream items. diff --git a/sunspear/compat.py b/sunspear/compat.py new file mode 100644 index 0000000..61060ca --- /dev/null +++ b/sunspear/compat.py @@ -0,0 +1,25 @@ +from __future__ import absolute_import, division, print_function, unicode_literals + +import traceback +from logging import getLogger + +import six + +logger = getLogger(__name__) + + +def must_be_str(arg): + """ + Some functions require `str` in Python 2, i.e. its binary type, + but also `str` in Python 3, which is its text type... + + Accommodate both. + """ + if six.PY2: + if isinstance(arg, six.text_type): + return arg.encode('utf-8') + # The idea of this function is to simply remove all function calls once we're on python 3, so let's be sure we + # always have the right type passed in in python 2, i.e. `unicode`. + traceback.print_stack() + logger.warn('Unexpectedly got non-unicode in `must_be_str`...', extra={'stack': True}) + return arg diff --git a/sunspear/exceptions.py b/sunspear/exceptions.py index 47eb1bc..b3b2792 100644 --- a/sunspear/exceptions.py +++ b/sunspear/exceptions.py @@ -1,3 +1,6 @@ +from __future__ import absolute_import, division, print_function, unicode_literals + + class SunspearBaseException(Exception): pass @@ -26,4 +29,4 @@ class SunspearInvalidActivityException(SunspearBaseException): pass class SunspearInvalidObjectException(SunspearBaseException): - pass \ No newline at end of file + pass diff --git a/sunspear/lib/dotdict.py b/sunspear/lib/dotdict.py index 50e4ce6..78576c1 100644 --- a/sunspear/lib/dotdict.py +++ b/sunspear/lib/dotdict.py @@ -1,5 +1,6 @@ #Originally 'borrowed' from http://stackoverflow.com/questions/3797957/python-easily-access-deeply-nested-dict-get-and-set #Some modifications mad to suit the needs of this project +from __future__ import absolute_import, division, print_function, unicode_literals class dotdictify(dict): diff --git a/sunspear/lib/rfc3339.py b/sunspear/lib/rfc3339.py index bfca1f4..46e525d 100644 --- a/sunspear/lib/rfc3339.py +++ b/sunspear/lib/rfc3339.py @@ -20,6 +20,7 @@ .. _BitBucket: https://bitbucket.org/henry/clan.cx/issues ''' +from __future__ import absolute_import, division, print_function, unicode_literals __author__ = 'Henry Precheur ' __license__ = 'ISCL' @@ -28,7 +29,6 @@ import datetime import time -import unittest def _timezone(utc_offset): diff --git a/tests/test_activitystreams.py b/tests/test_activitystreams.py index 7f492f0..b741b2c 100644 --- a/tests/test_activitystreams.py +++ b/tests/test_activitystreams.py @@ -1,12 +1,13 @@ -from __future__ import absolute_import +from __future__ import absolute_import, division, print_function, unicode_literals -from nose.tools import ok_, eq_, raises, set_trace -from mock import MagicMock, call, ANY +import datetime -from sunspear.activitystreams.models import Activity, MediaLink, Object, Model, ReplyActivity, LikeActivity -from sunspear.exceptions import SunspearValidationException +import six +from mock import MagicMock +from nose.tools import eq_, ok_, raises -import datetime +from sunspear.activitystreams.models import Activity, MediaLink, Model, Object +from sunspear.exceptions import SunspearValidationException class TestActivityModel(object): @@ -214,7 +215,7 @@ def test__set_defaults(self): obj = Model({}, backend=MagicMock()) obj_dict = obj._set_defaults({'id': 12}) - ok_(isinstance(obj_dict.get('id'), basestring)) + ok_(isinstance(obj_dict.get('id'), six.string_types)) def test__set_defaults_no_id_does_not_fail(self): obj = Model({}, backend=MagicMock()) @@ -229,7 +230,7 @@ def test__parse_date(self): eq_(obj._parse_date(d), d.strftime('%Y-%m-%dT%H:%M:%S') + "Z") #badly formatted string date - ok_(isinstance(obj._parse_date(date="qwerty"), basestring)) + ok_(isinstance(obj._parse_date(date="qwerty"), six.string_types)) #no date passed - ok_(isinstance(obj._parse_date(date=None), basestring)) + ok_(isinstance(obj._parse_date(date=None), six.string_types)) diff --git a/tests/test_aggregators.py b/tests/test_aggregators.py index d493b62..91ece85 100644 --- a/tests/test_aggregators.py +++ b/tests/test_aggregators.py @@ -1,10 +1,10 @@ -from __future__ import absolute_import +from __future__ import absolute_import, division, print_function, unicode_literals -from nose.tools import ok_, eq_, raises, set_trace +from itertools import groupby -from sunspear.aggregators.property import PropertyAggregator +from nose.tools import eq_, ok_, raises, set_trace -from itertools import groupby +from sunspear.aggregators.property import PropertyAggregator class TestPropertyAggregator(object): diff --git a/tests/test_backend.py b/tests/test_backend.py index 7b160ef..29143c4 100644 --- a/tests/test_backend.py +++ b/tests/test_backend.py @@ -1,19 +1,20 @@ -from __future__ import absolute_import +from __future__ import absolute_import, division, print_function, unicode_literals -from nose.tools import ok_, eq_, set_trace, raises -from mock import MagicMock, call, ANY +import datetime + +import six +from mock import ANY, call, MagicMock +from nose.tools import eq_, ok_, raises -from sunspear.exceptions import SunspearValidationException from sunspear.aggregators.property import PropertyAggregator from sunspear.backends.riak import RiakBackend - -import datetime +from sunspear.compat import must_be_str +from sunspear.exceptions import SunspearValidationException riak_connection_options = { "nodes": [ {'http_port': 8098, 'host': '127.0.0.1'}], 'protocol': 'http', - # "nodes": [{'host': '127.0.0.1', 'pb_port': 10017}, {'host': '127.0.0.1', 'pb_port': 10027}, {'host': '127.0.0.1', 'pb_port': 10037}], } @@ -172,7 +173,7 @@ def test_create_activity_stored_as_sparse(self): riak_obj = self._backend._activities.get('5') riak_obj_data = riak_obj.data - ok_(isinstance(riak_obj_data.get("target"), basestring)) + ok_(isinstance(riak_obj_data.get("target"), six.string_types)) def test_delete_activity(self): self._backend._activities.get('5').delete() @@ -730,8 +731,8 @@ def test_create_reply_maintains_dehydrate_state(self): self._backend.create_activity({"id": 5, "title": "Stream Item", "verb": "post", "actor": actor, "object": obj}) riak_obj_data = self._backend._activities.get(key="5").data - ok_(isinstance(riak_obj_data.get("actor"), basestring)) - ok_(isinstance(riak_obj_data.get("object"), basestring)) + ok_(isinstance(riak_obj_data.get("actor"), six.string_types)) + ok_(isinstance(riak_obj_data.get("object"), six.string_types)) #now create a reply for the activity reply_activity_dict, activity_obj_dict = self._backend.sub_activity_create( @@ -739,8 +740,8 @@ def test_create_reply_maintains_dehydrate_state(self): sub_activity_verb='reply') riak_obj_data = self._backend._activities.get(key="5").data - ok_(isinstance(riak_obj_data.get("actor"), basestring)) - ok_(isinstance(riak_obj_data.get("object"), basestring)) + ok_(isinstance(riak_obj_data.get("actor"), six.string_types)) + ok_(isinstance(riak_obj_data.get("object"), six.string_types)) def test_create_reply_with_extra_data(self): self._backend._activities.get('5').delete() @@ -843,8 +844,8 @@ def test_create_like_maintains_dehydrate_state(self): self._backend.create_activity({"id": 5, "title": "Stream Item", "verb": "post", "actor": actor, "object": obj}) riak_obj_data = self._backend._activities.get(key="5").data - ok_(isinstance(riak_obj_data.get("actor"), basestring)) - ok_(isinstance(riak_obj_data.get("object"), basestring)) + ok_(isinstance(riak_obj_data.get("actor"), six.string_types)) + ok_(isinstance(riak_obj_data.get("object"), six.string_types)) #now create a reply for the activity like_activity_dict, activity_obj_dict = self._backend.sub_activity_create( @@ -852,8 +853,8 @@ def test_create_like_maintains_dehydrate_state(self): sub_activity_verb='like') riak_obj_data = self._backend._activities.get(key="5").data - ok_(isinstance(riak_obj_data.get("actor"), basestring)) - ok_(isinstance(riak_obj_data.get("object"), basestring)) + ok_(isinstance(riak_obj_data.get("actor"), six.string_types)) + ok_(isinstance(riak_obj_data.get("object"), six.string_types)) def test_create_like(self): self._backend._activities.get('5').delete() @@ -950,15 +951,15 @@ def test_delete_like_maintains_dehydrated_state(self): 5, actor2_id, "", sub_activity_verb='like') riak_obj_data = self._backend._activities.get(key="5").data - ok_(isinstance(riak_obj_data.get("actor"), basestring)) - ok_(isinstance(riak_obj_data.get("object"), basestring)) + ok_(isinstance(riak_obj_data.get("actor"), six.string_types)) + ok_(isinstance(riak_obj_data.get("object"), six.string_types)) #now delete the like and make sure everything is ok: self._backend.sub_activity_delete(like_activity_dict['id'], 'like') riak_obj_data = self._backend._activities.get(key="5").data - ok_(isinstance(riak_obj_data.get("actor"), basestring)) - ok_(isinstance(riak_obj_data.get("object"), basestring)) + ok_(isinstance(riak_obj_data.get("actor"), six.string_types)) + ok_(isinstance(riak_obj_data.get("object"), six.string_types)) def test_reply_delete_maintains_dehydrated_state(self): self._backend._activities.get('5').delete() @@ -983,16 +984,16 @@ def test_reply_delete_maintains_dehydrated_state(self): 5, actor2_id, "This is a reply.", sub_activity_verb='reply') riak_obj_data = self._backend._activities.get(key="5").data - ok_(isinstance(riak_obj_data.get("actor"), basestring)) - ok_(isinstance(riak_obj_data.get("object"), basestring)) + ok_(isinstance(riak_obj_data.get("actor"), six.string_types)) + ok_(isinstance(riak_obj_data.get("object"), six.string_types)) #now delete the reply and make sure everything is ok: self._backend.sub_activity_delete( reply_activity_dict['id'], 'reply') riak_obj_data = self._backend._activities.get(key="5").data - ok_(isinstance(riak_obj_data.get("actor"), basestring)) - ok_(isinstance(riak_obj_data.get("object"), basestring)) + ok_(isinstance(riak_obj_data.get("actor"), six.string_types)) + ok_(isinstance(riak_obj_data.get("object"), six.string_types)) def test_reply_delete(self): self._backend._activities.get('5').delete() @@ -1576,7 +1577,7 @@ def test_get_activities_with_aggregation_pipline(self): activities = self._backend.activity_get(activity_ids, aggregation_pipeline=[PropertyAggregator(properties=['verb', 'actor'])]) - eq_([{u'id': u'7779', u'verb': u'like', u'target': {u'objectType': u'something', u'id': u'31415', u'published': u'2012-07-05T12:00:00Z'}, u'object': {u'inReplyTo': [], u'objectType': u'like', u'id': u'6669', u'published': u'2012-08-05T12:00:00Z'}, u'actor': {u'objectType': u'something', u'id': u'1234', u'published': u'2012-07-05T12:00:00Z'}}, {u'id': u'8889', u'verb': u'reply', u'target': {u'objectType': u'something', u'id': u'31415', u'published': u'2012-07-05T12:00:00Z'}, u'object': {u'content': u'This is my first reply', u'inReplyTo': [], u'objectType': u'reply', u'id': u'9999', u'published': u'2012-08-05T12:00:00Z'}, u'actor': {u'objectType': u'something', u'id': u'1234', u'published': u'2012-07-05T12:00:00Z'}}, {'grouped_by_attributes': ['verb', 'actor'], u'title': [u'Stream Item', u'Stream Item'], u'object': [{u'objectType': u'something', u'id': u'4353', u'published': u'2012-07-05T12:00:00Z'}, {u'published': u'2012-07-05T12:00:00Z', u'id': u'4353', u'objectType': u'something'}], u'actor': {u'published': u'2012-07-05T12:00:00Z', u'id': u'4321', u'objectType': u'something'}, u'verb': u'post', u'replies': [{u'totalItems': 2, u'items': [{u'verb': u'reply', u'actor': {u'objectType': u'something', u'id': u'1234', u'published': u'2012-07-05T12:00:00Z'}, u'object': {u'target': {u'objectType': u'something', u'id': u'31415', u'published': u'2012-07-05T12:00:00Z'}, u'object': {u'content': u'This is my first reply', u'inReplyTo': [], u'objectType': u'reply', u'id': u'9999', u'published': u'2012-08-05T12:00:00Z'}, u'actor': {u'objectType': u'something', u'id': u'1234', u'published': u'2012-07-05T12:00:00Z'}, u'verb': u'reply', u'id': u'8889', u'objectType': u'activity'}}, {u'verb': u'reply', u'actor': {u'objectType': u'something', u'id': u'1234', u'published': u'2012-07-05T12:00:00Z'}, u'object': {u'target': {u'objectType': u'something', u'id': u'1234', u'published': u'2012-07-05T12:00:00Z'}, u'object': {u'content': u'This is my second reply', u'inReplyTo': [], u'objectType': u'reply', u'id': u'9998', u'published': u'2012-08-05T12:05:00Z'}, u'actor': {u'objectType': u'something', u'id': u'4321', u'published': u'2012-07-05T12:00:00Z'}, u'verb': u'reply', u'id': u'8888', u'objectType': u'activity'}}]}, {u'totalItems': 2, u'items': [{u'verb': u'reply', u'actor': {u'objectType': u'something', u'id': u'1234', u'published': u'2012-07-05T12:00:00Z'}, u'object': {u'target': {u'objectType': u'something', u'id': u'31415', u'published': u'2012-07-05T12:00:00Z'}, u'object': {u'content': u'This is my first reply', u'inReplyTo': [], u'objectType': u'reply', u'id': u'9999', u'published': u'2012-08-05T12:00:00Z'}, u'actor': {u'objectType': u'something', u'id': u'1234', u'published': u'2012-07-05T12:00:00Z'}, u'verb': u'reply', u'id': u'8889', u'objectType': u'activity'}}, {u'verb': u'reply', u'actor': {u'objectType': u'something', u'id': u'1234', u'published': u'2012-07-05T12:00:00Z'}, u'object': {u'target': {u'objectType': u'something', u'id': u'1234', u'published': u'2012-07-05T12:00:00Z'}, u'object': {u'content': u'This is my second reply', u'inReplyTo': [], u'objectType': u'reply', u'id': u'9998', u'published': u'2012-08-05T12:05:00Z'}, u'actor': {u'objectType': u'something', u'id': u'4321', u'published': u'2012-07-05T12:00:00Z'}, u'verb': u'reply', u'id': u'8888', u'objectType': u'activity'}}]}], u'id': [u'5555', u'5556'], 'grouped_by_values': [u'post', {u'published': u'2012-07-05T12:00:00Z', u'id': u'4321', u'objectType': u'something'}]}, {u'id': u'7778', u'verb': u'like', u'target': {u'objectType': u'something', u'id': u'31415', u'published': u'2012-07-05T12:00:00Z'}, u'object': {u'inReplyTo': [], u'objectType': u'like', u'id': u'6669', u'published': u'2012-08-05T12:00:00Z'}, u'actor': {u'objectType': u'something', u'id': u'1234', u'published': u'2012-07-05T12:00:00Z'}}, {u'id': u'8888', u'verb': u'reply', u'target': {u'objectType': u'something', u'id': u'1234', u'published': u'2012-07-05T12:00:00Z'}, u'object': {u'content': u'This is my second reply', u'inReplyTo': [], u'objectType': u'reply', u'id': u'9998', u'published': u'2012-08-05T12:05:00Z'}, u'actor': {u'objectType': u'something', u'id': u'4321', u'published': u'2012-07-05T12:00:00Z'}}], activities) + eq_([{'id': '7779', 'verb': 'like', 'target': {'objectType': 'something', 'id': '31415', 'published': '2012-07-05T12:00:00Z'}, 'object': {'inReplyTo': [], 'objectType': 'like', 'id': '6669', 'published': '2012-08-05T12:00:00Z'}, 'actor': {'objectType': 'something', 'id': '1234', 'published': '2012-07-05T12:00:00Z'}}, {'id': '8889', 'verb': 'reply', 'target': {'objectType': 'something', 'id': '31415', 'published': '2012-07-05T12:00:00Z'}, 'object': {'content': 'This is my first reply', 'inReplyTo': [], 'objectType': 'reply', 'id': '9999', 'published': '2012-08-05T12:00:00Z'}, 'actor': {'objectType': 'something', 'id': '1234', 'published': '2012-07-05T12:00:00Z'}}, {'grouped_by_attributes': ['verb', 'actor'], 'title': ['Stream Item', 'Stream Item'], 'object': [{'objectType': 'something', 'id': '4353', 'published': '2012-07-05T12:00:00Z'}, {'published': '2012-07-05T12:00:00Z', 'id': '4353', 'objectType': 'something'}], 'actor': {'published': '2012-07-05T12:00:00Z', 'id': '4321', 'objectType': 'something'}, 'verb': 'post', 'replies': [{'totalItems': 2, 'items': [{'verb': 'reply', 'actor': {'objectType': 'something', 'id': '1234', 'published': '2012-07-05T12:00:00Z'}, 'object': {'target': {'objectType': 'something', 'id': '31415', 'published': '2012-07-05T12:00:00Z'}, 'object': {'content': 'This is my first reply', 'inReplyTo': [], 'objectType': 'reply', 'id': '9999', 'published': '2012-08-05T12:00:00Z'}, 'actor': {'objectType': 'something', 'id': '1234', 'published': '2012-07-05T12:00:00Z'}, 'verb': 'reply', 'id': '8889', 'objectType': 'activity'}}, {'verb': 'reply', 'actor': {'objectType': 'something', 'id': '1234', 'published': '2012-07-05T12:00:00Z'}, 'object': {'target': {'objectType': 'something', 'id': '1234', 'published': '2012-07-05T12:00:00Z'}, 'object': {'content': 'This is my second reply', 'inReplyTo': [], 'objectType': 'reply', 'id': '9998', 'published': '2012-08-05T12:05:00Z'}, 'actor': {'objectType': 'something', 'id': '4321', 'published': '2012-07-05T12:00:00Z'}, 'verb': 'reply', 'id': '8888', 'objectType': 'activity'}}]}, {'totalItems': 2, 'items': [{'verb': 'reply', 'actor': {'objectType': 'something', 'id': '1234', 'published': '2012-07-05T12:00:00Z'}, 'object': {'target': {'objectType': 'something', 'id': '31415', 'published': '2012-07-05T12:00:00Z'}, 'object': {'content': 'This is my first reply', 'inReplyTo': [], 'objectType': 'reply', 'id': '9999', 'published': '2012-08-05T12:00:00Z'}, 'actor': {'objectType': 'something', 'id': '1234', 'published': '2012-07-05T12:00:00Z'}, 'verb': 'reply', 'id': '8889', 'objectType': 'activity'}}, {'verb': 'reply', 'actor': {'objectType': 'something', 'id': '1234', 'published': '2012-07-05T12:00:00Z'}, 'object': {'target': {'objectType': 'something', 'id': '1234', 'published': '2012-07-05T12:00:00Z'}, 'object': {'content': 'This is my second reply', 'inReplyTo': [], 'objectType': 'reply', 'id': '9998', 'published': '2012-08-05T12:05:00Z'}, 'actor': {'objectType': 'something', 'id': '4321', 'published': '2012-07-05T12:00:00Z'}, 'verb': 'reply', 'id': '8888', 'objectType': 'activity'}}]}], 'id': ['5555', '5556'], 'grouped_by_values': ['post', {'published': '2012-07-05T12:00:00Z', 'id': '4321', 'objectType': 'something'}]}, {'id': '7778', 'verb': 'like', 'target': {'objectType': 'something', 'id': '31415', 'published': '2012-07-05T12:00:00Z'}, 'object': {'inReplyTo': [], 'objectType': 'like', 'id': '6669', 'published': '2012-08-05T12:00:00Z'}, 'actor': {'objectType': 'something', 'id': '1234', 'published': '2012-07-05T12:00:00Z'}}, {'id': '8888', 'verb': 'reply', 'target': {'objectType': 'something', 'id': '1234', 'published': '2012-07-05T12:00:00Z'}, 'object': {'content': 'This is my second reply', 'inReplyTo': [], 'objectType': 'reply', 'id': '9998', 'published': '2012-08-05T12:05:00Z'}, 'actor': {'objectType': 'something', 'id': '4321', 'published': '2012-07-05T12:00:00Z'}}], activities) class TestIndexes(object): @@ -1591,10 +1592,10 @@ def test_set_sub_item_indexes(self): self._backend.set_activity_indexes(riak_obj_mock) calls = [ - call.add_index('verb_bin', 'post'), - call.add_index('actor_bin', '1234'), - call.add_index('object_bin', '5678'), - call.add_index('target_bin', '4333'), + call.add_index(must_be_str('verb_bin'), 'post'), + call.add_index(must_be_str('actor_bin'), '1234'), + call.add_index(must_be_str('object_bin'), '5678'), + call.add_index(must_be_str('target_bin'), '4333'), ] riak_obj_mock.assert_has_calls(calls, any_order=True) @@ -1607,7 +1608,7 @@ def test_set_sub_item_indexes_reply(self): self._backend.set_sub_item_indexes(riak_obj_mock, activity_id=1234) calls = [ - call.add_index('inreplyto_bin', ANY), + call.add_index(must_be_str('inreplyto_bin'), ANY), ] riak_obj_mock.assert_has_calls(calls, any_order=True) @@ -1627,8 +1628,8 @@ def test_set_general_indexes_not_already_created_set(self): self._backend.set_general_indexes(riak_obj_mock) calls = [ - call.add_index('timestamp_int', ANY), - call.add_index('modified_int', ANY), + call.add_index(must_be_str('timestamp_int'), ANY), + call.add_index(must_be_str('modified_int'), ANY), ] riak_obj_mock.assert_has_calls(calls, any_order=True) @@ -1636,12 +1637,12 @@ def test_set_general_indexes_not_already_created_set(self): def test_set_general_indexes_already_created(self): riak_obj_mock = MagicMock() - riak_obj_mock.indexes = [('timestamp_int', 12343214,)] + riak_obj_mock.indexes = [(must_be_str('timestamp_int'), 12343214,)] self._backend.set_general_indexes(riak_obj_mock) calls = [ - call.add_index('modified_int', ANY), + call.add_index(must_be_str('modified_int'), ANY), ] riak_obj_mock.assert_has_calls(calls, any_order=True) @@ -1655,8 +1656,8 @@ def test_create_obj_indexes(self): riak_obj = self._backend._objects.get(key=actstream_obj['id']) riak_obj.data - ok_(filter(lambda x: x[0] == 'timestamp_int', riak_obj.indexes) != []) - ok_(filter(lambda x: x[0] == 'modified_int', riak_obj.indexes) != []) + ok_([x for x in riak_obj.indexes if x[0] == 'timestamp_int'] != []) + ok_([x for x in riak_obj.indexes if x[0] == 'modified_int'] != []) def test_create_activity_indexes(self): self._backend._activities.get('5').delete() @@ -1678,8 +1679,8 @@ def test_create_activity_indexes(self): riak_obj = self._backend._activities.get(key=act_obj_dict['id']) riak_obj.data - ok_(filter(lambda x: x[0] == 'timestamp_int', riak_obj.indexes) != []) - ok_(filter(lambda x: x[0] == 'modified_int', riak_obj.indexes) != []) + ok_([x for x in riak_obj.indexes if x[0] == 'timestamp_int'] != []) + ok_([x for x in riak_obj.indexes if x[0] == 'modified_int'] != []) eq_(filter(lambda x: x[0] == 'verb_bin', riak_obj.indexes)[0][1], 'post') eq_(filter(lambda x: x[0] == 'actor_bin', riak_obj.indexes)[0][1], actor_id) eq_(filter(lambda x: x[0] == 'object_bin', riak_obj.indexes)[0][1], object_id) @@ -1713,10 +1714,9 @@ def test_create_sub_activity_indexes(self): riak_obj = self._backend._activities.get(key=like_activity_dict['id']) riak_obj.data - ok_(filter(lambda x: x[0] == 'timestamp_int', riak_obj.indexes) != []) - ok_(filter(lambda x: x[0] == 'modified_int', riak_obj.indexes) != []) + ok_([x for x in riak_obj.indexes if x[0] == 'timestamp_int'] != []) + ok_([x for x in riak_obj.indexes if x[0] == 'modified_int'] != []) eq_(filter(lambda x: x[0] == 'verb_bin', riak_obj.indexes)[0][1], 'like') eq_(filter(lambda x: x[0] == 'actor_bin', riak_obj.indexes)[0][1], actor2_id) eq_(filter(lambda x: x[0] == 'object_bin', riak_obj.indexes)[0][1], like_activity_dict['object']['id']) eq_(filter(lambda x: x[0] == 'inreplyto_bin', riak_obj.indexes)[0][1], '5') - diff --git a/tests/test_client.py b/tests/test_client.py index 26ec940..3da4b3a 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -1,14 +1,14 @@ -from __future__ import absolute_import +from __future__ import absolute_import, division, print_function, unicode_literals -from nose.tools import ok_, eq_, set_trace, raises -from mock import MagicMock, call, ANY +import datetime + +from mock import ANY, call, MagicMock +from nose.tools import eq_, ok_, raises, set_trace from sunspear.aggregators.property import PropertyAggregator from sunspear.backends.riak import RiakBackend from sunspear.clients import SunspearClient -import datetime - riak_connection_options = { "nodes": [ {'http_port': 8098, 'host': '127.0.0.1'}], @@ -614,5 +614,4 @@ def test_get_activities_with_aggregation_pipline(self): activities = self._client.get_activities(activity_ids=activity_ids, aggregation_pipeline=[PropertyAggregator(properties=['verb', 'actor'])]) - eq_([{u'id': u'7779', u'verb': u'like', u'target': {u'objectType': u'something', u'id': u'31415', u'published': u'2012-07-05T12:00:00Z'}, u'object': {u'inReplyTo': [], u'objectType': u'like', u'id': u'6669', u'published': u'2012-08-05T12:00:00Z'}, u'actor': {u'objectType': u'something', u'id': u'1234', u'published': u'2012-07-05T12:00:00Z'}}, {u'id': u'8889', u'verb': u'reply', u'target': {u'objectType': u'something', u'id': u'31415', u'published': u'2012-07-05T12:00:00Z'}, u'object': {u'content': u'This is my first reply', u'inReplyTo': [], u'objectType': u'reply', u'id': u'9999', u'published': u'2012-08-05T12:00:00Z'}, u'actor': {u'objectType': u'something', u'id': u'1234', u'published': u'2012-07-05T12:00:00Z'}}, {'grouped_by_attributes': ['verb', 'actor'], u'title': [u'Stream Item', u'Stream Item'], u'object': [{u'objectType': u'something', u'id': u'4353', u'published': u'2012-07-05T12:00:00Z'}, {u'published': u'2012-07-05T12:00:00Z', u'id': u'4353', u'objectType': u'something'}], u'actor': {u'published': u'2012-07-05T12:00:00Z', u'id': u'4321', u'objectType': u'something'}, u'verb': u'post', u'replies': [{u'totalItems': 2, u'items': [{u'verb': u'reply', u'actor': {u'objectType': u'something', u'id': u'1234', u'published': u'2012-07-05T12:00:00Z'}, u'object': {u'target': {u'objectType': u'something', u'id': u'31415', u'published': u'2012-07-05T12:00:00Z'}, u'object': {u'content': u'This is my first reply', u'inReplyTo': [], u'objectType': u'reply', u'id': u'9999', u'published': u'2012-08-05T12:00:00Z'}, u'actor': {u'objectType': u'something', u'id': u'1234', u'published': u'2012-07-05T12:00:00Z'}, u'verb': u'reply', u'id': u'8889', u'objectType': u'activity'}}, {u'verb': u'reply', u'actor': {u'objectType': u'something', u'id': u'1234', u'published': u'2012-07-05T12:00:00Z'}, u'object': {u'target': {u'objectType': u'something', u'id': u'1234', u'published': u'2012-07-05T12:00:00Z'}, u'object': {u'content': u'This is my second reply', u'inReplyTo': [], u'objectType': u'reply', u'id': u'9998', u'published': u'2012-08-05T12:05:00Z'}, u'actor': {u'objectType': u'something', u'id': u'4321', u'published': u'2012-07-05T12:00:00Z'}, u'verb': u'reply', u'id': u'8888', u'objectType': u'activity'}}]}, {u'totalItems': 2, u'items': [{u'verb': u'reply', u'actor': {u'objectType': u'something', u'id': u'1234', u'published': u'2012-07-05T12:00:00Z'}, u'object': {u'target': {u'objectType': u'something', u'id': u'31415', u'published': u'2012-07-05T12:00:00Z'}, u'object': {u'content': u'This is my first reply', u'inReplyTo': [], u'objectType': u'reply', u'id': u'9999', u'published': u'2012-08-05T12:00:00Z'}, u'actor': {u'objectType': u'something', u'id': u'1234', u'published': u'2012-07-05T12:00:00Z'}, u'verb': u'reply', u'id': u'8889', u'objectType': u'activity'}}, {u'verb': u'reply', u'actor': {u'objectType': u'something', u'id': u'1234', u'published': u'2012-07-05T12:00:00Z'}, u'object': {u'target': {u'objectType': u'something', u'id': u'1234', u'published': u'2012-07-05T12:00:00Z'}, u'object': {u'content': u'This is my second reply', u'inReplyTo': [], u'objectType': u'reply', u'id': u'9998', u'published': u'2012-08-05T12:05:00Z'}, u'actor': {u'objectType': u'something', u'id': u'4321', u'published': u'2012-07-05T12:00:00Z'}, u'verb': u'reply', u'id': u'8888', u'objectType': u'activity'}}]}], u'id': [u'5555', u'5556'], 'grouped_by_values': [u'post', {u'published': u'2012-07-05T12:00:00Z', u'id': u'4321', u'objectType': u'something'}]}, {u'id': u'7778', u'verb': u'like', u'target': {u'objectType': u'something', u'id': u'31415', u'published': u'2012-07-05T12:00:00Z'}, u'object': {u'inReplyTo': [], u'objectType': u'like', u'id': u'6669', u'published': u'2012-08-05T12:00:00Z'}, u'actor': {u'objectType': u'something', u'id': u'1234', u'published': u'2012-07-05T12:00:00Z'}}, {u'id': u'8888', u'verb': u'reply', u'target': {u'objectType': u'something', u'id': u'1234', u'published': u'2012-07-05T12:00:00Z'}, u'object': {u'content': u'This is my second reply', u'inReplyTo': [], u'objectType': u'reply', u'id': u'9998', u'published': u'2012-08-05T12:05:00Z'}, u'actor': {u'objectType': u'something', u'id': u'4321', u'published': u'2012-07-05T12:00:00Z'}}], activities) - + eq_([{'id': '7779', 'verb': 'like', 'target': {'objectType': 'something', 'id': '31415', 'published': '2012-07-05T12:00:00Z'}, 'object': {'inReplyTo': [], 'objectType': 'like', 'id': '6669', 'published': '2012-08-05T12:00:00Z'}, 'actor': {'objectType': 'something', 'id': '1234', 'published': '2012-07-05T12:00:00Z'}}, {'id': '8889', 'verb': 'reply', 'target': {'objectType': 'something', 'id': '31415', 'published': '2012-07-05T12:00:00Z'}, 'object': {'content': 'This is my first reply', 'inReplyTo': [], 'objectType': 'reply', 'id': '9999', 'published': '2012-08-05T12:00:00Z'}, 'actor': {'objectType': 'something', 'id': '1234', 'published': '2012-07-05T12:00:00Z'}}, {'grouped_by_attributes': ['verb', 'actor'], 'title': ['Stream Item', 'Stream Item'], 'object': [{'objectType': 'something', 'id': '4353', 'published': '2012-07-05T12:00:00Z'}, {'published': '2012-07-05T12:00:00Z', 'id': '4353', 'objectType': 'something'}], 'actor': {'published': '2012-07-05T12:00:00Z', 'id': '4321', 'objectType': 'something'}, 'verb': 'post', 'replies': [{'totalItems': 2, 'items': [{'verb': 'reply', 'actor': {'objectType': 'something', 'id': '1234', 'published': '2012-07-05T12:00:00Z'}, 'object': {'target': {'objectType': 'something', 'id': '31415', 'published': '2012-07-05T12:00:00Z'}, 'object': {'content': 'This is my first reply', 'inReplyTo': [], 'objectType': 'reply', 'id': '9999', 'published': '2012-08-05T12:00:00Z'}, 'actor': {'objectType': 'something', 'id': '1234', 'published': '2012-07-05T12:00:00Z'}, 'verb': 'reply', 'id': '8889', 'objectType': 'activity'}}, {'verb': 'reply', 'actor': {'objectType': 'something', 'id': '1234', 'published': '2012-07-05T12:00:00Z'}, 'object': {'target': {'objectType': 'something', 'id': '1234', 'published': '2012-07-05T12:00:00Z'}, 'object': {'content': 'This is my second reply', 'inReplyTo': [], 'objectType': 'reply', 'id': '9998', 'published': '2012-08-05T12:05:00Z'}, 'actor': {'objectType': 'something', 'id': '4321', 'published': '2012-07-05T12:00:00Z'}, 'verb': 'reply', 'id': '8888', 'objectType': 'activity'}}]}, {'totalItems': 2, 'items': [{'verb': 'reply', 'actor': {'objectType': 'something', 'id': '1234', 'published': '2012-07-05T12:00:00Z'}, 'object': {'target': {'objectType': 'something', 'id': '31415', 'published': '2012-07-05T12:00:00Z'}, 'object': {'content': 'This is my first reply', 'inReplyTo': [], 'objectType': 'reply', 'id': '9999', 'published': '2012-08-05T12:00:00Z'}, 'actor': {'objectType': 'something', 'id': '1234', 'published': '2012-07-05T12:00:00Z'}, 'verb': 'reply', 'id': '8889', 'objectType': 'activity'}}, {'verb': 'reply', 'actor': {'objectType': 'something', 'id': '1234', 'published': '2012-07-05T12:00:00Z'}, 'object': {'target': {'objectType': 'something', 'id': '1234', 'published': '2012-07-05T12:00:00Z'}, 'object': {'content': 'This is my second reply', 'inReplyTo': [], 'objectType': 'reply', 'id': '9998', 'published': '2012-08-05T12:05:00Z'}, 'actor': {'objectType': 'something', 'id': '4321', 'published': '2012-07-05T12:00:00Z'}, 'verb': 'reply', 'id': '8888', 'objectType': 'activity'}}]}], 'id': ['5555', '5556'], 'grouped_by_values': ['post', {'published': '2012-07-05T12:00:00Z', 'id': '4321', 'objectType': 'something'}]}, {'id': '7778', 'verb': 'like', 'target': {'objectType': 'something', 'id': '31415', 'published': '2012-07-05T12:00:00Z'}, 'object': {'inReplyTo': [], 'objectType': 'like', 'id': '6669', 'published': '2012-08-05T12:00:00Z'}, 'actor': {'objectType': 'something', 'id': '1234', 'published': '2012-07-05T12:00:00Z'}}, {'id': '8888', 'verb': 'reply', 'target': {'objectType': 'something', 'id': '1234', 'published': '2012-07-05T12:00:00Z'}, 'object': {'content': 'This is my second reply', 'inReplyTo': [], 'objectType': 'reply', 'id': '9998', 'published': '2012-08-05T12:05:00Z'}, 'actor': {'objectType': 'something', 'id': '4321', 'published': '2012-07-05T12:00:00Z'}}], activities) diff --git a/tests/test_dotdict.py b/tests/test_dotdict.py index 602704e..f387db5 100644 --- a/tests/test_dotdict.py +++ b/tests/test_dotdict.py @@ -1,8 +1,8 @@ -from __future__ import absolute_import +from __future__ import absolute_import, division, print_function, unicode_literals -from sunspear.lib.dotdict import dotdictify +from nose.tools import eq_, ok_, raises -from nose.tools import ok_, eq_, raises +from sunspear.lib.dotdict import dotdictify class TestDotDictify(object): diff --git a/tests/test_rfc3339.py b/tests/test_rfc3339.py index a7bc723..2522222 100644 --- a/tests/test_rfc3339.py +++ b/tests/test_rfc3339.py @@ -1,11 +1,11 @@ -from __future__ import absolute_import +from __future__ import absolute_import, division, print_function, unicode_literals -from sunspear.lib.rfc3339 import rfc3339, _timezone, _utc_offset, _timedelta_to_seconds +import datetime +import time from nose.tools import eq_, ok_ -import datetime -import time +from sunspear.lib.rfc3339 import _timedelta_to_seconds, _timezone, _utc_offset, rfc3339 class TestRFC3339(object): @@ -91,13 +91,13 @@ def test_timestamp_utc(self): self.local_timezone)) def test_before_1970(self): - d = datetime.date(1885, 01, 04) + d = datetime.date(1885, 0o1, 0o4) ok_(rfc3339(d).startswith('1885-01-04T00:00:00')) eq_(rfc3339(d, utc=True, use_system_timezone=False), '1885-01-04T00:00:00Z') def test_1920(self): - d = datetime.date(1920, 02, 29) + d = datetime.date(1920, 0o2, 29) x = rfc3339(d, utc=False, use_system_timezone=True) ok_(x.startswith('1920-02-29T00:00:00'))