summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/news.txt5
-rw-r--r--docs/paste-deploy.txt51
-rw-r--r--paste/deploy/interfaces.py28
-rw-r--r--paste/deploy/loadwsgi.py66
-rw-r--r--tests/conftest.py4
-rw-r--r--tests/fake_packages/FakeApp.egg/FakeApp.egg-info/entry_points.txt14
-rw-r--r--tests/fake_packages/FakeApp.egg/setup.py8
-rw-r--r--tests/sample_configs/test_config_included.ini2
-rw-r--r--tests/sample_configs/test_filter.ini3
-rw-r--r--tests/test_filter.py6
10 files changed, 118 insertions, 69 deletions
diff --git a/docs/news.txt b/docs/news.txt
index d8eecd7..8ea663c 100644
--- a/docs/news.txt
+++ b/docs/news.txt
@@ -4,6 +4,11 @@ Paste Deployment News
Version 0.2 (svn trunk)
-----------------------
+* Added a ``filter-with`` setting to applications.
+
+* Removed the ``1`` from all the protocol names (e.g.,
+ ``paste.app_factory1`` is not ``paste.app_factory``).
+
* Added ``filter-app:`` and ``pipeline:`` sections. `Docs
<paste-deploy.html#filter-composition>`__.
diff --git a/docs/paste-deploy.txt b/docs/paste-deploy.txt
index 5e64dd0..e7852cb 100644
--- a/docs/paste-deploy.txt
+++ b/docs/paste-deploy.txt
@@ -132,10 +132,10 @@ The other way to define an application is to point exactly to some
Python code::
[app:myapp]
- paste.app_factory1 = myapp.modulename:app_factory
+ paste.app_factory = myapp.modulename:app_factory
You must give an explicit *protocol* (in this case
-``paste.app_factory1``), and the value is something to import. In
+``paste.app_factory``), and the value is something to import. In
this case the module ``myapp.modulename`` is loaded, and the
``app_factory`` object retrieved from it.
@@ -227,9 +227,21 @@ of objects.
Filter Composition
~~~~~~~~~~~~~~~~~~
-Two special section types exist to apply filters more easily to your
-applications: ``[filter-app:...]`` and ``[pipeline:...]``. Both of these
-sections define applications, and so can be used wherever an
+There are several ways to apply filters to applications. It mostly
+depends on how many filters, and in what order you want to apply them.
+
+The first way is to use the ``filter-with`` setting, like::
+
+ [app:main]
+ use = egg:MyEgg
+ filter-with = printdebug
+
+ [filter:printdebug]
+ use = egg:Paste#printdebug
+
+Also, two special section types exist to apply filters to your
+applications: ``[filter-app:...]`` and ``[pipeline:...]``. Both of
+these sections define applications, and so can be used wherever an
application is needed.
``filter-app`` defines a filter (just like you would in a
@@ -244,6 +256,9 @@ ended by an application, like::
[pipeline:main]
pipeline = filter1 egg:FilterEgg#filter2 filter3 app
+ [filter:filter1]
+ ...
+
``egg:`` URIs
-------------
@@ -286,7 +301,7 @@ argument to ``setup()`` like::
name='MyApp',
...
entry_points={
- 'paste.app_factory1': [
+ 'paste.app_factory': [
'main=myapp.mymodule:app_factory',
'ob2=myapp.mymodule:ob_factory'],
},
@@ -309,12 +324,12 @@ This lets you point to factories (that obey the specific protocols we
mentioned). But that's not much use unless you can create factories
for your applications.
-There's a few protocols: ``paste.app_factory1``,
-``paste.composit_factory1``, ``paste.filter_factory1``, and lastly
-``paste.server_factory1``. Each of these expects a callable (like a
+There's a few protocols: ``paste.app_factory``,
+``paste.composit_factory``, ``paste.filter_factory``, and lastly
+``paste.server_factory``. Each of these expects a callable (like a
function, method, or class).
-``paste.app_factory1``
+``paste.app_factory``
~~~~~~~~~~~~~~~~~~~~~~
The application is the most common. You define one like::
@@ -325,7 +340,7 @@ The application is the most common. You define one like::
The ``global_config`` is a dictionary, and local configuration is
passed as keyword arguments. The function returns a WSGI application.
-``paste.composit_factory1``
+``paste.composit_factory``
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Composits are just slightly more complex::
@@ -364,7 +379,7 @@ Then we use it like::
[app:myapp]
use = egg:MyApp
-``paste.filter_factory1``
+``paste.filter_factory``
~~~~~~~~~~~~~~~~~~~~~~~~~
Filter factories are just like app factories (same signature), except
@@ -394,10 +409,10 @@ variable is set, creating a really simple authentication filter::
'403 Forbidden', [('Content-type', 'text/html')])
return ['You are forbidden to view this resource']
-``paste.filter_app_factory1``
+``paste.filter_app_factory``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-This is very similar to ``paste.filter_factory1``, except that it also
+This is very similar to ``paste.filter_factory``, except that it also
takes a ``wsgi_app`` argument, and returns a WSGI application. So if
you changed the above example to::
@@ -409,7 +424,7 @@ Then ``AuthFilter`` would serve as a filter_app_factory
(``req_usernames`` is a required local configuration key in this
case).
-``paste.server_factory1``
+``paste.server_factory``
~~~~~~~~~~~~~~~~~~~~~~~~~
This takes the same signature as applications and filters, but returns
@@ -429,10 +444,10 @@ An example might look like::
An implementation of ``Server`` is left to the user.
-``paste.server_runner1``
+``paste.server_runner``
~~~~~~~~~~~~~~~~~~~~~~~~
-Like ``paste.server_factory1``, except ``wsgi_app`` is passed as the
+Like ``paste.server_factory``, except ``wsgi_app`` is passed as the
first argument, and the server should run immediately.
Outstanding Issues
@@ -444,7 +459,7 @@ Outstanding Issues
* Should there be a "default" protocol for each type of object? Since
there's currently only one protocol, it seems like it makes sense
(in the future there could be multiple). Except that
- ``paste.app_factory1`` and ``paste.composit_factory1`` overlap
+ ``paste.app_factory`` and ``paste.composit_factory`` overlap
considerably.
* ConfigParser's INI parsing is kind of annoying. I'd like it both
diff --git a/paste/deploy/interfaces.py b/paste/deploy/interfaces.py
index 5f649cb..63e37b2 100644
--- a/paste/deploy/interfaces.py
+++ b/paste/deploy/interfaces.py
@@ -35,10 +35,10 @@ def loadserver(uri, name=None, relative_to=None, global_conf=None):
## Factories
############################################################
-class IPasteAppFactory1:
+class IPasteAppFactory:
"""
- This is the spec for the ``paste.app_factory1``
+ This is the spec for the ``paste.app_factory``
protocol/entry_point.
"""
@@ -51,28 +51,28 @@ class IPasteAppFactory1:
capture these values).
"""
-class IPasteCompositFactory1:
+class IPasteCompositFactory:
"""
- This is the spec for the ``paste.composit_factory1``
+ This is the spec for the ``paste.composit_factory``
protocol/entry_point.
- This also produces WSGI applications, like ``paste.app_factory1``,
+ This also produces WSGI applications, like ``paste.app_factory``,
but is given more access to the context in which it is loaded.
"""
def __call__(loader, global_conf, **local_conf):
"""
- Like IPasteAppFactory1 this returns a WSGI application
+ Like IPasteAppFactory this returns a WSGI application
(IWSGIApp). The ``loader`` value conforms to the ``ILoader``
interface, and can be used to load (contextually) more
applications.
"""
-class IPasteFilterFactory1:
+class IPasteFilterFactory:
"""
- This is the spec for the ``paste.filter_factory1``
+ This is the spec for the ``paste.filter_factory``
protocol/entry_point.
"""
@@ -81,10 +81,10 @@ class IPasteFilterFactory1:
Returns a IFilter object.
"""
-class IPasteFilterAppFactory1:
+class IPasteFilterAppFactory:
"""
- This is the spec for the ``paste.filter_app_factory1``
+ This is the spec for the ``paste.filter_app_factory``
protocol/entry_point.
"""
@@ -96,10 +96,10 @@ class IPasteFilterAppFactory1:
objects that implement the IFilter interface.
"""
-class IPasteServerFactory1:
+class IPasteServerFactory:
"""
- This is the spec for the ``paste.server_factory1``
+ This is the spec for the ``paste.server_factory``
protocol/entry_point.
"""
@@ -108,10 +108,10 @@ class IPasteServerFactory1:
Returns a IServer object.
"""
-class IPasteServerRunner1:
+class IPasteServerRunner:
"""
- This is the spec for the ``paste.server_runner1``
+ This is the spec for the ``paste.server_runner``
protocol/entry_point.
"""
diff --git a/paste/deploy/loadwsgi.py b/paste/deploy/loadwsgi.py
index 9a970b9..9e892d7 100644
--- a/paste/deploy/loadwsgi.py
+++ b/paste/deploy/loadwsgi.py
@@ -57,14 +57,14 @@ class _ObjectType(object):
APP = _ObjectType(
'application',
- ['paste.app_factory1', 'paste.composit_factory1'],
+ ['paste.app_factory', 'paste.composit_factory'],
[['app', 'application'], 'composit', 'pipeline', 'filter-app'])
def APP_invoke(context):
- if context.protocol == 'paste.composit_factory1':
+ if context.protocol == 'paste.composit_factory':
return context.object(context.loader, context.global_conf,
**context.local_conf)
- elif context.protocol == 'paste.app_factory1':
+ elif context.protocol == 'paste.app_factory':
return context.object(context.global_conf, **context.local_conf)
else:
assert 0, "Protocol %r unknown" % context.protocol
@@ -73,13 +73,13 @@ APP.invoke = APP_invoke
FILTER = _ObjectType(
'filter',
- [['paste.filter_factory1', 'paste.filter_app_factory1']],
+ [['paste.filter_factory', 'paste.filter_app_factory']],
['filter'])
def FILTER_invoke(context):
- if context.protocol == 'paste.filter_factory1':
+ if context.protocol == 'paste.filter_factory':
return context.object(context.global_conf, **context.local_conf)
- elif context.protocol == 'paste.filter_app_factory1':
+ elif context.protocol == 'paste.filter_app_factory':
def filter_wrapper(wsgi_app):
# This should be an object, so it has a nicer __repr__
return context.object(wsgi_app, context.global_conf,
@@ -92,13 +92,13 @@ FILTER.invoke = FILTER_invoke
SERVER = _ObjectType(
'server',
- [['paste.server_factory1', 'paste.server_runner1']],
+ [['paste.server_factory', 'paste.server_runner']],
['server'])
def SERVER_invoke(context):
- if context.protocol == 'paste.server_factory1':
+ if context.protocol == 'paste.server_factory':
return context.object(context.global_conf, **context.local_conf)
- elif context.protocol == 'paste.server_runner1':
+ elif context.protocol == 'paste.server_runner':
def server_wrapper(wsgi_app):
# This should be an object, so it has a nicer __repr__
return context.object(wsgi_app, context.global_conf,
@@ -137,6 +137,16 @@ def FILTER_APP_invoke(context):
FILTER_APP.invoke = FILTER_APP_invoke
+FILTER_WITH = _ObjectType(
+ 'filtered_app', [], [])
+
+def FILTER_WITH_invoke(context):
+ filter = context.filter_context.create()
+ app = APP_invoke(context)
+ return filter(app)
+
+FILTER_WITH.invoke = FILTER_WITH_invoke
+
############################################################
## Loaders
############################################################
@@ -285,25 +295,37 @@ class ConfigLoader(_Loader):
# @@: It's a global option (?), so skip it
continue
local_conf[option] = self.parser.get(section, option)
+ if object_type is APP and 'filter-with' in local_conf:
+ filter_with = local_conf.pop('filter-with')
+ else:
+ filter_with = None
if section.startswith('filter-app:'):
- return self._filter_app_context(
+ context = self._filter_app_context(
object_type, section, name=name,
global_conf=global_conf, local_conf=local_conf,
global_additions=global_additions)
- if section.startswith('pipeline:'):
- return self._pipeline_app_context(
+ elif section.startswith('pipeline:'):
+ context = self._pipeline_app_context(
object_type, section, name=name,
global_conf=global_conf, local_conf=local_conf,
global_additions=global_additions)
- if 'use' in local_conf:
- return self._context_from_use(
- object_type, local_conf, global_conf, global_additions)
+ elif 'use' in local_conf:
+ context = self._context_from_use(
+ object_type, local_conf, global_conf, global_additions,
+ section)
else:
- return self._context_from_explicit(
- object_type, local_conf, global_conf, global_additions)
+ context = self._context_from_explicit(
+ object_type, local_conf, global_conf, global_additions,
+ section)
+ if filter_with is not None:
+ filter_context = self.filter_context(
+ name=filter_with, global_conf=global_conf)
+ context.object_type = FILTER_WITH
+ context.filter_context = filter_context
+ return context
def _context_from_use(self, object_type, local_conf, global_conf,
- global_additions):
+ global_additions, section):
use = local_conf.pop('use')
context = self.get_context(
object_type, name=use, global_conf=global_conf)
@@ -314,7 +336,7 @@ class ConfigLoader(_Loader):
return context
def _context_from_explicit(self, object_type, local_conf, global_conf,
- global_addition):
+ global_addition, section):
possible = []
for protocol_options in object_type.egg_protocols:
for protocol in protocol_options:
@@ -349,10 +371,12 @@ class ConfigLoader(_Loader):
APP, next_name, global_conf)
if 'use' in local_conf:
context.filter_context = self._context_from_use(
- FILTER, local_conf, global_conf, global_additions)
+ FILTER, local_conf, global_conf, global_additions,
+ section)
else:
context.filter_context = self._context_from_explicit(
- FILTER, local_conf, global_conf, global_additions)
+ FILTER, local_conf, global_conf, global_additions,
+ section)
return context
def _pipeline_app_context(self, object_type, section, name,
diff --git a/tests/conftest.py b/tests/conftest.py
index 0cc7d9b..d48c2d6 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -14,7 +14,3 @@ import pkg_resources
sys.path.insert(0, base)
#pkg_resources.require('Paste-Deploy')
-# This is where applications we test go; these applications
-# are only used for testing, they aren't "real".
-sys.path.append(os.path.join(here, 'fake_packages'))
-
diff --git a/tests/fake_packages/FakeApp.egg/FakeApp.egg-info/entry_points.txt b/tests/fake_packages/FakeApp.egg/FakeApp.egg-info/entry_points.txt
index 8ecaf21..9bfc986 100644
--- a/tests/fake_packages/FakeApp.egg/FakeApp.egg-info/entry_points.txt
+++ b/tests/fake_packages/FakeApp.egg/FakeApp.egg-info/entry_points.txt
@@ -1,22 +1,22 @@
-[paste.app_factory1]
+[paste.app_factory]
basic_app=fakeapp.apps:make_basic_app
other=fakeapp.apps:make_basic_app2
configed=fakeapp.configapps:SimpleApp.make_app
-[paste.filter_factory1]
+[paste.composit_factory]
- caps=fakeapp.apps:make_cap_filter
+ remote_addr=fakeapp.apps:make_remote_addr
-[paste.composit_factory1]
+[paste.filter_app_factory]
- remote_addr=fakeapp.apps:make_remote_addr
+ caps2=fakeapp.apps:CapFilter
-[paste.filter_app_factory1]
+[paste.filter_factory]
- caps2=fakeapp.apps:CapFilter
+ caps=fakeapp.apps:make_cap_filter
diff --git a/tests/fake_packages/FakeApp.egg/setup.py b/tests/fake_packages/FakeApp.egg/setup.py
index febdf9f..854483e 100644
--- a/tests/fake_packages/FakeApp.egg/setup.py
+++ b/tests/fake_packages/FakeApp.egg/setup.py
@@ -5,18 +5,18 @@ setup(
version="1.0",
packages=find_packages(),
entry_points={
- 'paste.app_factory1': """
+ 'paste.app_factory': """
basic_app=fakeapp.apps:make_basic_app
other=fakeapp.apps:make_basic_app2
configed=fakeapp.configapps:SimpleApp.make_app
""",
- 'paste.composit_factory1': """
+ 'paste.composit_factory': """
remote_addr=fakeapp.apps:make_remote_addr
""",
- 'paste.filter_factory1': """
+ 'paste.filter_factory': """
caps=fakeapp.apps:make_cap_filter
""",
- 'paste.filter_app_factory1': """
+ 'paste.filter_app_factory': """
caps2=fakeapp.apps:CapFilter
""",
},
diff --git a/tests/sample_configs/test_config_included.ini b/tests/sample_configs/test_config_included.ini
index aa24a61..cc0da7a 100644
--- a/tests/sample_configs/test_config_included.ini
+++ b/tests/sample_configs/test_config_included.ini
@@ -4,7 +4,7 @@ def3 = c
[app:main]
# Equivalent to the egg reference, but just for kicks...
-paste.app_factory1 = fakeapp.configapps:SimpleApp.make_app
+paste.app_factory = fakeapp.configapps:SimpleApp.make_app
set glob = orig
bob = your uncle
another = BAR
diff --git a/tests/sample_configs/test_filter.ini b/tests/sample_configs/test_filter.ini
index f948b97..bfad8dc 100644
--- a/tests/sample_configs/test_filter.ini
+++ b/tests/sample_configs/test_filter.ini
@@ -17,3 +17,6 @@ use = egg:FakeApp#caps2
method_to_call = lower
next = normal
+[app:inv]
+use = egg:FakeApp#basic_app
+filter-with = egg:FakeApp#caps
diff --git a/tests/test_filter.py b/tests/test_filter.py
index 5740223..6829ada 100644
--- a/tests/test_filter.py
+++ b/tests/test_filter.py
@@ -31,3 +31,9 @@ def test_pipeline2():
assert isinstance(app, fakeapp.apps.CapFilter)
assert app.app is fakeapp.apps.basic_app
assert app.method_to_call == 'upper'
+
+def test_filter_app_inverted():
+ app = loadapp('config:sample_configs/test_filter.ini#inv',
+ relative_to=here)
+ assert isinstance(app, fakeapp.apps.CapFilter)
+ assert app.app is fakeapp.apps.basic_app