summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES.txt16
-rw-r--r--docs/api.rst1
-rw-r--r--docs/api/static.rst11
-rw-r--r--docs/narr/assets.rst29
-rw-r--r--docs/narr/hybrid.rst17
-rw-r--r--pyramid/static.py18
-rw-r--r--pyramid/tests/test_integration.py4
-rw-r--r--pyramid/tests/test_static.py56
-rw-r--r--pyramid/tests/test_view.py54
-rw-r--r--pyramid/view.py25
10 files changed, 184 insertions, 47 deletions
diff --git a/CHANGES.txt b/CHANGES.txt
index cd9f42dd9..d898c5ca6 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -8,6 +8,22 @@ Features
rendererinfo to clear out old registry on a rescan. See
https://github.com/Pylons/pyramid/pull/234.
+- New API class: ``pyramid.static.static_view``. This supersedes the
+ deprecated ``pyramid.view.static`` class. ``pyramid.satic.static_view`` by
+ default serves up documents as the result of the request's ``path_info``,
+ attribute rather than it's ``subpath`` attribute (the inverse was true of
+ ``pyramid.view.static``, and still is). ``pyramid.static.static_view``
+ exposes a ``use_subpath`` flag for use when you don't want the static view
+ to behave like the older deprecated version.
+
+Deprecations
+------------
+
+- The ``pyramid.view.static`` class has been deprecated in favor of the newer
+ ``pyramid.static.static_view`` class. A deprecation warning is raised when
+ it is used. You should replace it with a reference to
+ ``pyramid.static.static_view`` with the ``use_subpath=True`` argument.
+
1.1b2 (2011-07-13)
==================
diff --git a/docs/api.rst b/docs/api.rst
index be7942502..a7e1566d3 100644
--- a/docs/api.rst
+++ b/docs/api.rst
@@ -28,6 +28,7 @@ documentation is organized alphabetically by module name.
api/security
api/session
api/settings
+ api/static
api/testing
api/threadlocal
api/traversal
diff --git a/docs/api/static.rst b/docs/api/static.rst
new file mode 100644
index 000000000..c28473584
--- /dev/null
+++ b/docs/api/static.rst
@@ -0,0 +1,11 @@
+.. _static_module:
+
+:mod:`pyramid.static`
+---------------------
+
+.. automodule:: pyramid.static
+
+ .. autoclass:: static_view
+ :members:
+ :inherited-members:
+
diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst
index 0d50b0106..d57687477 100644
--- a/docs/narr/assets.rst
+++ b/docs/narr/assets.rst
@@ -299,7 +299,7 @@ URLs against assets made accessible by registering a custom static view.
Root-Relative Custom Static View (URL Dispatch Only)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-The :class:`pyramid.view.static` helper class generates a Pyramid view
+The :class:`pyramid.static.static_view` helper class generates a Pyramid view
callable. This view callable can serve static assets from a directory. An
instance of this class is actually used by the
:meth:`~pyramid.config.Configurator.add_static_view` configuration method, so
@@ -310,26 +310,27 @@ its behavior is almost exactly the same once it's configured.
exclusively. The root-relative route we'll be registering will always be
matched before traversal takes place, subverting any views registered via
``add_view`` (at least those without a ``route_name``). A
- :class:`~pyramid.view.static` static view cannot be made root-relative when
- you use traversal.
+ :class:`~pyramid.static.static_view` static view cannot be made
+ root-relative when you use traversal unless it's registered as a
+ :term:`NotFound view`.
To serve files within a directory located on your filesystem at
``/path/to/static/dir`` as the result of a "catchall" route hanging from the
root that exists at the end of your routing table, create an instance of the
-:class:`~pyramid.view.static` class inside a ``static.py`` file in your
-application root as below.
+:class:`~pyramid.static.static_view` class inside a ``static.py`` file in
+your application root as below.
.. ignore-next-block
.. code-block:: python
:linenos:
- from pyramid.view import static
- static_view = static('/path/to/static/dir')
+ from pyramid.static import static
+ static_view = static_view('/path/to/static/dir', use_subpath=True)
.. note:: For better cross-system flexibility, use an :term:`asset
- specification` as the argument to :class:`~pyramid.view.static` instead of
- a physical absolute filesystem path, e.g. ``mypackage:static`` instead of
- ``/path/to/mypackage/static``.
+ specification` as the argument to :class:`~pyramid.static.static_view`
+ instead of a physical absolute filesystem path, e.g. ``mypackage:static``
+ instead of ``/path/to/mypackage/static``.
Subsequently, you may wire the files that are served by this view up to be
accessible as ``/<filename>`` using a configuration method in your
@@ -345,8 +346,8 @@ application's startup code.
config.add_view('myapp.static.static_view', route_name='catchall_static')
The special name ``*subpath`` above is used by the
-:class:`~pyramid.view.static` view callable to signify the path of the file
-relative to the directory you're serving.
+:class:`~pyramid.static.static_view` view callable to signify the path of the
+file relative to the directory you're serving.
Registering A View Callable to Serve a "Static" Asset
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -425,10 +426,10 @@ feature, a :term:`Configurator` API exists named
- A directory containing multiple Chameleon templates.
- Individual static files served up by an instance of the
- ``pyramid.view.static`` helper class.
+ ``pyramid.static.static_view`` helper class.
- A directory of static files served up by an instance of the
- ``pyramid.view.static`` helper class.
+ ``pyramid.static.static_view`` helper class.
- Any other asset (or set of assets) addressed by code that uses the
setuptools :term:`pkg_resources` API.
diff --git a/docs/narr/hybrid.rst b/docs/narr/hybrid.rst
index 97adaeafd..a0a6a108c 100644
--- a/docs/narr/hybrid.rst
+++ b/docs/narr/hybrid.rst
@@ -431,8 +431,9 @@ Using ``*subpath`` in a Route Pattern
There are certain extremely rare cases when you'd like to influence the
traversal :term:`subpath` when a route matches without actually performing
traversal. For instance, the :func:`pyramid.wsgi.wsgiapp2` decorator and the
-:class:`pyramid.view.static` helper attempt to compute ``PATH_INFO`` from the
-request's subpath, so it's useful to be able to influence this value.
+:class:`pyramid.static.static_view` helper attempt to compute ``PATH_INFO``
+from the request's subpath when its ``use_subpath`` argument is ``True``, so
+it's useful to be able to influence this value.
When ``*subpath`` exists in a pattern, no path is actually traversed,
but the traversal algorithm will return a :term:`subpath` list implied
@@ -442,12 +443,16 @@ commonly in route declarations that look like this:
.. code-block:: python
:linenos:
+ from pryamid.static import static_view
+
+ www = static_view('mypackage:static', use_subpath=True)
+
config.add_route('static', '/static/*subpath')
- config.add_view('mypackage.views.static_view', route_name='static')
+ config.add_view(www, route_name='static')
-Where ``mypackage.views.static_view`` is an instance of
-:class:`pyramid.view.static`. This effectively tells the static helper to
-traverse everything in the subpath as a filename.
+``mypackage.views.www`` is an instance of
+:class:`pyramid.static.static_view`. This effectively tells the static
+helper to traverse everything in the subpath as a filename.
Corner Cases
------------
diff --git a/pyramid/static.py b/pyramid/static.py
index ec7b4cb00..9d8afc09b 100644
--- a/pyramid/static.py
+++ b/pyramid/static.py
@@ -136,7 +136,8 @@ class StaticURLInfo(object):
# it's a view name
cache_max_age = extra.pop('cache_max_age', None)
# create a view
- view = static_view(spec, cache_max_age=cache_max_age)
+ view = static_view(spec, cache_max_age=cache_max_age,
+ use_subpath=True)
# Mutate extra to allow factory, etc to be passed through here.
# Treat permission specially because we'd like to default to
@@ -199,6 +200,13 @@ class static_view(object):
response headers returned by the view (default is 3600 seconds or
five minutes).
+ ``use_subpath`` influences whether ``request.subpath`` will be used as
+ ``PATH_INFO`` when calling the underlying WSGI application which actually
+ serves the static files. If it is ``True``, the static application will
+ consider ``request.subpath`` as ``PATH_INFO`` input. If it is ``False``,
+ the static application will consider request.path_info as ``PATH_INFO``
+ input. By default, this is ``False``.
+
.. note:: If the ``root_dir`` is relative to a :term:`package`, or
is a :term:`asset specification` the :app:`Pyramid`
:class:`pyramid.config.Configurator` method can be
@@ -207,7 +215,8 @@ class static_view(object):
absolute, configuration will not be able to
override the assets it contains. """
- def __init__(self, root_dir, cache_max_age=3600, package_name=None):
+ def __init__(self, root_dir, cache_max_age=3600, package_name=None,
+ use_subpath=False):
# package_name is for bw compat; it is preferred to pass in a
# package-relative path as root_dir
# (e.g. ``anotherpackage:foo/static``).
@@ -220,6 +229,9 @@ class static_view(object):
app = PackageURLParser(
package_name, root_dir, cache_max_age=cache_max_age)
self.app = app
+ self.use_subpath = use_subpath
def __call__(self, context, request):
- return call_app_with_subpath_as_path_info(request, self.app)
+ if self.use_subpath:
+ return call_app_with_subpath_as_path_info(request, self.app)
+ return request.get_response(self.app)
diff --git a/pyramid/tests/test_integration.py b/pyramid/tests/test_integration.py
index 0ef1e1631..1ebf83062 100644
--- a/pyramid/tests/test_integration.py
+++ b/pyramid/tests/test_integration.py
@@ -3,7 +3,7 @@ import unittest
from pyramid.wsgi import wsgiapp
from pyramid.view import view_config
-from pyramid.view import static
+from pyramid.static import static_view
from zope.interface import Interface
@@ -42,7 +42,7 @@ class WGSIAppPlusViewConfigTests(unittest.TestCase):
self.assertEqual(view.__original_view__, wsgiapptest)
here = os.path.dirname(__file__)
-staticapp = static(os.path.join(here, 'fixtures'))
+staticapp = static_view(os.path.join(here, 'fixtures'), use_subpath=True)
class TestStaticApp(unittest.TestCase):
def test_basic(self):
diff --git a/pyramid/tests/test_static.py b/pyramid/tests/test_static.py
index e7506628a..a15459da2 100644
--- a/pyramid/tests/test_static.py
+++ b/pyramid/tests/test_static.py
@@ -190,11 +190,12 @@ class Test_static_view(unittest.TestCase):
cleanUp()
def _getTargetClass(self):
- from pyramid.view import static
- return static
+ from pyramid.static import static_view
+ return static_view
- def _makeOne(self, path, package_name=None):
- return self._getTargetClass()(path, package_name=package_name)
+ def _makeOne(self, path, package_name=None, use_subpath=False):
+ return self._getTargetClass()(path, package_name=package_name,
+ use_subpath=use_subpath)
def _makeEnviron(self, **extras):
environ = {
@@ -207,10 +208,10 @@ class Test_static_view(unittest.TestCase):
environ.update(extras)
return environ
- def test_abspath(self):
+ def test_abspath_subpath(self):
import os.path
path = os.path.dirname(__file__)
- view = self._makeOne(path)
+ view = self._makeOne(path, use_subpath=True)
context = DummyContext()
request = DummyRequest()
request.subpath = ['__init__.py']
@@ -219,9 +220,9 @@ class Test_static_view(unittest.TestCase):
self.assertEqual(request.copied, True)
self.assertEqual(response.directory, os.path.normcase(path))
- def test_relpath(self):
+ def test_relpath_subpath(self):
path = 'fixtures'
- view = self._makeOne(path)
+ view = self._makeOne(path, use_subpath=True)
context = DummyContext()
request = DummyRequest()
request.subpath = ['__init__.py']
@@ -233,8 +234,22 @@ class Test_static_view(unittest.TestCase):
self.assertEqual(response.package_name, 'pyramid.tests')
self.assertEqual(response.cache_max_age, 3600)
- def test_relpath_withpackage(self):
- view = self._makeOne('another:fixtures')
+ def test_relpath_notsubpath(self):
+ path = 'fixtures'
+ view = self._makeOne(path)
+ context = DummyContext()
+ request = DummyRequest()
+ request.subpath = ['__init__.py']
+ request.environ = self._makeEnviron()
+ response = view(context, request)
+ self.assertTrue(not hasattr(request, 'copied'))
+ self.assertEqual(response.root_resource, 'fixtures')
+ self.assertEqual(response.resource_name, 'fixtures')
+ self.assertEqual(response.package_name, 'pyramid.tests')
+ self.assertEqual(response.cache_max_age, 3600)
+
+ def test_relpath_withpackage_subpath(self):
+ view = self._makeOne('another:fixtures', use_subpath=True)
context = DummyContext()
request = DummyRequest()
request.subpath = ['__init__.py']
@@ -246,8 +261,9 @@ class Test_static_view(unittest.TestCase):
self.assertEqual(response.package_name, 'another')
self.assertEqual(response.cache_max_age, 3600)
- def test_relpath_withpackage_name(self):
- view = self._makeOne('fixtures', package_name='another')
+ def test_relpath_withpackage_name_subpath(self):
+ view = self._makeOne('fixtures', package_name='another',
+ use_subpath=True)
context = DummyContext()
request = DummyRequest()
request.subpath = ['__init__.py']
@@ -259,8 +275,9 @@ class Test_static_view(unittest.TestCase):
self.assertEqual(response.package_name, 'another')
self.assertEqual(response.cache_max_age, 3600)
- def test_no_subpath_preserves_path_info_and_script_name(self):
- view = self._makeOne('fixtures', package_name='another')
+ def test_no_subpath_preserves_path_info_and_script_name_subpath(self):
+ view = self._makeOne('fixtures', package_name='another',
+ use_subpath=True)
context = DummyContext()
request = DummyRequest()
request.subpath = ()
@@ -272,8 +289,9 @@ class Test_static_view(unittest.TestCase):
self.assertEqual(request.environ['SCRIPT_NAME'],
'/script_name/path_info')
- def test_with_subpath_path_info_ends_with_slash(self):
- view = self._makeOne('fixtures', package_name='another')
+ def test_with_subpath_path_info_ends_with_slash_subpath(self):
+ view = self._makeOne('fixtures', package_name='another',
+ use_subpath=True)
context = DummyContext()
request = DummyRequest()
request.subpath = ('subpath',)
@@ -284,7 +302,8 @@ class Test_static_view(unittest.TestCase):
self.assertEqual(request.environ['SCRIPT_NAME'], '/path_info')
def test_with_subpath_original_script_name_preserved(self):
- view = self._makeOne('fixtures', package_name='another')
+ view = self._makeOne('fixtures', package_name='another',
+ use_subpath=True)
context = DummyContext()
request = DummyRequest()
request.subpath = ('subpath',)
@@ -297,7 +316,8 @@ class Test_static_view(unittest.TestCase):
'/scriptname/path_info')
def test_with_subpath_new_script_name_fixes_trailing_slashes(self):
- view = self._makeOne('fixtures', package_name='another')
+ view = self._makeOne('fixtures', package_name='another',
+ use_subpath=True)
context = DummyContext()
request = DummyRequest()
request.subpath = ('sub', 'path')
diff --git a/pyramid/tests/test_view.py b/pyramid/tests/test_view.py
index d46cfb3f5..8e5861e7b 100644
--- a/pyramid/tests/test_view.py
+++ b/pyramid/tests/test_view.py
@@ -565,6 +565,48 @@ class Test_patch_mimetypes(unittest.TestCase):
result = self._callFUT(module)
self.assertEqual(result, False)
+class Test_static(unittest.TestCase):
+ def setUp(self):
+ from zope.deprecation import __show__
+ __show__.off()
+
+ def tearDown(self):
+ from zope.deprecation import __show__
+ __show__.on()
+
+ def _getTargetClass(self):
+ from pyramid.view import static
+ return static
+
+ def _makeOne(self, path, package_name=None):
+ return self._getTargetClass()(path, package_name=package_name)
+
+ def _makeEnviron(self, **extras):
+ environ = {
+ 'wsgi.url_scheme':'http',
+ 'wsgi.version':(1,0),
+ 'SERVER_NAME':'localhost',
+ 'SERVER_PORT':'8080',
+ 'REQUEST_METHOD':'GET',
+ }
+ environ.update(extras)
+ return environ
+
+
+ def test_relpath_subpath(self):
+ path = 'fixtures'
+ view = self._makeOne(path)
+ context = DummyContext()
+ request = DummyRequest()
+ request.subpath = ['__init__.py']
+ request.environ = self._makeEnviron()
+ response = view(context, request)
+ self.assertEqual(request.copied, True)
+ self.assertEqual(response.root_resource, 'fixtures')
+ self.assertEqual(response.resource_name, 'fixtures')
+ self.assertEqual(response.package_name, 'pyramid.tests')
+ self.assertEqual(response.cache_max_age, 3600)
+
class ExceptionResponse(Exception):
status = '404 Not Found'
app_iter = ['Not Found']
@@ -581,6 +623,18 @@ def make_view(response):
class DummyRequest:
exception = None
+ def __init__(self, environ=None):
+ if environ is None:
+ environ = {}
+ self.environ = environ
+
+ def get_response(self, application):
+ return application
+
+ def copy(self):
+ self.copied = True
+ return self
+
from pyramid.interfaces import IResponse
from zope.interface import implements
diff --git a/pyramid/view.py b/pyramid/view.py
index 6b28601e2..1b59a2ed9 100644
--- a/pyramid/view.py
+++ b/pyramid/view.py
@@ -1,5 +1,6 @@
import mimetypes
import venusian
+import warnings
from zope.interface import providedBy
from zope.deprecation import deprecated
@@ -11,6 +12,7 @@ from pyramid.interfaces import IRendererInfo
from pyramid.httpexceptions import HTTPFound
from pyramid.httpexceptions import default_exceptionresponse_view
+from pyramid.path import caller_package
from pyramid.renderers import RendererHelper
from pyramid.static import static_view
from pyramid.threadlocal import get_current_registry
@@ -30,12 +32,27 @@ def init_mimetypes(mimetypes):
# fallout.
init_mimetypes(mimetypes)
-# Nasty BW compat hack: dont yet deprecate this (ever?)
-class static(static_view): # only subclass for purposes of autodoc
- __doc__ = static_view.__doc__
-
_marker = object()
+class static(static_view):
+ """ Backwards compatibility alias for
+ :class:`pyramid.static.static_view`; it overrides that class' constructor
+ to pass ``use_subpath=True`` by default. This class is deprecated as of
+ :app:`Pyramid` 1.1. Use :class:`pyramid.static.static_view` instead
+ (probably with a ``use_subpath=True`` argument).
+ """
+ def __init__(self, root_dir, cache_max_age=3600, package_name=None):
+ if package_name is None:
+ package_name = caller_package().__name__
+ static_view.__init__(self, root_dir, cache_max_age=cache_max_age,
+ package_name=package_name, use_subpath=True)
+
+deprecated(
+ 'static',
+ 'The "pyramid.view.static" class is deprecated as of Pyramid 1.1; '
+ 'use the "pyramid.static.static_view" class instead with the '
+ '"use_subpath" argument set to True.')
+
def render_view_to_response(context, request, name='', secure=True):
""" Call the :term:`view callable` configured with a :term:`view
configuration` that matches the :term:`view name` ``name``