Commits

Jesper Nøhr committed 2cc125f Merge

resolving merge between ephelon's fork and the rest, all tests pass

  • Participants
  • Parent commits fa0e604, 7236916

Comments (0)

Files changed (10)

 James Emerton for making the OAuth parts more usable/friendly
 Anton Tsigularov for providing a patch for incorrect multipart detection
 Remco Wendt for fixing up the example blog server to conform with 0.2.2, et. al
+Benoit Garret for providing a fix for oauth headers, issue #56
+Stephan Preeker for providing some fixes to documentation generation
 import inspect, handler
 
 from piston.handler import typemapper
+from piston.handler import handler_tracker
 
 from django.core.urlresolvers import get_resolver, get_callable, get_script_prefix
 from django.shortcuts import render_to_response
             else:
                 yield (arg, None)
         
-    def get_signature(self, parse_optional=True):
+    @property
+    def signature(self, parse_optional=True):
         spec = ""
 
         for argn, argdef in self.iter_args():
             return spec.replace("=None", "=<optional>")
             
         return spec
-
-    signature = property(get_signature)
         
-    def get_doc(self):
+    @property
+    def doc(self):
         return inspect.getdoc(self.method)
     
-    doc = property(get_doc)
+    @property
+    def name(self):
+        return self.method.__name__
     
-    def get_name(self):
-        return self.method.__name__
-        
-    name = property(get_name)
+    @property
+    def http_name(self):
+        if self.name == 'read':
+            return 'GET'
+        elif self.name == 'create':
+            return 'POST'
+        elif self.name == 'delete':
+            return 'DELETE'
+        elif self.name == 'update':
+            return 'PUT'
     
     def __repr__(self):
         return "<Method: %s>" % self.name
     def get_model(self):
         return getattr(self, 'model', None)
             
-    def get_doc(self):
+    @property
+    def has_anonymous(self):
+        return self.handler.anonymous
+            
+    @property
+    def anonymous(self):
+        if self.has_anonymous:
+            return HandlerDocumentation(self.handler.anonymous)
+            
+    @property
+    def doc(self):
         return self.handler.__doc__
     
-    doc = property(get_doc)
-
     @property
     def name(self):
         return self.handler.__name__
     """
     docs = [ ]
 
-    for handler, (model, anonymous) in typemapper.iteritems():
+    for handler in handler_tracker: 
         docs.append(generate_doc(handler))
-        
+
+    def _compare(doc1, doc2): 
+       #handlers and their anonymous counterparts are put next to each other.
+       name1 = doc1.name.replace("Anonymous", "")
+       name2 = doc2.name.replace("Anonymous", "")
+       return cmp(name1, name2)    
+ 
+    docs.sort(_compare)
+       
     return render_to_response('documentation.html', 
         { 'docs': docs }, RequestContext(request))

piston/emitters.py

 from __future__ import generators
 
 import decimal, re, inspect
+import copy
 
 try:
     # yaml isn't standard with python.  It shouldn't be required if it
         ret = dict()
             
         for field in fields:
-            if field in has:
+            if field in has and callable(field):
                 ret[field] = getattr(data, field)
         
         return ret
                     get_fields = set(fields)
 
                 met_fields = self.method_fields(handler, get_fields)
-
+                
                 for f in data._meta.local_fields:
                     if f.serialize and not any([ p in met_fields for p in [ f.attname, f.name ]]):
                         if not f.rel:
                 
                 # try to get the remainder of fields
                 for maybe_field in get_fields:
-                    
                     if isinstance(maybe_field, (list, tuple)):
                         model, fields = maybe_field
                         inst = getattr(data, model, None)
 
 class OAuthAuthenticationForm(forms.Form):
     oauth_token = forms.CharField(widget=forms.HiddenInput)
-    oauth_callback = forms.URLField(widget=forms.HiddenInput)
+    oauth_callback = forms.CharField(widget=forms.HiddenInput)
     authorize_access = forms.BooleanField(required=True)
     csrf_signature = forms.CharField(widget=forms.HiddenInput)
 

piston/handler.py

 from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned
 
 typemapper = { }
+handler_tracker = [ ]
 
 class HandlerMetaClass(type):
     """
         if hasattr(new_cls, 'model'):
             typemapper[new_cls] = (new_cls.model, new_cls.is_anonymous)
         
+        if name not in ('BaseHandler', 'AnonymousBaseHandler'):
+            handler_tracker.append(new_cls)
+
         return new_cls
 
 class BaseHandler(object):
     @staticmethod
     def _split_header(header):
         params = {}
+        header = header.replace('OAuth ', '', 1)
         parts = header.split(',')
         for param in parts:
             # ignore realm parameter
-            if param.find('OAuth realm') > -1:
+            if param.find('realm') > -1:
                 continue
             # remove whitespace
             param = param.strip()

