Skip to content

Commit 2ae8fa7

Browse files
committed
Reinitialize with buildout
0 parents  commit 2ae8fa7

File tree

7 files changed

+601
-0
lines changed

7 files changed

+601
-0
lines changed

LICENSE

+339
Large diffs are not rendered by default.

README

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
pyroutes
2+
=========
3+
A really small wrapper for rapid development of small python
4+
web applications
5+
6+
Why?
7+
-----
8+
I got tired of dealing with the same boring WSGI-stuff everytime
9+
I wanted to make a small web-utility in django, but I didn't want
10+
to go to far away from it, so I made this little thing to ease the
11+
work a bit.
12+
13+
How it works
14+
-------------
15+
The core of the system is WSGI, and a decorator called @route.
16+
You simple create add a route decorator in front of the function
17+
you want to handle requests to a certain path. pyroutes always
18+
tries to use the most specified path-handler available for the request.
19+
That means `@route('/foo/bar')` will always be used over `@route('/foo')`
20+
given that request path is `/foo/bar` or longer that is :-)
21+
Notice that paths have to be given without a trailing slash.
22+
23+
The decorated function should return the helper `Response` class.
24+
The `Response` class takes three arguments: `content`, `headers` and `status_code`.
25+
`content` is the data that should be returned, `headers` a list of tuples representing
26+
the http-headers returned and `status_code` a valid HTTP status code. If `headers` and `status_code`
27+
is omitted it defaults to `text/html` as content type and `200 OK` as status code.
28+
29+
Example:
30+
31+
@route('/')
32+
def index(environ, data):
33+
return(Response('Hello world!', [('Content-Type', 'text/html')], '200 OK'))
34+
35+
36+
Noticed the parameters to the index function? Those are mandatory.
37+
The `environ`-parameter is the unmodified environment from WSGI and
38+
`data` is a dictionary with the GET and POST parameters.
39+
40+
For more information about usage, see the wiki example.

bootstrap.py

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
##############################################################################
2+
#
3+
# Copyright (c) 2006 Zope Corporation and Contributors.
4+
# All Rights Reserved.
5+
#
6+
# This software is subject to the provisions of the Zope Public License,
7+
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
8+
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
9+
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
10+
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
11+
# FOR A PARTICULAR PURPOSE.
12+
#
13+
##############################################################################
14+
"""Bootstrap a buildout-based project
15+
16+
Simply run this script in a directory containing a buildout.cfg.
17+
The script accepts buildout command-line options, so you can
18+
use the -c option to specify an alternate configuration file.
19+
20+
$Id$
21+
"""
22+
23+
import os, shutil, sys, tempfile, urllib2
24+
25+
tmpeggs = tempfile.mkdtemp()
26+
27+
is_jython = sys.platform.startswith('java')
28+
29+
try:
30+
import pkg_resources
31+
except ImportError:
32+
ez = {}
33+
exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py'
34+
).read() in ez
35+
ez['use_setuptools'](to_dir=tmpeggs, download_delay=0)
36+
37+
import pkg_resources
38+
39+
if sys.platform == 'win32':
40+
def quote(c):
41+
if ' ' in c:
42+
return '"%s"' % c # work around spawn lamosity on windows
43+
else:
44+
return c
45+
else:
46+
def quote (c):
47+
return c
48+
49+
cmd = 'from setuptools.command.easy_install import main; main()'
50+
ws = pkg_resources.working_set
51+
52+
if len(sys.argv) > 2 and sys.argv[1] == '--version':
53+
VERSION = ' == %s' % sys.argv[2]
54+
args = sys.argv[3:] + ['bootstrap']
55+
else:
56+
VERSION = ''
57+
args = sys.argv[1:] + ['bootstrap']
58+
59+
if is_jython:
60+
import subprocess
61+
62+
assert subprocess.Popen([sys.executable] + ['-c', quote(cmd), '-mqNxd',
63+
quote(tmpeggs), 'zc.buildout' + VERSION],
64+
env=dict(os.environ,
65+
PYTHONPATH=
66+
ws.find(pkg_resources.Requirement.parse('setuptools')).location
67+
),
68+
).wait() == 0
69+
70+
else:
71+
assert os.spawnle(
72+
os.P_WAIT, sys.executable, quote (sys.executable),
73+
'-c', quote (cmd), '-mqNxd', quote (tmpeggs), 'zc.buildout' + VERSION,
74+
dict(os.environ,
75+
PYTHONPATH=
76+
ws.find(pkg_resources.Requirement.parse('setuptools')).location
77+
),
78+
) == 0
79+
80+
ws.add_entry(tmpeggs)
81+
ws.require('zc.buildout' + VERSION)
82+
import zc.buildout.buildout
83+
zc.buildout.buildout.main(args)
84+
shutil.rmtree(tmpeggs)

