diff options
| author | Michael Merickel <michael@merickel.org> | 2012-05-03 00:11:50 -0500 |
|---|---|---|
| committer | Michael Merickel <michael@merickel.org> | 2012-05-03 00:11:50 -0500 |
| commit | c1c2b6ad8e22f9cba291de8903edfa4c7c741dca (patch) | |
| tree | c3bfa436eafa3903af04a4f4f3750a7ddb216830 | |
| parent | c3df7a76fa9f92201fbf57693b580b8904fac038 (diff) | |
| parent | 004882434aa166a58c3b2148322e08ce61ec4cb7 (diff) | |
| download | pyramid-c1c2b6ad8e22f9cba291de8903edfa4c7c741dca.tar.gz pyramid-c1c2b6ad8e22f9cba291de8903edfa4c7c741dca.tar.bz2 pyramid-c1c2b6ad8e22f9cba291de8903edfa4c7c741dca.zip | |
Merge branch 'master' into feature.json-api
31 files changed, 134 insertions, 95 deletions
diff --git a/CHANGES.txt b/CHANGES.txt index 337754162..34d60090d 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -9,7 +9,6 @@ Bug Fixes return the empty list. This was incorrect, it should have unconditionally returned ``[Everyone]``, and now does. - Features -------- @@ -21,7 +20,7 @@ Features - As of this release, the ``request_method`` predicate, when used, will also imply that ``HEAD`` is implied when you use ``GET``. For example, using ``@view_config(request_method='GET')`` is equivalent to using - ``@view_config(request_method='HEAD')``. Using + ``@view_config(request_method=('GET', 'HEAD'))``. Using ``@view_config(request_method=('GET', 'POST')`` is equivalent to using ``@view_config(request_method=('GET', 'HEAD', 'POST')``. This is because HEAD is a variant of GET that omits the body, and WebOb has special support @@ -29,3 +28,13 @@ Features - ``config.set_request_property`` now causes less code to be executed at request construction time. + +- Don't add a ``?`` to URLs generated by request.resource_url if the + ``query`` argument is provided but empty. + +- Don't add a ``?`` to URLs generated by request.route_url if the + ``_query`` argument is provided but empty. + +- The static view machinery now raises (rather than returns) ``HTTPNotFound`` + and ``HTTPMovedPermanently`` exceptions, so these can be caught by the + NotFound view (and other exception views). @@ -4,6 +4,10 @@ Pyramid TODOs Nice-to-Have ------------ +- config.set_registry_attr (with conflict detection). + +- _fix_registry should dictify the registry being fixed. + - Provide the presumed renderer name to the called view as an attribute of the request. @@ -67,8 +71,6 @@ Nice-to-Have app1" and "domain app1.localhost = app1"), ProxyPreserveHost and the nginx equivalent, preserving HTTPS URLs. -- _fix_registry should dictify the registry being fixed. - - Make "localizer" a property of request (instead of requiring "get_localizer(request)"? @@ -126,6 +128,9 @@ Future - 1.5: Remove ``pyramid.requests.DeprecatedRequestMethodsMixin``. +- 1.5: Maybe? deprecate set_request_property in favor of pointing people at + set_request_method. + - 1.6: Remove IContextURL and TraversalContextURL. Probably Bad Ideas diff --git a/docs/glossary.rst b/docs/glossary.rst index 88598354a..45a79326f 100644 --- a/docs/glossary.rst +++ b/docs/glossary.rst @@ -922,9 +922,9 @@ Glossary http://docs.pylonsproject.org/projects/pyramid_debugtoolbar/dev/ . scaffold - A project template that helps users get started writing a Pyramid - application quickly. Scaffolds are usually used via the ``pcreate`` - command. + A project template that generates some of the major parts of a Pyramid + application and helps users to quickly get started writing larger + applications. Scaffolds are usually used via the ``pcreate`` command. pyramid_exclog A package which logs Pyramid application exception (error) information diff --git a/docs/narr/commandline.rst b/docs/narr/commandline.rst index 886e075e3..4be436836 100644 --- a/docs/narr/commandline.rst +++ b/docs/narr/commandline.rst @@ -460,7 +460,7 @@ to the console. You can add request header values by using the ``--header`` option:: - $ bin/prequest --header=Host=example.com development.ini / + $ bin/prequest --header=Host:example.com development.ini / Headers are added to the WSGI environment by converting them to their CGI/WSGI equivalents (e.g. ``Host=example.com`` will insert the ``HTTP_HOST`` @@ -718,7 +718,7 @@ we'll pretend you have a distribution with a package in it named def settings_show(): description = """\ Print the deployment settings for a Pyramid application. Example: - 'psettings deployment.ini' + 'show_settings deployment.ini' """ usage = "usage: %prog config_uri" parser = optparse.OptionParser( diff --git a/docs/narr/startup.rst b/docs/narr/startup.rst index 8e28835af..f5c741f52 100644 --- a/docs/narr/startup.rst +++ b/docs/narr/startup.rst @@ -42,8 +42,8 @@ Here's a high-level time-ordered overview of what happens when you press ``[pipeline:main]``, or ``[composite:main]`` in the ``.ini`` file. This section represents the configuration of a :term:`WSGI` application that will be served. If you're using a simple application (e.g. - ``[app:main]``), the application :term:`entry point` or :term:`dotted - Python name` will be named on the ``use=`` line within the section's + ``[app:main]``), the application's ``paste.app_factory`` :term:`entry + point` will be named on the ``use=`` line within the section's configuration. If, instead of a simple application, you're using a WSGI :term:`pipeline` (e.g. a ``[pipeline:main]`` section), the application named on the "last" element will refer to your :app:`Pyramid` application. @@ -59,11 +59,11 @@ Here's a high-level time-ordered overview of what happens when you press system for this application. See :ref:`logging_config` for more information. -#. The application's *constructor* named by the entry point reference or - dotted Python name on the ``use=`` line of the section representing your - :app:`Pyramid` application is passed the key/value parameters mentioned - within the section in which it's defined. The constructor is meant to - return a :term:`router` instance, which is a :term:`WSGI` application. +#. The application's *constructor* named by the entry point reference on the + ``use=`` line of the section representing your :app:`Pyramid` application + is passed the key/value parameters mentioned within the section in which + it's defined. The constructor is meant to return a :term:`router` + instance, which is a :term:`WSGI` application. For :app:`Pyramid` applications, the constructor will be a function named ``main`` in the ``__init__.py`` file within the :term:`package` in which diff --git a/docs/narr/urldispatch.rst b/docs/narr/urldispatch.rst index f036ce94e..acbccbdfd 100644 --- a/docs/narr/urldispatch.rst +++ b/docs/narr/urldispatch.rst @@ -547,7 +547,7 @@ add to your application: config.add_route('idea', 'ideas/{idea}') config.add_route('user', 'users/{user}') - config.add_route('tag', 'tags/{tags}') + config.add_route('tag', 'tags/{tag}') config.add_view('mypackage.views.idea_view', route_name='idea') config.add_view('mypackage.views.user_view', route_name='user') diff --git a/docs/tutorials/wiki/installation.rst b/docs/tutorials/wiki/installation.rst index 63b30da5a..868c99dee 100644 --- a/docs/tutorials/wiki/installation.rst +++ b/docs/tutorials/wiki/installation.rst @@ -130,9 +130,10 @@ Preparation, Windows Make a Project ============== -Your next step is to create a project. :app:`Pyramid` supplies a variety of -scaffolds to generate sample projects. For this tutorial, we will use the -:term:`ZODB` -oriented scaffold named ``zodb``. +Your next step is to create a project. For this tutorial, we will use the +:term:`scaffold` named ``zodb``, which generates an application +that uses :term:`ZODB` and :term:`traversal`. :app:`Pyramid` +supplies a variety of scaffolds to generate sample projects. The below instructions assume your current working directory is the "virtualenv" named "pyramidtut". diff --git a/docs/tutorials/wiki2/installation.rst b/docs/tutorials/wiki2/installation.rst index 4ee2728c2..6589a1557 100644 --- a/docs/tutorials/wiki2/installation.rst +++ b/docs/tutorials/wiki2/installation.rst @@ -67,10 +67,10 @@ Preparation, Windows Making a Project ================ -Your next step is to create a project. :app:`Pyramid` supplies a -variety of scaffolds to generate sample projects. We will use the -``alchemy`` scaffold, which generates an application -that uses :term:`SQLAlchemy` and :term:`URL dispatch`. +Your next step is to create a project. For this tutorial, we will use the +:term:`scaffold` named ``alchemy``, which generates an application +that uses :term:`SQLAlchemy` and :term:`URL dispatch`. :app:`Pyramid` +supplies a variety of scaffolds to generate sample projects. The below instructions assume your current working directory is the "virtualenv" named "pyramidtut". @@ -254,7 +254,7 @@ The output to your console should be something like this:: 2011-11-26 14:42:25,140 INFO [sqlalchemy.engine.base.Engine][MainThread] COMMIT -Success! You should now have a ``tutorial.db`` file in your current working +Success! You should now have a ``tutorial.sqlite`` file in your current working directory. This will be a SQLite database with a single table defined in it (``models``). diff --git a/docs/tutorials/wiki2/src/authorization/development.ini b/docs/tutorials/wiki2/src/authorization/development.ini index 38738f3c6..eb2f878c5 100644 --- a/docs/tutorials/wiki2/src/authorization/development.ini +++ b/docs/tutorials/wiki2/src/authorization/development.ini @@ -10,7 +10,7 @@ pyramid.includes = pyramid_debugtoolbar pyramid_tm -sqlalchemy.url = sqlite:///%(here)s/tutorial.db +sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite [server:main] use = egg:waitress#main diff --git a/docs/tutorials/wiki2/src/authorization/production.ini b/docs/tutorials/wiki2/src/authorization/production.ini index c4034abad..4684d2f7a 100644 --- a/docs/tutorials/wiki2/src/authorization/production.ini +++ b/docs/tutorials/wiki2/src/authorization/production.ini @@ -9,7 +9,7 @@ pyramid.default_locale_name = en pyramid.includes = pyramid_tm -sqlalchemy.url = sqlite:///%(here)s/tutorial.db +sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite [server:main] use = egg:waitress#main diff --git a/docs/tutorials/wiki2/src/basiclayout/development.ini b/docs/tutorials/wiki2/src/basiclayout/development.ini index 38738f3c6..eb2f878c5 100644 --- a/docs/tutorials/wiki2/src/basiclayout/development.ini +++ b/docs/tutorials/wiki2/src/basiclayout/development.ini @@ -10,7 +10,7 @@ pyramid.includes = pyramid_debugtoolbar pyramid_tm -sqlalchemy.url = sqlite:///%(here)s/tutorial.db +sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite [server:main] use = egg:waitress#main diff --git a/docs/tutorials/wiki2/src/basiclayout/production.ini b/docs/tutorials/wiki2/src/basiclayout/production.ini index c4034abad..4684d2f7a 100644 --- a/docs/tutorials/wiki2/src/basiclayout/production.ini +++ b/docs/tutorials/wiki2/src/basiclayout/production.ini @@ -9,7 +9,7 @@ pyramid.default_locale_name = en pyramid.includes = pyramid_tm -sqlalchemy.url = sqlite:///%(here)s/tutorial.db +sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite [server:main] use = egg:waitress#main diff --git a/docs/tutorials/wiki2/src/models/development.ini b/docs/tutorials/wiki2/src/models/development.ini index 38738f3c6..eb2f878c5 100644 --- a/docs/tutorials/wiki2/src/models/development.ini +++ b/docs/tutorials/wiki2/src/models/development.ini @@ -10,7 +10,7 @@ pyramid.includes = pyramid_debugtoolbar pyramid_tm -sqlalchemy.url = sqlite:///%(here)s/tutorial.db +sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite [server:main] use = egg:waitress#main diff --git a/docs/tutorials/wiki2/src/models/production.ini b/docs/tutorials/wiki2/src/models/production.ini index c4034abad..4684d2f7a 100644 --- a/docs/tutorials/wiki2/src/models/production.ini +++ b/docs/tutorials/wiki2/src/models/production.ini @@ -9,7 +9,7 @@ pyramid.default_locale_name = en pyramid.includes = pyramid_tm -sqlalchemy.url = sqlite:///%(here)s/tutorial.db +sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite [server:main] use = egg:waitress#main diff --git a/docs/tutorials/wiki2/src/tests/development.ini b/docs/tutorials/wiki2/src/tests/development.ini index 38738f3c6..eb2f878c5 100644 --- a/docs/tutorials/wiki2/src/tests/development.ini +++ b/docs/tutorials/wiki2/src/tests/development.ini @@ -10,7 +10,7 @@ pyramid.includes = pyramid_debugtoolbar pyramid_tm -sqlalchemy.url = sqlite:///%(here)s/tutorial.db +sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite [server:main] use = egg:waitress#main diff --git a/docs/tutorials/wiki2/src/tests/production.ini b/docs/tutorials/wiki2/src/tests/production.ini index c4034abad..4684d2f7a 100644 --- a/docs/tutorials/wiki2/src/tests/production.ini +++ b/docs/tutorials/wiki2/src/tests/production.ini @@ -9,7 +9,7 @@ pyramid.default_locale_name = en pyramid.includes = pyramid_tm -sqlalchemy.url = sqlite:///%(here)s/tutorial.db +sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite [server:main] use = egg:waitress#main diff --git a/docs/tutorials/wiki2/src/views/development.ini b/docs/tutorials/wiki2/src/views/development.ini index 38738f3c6..eb2f878c5 100644 --- a/docs/tutorials/wiki2/src/views/development.ini +++ b/docs/tutorials/wiki2/src/views/development.ini @@ -10,7 +10,7 @@ pyramid.includes = pyramid_debugtoolbar pyramid_tm -sqlalchemy.url = sqlite:///%(here)s/tutorial.db +sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite [server:main] use = egg:waitress#main diff --git a/docs/tutorials/wiki2/src/views/production.ini b/docs/tutorials/wiki2/src/views/production.ini index c4034abad..4684d2f7a 100644 --- a/docs/tutorials/wiki2/src/views/production.ini +++ b/docs/tutorials/wiki2/src/views/production.ini @@ -9,7 +9,7 @@ pyramid.default_locale_name = en pyramid.includes = pyramid_tm -sqlalchemy.url = sqlite:///%(here)s/tutorial.db +sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite [server:main] use = egg:waitress#main diff --git a/pyramid/scaffolds/alchemy/README.txt_tmpl b/pyramid/scaffolds/alchemy/README.txt_tmpl index efea71c5c..9e4aa1125 100644 --- a/pyramid/scaffolds/alchemy/README.txt_tmpl +++ b/pyramid/scaffolds/alchemy/README.txt_tmpl @@ -8,7 +8,7 @@ Getting Started - $venv/bin/python setup.py develop -- $venv/bin/populate_{{project}} development.ini +- $venv/bin/initialize_{{project}}_db development.ini - $venv/bin/pserve development.ini diff --git a/pyramid/scaffolds/alchemy/development.ini_tmpl b/pyramid/scaffolds/alchemy/development.ini_tmpl index bcba06c1c..eebfbcc3e 100644 --- a/pyramid/scaffolds/alchemy/development.ini_tmpl +++ b/pyramid/scaffolds/alchemy/development.ini_tmpl @@ -10,7 +10,7 @@ pyramid.includes = pyramid_debugtoolbar pyramid_tm -sqlalchemy.url = sqlite:///%(here)s/{{project}}.db +sqlalchemy.url = sqlite:///%(here)s/{{project}}.sqlite [server:main] use = egg:waitress#main diff --git a/pyramid/scaffolds/alchemy/production.ini_tmpl b/pyramid/scaffolds/alchemy/production.ini_tmpl index dc9145d12..9488f1811 100644 --- a/pyramid/scaffolds/alchemy/production.ini_tmpl +++ b/pyramid/scaffolds/alchemy/production.ini_tmpl @@ -9,7 +9,7 @@ pyramid.default_locale_name = en pyramid.includes = pyramid_tm -sqlalchemy.url = sqlite:///%(here)s/{{project}}.db +sqlalchemy.url = sqlite:///%(here)s/{{project}}.sqlite [server:main] use = egg:waitress#main diff --git a/pyramid/scaffolds/alchemy/setup.py_tmpl b/pyramid/scaffolds/alchemy/setup.py_tmpl index b80fc52a8..2d8ed028f 100644 --- a/pyramid/scaffolds/alchemy/setup.py_tmpl +++ b/pyramid/scaffolds/alchemy/setup.py_tmpl @@ -22,7 +22,7 @@ setup(name='{{project}}', long_description=README + '\n\n' + CHANGES, classifiers=[ "Programming Language :: Python", - "Framework :: Pylons", + "Framework :: Pyramid", "Topic :: Internet :: WWW/HTTP", "Topic :: Internet :: WWW/HTTP :: WSGI :: Application", ], diff --git a/pyramid/scaffolds/starter/setup.py_tmpl b/pyramid/scaffolds/starter/setup.py_tmpl index 39ac6de9d..58c0a79fc 100644 --- a/pyramid/scaffolds/starter/setup.py_tmpl +++ b/pyramid/scaffolds/starter/setup.py_tmpl @@ -18,7 +18,7 @@ setup(name='{{project}}', long_description=README + '\n\n' + CHANGES, classifiers=[ "Programming Language :: Python", - "Framework :: Pylons", + "Framework :: Pyramid", "Topic :: Internet :: WWW/HTTP", "Topic :: Internet :: WWW/HTTP :: WSGI :: Application", ], diff --git a/pyramid/scaffolds/zodb/setup.py_tmpl b/pyramid/scaffolds/zodb/setup.py_tmpl index 965c0178f..acdf095d5 100644 --- a/pyramid/scaffolds/zodb/setup.py_tmpl +++ b/pyramid/scaffolds/zodb/setup.py_tmpl @@ -21,7 +21,7 @@ setup(name='{{project}}', long_description=README + '\n\n' + CHANGES, classifiers=[ "Programming Language :: Python", - "Framework :: Pylons", + "Framework :: Pyramid", "Topic :: Internet :: WWW/HTTP", "Topic :: Internet :: WWW/HTTP :: WSGI :: Application", ], diff --git a/pyramid/static.py b/pyramid/static.py index dfb602ee0..63ca58597 100644 --- a/pyramid/static.py +++ b/pyramid/static.py @@ -101,17 +101,17 @@ class static_view(object): path = _secure_path(path_tuple) if path is None: - return HTTPNotFound('Out of bounds: %s' % request.url) + raise HTTPNotFound('Out of bounds: %s' % request.url) if self.package_name: # package resource resource_path ='%s/%s' % (self.docroot.rstrip('/'), path) if resource_isdir(self.package_name, resource_path): if not request.path_url.endswith('/'): - return self.add_slash_redirect(request) + self.add_slash_redirect(request) resource_path = '%s/%s' % (resource_path.rstrip('/'),self.index) if not resource_exists(self.package_name, resource_path): - return HTTPNotFound(request.url) + raise HTTPNotFound(request.url) filepath = resource_filename(self.package_name, resource_path) else: # filesystem file @@ -120,10 +120,10 @@ class static_view(object): filepath = normcase(normpath(join(self.norm_docroot, path))) if isdir(filepath): if not request.path_url.endswith('/'): - return self.add_slash_redirect(request) + self.add_slash_redirect(request) filepath = join(filepath, self.index) if not exists(filepath): - return HTTPNotFound(request.url) + raise HTTPNotFound(request.url) return FileResponse(filepath, request, self.cache_max_age) @@ -132,7 +132,7 @@ class static_view(object): qs = request.query_string if qs: url = url + '?' + qs - return HTTPMovedPermanently(url) + raise HTTPMovedPermanently(url) _seps = set(['/', os.sep]) def _contains_slash(item): diff --git a/pyramid/tests/test_scaffolds/test_copydir.py b/pyramid/tests/test_scaffolds/test_copydir.py index 42edd9d23..68cefbe6e 100644 --- a/pyramid/tests/test_scaffolds/test_copydir.py +++ b/pyramid/tests/test_scaffolds/test_copydir.py @@ -170,9 +170,11 @@ class Test_makedirs(unittest.TestCase): def test_makedirs_parent_dir(self): import shutil - target = "/tmp/nonexistent_dir/nonexistent_subdir" + import tempfile + tmpdir = tempfile.mkdtemp() + target = os.path.join(tmpdir, 'nonexistent_subdir') self._callFUT(target, 2, None) - shutil.rmtree("/tmp/nonexistent_dir") + shutil.rmtree(tmpdir) class Test_support_functions(unittest.TestCase): diff --git a/pyramid/tests/test_static.py b/pyramid/tests/test_static.py index 7f94df990..94497d4f6 100644 --- a/pyramid/tests/test_static.py +++ b/pyramid/tests/test_static.py @@ -38,11 +38,9 @@ class Test_static_view_use_subpath_False(unittest.TestCase): inst = self._makeOne('pyramid.tests:fixtures/static') request = self._makeRequest({'PATH_INFO':''}) context = DummyContext() - response = inst(context, request) - response.prepare(request.environ) - self.assertEqual(response.status, '301 Moved Permanently') - self.assertTrue(b'http://example.com:6543/' in response.body) - + from pyramid.httpexceptions import HTTPMovedPermanently + self.assertRaises(HTTPMovedPermanently, inst, context, request) + def test_path_info_slash_means_index_html(self): inst = self._makeOne('pyramid.tests:fixtures/static') request = self._makeRequest() @@ -70,16 +68,16 @@ class Test_static_view_use_subpath_False(unittest.TestCase): inst = self._makeOne('pyramid.tests:fixtures/static') request = self._makeRequest({'PATH_INFO':'/subdir/../../minimal.pt'}) context = DummyContext() - response = inst(context, request) - self.assertEqual(response.status, '404 Not Found') + from pyramid.httpexceptions import HTTPNotFound + self.assertRaises(HTTPNotFound, inst, context, request) def test_oob_dotdotslash_encoded(self): inst = self._makeOne('pyramid.tests:fixtures/static') request = self._makeRequest( {'PATH_INFO':'/subdir/%2E%2E%2F%2E%2E/minimal.pt'}) context = DummyContext() - response = inst(context, request) - self.assertEqual(response.status, '404 Not Found') + from pyramid.httpexceptions import HTTPNotFound + self.assertRaises(HTTPNotFound, inst, context, request) def test_oob_os_sep(self): import os @@ -88,15 +86,15 @@ class Test_static_view_use_subpath_False(unittest.TestCase): request = self._makeRequest({'PATH_INFO':'/subdir/%s%sminimal.pt' % (dds, dds)}) context = DummyContext() - response = inst(context, request) - self.assertEqual(response.status, '404 Not Found') + from pyramid.httpexceptions import HTTPNotFound + self.assertRaises(HTTPNotFound, inst, context, request) def test_resource_doesnt_exist(self): inst = self._makeOne('pyramid.tests:fixtures/static') request = self._makeRequest({'PATH_INFO':'/notthere'}) context = DummyContext() - response = inst(context, request) - self.assertEqual(response.status, '404 Not Found') + from pyramid.httpexceptions import HTTPNotFound + self.assertRaises(HTTPNotFound, inst, context, request) def test_resource_isdir(self): inst = self._makeOne('pyramid.tests:fixtures/static') @@ -174,8 +172,8 @@ class Test_static_view_use_subpath_False(unittest.TestCase): inst = self._makeOne('pyramid.tests:fixtures/static') request = self._makeRequest({'PATH_INFO':'/notthere.html'}) context = DummyContext() - response = inst(context, request) - self.assertEqual(response.status, '404 Not Found') + from pyramid.httpexceptions import HTTPNotFound + self.assertRaises(HTTPNotFound, inst, context, request) def test_resource_with_content_encoding(self): inst = self._makeOne('pyramid.tests:fixtures/static') @@ -233,11 +231,9 @@ class Test_static_view_use_subpath_True(unittest.TestCase): request = self._makeRequest({'PATH_INFO':''}) request.subpath = () context = DummyContext() - response = inst(context, request) - response.prepare(request.environ) - self.assertEqual(response.status, '301 Moved Permanently') - self.assertTrue(b'http://example.com:6543/' in response.body) - + from pyramid.httpexceptions import HTTPMovedPermanently + self.assertRaises(HTTPMovedPermanently, inst, context, request) + def test_path_info_slash_means_index_html(self): inst = self._makeOne('pyramid.tests:fixtures/static') request = self._makeRequest() @@ -251,33 +247,33 @@ class Test_static_view_use_subpath_True(unittest.TestCase): request = self._makeRequest() request.subpath = ('.', 'index.html') context = DummyContext() - response = inst(context, request) - self.assertEqual(response.status, '404 Not Found') + from pyramid.httpexceptions import HTTPNotFound + self.assertRaises(HTTPNotFound, inst, context, request) def test_oob_emptyelement(self): inst = self._makeOne('pyramid.tests:fixtures/static') request = self._makeRequest() request.subpath = ('', 'index.html') context = DummyContext() - response = inst(context, request) - self.assertEqual(response.status, '404 Not Found') + from pyramid.httpexceptions import HTTPNotFound + self.assertRaises(HTTPNotFound, inst, context, request) def test_oob_dotdotslash(self): inst = self._makeOne('pyramid.tests:fixtures/static') request = self._makeRequest() request.subpath = ('subdir', '..', '..', 'minimal.pt') context = DummyContext() - response = inst(context, request) - self.assertEqual(response.status, '404 Not Found') + from pyramid.httpexceptions import HTTPNotFound + self.assertRaises(HTTPNotFound, inst, context, request) def test_oob_dotdotslash_encoded(self): inst = self._makeOne('pyramid.tests:fixtures/static') request = self._makeRequest() request.subpath = ('subdir', '%2E%2E', '%2E%2E', 'minimal.pt') context = DummyContext() - response = inst(context, request) - self.assertEqual(response.status, '404 Not Found') - + from pyramid.httpexceptions import HTTPNotFound + self.assertRaises(HTTPNotFound, inst, context, request) + def test_oob_os_sep(self): import os inst = self._makeOne('pyramid.tests:fixtures/static') @@ -285,16 +281,16 @@ class Test_static_view_use_subpath_True(unittest.TestCase): request = self._makeRequest() request.subpath = ('subdir', dds, dds, 'minimal.pt') context = DummyContext() - response = inst(context, request) - self.assertEqual(response.status, '404 Not Found') + from pyramid.httpexceptions import HTTPNotFound + self.assertRaises(HTTPNotFound, inst, context, request) def test_resource_doesnt_exist(self): inst = self._makeOne('pyramid.tests:fixtures/static') request = self._makeRequest() request.subpath = ('notthere,') context = DummyContext() - response = inst(context, request) - self.assertEqual(response.status, '404 Not Found') + from pyramid.httpexceptions import HTTPNotFound + self.assertRaises(HTTPNotFound, inst, context, request) def test_resource_isdir(self): inst = self._makeOne('pyramid.tests:fixtures/static') @@ -361,8 +357,8 @@ class Test_static_view_use_subpath_True(unittest.TestCase): request = self._makeRequest() request.subpath = ('notthere.html',) context = DummyContext() - response = inst(context, request) - self.assertEqual(response.status, '404 Not Found') + from pyramid.httpexceptions import HTTPNotFound + self.assertRaises(HTTPNotFound, inst, context, request) class DummyContext: pass diff --git a/pyramid/tests/test_url.py b/pyramid/tests/test_url.py index 0dff1e648..50deb63f3 100644 --- a/pyramid/tests/test_url.py +++ b/pyramid/tests/test_url.py @@ -113,6 +113,14 @@ class TestURLMethodsMixin(unittest.TestCase): self.assertEqual(result, 'http://example.com:5432/context/a?a=hi+there&b=La+Pe%C3%B1a') + def test_resource_url_with_query_empty(self): + request = self._makeOne() + self._registerResourceURL(request.registry) + context = DummyContext() + result = request.resource_url(context, 'a', query=[]) + self.assertEqual(result, + 'http://example.com:5432/context/a') + def test_resource_url_anchor_is_after_root_when_no_elements(self): request = self._makeOne() self._registerResourceURL(request.registry) @@ -334,6 +342,15 @@ class TestURLMethodsMixin(unittest.TestCase): self.assertEqual(result, 'http://example.com:5432/1/2/3?q=1') + def test_route_url_with_empty_query(self): + from pyramid.interfaces import IRoutesMapper + request = self._makeOne() + mapper = DummyRoutesMapper(route=DummyRoute('/1/2/3')) + request.registry.registerUtility(mapper, IRoutesMapper) + result = request.route_url('flub', _query={}) + self.assertEqual(result, + 'http://example.com:5432/1/2/3') + def test_route_url_with_app_url(self): from pyramid.interfaces import IRoutesMapper request = self._makeOne() diff --git a/pyramid/url.py b/pyramid/url.py index 022867967..dd83bb631 100644 --- a/pyramid/url.py +++ b/pyramid/url.py @@ -218,7 +218,9 @@ class URLMethodsMixin(object): port = None if '_query' in kw: - qs = '?' + urlencode(kw.pop('_query'), doseq=True) + query = kw.pop('_query') + if query: + qs = '?' + urlencode(query, doseq=True) if '_anchor' in kw: anchor = kw.pop('_anchor') @@ -494,7 +496,9 @@ class URLMethodsMixin(object): anchor = '' if 'query' in kw: - qs = '?' + urlencode(kw['query'], doseq=True) + query = kw['query'] + if query: + qs = '?' + urlencode(query, doseq=True) if 'anchor' in kw: anchor = kw['anchor'] @@ -10,4 +10,4 @@ cover-erase=1 [aliases] dev = develop easy_install pyramid[testing] - +docs = develop easy_install pyramid[docs] @@ -50,18 +50,22 @@ install_requires=[ tests_require = [ 'WebTest >= 1.3.1', # py3 compat - 'virtualenv', ] if not PY3: - tests_require.extend([ - 'Sphinx', - 'docutils', - 'repoze.sphinx.autointerface', - 'zope.component>=3.11.0', - ]) + tests_require.append('zope.component>=3.11.0') -testing_extras = tests_require + ['nose', 'coverage'] +docs_extras = [ + 'Sphinx', + 'docutils', + 'repoze.sphinx.autointerface', + ] + +testing_extras = tests_require + [ + 'nose', + 'coverage', + 'virtualenv', # for scaffolding tests + ] setup(name='pyramid', version='1.4dev', @@ -93,6 +97,7 @@ setup(name='pyramid', install_requires = install_requires, extras_require = { 'testing':testing_extras, + 'docs':docs_extras, }, tests_require = tests_require, test_suite="pyramid.tests", |
