From 342fd15ce9c66754c96c9d6d4715bda6eb3a2e4a Mon Sep 17 00:00:00 2001 From: cellularmitosis Date: Sun, 4 Mar 2012 20:28:42 -0600 Subject: [PATCH 1/7] push re_url and url from RESPONSE_MAPPING down into each method. --- itty.py | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/itty.py b/itty.py index d4d179b..0bb2bbf 100644 --- a/itty.py +++ b/itty.py @@ -317,10 +317,11 @@ def find_matching_url(request): if not request.method in REQUEST_MAPPINGS: raise NotFound("The HTTP request method '%s' is not supported." % request.method) - for url_set in REQUEST_MAPPINGS[request.method]: - match = url_set[0].search(request.path) + for method in REQUEST_MAPPINGS[request.method]: + match = method.re_url.search(request.path) if match is not None: + url_set = (method.re_url, method.url, method) return (url_set, match.groupdict()) raise NotFound("Sorry, nothing here.") @@ -405,8 +406,9 @@ def get(url): """Registers a method as capable of processing GET requests.""" def wrapped(method): # Register. - re_url = re.compile("^%s$" % add_slash(url)) - REQUEST_MAPPINGS['GET'].append((re_url, url, method)) + method.url = url + method.re_url = re.compile("^%s$" % add_slash(url)) + REQUEST_MAPPINGS['GET'].append(method) return method return wrapped @@ -415,8 +417,9 @@ def post(url): """Registers a method as capable of processing POST requests.""" def wrapped(method): # Register. - re_url = re.compile("^%s$" % add_slash(url)) - REQUEST_MAPPINGS['POST'].append((re_url, url, method)) + method.url = url + method.re_url = re.compile("^%s$" % add_slash(url)) + REQUEST_MAPPINGS['POST'].append(method) return method return wrapped @@ -425,8 +428,9 @@ def put(url): """Registers a method as capable of processing PUT requests.""" def wrapped(method): # Register. - re_url = re.compile("^%s$" % add_slash(url)) - REQUEST_MAPPINGS['PUT'].append((re_url, url, method)) + method.url = url + method.re_url = re.compile("^%s$" % add_slash(url)) + REQUEST_MAPPINGS['PUT'].append(method) new.status = 201 return method return wrapped @@ -436,8 +440,9 @@ def delete(url): """Registers a method as capable of processing DELETE requests.""" def wrapped(method): # Register. - re_url = re.compile("^%s$" % add_slash(url)) - REQUEST_MAPPINGS['DELETE'].append((re_url, url, method)) + method.url = url + method.re_url = re.compile("^%s$" % add_slash(url)) + REQUEST_MAPPINGS['DELETE'].append(method) return method return wrapped From 9ce0f1cacf6335384c873e4a84086fcea0943a45 Mon Sep 17 00:00:00 2001 From: cellularmitosis Date: Sun, 4 Mar 2012 20:43:59 -0600 Subject: [PATCH 2/7] adding rudimentary Accept: request header support. --- itty.py | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/itty.py b/itty.py index 0bb2bbf..4656ff3 100644 --- a/itty.py +++ b/itty.py @@ -312,6 +312,20 @@ def handle_error(exception, request=None): return not_found(request, exception) +def method_supports_mime_type_in_accept_header(method, accept_string): + """Determine if the MIME types supported by the method match those in the Accept header.""" + if hasattr(method, 'accepted_mime_types') == False: + # if an @accept() decorator hasn't been used, we assume */* + return True + + parts = accept_string.split(',') + mime_types_accepted_by_requester = [part.split(';')[0] for part in parts] + for mime_type in mime_types_accepted_by_requester: + if mime_type in method.accepted_mime_types: + return True + return False + + def find_matching_url(request): """Searches through the methods who've registed themselves with the HTTP decorators.""" if not request.method in REQUEST_MAPPINGS: @@ -320,9 +334,15 @@ def find_matching_url(request): for method in REQUEST_MAPPINGS[request.method]: match = method.re_url.search(request.path) - if match is not None: - url_set = (method.re_url, method.url, method) - return (url_set, match.groupdict()) + if match == None: + continue + + if hasattr(request, 'HTTP_ACCEPT') == True: + if method_supports_mime_type_in_accept_header(method, request.HTTP_ACCEPT) == False: + continue + + url_set = (method.re_url, method.url, method) + return (url_set, match.groupdict()) raise NotFound("Sorry, nothing here.") @@ -456,6 +476,16 @@ def wrapped(method): return wrapped +def accept(mime_type): + """Specifies which MIME types a method handles.""" + def wrapped(method): + if method.__dict__.has_key('accepted_mime_types') is False: + method.accepted_mime_types = [] + method.accepted_mime_types.append(mime_type) + return method + return wrapped + + # Error handlers @error(403) From 150cd899570589238a8f6e478b35fe547195bfcf Mon Sep 17 00:00:00 2001 From: cellularmitosis Date: Sun, 4 Mar 2012 20:51:14 -0600 Subject: [PATCH 3/7] changing README to explain changes in this fork. --- README.rst | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/README.rst b/README.rst index db75719..96a3ea3 100644 --- a/README.rst +++ b/README.rst @@ -1,3 +1,56 @@ +This is a modified version of itty.py which attempts to add support for the HTTP 'Accept:' request header. + +example code: + +``` +@get('/') +@accept('application/x-plist') +def index(request): + return "here we would return a binary plist\n" + +@get('/') +@accept('application/json') +def index(request): + return "here we would return JSON\n" + +@get('/') +@accept('text/plain') +def index(request): + return "here we would return plain text\n" + +@get('/') +def index(request): + return "this is the default (returns text/html)\n" +``` + +output: + +``` +$ wget -q -O - --header='Accept: application/x-plist' http://localhost:8080 +here we would return a binary plist +$ wget -q -O - --header='Accept: application/json' http://localhost:8080 +here we would return JSON +$ wget -q -O - --header='Accept: text/plain' http://localhost:8080 +here we would return plain text +$ wget -q -O - --header='Accept: text/html' http://localhost:8080 +this is the default (returns text/html) +$ wget -q -O - --header='Accept: */*' http://localhost:8080 +this is the default (returns text/html) +$ wget -q -O - --header='Accept: some/junk' http://localhost:8080 +this is the default (returns text/html) +``` + +This is just a first stab to flesh out the idea. + +Limitations (i.e. things which could be improved upon): +* You have to define your methods in order from most specific to least specific. +* Wildcards and 'q' aren't supported yet. + +Feel free to take this idea and run with it. Have fun! +Jason Pepas +jason@pepas.com + + ======= itty.py ======= From 8309d2c7fbfc2899cb477ffde2107be6755fd7e9 Mon Sep 17 00:00:00 2001 From: cellularmitosis Date: Sun, 4 Mar 2012 20:56:21 -0600 Subject: [PATCH 4/7] oops, this README is in rst format, not github flavored markdown. --- README.rst | 64 +++++++++++++++++++++++++----------------------------- 1 file changed, 30 insertions(+), 34 deletions(-) diff --git a/README.rst b/README.rst index 96a3ea3..c76de52 100644 --- a/README.rst +++ b/README.rst @@ -2,43 +2,39 @@ This is a modified version of itty.py which attempts to add support for the HTTP example code: -``` -@get('/') -@accept('application/x-plist') -def index(request): - return "here we would return a binary plist\n" - -@get('/') -@accept('application/json') -def index(request): - return "here we would return JSON\n" - -@get('/') -@accept('text/plain') -def index(request): - return "here we would return plain text\n" - -@get('/') -def index(request): - return "this is the default (returns text/html)\n" -``` + @get('/') + @accept('application/x-plist') + def index(request): + return "here we would return a binary plist\n" + + @get('/') + @accept('application/json') + def index(request): + return "here we would return JSON\n" + + @get('/') + @accept('text/plain') + def index(request): + return "here we would return plain text\n" + + @get('/') + def index(request): + return "this is the default (returns text/html)\n" output: -``` -$ wget -q -O - --header='Accept: application/x-plist' http://localhost:8080 -here we would return a binary plist -$ wget -q -O - --header='Accept: application/json' http://localhost:8080 -here we would return JSON -$ wget -q -O - --header='Accept: text/plain' http://localhost:8080 -here we would return plain text -$ wget -q -O - --header='Accept: text/html' http://localhost:8080 -this is the default (returns text/html) -$ wget -q -O - --header='Accept: */*' http://localhost:8080 -this is the default (returns text/html) -$ wget -q -O - --header='Accept: some/junk' http://localhost:8080 -this is the default (returns text/html) -``` + $ wget -q -O - --header='Accept: application/x-plist' http://localhost:8080 + here we would return a binary plist + $ wget -q -O - --header='Accept: application/json' http://localhost:8080 + here we would return JSON + $ wget -q -O - --header='Accept: text/plain' http://localhost:8080 + here we would return plain text + $ wget -q -O - --header='Accept: text/html' http://localhost:8080 + this is the default (returns text/html) + $ wget -q -O - --header='Accept: */*' http://localhost:8080 + this is the default (returns text/html) + $ wget -q -O - --header='Accept: some/junk' http://localhost:8080 + this is the default (returns text/html) This is just a first stab to flesh out the idea. From 181d8f94c520d96e55e2f9329b70484494df4440 Mon Sep 17 00:00:00 2001 From: cellularmitosis Date: Sun, 4 Mar 2012 20:57:34 -0600 Subject: [PATCH 5/7] argh. struggling with rst. --- README.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.rst b/README.rst index c76de52..3d1b215 100644 --- a/README.rst +++ b/README.rst @@ -2,6 +2,8 @@ This is a modified version of itty.py which attempts to add support for the HTTP example code: +:: + @get('/') @accept('application/x-plist') def index(request): @@ -23,6 +25,8 @@ example code: output: +:: + $ wget -q -O - --header='Accept: application/x-plist' http://localhost:8080 here we would return a binary plist $ wget -q -O - --header='Accept: application/json' http://localhost:8080 From 663ce3d79c81104f6a9fb810d8c724f5fbf91286 Mon Sep 17 00:00:00 2001 From: cellularmitosis Date: Sun, 4 Mar 2012 20:58:14 -0600 Subject: [PATCH 6/7] more formatting of README --- README.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/README.rst b/README.rst index 3d1b215..b9a40a5 100644 --- a/README.rst +++ b/README.rst @@ -43,6 +43,7 @@ output: This is just a first stab to flesh out the idea. Limitations (i.e. things which could be improved upon): + * You have to define your methods in order from most specific to least specific. * Wildcards and 'q' aren't supported yet. From 78a675836e4e72c6887ad1655b1246815e8ec669 Mon Sep 17 00:00:00 2001 From: cellularmitosis Date: Mon, 5 Mar 2012 01:46:01 -0600 Subject: [PATCH 7/7] Using a more illustrative example in the README. --- README.rst | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/README.rst b/README.rst index b9a40a5..3bef411 100644 --- a/README.rst +++ b/README.rst @@ -5,40 +5,41 @@ example code: :: @get('/') - @accept('application/x-plist') + @accept('text/plain') def index(request): - return "here we would return a binary plist\n" + return "Hello, World!\n" @get('/') - @accept('application/json') + @accept('text/xml') def index(request): - return "here we would return JSON\n" + return 'Hello, World!\n' @get('/') - @accept('text/plain') + @accept('application/json') def index(request): - return "here we would return plain text\n" + return '{ "greeting": "Hello, World!" }\n' @get('/') def index(request): - return "this is the default (returns text/html)\n" + return "Hello, World!\n" + output: :: - $ wget -q -O - --header='Accept: application/x-plist' http://localhost:8080 - here we would return a binary plist - $ wget -q -O - --header='Accept: application/json' http://localhost:8080 - here we would return JSON $ wget -q -O - --header='Accept: text/plain' http://localhost:8080 - here we would return plain text + Hello, World! + + $ wget -q -O - --header='Accept: text/xml' http://localhost:8080 + Hello, World! + + $ wget -q -O - --header='Accept: application/json' http://localhost:8080 + { "greeting": "Hello, World!" } + $ wget -q -O - --header='Accept: text/html' http://localhost:8080 - this is the default (returns text/html) - $ wget -q -O - --header='Accept: */*' http://localhost:8080 - this is the default (returns text/html) - $ wget -q -O - --header='Accept: some/junk' http://localhost:8080 - this is the default (returns text/html) + Hello, World! + This is just a first stab to flesh out the idea.