commit
fed7d0fb3d
|
@ -24,7 +24,7 @@ Please give me a docstring!
|
|||
from milla.controllers import FaviconController
|
||||
from milla.util import asbool
|
||||
from webob.exc import HTTPNotFound, WSGIHTTPException, HTTPMethodNotAllowed
|
||||
import milla.dispatch
|
||||
import milla.dispatch.traversal
|
||||
|
||||
__all__ = ['Application']
|
||||
|
||||
|
@ -35,9 +35,8 @@ class Application(object):
|
|||
alternatively, a root object that will be passed to a new
|
||||
:py:class:`milla.dispatch.traversal.Traverser`.
|
||||
|
||||
:param root: A root object, passed to a traverser, which is
|
||||
automatically created if a root is given
|
||||
:param dispatcher: An object implementing the dispatcher protocol
|
||||
:param obj: An object implementing the dispatcher protocol, or an
|
||||
object to be used as the root for a Traverser
|
||||
|
||||
``Application`` instances are WSGI applications.
|
||||
|
||||
|
@ -49,8 +48,11 @@ class Application(object):
|
|||
|
||||
DEFAULT_ALLOWED_METHODS = ['GET', 'HEAD']
|
||||
|
||||
def __init__(self, dispatcher):
|
||||
self.dispatcher = dispatcher
|
||||
def __init__(self, obj):
|
||||
if not hasattr(obj, 'resolve'):
|
||||
# Object is not a dispatcher, but the root object for traversal
|
||||
obj = milla.dispatch.traversal.Traverser(obj)
|
||||
self.dispatcher = obj
|
||||
self.config = {'milla.favicon': True}
|
||||
|
||||
def __call__(self, environ, start_response):
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
try:
|
||||
import configparser
|
||||
except ImportError:
|
||||
import ConfigParser as configparser
|
||||
|
||||
def read_config(filename):
|
||||
'''Parse an ini file into a nested dictionary
|
||||
|
||||
:param string filename: Path to the ini file to read
|
||||
:returns: A dictionary whose keys correspond to the section and
|
||||
option, joined with a dot character (.)
|
||||
|
||||
For example, consider the following ini file::
|
||||
|
||||
[xmen]
|
||||
storm = Ororo Monroe
|
||||
cyclops = Scott Summers
|
||||
|
||||
[avengers]
|
||||
hulk = Bruce Banner
|
||||
iron_man = Tony Stark
|
||||
|
||||
The resulting dictionary would look like this::
|
||||
|
||||
{
|
||||
'xmen.storm': 'Ororo Monroe',
|
||||
'xmen.cyclops': 'Scott Summers',
|
||||
'avengers.hulk': 'Bruce Banner',
|
||||
'avengers.iron_man': 'Tony Stark',
|
||||
}
|
||||
|
||||
Thus, the option values for any section can be obtained as follows::
|
||||
|
||||
config['xmen.storm']
|
||||
|
||||
This dictionary can be used to configure an :py:class:`~milla.Application`
|
||||
instance by using the ``update`` method::
|
||||
|
||||
app = milla.Application(router)
|
||||
app.config.update(config)
|
||||
'''
|
||||
|
||||
cparser = configparser.SafeConfigParser()
|
||||
cparser.readfp(open(filename))
|
||||
|
||||
config = {}
|
||||
for section in cparser.sections():
|
||||
for option in cparser.options(section):
|
||||
config['.'.join((section, option))] = cparser.get(section, option)
|
||||
return config
|
|
@ -97,7 +97,7 @@ class Router(object):
|
|||
for attr in functools.WRAPPER_ASSIGNMENTS:
|
||||
try:
|
||||
value = getattr(controller, attr)
|
||||
except AttributeError:
|
||||
except AttributeError: #pragma: no cover
|
||||
pass
|
||||
else:
|
||||
setattr(func, attr, value)
|
||||
|
|
|
@ -457,3 +457,31 @@ def test_create_href_full_keywords():
|
|||
request = milla.Request(environ)
|
||||
url = request.create_href_full('/bar', foo='baz')
|
||||
assert url == 'http://127.0.0.1/bar?foo=baz'
|
||||
|
||||
def test_static_resource():
|
||||
'''Request.static_resource creates valid URL from config'''
|
||||
|
||||
def controller(request):
|
||||
return request.static_resource('/image.png')
|
||||
|
||||
environ = environ_for_testing()
|
||||
app = milla.Application(StubResolver(controller))
|
||||
app.config['milla.static_root'] = '/static'
|
||||
response = ResponseMaker()
|
||||
app_iter = app(environ, response.start_response)
|
||||
response.finish_response(app_iter)
|
||||
assert response.body == b'/static/image.png', response.body
|
||||
|
||||
def test_static_resource_undefined():
|
||||
'''Request.static_resource returns the path unmodified with no root defined'''
|
||||
|
||||
def controller(request):
|
||||
return request.static_resource('/image.png')
|
||||
|
||||
environ = environ_for_testing()
|
||||
app = milla.Application(StubResolver(controller))
|
||||
response = ResponseMaker()
|
||||
app_iter = app(environ, response.start_response)
|
||||
response.finish_response(app_iter)
|
||||
assert response.body == b'/image.png', response.body
|
||||
|
|
@ -6,6 +6,7 @@
|
|||
:Updater: $Author$
|
||||
'''
|
||||
import milla.dispatch.routing
|
||||
import nose.tools
|
||||
|
||||
def fake_controller():
|
||||
pass
|
||||
|
@ -44,6 +45,7 @@ def test_urlvars():
|
|||
assert func.keywords['bar'] == 'abc'
|
||||
assert func.keywords['baz'] == 'def'
|
||||
|
||||
@nose.tools.raises(milla.dispatch.UnresolvedPath)
|
||||
def test_regexp_urlvar():
|
||||
'''Ensure the dispatcher can resolve alternate regexps in urlvars
|
||||
|
||||
|
@ -61,13 +63,9 @@ def test_regexp_urlvar():
|
|||
assert func.func == controller
|
||||
assert func.keywords['arg'] == 'abcde'
|
||||
|
||||
try:
|
||||
func = router.resolve('/test/1234')
|
||||
except milla.dispatch.UnresolvedPath:
|
||||
pass
|
||||
else:
|
||||
raise AssertionError
|
||||
router.resolve('/test/1234')
|
||||
|
||||
@nose.tools.raises(milla.dispatch.UnresolvedPath)
|
||||
def test_unresolved():
|
||||
'''Ensure the resolver raises an exception for unresolved paths
|
||||
|
||||
|
@ -80,12 +78,7 @@ def test_unresolved():
|
|||
|
||||
router = milla.dispatch.routing.Router()
|
||||
router.add_route('/test', controller)
|
||||
try:
|
||||
router.resolve('/tset')
|
||||
except milla.dispatch.UnresolvedPath:
|
||||
pass
|
||||
else:
|
||||
raise AssertionError
|
||||
router.resolve('/tset')
|
||||
|
||||
def test_unrelated():
|
||||
'''Ensure the dispatcher is not confused by unrelated paths
|
||||
|
@ -119,3 +112,41 @@ def test_string_controller():
|
|||
router.add_route('/test', 'milla.tests.test_routing:fake_controller')
|
||||
func = router.resolve('/test')
|
||||
assert func.func == fake_controller
|
||||
|
||||
@nose.tools.raises(milla.HTTPMovedPermanently)
|
||||
def test_trailing_slash_redir():
|
||||
'''Paths that match except the trailing slash return a HTTP redirect
|
||||
'''
|
||||
|
||||
def controller():
|
||||
pass
|
||||
|
||||
router = milla.dispatch.routing.Router()
|
||||
router.add_route('/test/', controller)
|
||||
func = router.resolve('/test')
|
||||
assert func is not controller
|
||||
func()
|
||||
|
||||
@nose.tools.raises(milla.dispatch.routing.UnresolvedPath)
|
||||
def test_trailing_slash_none():
|
||||
'''Paths that match except the trailing slash are ignored
|
||||
'''
|
||||
|
||||
def controller():
|
||||
pass
|
||||
|
||||
router = milla.dispatch.routing.Router(None)
|
||||
router.add_route('/test/', controller)
|
||||
router.resolve('/test')
|
||||
|
||||
def test_trailing_slash_silent():
|
||||
'''Paths that match except the trailing slash are treated the same
|
||||
'''
|
||||
|
||||
def controller():
|
||||
pass
|
||||
|
||||
router = milla.dispatch.routing.Router(milla.dispatch.routing.Router.SILENT)
|
||||
router.add_route('/test/', controller)
|
||||
func = router.resolve('/test')
|
||||
assert func.func is controller
|
Loading…
Reference in New Issue