Permalink
Browse files

added sub types

Signed-off-by: Flavio Curella <flavio.curella@gmail.com>
  • Loading branch information...
1 parent d28582c commit 69db2aeacbdd5e201c88df858e3d2a371f5d34bb @fcurella fcurella committed May 26, 2011
Showing with 130 additions and 8 deletions.
  1. +7 −1 docs/content.rst
  2. +4 −0 docs/index.rst
  3. +2 −0 storymarket/__init__.py
  4. +10 −2 storymarket/content.py
  5. +50 −0 storymarket/subtypes.py
  6. +37 −3 tests/fakeserver.py
  7. +3 −2 tests/test_content.py
  8. +17 −0 tests/test_subtypes.py
View
@@ -94,7 +94,8 @@ specific to each type are then listed next to that type.
``tags``, ``title`` ``fact_checked``,
``one_off_author``,
``pricing_scheme``,
- ``rights_scheme``
+ ``rights_scheme``,
+ ``sub_type``
Audio ``duration``, ``expire_date``
@@ -166,6 +167,7 @@ Audio
.. attribute:: audio
.. attribute:: author
.. attribute:: category
+ .. attribute:: sub_type
.. attribute:: description
.. attribute:: duration
.. attribute:: expire_date
@@ -190,6 +192,7 @@ Data
.. attribute:: author
.. attribute:: category
+ .. attribute:: sub_type
.. attribute:: data
.. attribute:: description
.. attribute:: duration
@@ -216,6 +219,7 @@ Photos
.. attribute:: author
.. attribute:: caption
.. attribute:: category
+ .. attribute:: sub_type
.. attribute:: description
.. attribute:: duration
.. attribute:: expire_date
@@ -241,6 +245,7 @@ Text
.. attribute:: author
.. attribute:: category
+ .. attribute:: sub_type
.. attribute:: content
.. attribute:: data
.. attribute:: description
@@ -268,6 +273,7 @@ Video
.. attribute:: author
.. attribute:: category
+ .. attribute:: sub_type
.. attribute:: description
.. attribute:: duration
.. attribute:: expire_date
View
@@ -55,6 +55,10 @@ Then call on the :class:`Storymarket` object:
.. attribute:: subcategories
A :class:`SubcategoryManager` - get subcategories.
+
+ .. attribute:: sub_type
+
+ A :class:`SubtypeManager` - get subtypes.
.. attribute:: orgs
@@ -5,6 +5,7 @@
from . import exceptions
from .client import StorymarketClient
from .categories import Category, CategoryManager, SubcategoryManager
+from .subtypes import Subtype, SubtypeManager
from .content import (Audio, Data, Photo, Text, Video, AudioManager,
DataManager, PhotoManager, TextManager, VideoManager)
from .orgs import Org, OrgManager
@@ -31,6 +32,7 @@ def __init__(self, key):
self.client = StorymarketClient(key)
self.audio = AudioManager(self)
self.categories = CategoryManager(self)
+ self.sub_types = SubtypeManager(self)
self.data = DataManager(self)
self.orgs = OrgManager(self)
self.packages = PackageManager(self)
@@ -10,6 +10,7 @@
from .schemes import PricingScheme, RightsScheme
from .orgs import Org
from .categories import Category
+from .subtypes import Subtype
class User(object):
"""
@@ -34,7 +35,7 @@ class ContentResource(links.LinkedResource):
Abstract base class for content resources.
"""
# List of key names of related items.
- _related_keys = ['author', 'category', 'org', 'pricing_scheme',
+ _related_keys = ['author', 'sub_type', 'category', 'org', 'pricing_scheme',
'rights_scheme', 'uploaded_by']
def _add_details(self, info):
@@ -55,6 +56,11 @@ def category(self):
if self._category else None
@property
+ def sub_type(self):
+ return Subtype(self.manager.api.sub_types, self._sub_type) \
+ if self._sub_type else None
+
+ @property
def org(self):
return Org(self.manager.api.orgs, self._org) \
if self._org else None
@@ -97,7 +103,7 @@ class ContentManager(base.Manager):
urlbit = None
# Subclasses should extend this with extra fields that need to be flattened.
- flatten_fields = ['category', 'author', 'title', 'org', 'tags']
+ flatten_fields = ['category', 'sub_type', 'author', 'title', 'org', 'tags']
def all(self):
"""
@@ -182,6 +188,8 @@ def _flatten(self, resource):
flattened[key] = '/orgs/%s/' % base.getid(value)
elif key == 'category' and not isinstance(value, basestring):
flattened[key] = '/content/sub_category/%s/' % base.getid(value)
+ elif key == 'sub_type' and not isinstance(value, basestring):
+ flattened[key] = '/content/sub_type/%s/' % base.getid(value)
elif key == 'pricing_scheme' and not isinstance(value, basestring):
flattened[key] = '/pricing/%s/' % base.getid(value)
elif key == 'rights_scheme' and not isinstance(value, basestring):
@@ -0,0 +1,50 @@
+"""
+API classes for subtypes.
+"""
+
+from __future__ import absolute_import
+from urllib import urlencode
+from . import base
+from . import links
+
+
+class Subtype(links.LinkedResource):
+ """
+ A sub-type.
+ """
+ def __repr__(self):
+ return "<%s: %s>" % (self.__class__.__name__, self.name)
+
+class SubtypeManager(base.Manager):
+ """
+ Manage subtypes.
+ """
+ resource_class = Subtype
+ urlbit = 'sub_type'
+
+ def all(self):
+ """
+ Get a list of all subtypes.
+
+ :rtype: A list of subtype instances.
+ """
+ return self._list('/content/%s/' % self.urlbit)
+
+ def filter(self, *args, **kwargs):
+ """
+ Get a list of subtypes filtered by content type.
+
+ :param type__model: (optional) Filters by content type name, eg: 'text','photo','video', ecc.
+ :param is_default: (optional) (Bool): Filters by is_default attribute.
+ :rtype: A list of subtype instances.
+ """
+ return self._list('/content/%s/?%s' % (self.urlbit, urlencode(kwargs)))
+
+ def get(self, resource):
+ """
+ Get an individual subtype.
+
+ :param resource: The resource instance or its ID.
+ :rtype: A list of subtype instances.
+ """
+ return self._get('/content/%s/%s/' % (self.urlbit, base.getid(resource)))
View
@@ -45,7 +45,7 @@ def _storymarket_request(self, url, method, *args, **kwargs):
assert_equal(kwargs['headers']['Authorization'], self.apikey)
# Call the method
- munged_url = url.strip('/').replace('/', '_').replace('.', '_')
+ munged_url = url.strip('/').replace('/', '_').replace('.', '_').replace('?','filter')
callback = "%s_%s" % (method.lower(), munged_url)
if not hasattr(self, callback):
fail('Called unknown API method: %s %s' % (method, url))
@@ -73,7 +73,40 @@ def get_content_category_1(self, **kw):
get_content_sub_category = get_content_category
get_content_sub_category_1 = get_content_category_1
-
+
+ def get_content_sub_type(self, **kw):
+ return (200, [self.get_content_sub_type_proto()[1]])
+
+ def get_content_sub_type_filter(self, **kw):
+ return (200, [self.get_content_sub_type_proto()[1]])
+
+ def get_content_sub_type_proto(self, type_model='text', id=1, **kw):
+ return (200, {
+ u"id": 1,
+ u"name": type_model.title(),
+ u"is_default": True,
+ u"links": [
+ {u"rel": u"self",
+ u"href": u"content/sub_type/%d/" % id,
+ u"allowed_methods": [u"GET"]},
+ ],
+ })
+
+ def get_content_sub_type_1(self, **kw):
+ return self.get_content_sub_type_proto(type_model='text', id=1)
+
+ def get_content_sub_type_2(self, **kw):
+ return self.get_content_sub_type_proto(type_model='photo', id=2)
+
+ def get_content_sub_type_3(self, **kw):
+ return self.get_content_sub_type_proto(type_model='audio', id=3)
+
+ def get_content_sub_type_4(self, **kw):
+ return self.get_content_sub_type_proto(type_model='video', id=4)
+
+ def get_content_sub_type_5(self, **kw):
+ return self.get_content_sub_type_proto(type_model='data', id=5)
+
def get_content_data(self, **kw):
return (200, [self.get_content_data_1()[1]])
@@ -195,7 +228,7 @@ def _delete_method(self, **kw):
def _check_post_method(self, body, required=(), optional=()):
assert_has_keys(body,
required = required + ('org', 'category', 'title', ),
- optional = optional + ('author', 'one_off_author', 'fact_checked',
+ optional = optional + ('author', 'sub_type', 'one_off_author', 'fact_checked',
'description', 'rights_scheme',
'pricing_scheme', 'tags')
)
@@ -300,6 +333,7 @@ def _content_dict(self, type, **kw):
d = {
u"id": 1,
u"category": self.get_content_sub_category_1()[1],
+ u"sub_type": self.get_content_sub_type_proto(type_model='text')[1],
u"uploaded_by": {
u"username": u"frank",
u"first_name": u"Frank",
@@ -2,7 +2,7 @@
import mock
from nose.tools import assert_equal, assert_not_equal
-from storymarket import (Audio, Data, Photo, Text, Video, Category, Org,
+from storymarket import (Audio, Data, Photo, Text, Video, Category, Subtype, Org,
PricingScheme, RightsScheme)
from storymarket.content import User, BinaryContentManager
from StringIO import StringIO
@@ -69,6 +69,7 @@ def test_related_resource_properties():
test_data = [
('author', User),
('category', Category),
+ ('sub_type', Subtype),
('org', Org),
('pricing_scheme', PricingScheme),
('rights_scheme', RightsScheme),
@@ -111,7 +112,7 @@ def check_blob_upload(manager, urlbit, data):
'--%s\r\n' % BOUNDARY +
'Content-Disposition: form-data; name="blob"\r\n' +
'Content-Type: text/plain; charset=utf-8\r\n' +
- 'Content-Length: %s\r\n' % len(new_data) +
+ #'Content-Length: %s\r\n' % len(new_data) +
'\r\n%s\r\n' % new_data +
'--%s--\r\n' % BOUNDARY
)
@@ -0,0 +1,17 @@
+from __future__ import absolute_import
+
+from storymarket import Subtype
+from .fakeserver import FakeStorymarket
+from .utils import assert_list_api, assert_get_api
+
+sm = FakeStorymarket()
+
+def test_list_subtypes():
+ assert_list_api(sm, sm.sub_types.all, Subtype, 'content/sub_type/')
+
+def test_filter_subtype():
+ assert_list_api(sm, sm.sub_types.filter, Subtype, 'content/sub_type/?')
+
+def test_get_subtype():
+ assert_get_api(sm, sm.sub_types.get, Subtype, 'content/sub_type/1/')
+

0 comments on commit 69db2ae

Please sign in to comment.