tests/test_project/apps/testapp/handlers.py

 from piston.handler import BaseHandler
 from piston.utils import rc, validate
 
-from models import TestModel, ExpressiveTestModel, Comment, InheritedModel, PlainOldObject, ListFieldsModel
+from models import TestModel, ExpressiveTestModel, Comment, InheritedModel, PlainOldObject, Issue58Model, ListFieldsModel
 from forms import EchoForm
 from test_project.apps.testapp import signals
 
-
 class EntryHandler(BaseHandler):
     model = TestModel
     allowed_methods = ['GET', 'PUT', 'POST']
     fields = ('id','kind','variety','color')
     list_fields = ('id','variety')
 
+class Issue58Handler(BaseHandler):
+    model = Issue58Model
+
+    def read(self, request):
+        return Issue58Model.objects.all()
+                
+    def create(self, request):
+        if request.content_type:
+            data = request.data
+            em = self.model(read=data['read'], model=data['model'])
+            em.save()
+            return rc.CREATED
+        else:
+            super(Issue58Model, self).create(request)

tests/test_project/apps/testapp/models.py

         return {'type': 'plain',
                 'field': 'a field'}
 
-
 class ListFieldsModel(models.Model):
     kind = models.CharField(max_length=15)
     variety = models.CharField(max_length=15)
     color = models.CharField(max_length=15)
+
+class Issue58Model(models.Model):
+    read = models.BooleanField(default=False)
+    model = models.CharField(max_length=1, blank=True, null=True)

tests/test_project/apps/testapp/tests.py

 
 import urllib, base64
 
-from test_project.apps.testapp.models import TestModel, ExpressiveTestModel, Comment, InheritedModel, ListFieldsModel
+from test_project.apps.testapp.models import TestModel, ExpressiveTestModel, Comment, InheritedModel, Issue58Model, ListFieldsModel
 from test_project.apps.testapp import signals
 
 class MainTests(TestCase):
         resp = self.client.get('/api/popo')
         self.assertEquals(resp.status_code, 200)
         self.assertEquals({'type': 'plain', 'field': 'a field'}, simplejson.loads(resp.content))
-        
-
 
 class ListFieldsTest(MainTests):
     def init_delegate(self):
         self.assertEquals(resp.status_code, 200)
         self.assertEquals(resp.content, expect)
         
+class Issue58ModelTests(MainTests):
+    """
+    This testcase addresses #58 in django-piston where if a model
+    has one of the ['read','update','delete','create'] defined
+    it make piston crash with a `TypeError`
+    """
+    def init_delegate(self):
+        m1 = Issue58Model(read=True,model='t') 
+        m1.save()
+        m2 = Issue58Model(read=False,model='f')
+        m2.save()
+
+    def test_incoming_json(self):
+        outgoing = simplejson.dumps({ 'read': True, 'model': 'T'})
+
+        expected = """[
+    {
+        "read": true, 
+        "model": "t"
+    }, 
+    {
+        "read": false, 
+        "model": "f"
+    }
+]"""
+
+        # test GET
+        result = self.client.get('/api/issue58.json',
+                                HTTP_AUTHORIZATION=self.auth_string).content
+        self.assertEquals(result, expected)
+
+        # test POST
+        resp = self.client.post('/api/issue58.json', outgoing, content_type='application/json',
+                                HTTP_AUTHORIZATION=self.auth_string)
+        self.assertEquals(resp.status_code, 201)
+        

tests/test_project/apps/testapp/urls.py

 from piston.resource import Resource
 from piston.authentication import HttpBasicAuthentication
 
-from test_project.apps.testapp.handlers import EntryHandler, ExpressiveHandler, AbstractHandler, EchoHandler, PlainOldObjectHandler, ListFieldsHandler
+from test_project.apps.testapp.handlers import EntryHandler, ExpressiveHandler, AbstractHandler, EchoHandler, PlainOldObjectHandler, Issue58Handler, ListFieldsHandler
 
 auth = HttpBasicAuthentication(realm='TestApplication')
 
 echo = Resource(handler=EchoHandler)
 popo = Resource(handler=PlainOldObjectHandler)
 list_fields = Resource(handler=ListFieldsHandler)
-
+issue58 = Resource(handler=Issue58Handler)
 
 urlpatterns = patterns('',
     url(r'^entries/$', entries),
     url(r'^entries\.(?P<emitter_format>.+)', entries),
     url(r'^entry-(?P<pk>.+)\.(?P<emitter_format>.+)', entries),
 
+    url(r'^issue58\.(?P<emitter_format>.+)$', issue58),
+
     url(r'^expressive\.(?P<emitter_format>.+)$', expressive),
 
     url(r'^abstract\.(?P<emitter_format>.+)$', abstract),