buildout.cfg

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[buildout]
2+
parts = python
3+
develop = .
4+
eggs = pyroutes
5+
6+
[python]
7+
recipe = zc.recipe.egg
8+
interpreter = python
9+
eggs = ${buildout:eggs}
10+

setup.py

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#!/usr/bin/env python
2+
# encoding: utf-8
3+
4+
from setuptools import setup, find_packages
5+
import os
6+
7+
setup(
8+
name = "pyroutes",
9+
version = "0.1.2",
10+
url = 'http://github.com/klette/pyroutes',
11+
license = 'GPLv2',
12+
description = "A small WSGI wrapper for creating small python web apps",
13+
long_description = open(os.path.join(os.path.dirname(__file__), 'README')).read(),
14+
author = 'Kristian Klette',
15+
author_email = '[email protected]',
16+
packages = find_packages('src'),
17+
package_dir = {'': 'src'},
18+
install_requires = ['setuptools'],
19+
20+
classifiers = [
21+
'Development Status :: 3 - Alpha',
22+
'Intended Audience :: Developers',
23+
'License :: OSI Approved :: GNU General Public License (GPL)',
24+
'Programming Language :: Python',
25+
'Topic :: Internet :: WWW/HTTP',
26+
'Topic :: Internet :: WWW/HTTP :: WSGI',
27+
'Topic :: Software Development :: Libraries :: Python Modules',
28+
'Operating System :: OS Independent',
29+
]
30+
31+
)
32+

src/pyroutes/__init__.py

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
#!/usr/bin/env python
2+
#encoding: utf-8
3+
4+
from wsgiref.util import shift_path_info
5+
import cgi
6+
7+
global __request__handlers__
8+
__request__handlers__ = {}
9+
10+
def route(path):
11+
"""
12+
Decorates a function for handling page requests to
13+
a certain path
14+
"""
15+
global __request__handlers__
16+
17+
def decorator(func):
18+
__request__handlers__[path] = func
19+
return decorator
20+
21+
def application(environ, start_response):
22+
"""
23+
Searches for a handler for a certain request and
24+
dispatches it if found. Returns 404 if not found.
25+
"""
26+
_environ = environ.copy()
27+
handlers = __request__handlers__.keys()
28+
path = shift_path_info(_environ)
29+
request = []
30+
if not path:
31+
request = ['/']
32+
else:
33+
while path:
34+
request.append(path)
35+
path = shift_path_info(_environ)
36+
37+
handler = None
38+
complete_path = '/%s' % '/'.join(request)
39+
current_path = complete_path
40+
41+
while handler is None:
42+
if current_path in handlers:
43+
handler = __request__handlers__[current_path]
44+
break
45+
current_path = current_path[:current_path.rfind("/")]
46+
if not current_path:
47+
start_response('404 Not Found', [('Content-type', 'text/plain')])
48+
return ["No handler found for path %s" % complete_path]
49+
try:
50+
_data = cgi.FieldStorage(
51+
fp=environ['wsgi.input'],
52+
environ=environ,
53+
keep_blank_values=False
54+
)
55+
data = {}
56+
for key in _data.keys():
57+
data[key] = _data.getvalue(key)
58+
response = handler(environ, data)
59+
start_response(response.status_code, response.headers)
60+
return[response.content]
61+
except Exception, exception:
62+
start_response('500 Error', [('Content-type', 'text/plain')])
63+
return ["An error occurred\n%s" % str(exception)]
64+
65+

src/pyroutes/http.py

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#!/usr/bin/env python
2+
# encoding: utf-8
3+
"""
4+
http.py
5+
6+
A collection of Response classes for pyroutes
7+
"""
8+
9+
class Response():
10+
"""
11+
A wrapper class for a response to a route. Takes
12+
a content, headers and status_code parameter.
13+
headers should be passed in as a tuple.
14+
"""
15+
def __init__(self, content=None, headers=[('Content-Type', 'text/html')], status_code='200 OK'):
16+
self.content = content
17+
self.headers = headers
18+
self.status_code = status_code
19+
20+
21+
class Redirect(Response):
22+
"""
23+
A redirect shortcut class for redirection responses
24+
"""
25+
26+
def __init__(self, location):
27+
self.content = "redirect"
28+
self.headers = [('Location', location)]
29+
self.status_code = "302 See Other"
30+
31+

0 commit comments

Comments
 (0)