summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/__init__.py2
-rw-r--r--tests/fixtures/dummy.ini4
-rw-r--r--tests/fixtures/manifest.json4
-rw-r--r--tests/fixtures/manifest2.json4
-rw-r--r--tests/fixtures/minimal.jpgbin0 -> 631 bytes
-rwxr-xr-xtests/fixtures/minimal.pdfbin0 -> 1054 bytes
-rw-r--r--tests/fixtures/minimal.txt1
-rw-r--r--tests/fixtures/minimal.xml1
-rw-r--r--tests/fixtures/nonminimal.txt1
-rw-r--r--tests/fixtures/static/.hiddenfile2
-rw-r--r--tests/fixtures/static/arcs.svg.tgz73
-rw-r--r--tests/fixtures/static/index.html1
-rw-r--r--tests/fixtures/static/subdir/index.html1
-rw-r--r--tests/pkgs/__init__.py1
-rw-r--r--tests/pkgs/ccbugapp/__init__.py20
-rw-r--r--tests/pkgs/conflictapp/__init__.py29
-rw-r--r--tests/pkgs/conflictapp/included.py9
-rw-r--r--tests/pkgs/defpermbugapp/__init__.py30
-rw-r--r--tests/pkgs/eventonly/__init__.py75
-rw-r--r--tests/pkgs/exceptionviewapp/__init__.py47
-rw-r--r--tests/pkgs/exceptionviewapp/models.py22
-rw-r--r--tests/pkgs/exceptionviewapp/views.py31
-rw-r--r--tests/pkgs/fixtureapp/__init__.py14
-rw-r--r--tests/pkgs/fixtureapp/models.py9
-rw-r--r--tests/pkgs/fixtureapp/subpackage/__init__.py1
-rw-r--r--tests/pkgs/fixtureapp/views.py27
-rw-r--r--tests/pkgs/forbiddenapp/__init__.py28
-rw-r--r--tests/pkgs/forbiddenview/__init__.py35
-rw-r--r--tests/pkgs/hybridapp/__init__.py46
-rw-r--r--tests/pkgs/hybridapp/views.py49
-rw-r--r--tests/pkgs/includeapp1/__init__.py1
-rw-r--r--tests/pkgs/includeapp1/root.py11
-rw-r--r--tests/pkgs/includeapp1/three.py11
-rw-r--r--tests/pkgs/includeapp1/two.py11
-rw-r--r--tests/pkgs/localeapp/__init__.py1
-rw-r--r--tests/pkgs/localeapp/locale/GARBAGE1
-rw-r--r--tests/pkgs/localeapp/locale/be/LC_MESSAGES1
-rw-r--r--tests/pkgs/localeapp/locale/de/LC_MESSAGES/deformsite.mobin0 -> 543 bytes
-rw-r--r--tests/pkgs/localeapp/locale/de/LC_MESSAGES/deformsite.po31
-rw-r--r--tests/pkgs/localeapp/locale/de_DE/LC_MESSAGES/deformsite.mobin0 -> 531 bytes
-rw-r--r--tests/pkgs/localeapp/locale/de_DE/LC_MESSAGES/deformsite.po26
-rw-r--r--tests/pkgs/localeapp/locale/en/LC_MESSAGES/deformsite.mobin0 -> 543 bytes
-rw-r--r--tests/pkgs/localeapp/locale/en/LC_MESSAGES/deformsite.po31
-rw-r--r--tests/pkgs/localeapp/locale2/GARBAGE1
-rw-r--r--tests/pkgs/localeapp/locale2/be/LC_MESSAGES1
-rw-r--r--tests/pkgs/localeapp/locale2/de/LC_MESSAGES/deformsite.mobin0 -> 543 bytes
-rw-r--r--tests/pkgs/localeapp/locale2/de/LC_MESSAGES/deformsite.po31
-rw-r--r--tests/pkgs/localeapp/locale2/en/LC_MESSAGES/deformsite.mobin0 -> 543 bytes
-rw-r--r--tests/pkgs/localeapp/locale2/en/LC_MESSAGES/deformsite.po31
-rw-r--r--tests/pkgs/localeapp/locale3/GARBAGE1
-rw-r--r--tests/pkgs/localeapp/locale3/be/LC_MESSAGES1
-rw-r--r--tests/pkgs/localeapp/locale3/de/LC_MESSAGES/deformsite.mobin0 -> 543 bytes
-rw-r--r--tests/pkgs/localeapp/locale3/de/LC_MESSAGES/deformsite.po31
-rw-r--r--tests/pkgs/localeapp/locale3/en/LC_MESSAGES/deformsite.mobin0 -> 543 bytes
-rw-r--r--tests/pkgs/localeapp/locale3/en/LC_MESSAGES/deformsite.po31
-rw-r--r--tests/pkgs/notfoundview/__init__.py35
-rw-r--r--tests/pkgs/permbugapp/__init__.py27
-rw-r--r--tests/pkgs/rendererscanapp/__init__.py10
-rw-r--r--tests/pkgs/rendererscanapp/two/__init__.py6
-rw-r--r--tests/pkgs/restbugapp/__init__.py19
-rw-r--r--tests/pkgs/restbugapp/views.py17
-rw-r--r--tests/pkgs/static_abspath/__init__.py7
-rw-r--r--tests/pkgs/static_assetspec/__init__.py2
-rw-r--r--tests/pkgs/static_routeprefix/__init__.py7
-rw-r--r--tests/pkgs/staticpermapp/__init__.py32
-rw-r--r--tests/pkgs/subrequestapp/__init__.py58
-rw-r--r--tests/pkgs/viewdecoratorapp/__init__.py2
-rw-r--r--tests/pkgs/viewdecoratorapp/views/__init__.py1
-rw-r--r--tests/pkgs/viewdecoratorapp/views/views.py11
-rw-r--r--tests/pkgs/wsgiapp2app/__init__.py20
-rw-r--r--tests/test_asset.py94
-rw-r--r--tests/test_authentication.py2034
-rw-r--r--tests/test_authorization.py291
-rw-r--r--tests/test_compat.py32
-rw-r--r--tests/test_config/__init__.py70
-rw-r--r--tests/test_config/files/assets/dummy.txt1
-rw-r--r--tests/test_config/files/minimal.txt1
-rw-r--r--tests/test_config/path/scanerror/__init__.py1
-rw-r--r--tests/test_config/path/scanerror/will_raise_error.py1
-rw-r--r--tests/test_config/pkgs/__init__.py1
-rw-r--r--tests/test_config/pkgs/asset/__init__.py1
-rw-r--r--tests/test_config/pkgs/asset/subpackage/__init__.py1
-rw-r--r--tests/test_config/pkgs/asset/subpackage/templates/bar.pt0
-rw-r--r--tests/test_config/pkgs/scanextrakw/__init__.py17
-rw-r--r--tests/test_config/pkgs/scannable/__init__.py117
-rw-r--r--tests/test_config/pkgs/scannable/another.py83
-rw-r--r--tests/test_config/pkgs/scannable/pod/notinit.py7
-rw-r--r--tests/test_config/pkgs/scannable/subpackage/__init__.py7
-rw-r--r--tests/test_config/pkgs/scannable/subpackage/notinit.py7
-rw-r--r--tests/test_config/pkgs/scannable/subpackage/subsubpackage/__init__.py7
-rw-r--r--tests/test_config/pkgs/selfscan/__init__.py14
-rw-r--r--tests/test_config/pkgs/selfscan/another.py6
-rw-r--r--tests/test_config/test_actions.py1090
-rw-r--r--tests/test_config/test_adapters.py431
-rw-r--r--tests/test_config/test_assets.py1081
-rw-r--r--tests/test_config/test_factories.py203
-rw-r--r--tests/test_config/test_i18n.py171
-rw-r--r--tests/test_config/test_init.py1455
-rw-r--r--tests/test_config/test_predicates.py480
-rw-r--r--tests/test_config/test_rendering.py43
-rw-r--r--tests/test_config/test_routes.py322
-rw-r--r--tests/test_config/test_security.py151
-rw-r--r--tests/test_config/test_settings.py635
-rw-r--r--tests/test_config/test_testing.py235
-rw-r--r--tests/test_config/test_tweens.py484
-rw-r--r--tests/test_config/test_views.py4360
-rw-r--r--tests/test_csrf.py436
-rw-r--r--tests/test_decorator.py30
-rw-r--r--tests/test_docs.py36
-rw-r--r--tests/test_encode.py89
-rw-r--r--tests/test_events.py411
-rw-r--r--tests/test_exceptions.py113
-rw-r--r--tests/test_httpexceptions.py529
-rw-r--r--tests/test_i18n.py553
-rw-r--r--tests/test_integration.py933
-rw-r--r--tests/test_location.py51
-rw-r--r--tests/test_paster.py193
-rw-r--r--tests/test_path.py665
-rw-r--r--tests/test_predicates.py594
-rw-r--r--tests/test_registry.py452
-rw-r--r--tests/test_renderers.py780
-rw-r--r--tests/test_request.py657
-rw-r--r--tests/test_response.py262
-rw-r--r--tests/test_router.py1724
-rw-r--r--tests/test_scripting.py242
-rw-r--r--tests/test_scripts/__init__.py1
-rw-r--r--tests/test_scripts/dummy.py220
-rw-r--r--tests/test_scripts/pystartup.txt3
-rw-r--r--tests/test_scripts/test_common.py16
-rw-r--r--tests/test_scripts/test_pdistreport.py84
-rw-r--r--tests/test_scripts/test_prequest.py258
-rw-r--r--tests/test_scripts/test_proutes.py823
-rw-r--r--tests/test_scripts/test_pserve.py139
-rw-r--r--tests/test_scripts/test_pshell.py431
-rw-r--r--tests/test_scripts/test_ptweens.py69
-rw-r--r--tests/test_scripts/test_pviews.py597
-rw-r--r--tests/test_security.py541
-rw-r--r--tests/test_session.py640
-rw-r--r--tests/test_settings.py86
-rw-r--r--tests/test_static.py521
-rw-r--r--tests/test_testing.py789
-rw-r--r--tests/test_threadlocal.py105
-rw-r--r--tests/test_traversal.py1313
-rw-r--r--tests/test_tweens.py108
-rw-r--r--tests/test_url.py1453
-rw-r--r--tests/test_urldispatch.py655
-rw-r--r--tests/test_util.py1242
-rw-r--r--tests/test_view.py1279
-rw-r--r--tests/test_viewderivers.py2158
-rw-r--r--tests/test_wsgi.py139
150 files changed, 37428 insertions, 0 deletions
diff --git a/tests/__init__.py b/tests/__init__.py
new file mode 100644
index 000000000..944343e82
--- /dev/null
+++ b/tests/__init__.py
@@ -0,0 +1,2 @@
+def dummy_extend(*args):
+ """used to test Configurator.extend"""
diff --git a/tests/fixtures/dummy.ini b/tests/fixtures/dummy.ini
new file mode 100644
index 000000000..fffaf75c8
--- /dev/null
+++ b/tests/fixtures/dummy.ini
@@ -0,0 +1,4 @@
+[app:myapp]
+use = call:tests.test_paster:make_dummyapp
+
+foo = %(bar)s
diff --git a/tests/fixtures/manifest.json b/tests/fixtures/manifest.json
new file mode 100644
index 000000000..0a43bc5e3
--- /dev/null
+++ b/tests/fixtures/manifest.json
@@ -0,0 +1,4 @@
+{
+ "css/main.css": "css/main-test.css",
+ "images/background.png": "images/background-a8169106.png"
+}
diff --git a/tests/fixtures/manifest2.json b/tests/fixtures/manifest2.json
new file mode 100644
index 000000000..fd6b9a7bb
--- /dev/null
+++ b/tests/fixtures/manifest2.json
@@ -0,0 +1,4 @@
+{
+ "css/main.css": "css/main-678b7c80.css",
+ "images/background.png": "images/background-a8169106.png"
+}
diff --git a/tests/fixtures/minimal.jpg b/tests/fixtures/minimal.jpg
new file mode 100644
index 000000000..1cda9a53d
--- /dev/null
+++ b/tests/fixtures/minimal.jpg
Binary files differ
diff --git a/tests/fixtures/minimal.pdf b/tests/fixtures/minimal.pdf
new file mode 100755
index 000000000..e267be996
--- /dev/null
+++ b/tests/fixtures/minimal.pdf
Binary files differ
diff --git a/tests/fixtures/minimal.txt b/tests/fixtures/minimal.txt
new file mode 100644
index 000000000..18832d351
--- /dev/null
+++ b/tests/fixtures/minimal.txt
@@ -0,0 +1 @@
+Hello.
diff --git a/tests/fixtures/minimal.xml b/tests/fixtures/minimal.xml
new file mode 100644
index 000000000..1972c155d
--- /dev/null
+++ b/tests/fixtures/minimal.xml
@@ -0,0 +1 @@
+<hello/> \ No newline at end of file
diff --git a/tests/fixtures/nonminimal.txt b/tests/fixtures/nonminimal.txt
new file mode 100644
index 000000000..9de95ec92
--- /dev/null
+++ b/tests/fixtures/nonminimal.txt
@@ -0,0 +1 @@
+Hello, ${name}!
diff --git a/tests/fixtures/static/.hiddenfile b/tests/fixtures/static/.hiddenfile
new file mode 100644
index 000000000..86d345000
--- /dev/null
+++ b/tests/fixtures/static/.hiddenfile
@@ -0,0 +1,2 @@
+<html>I'm hidden</html>
+
diff --git a/tests/fixtures/static/arcs.svg.tgz b/tests/fixtures/static/arcs.svg.tgz
new file mode 100644
index 000000000..376c42ac8
--- /dev/null
+++ b/tests/fixtures/static/arcs.svg.tgz
@@ -0,0 +1,73 @@
+<?xml version="1.0"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ id="canvas"
+ width="2000"
+ height="2000"
+ onload="init()">
+
+ <style type="text/css">
+ .ellipse
+ {
+ stroke: red;
+ stroke-width: 2;
+ fill: blue;
+ fill-opacity: 0.1;
+ }
+
+ .axes
+ {
+ stroke: blue;
+ stroke-width: 1;
+ }
+ </style>
+
+ <script>
+ <![CDATA[
+ var COLS = 4;
+ var ROWS = 4;
+ var RX = 80;
+ var RY = 30;
+
+ function init()
+ {
+ var canvas = document.getElementById("canvas");
+
+ var angleStep = 360.0/(COLS*ROWS);
+ var spacing = 2*Math.max(RX, RY)+10;
+ for (var c = 0; c < COLS; ++c) {
+ for (var r = 0; r < ROWS; ++r) {
+ var ellipse = createEllipse((c+ COLS*r)*angleStep, spacing*(c+0.5), spacing*(r+0.5), RX, RY);
+ canvas.appendChild(ellipse);
+ }
+ }
+ }
+
+ function createEllipse(phi, x, y, rx, ry)
+ {
+ var degPerRad = Math.PI/180.0;
+ var e1x = rx*Math.cos(phi*degPerRad);
+ var e1y = rx*Math.sin(phi*degPerRad);
+ var e2x = ry*Math.cos((phi+90)*degPerRad);
+ var e2y = ry*Math.sin((phi+90)*degPerRad);
+
+ var axes = document.createElementNS("http://www.w3.org/2000/svg", "path");
+ axes.setAttribute("class", "axes");
+ axes.setAttribute("d", "M"+x+","+y+" l"+e1x+","+e1y+"M"+x+","+y+" l"+e2x+","+e2y);
+ var ellipse = document.createElementNS("http://www.w3.org/2000/svg", "path");
+ ellipse.setAttribute("class", "ellipse");
+ ellipse.setAttribute("d", "M" + (x+e1x) + "," + (y+e1y) +
+ "A" + rx + "," + ry + " " + phi + " 0,1 " + (x+e2x) + "," + (y+e2y) +
+ "A" + rx + "," + ry + " " + phi + " 1,1 " + (x+e1x) + "," + (y+e1y) +"z");
+
+ var group = document.createElementNS("http://www.w3.org/2000/svg", "g");
+ group.appendChild(axes);
+ group.appendChild(ellipse);
+ return group;
+ }
+
+ ]]>
+ </script>
+</svg>
diff --git a/tests/fixtures/static/index.html b/tests/fixtures/static/index.html
new file mode 100644
index 000000000..0470710b2
--- /dev/null
+++ b/tests/fixtures/static/index.html
@@ -0,0 +1 @@
+<html>static</html> \ No newline at end of file
diff --git a/tests/fixtures/static/subdir/index.html b/tests/fixtures/static/subdir/index.html
new file mode 100644
index 000000000..bb84fad04
--- /dev/null
+++ b/tests/fixtures/static/subdir/index.html
@@ -0,0 +1 @@
+<html>subdir</html>
diff --git a/tests/pkgs/__init__.py b/tests/pkgs/__init__.py
new file mode 100644
index 000000000..5bb534f79
--- /dev/null
+++ b/tests/pkgs/__init__.py
@@ -0,0 +1 @@
+# package
diff --git a/tests/pkgs/ccbugapp/__init__.py b/tests/pkgs/ccbugapp/__init__.py
new file mode 100644
index 000000000..908a36e3e
--- /dev/null
+++ b/tests/pkgs/ccbugapp/__init__.py
@@ -0,0 +1,20 @@
+from webob import Response
+
+
+def rdf_view(request):
+ """ """
+ return Response('rdf')
+
+
+def juri_view(request):
+ """ """
+ return Response('juri')
+
+
+def includeme(config):
+ config.add_route('rdf', 'licenses/:license_code/:license_version/rdf')
+ config.add_route(
+ 'juri', 'licenses/:license_code/:license_version/:jurisdiction'
+ )
+ config.add_view(rdf_view, route_name='rdf')
+ config.add_view(juri_view, route_name='juri')
diff --git a/tests/pkgs/conflictapp/__init__.py b/tests/pkgs/conflictapp/__init__.py
new file mode 100644
index 000000000..840813994
--- /dev/null
+++ b/tests/pkgs/conflictapp/__init__.py
@@ -0,0 +1,29 @@
+from pyramid.response import Response
+from pyramid.authentication import AuthTktAuthenticationPolicy
+from pyramid.authorization import ACLAuthorizationPolicy
+
+
+def aview(request):
+ return Response('a view')
+
+
+def routeview(request):
+ return Response('route view')
+
+
+def protectedview(request):
+ return Response('protected view')
+
+
+def includeme(config):
+ # purposely sorta-randomly ordered (route comes after view naming it,
+ # authz comes after views)
+ config.add_view(aview)
+ config.add_view(protectedview, name='protected', permission='view')
+ config.add_view(routeview, route_name='aroute')
+ config.add_route('aroute', '/route')
+ config.set_authentication_policy(
+ AuthTktAuthenticationPolicy('seekri1t', hashalg='sha512')
+ )
+ config.set_authorization_policy(ACLAuthorizationPolicy())
+ config.include('tests.pkgs.conflictapp.included')
diff --git a/tests/pkgs/conflictapp/included.py b/tests/pkgs/conflictapp/included.py
new file mode 100644
index 000000000..fc42c317e
--- /dev/null
+++ b/tests/pkgs/conflictapp/included.py
@@ -0,0 +1,9 @@
+from webob import Response
+
+
+def bview(request): # pragma: no cover
+ return Response('b view')
+
+
+def includeme(config):
+ config.add_view(bview)
diff --git a/tests/pkgs/defpermbugapp/__init__.py b/tests/pkgs/defpermbugapp/__init__.py
new file mode 100644
index 000000000..81897e86a
--- /dev/null
+++ b/tests/pkgs/defpermbugapp/__init__.py
@@ -0,0 +1,30 @@
+from webob import Response
+from pyramid.security import NO_PERMISSION_REQUIRED
+from pyramid.view import view_config
+
+
+@view_config(name='x')
+def x_view(request): # pragma: no cover
+ return Response('this is private!')
+
+
+@view_config(name='y', permission='private2')
+def y_view(request): # pragma: no cover
+ return Response('this is private too!')
+
+
+@view_config(name='z', permission=NO_PERMISSION_REQUIRED)
+def z_view(request):
+ return Response('this is public')
+
+
+def includeme(config):
+ from pyramid.authorization import ACLAuthorizationPolicy
+ from pyramid.authentication import AuthTktAuthenticationPolicy
+
+ authn_policy = AuthTktAuthenticationPolicy('seekt1t', hashalg='sha512')
+ authz_policy = ACLAuthorizationPolicy()
+ config.scan('tests.pkgs.defpermbugapp')
+ config._set_authentication_policy(authn_policy)
+ config._set_authorization_policy(authz_policy)
+ config.set_default_permission('private')
diff --git a/tests/pkgs/eventonly/__init__.py b/tests/pkgs/eventonly/__init__.py
new file mode 100644
index 000000000..c48b539a1
--- /dev/null
+++ b/tests/pkgs/eventonly/__init__.py
@@ -0,0 +1,75 @@
+from pyramid.view import view_config
+from pyramid.events import subscriber
+
+
+class Yup(object):
+ def __init__(self, val, config):
+ self.val = val
+
+ def text(self):
+ return 'path_startswith = %s' % (self.val,)
+
+ phash = text
+
+ def __call__(self, event):
+ return getattr(event.response, 'yup', False)
+
+
+class Foo(object):
+ def __init__(self, response):
+ self.response = response
+
+
+class Bar(object):
+ pass
+
+
+@subscriber(Foo)
+def foo(event):
+ event.response.text += 'foo '
+
+
+@subscriber(Foo, yup=True)
+def fooyup(event):
+ event.response.text += 'fooyup '
+
+
+@subscriber([Foo, Bar])
+def foobar(event):
+ event.response.text += 'foobar '
+
+
+@subscriber([Foo, Bar])
+def foobar2(event, context):
+ event.response.text += 'foobar2 '
+
+
+@subscriber([Foo, Bar], yup=True)
+def foobaryup(event):
+ event.response.text += 'foobaryup '
+
+
+@subscriber([Foo, Bar], yup=True)
+def foobaryup2(event, context):
+ event.response.text += 'foobaryup2 '
+
+
+@view_config(name='sendfoo')
+def sendfoo(request):
+ response = request.response
+ response.yup = True
+ request.registry.notify(Foo(response))
+ return response
+
+
+@view_config(name='sendfoobar')
+def sendfoobar(request):
+ response = request.response
+ response.yup = True
+ request.registry.notify(Foo(response), Bar())
+ return response
+
+
+def includeme(config):
+ config.add_subscriber_predicate('yup', Yup)
+ config.scan('tests.pkgs.eventonly')
diff --git a/tests/pkgs/exceptionviewapp/__init__.py b/tests/pkgs/exceptionviewapp/__init__.py
new file mode 100644
index 000000000..19804d242
--- /dev/null
+++ b/tests/pkgs/exceptionviewapp/__init__.py
@@ -0,0 +1,47 @@
+from pyramid.httpexceptions import HTTPException
+
+
+def includeme(config):
+ config.add_route('route_raise_exception', 'route_raise_exception')
+ config.add_route('route_raise_httpexception', 'route_raise_httpexception')
+ config.add_route(
+ 'route_raise_exception2',
+ 'route_raise_exception2',
+ factory='.models.route_factory',
+ )
+ config.add_route(
+ 'route_raise_exception3',
+ 'route_raise_exception3',
+ factory='.models.route_factory2',
+ )
+ config.add_route('route_raise_exception4', 'route_raise_exception4')
+ config.add_view('.views.maybe')
+ config.add_view('.views.no', context='.models.NotAnException')
+ config.add_view('.views.yes', context=".models.AnException")
+ config.add_view('.views.raise_exception', name='raise_exception')
+ config.add_view(
+ '.views.raise_exception', route_name='route_raise_exception'
+ )
+ config.add_view(
+ '.views.raise_exception', route_name='route_raise_exception2'
+ )
+ config.add_view(
+ '.views.raise_exception', route_name='route_raise_exception3'
+ )
+ config.add_view(
+ '.views.whoa',
+ context='.models.AnException',
+ route_name='route_raise_exception3',
+ )
+ config.add_view(
+ '.views.raise_exception', route_name='route_raise_exception4'
+ )
+ config.add_view(
+ '.views.whoa',
+ context='.models.AnException',
+ route_name='route_raise_exception4',
+ )
+ config.add_view(
+ '.views.raise_httpexception', route_name='route_raise_httpexception'
+ )
+ config.add_view('.views.catch_httpexception', context=HTTPException)
diff --git a/tests/pkgs/exceptionviewapp/models.py b/tests/pkgs/exceptionviewapp/models.py
new file mode 100644
index 000000000..25f8e9156
--- /dev/null
+++ b/tests/pkgs/exceptionviewapp/models.py
@@ -0,0 +1,22 @@
+class NotAnException(object):
+ pass
+
+
+class AnException(Exception):
+ pass
+
+
+class RouteContext(object):
+ pass
+
+
+class RouteContext2(object):
+ pass
+
+
+def route_factory(*arg):
+ return RouteContext()
+
+
+def route_factory2(*arg):
+ return RouteContext2()
diff --git a/tests/pkgs/exceptionviewapp/views.py b/tests/pkgs/exceptionviewapp/views.py
new file mode 100644
index 000000000..ca2c4fffb
--- /dev/null
+++ b/tests/pkgs/exceptionviewapp/views.py
@@ -0,0 +1,31 @@
+from webob import Response
+from .models import AnException
+from pyramid.httpexceptions import HTTPBadRequest
+
+
+def no(request):
+ return Response('no')
+
+
+def yes(request):
+ return Response('yes')
+
+
+def maybe(request):
+ return Response('maybe')
+
+
+def whoa(request):
+ return Response('whoa')
+
+
+def raise_exception(request):
+ raise AnException()
+
+
+def raise_httpexception(request):
+ raise HTTPBadRequest
+
+
+def catch_httpexception(request):
+ return Response('caught')
diff --git a/tests/pkgs/fixtureapp/__init__.py b/tests/pkgs/fixtureapp/__init__.py
new file mode 100644
index 000000000..ffc8adb4a
--- /dev/null
+++ b/tests/pkgs/fixtureapp/__init__.py
@@ -0,0 +1,14 @@
+def includeme(config):
+ config.add_view('.views.fixture_view')
+ config.add_view('.views.exception_view', context=RuntimeError)
+ config.add_view('.views.protected_view', name='protected.html')
+ config.add_view('.views.erroneous_view', name='error.html')
+ config.add_view(
+ '.views.fixture_view',
+ name='dummyskin.html',
+ request_type='.views.IDummy',
+ )
+ from .models import fixture, IFixture
+
+ config.registry.registerUtility(fixture, IFixture)
+ config.add_view('.views.fixture_view', name='another.html')
diff --git a/tests/pkgs/fixtureapp/models.py b/tests/pkgs/fixtureapp/models.py
new file mode 100644
index 000000000..5ad640df9
--- /dev/null
+++ b/tests/pkgs/fixtureapp/models.py
@@ -0,0 +1,9 @@
+from zope.interface import Interface
+
+
+class IFixture(Interface):
+ pass
+
+
+def fixture():
+ """ """
diff --git a/tests/pkgs/fixtureapp/subpackage/__init__.py b/tests/pkgs/fixtureapp/subpackage/__init__.py
new file mode 100644
index 000000000..5bb534f79
--- /dev/null
+++ b/tests/pkgs/fixtureapp/subpackage/__init__.py
@@ -0,0 +1 @@
+# package
diff --git a/tests/pkgs/fixtureapp/views.py b/tests/pkgs/fixtureapp/views.py
new file mode 100644
index 000000000..78df81c6f
--- /dev/null
+++ b/tests/pkgs/fixtureapp/views.py
@@ -0,0 +1,27 @@
+from zope.interface import Interface
+from webob import Response
+from pyramid.httpexceptions import HTTPForbidden
+
+
+def fixture_view(context, request):
+ """ """
+ return Response('fixture')
+
+
+def erroneous_view(context, request):
+ """ """
+ raise RuntimeError()
+
+
+def exception_view(context, request):
+ """ """
+ return Response('supressed')
+
+
+def protected_view(context, request):
+ """ """
+ raise HTTPForbidden()
+
+
+class IDummy(Interface):
+ pass
diff --git a/tests/pkgs/forbiddenapp/__init__.py b/tests/pkgs/forbiddenapp/__init__.py
new file mode 100644
index 000000000..9ebf62a9d
--- /dev/null
+++ b/tests/pkgs/forbiddenapp/__init__.py
@@ -0,0 +1,28 @@
+from webob import Response
+from pyramid.httpexceptions import HTTPForbidden
+from pyramid.compat import bytes_
+
+
+def x_view(request): # pragma: no cover
+ return Response('this is private!')
+
+
+def forbidden_view(context, request):
+ msg = context.message
+ result = context.result
+ message = msg + '\n' + str(result)
+ resp = HTTPForbidden()
+ resp.body = bytes_(message)
+ return resp
+
+
+def includeme(config):
+ from pyramid.authentication import AuthTktAuthenticationPolicy
+ from pyramid.authorization import ACLAuthorizationPolicy
+
+ authn_policy = AuthTktAuthenticationPolicy('seekr1t', hashalg='sha512')
+ authz_policy = ACLAuthorizationPolicy()
+ config._set_authentication_policy(authn_policy)
+ config._set_authorization_policy(authz_policy)
+ config.add_view(x_view, name='x', permission='private')
+ config.add_view(forbidden_view, context=HTTPForbidden)
diff --git a/tests/pkgs/forbiddenview/__init__.py b/tests/pkgs/forbiddenview/__init__.py
new file mode 100644
index 000000000..4c78d961c
--- /dev/null
+++ b/tests/pkgs/forbiddenview/__init__.py
@@ -0,0 +1,35 @@
+from pyramid.view import forbidden_view_config, view_config
+from pyramid.response import Response
+from pyramid.authentication import AuthTktAuthenticationPolicy
+from pyramid.authorization import ACLAuthorizationPolicy
+
+
+@forbidden_view_config(route_name='foo')
+def foo_forbidden(request): # pragma: no cover
+ return Response('foo_forbidden')
+
+
+@forbidden_view_config()
+def forbidden(request):
+ return Response('generic_forbidden')
+
+
+@view_config(route_name='foo')
+def foo(request): # pragma: no cover
+ return Response('OK foo')
+
+
+@view_config(route_name='bar')
+def bar(request): # pragma: no cover
+ return Response('OK bar')
+
+
+def includeme(config):
+ authn_policy = AuthTktAuthenticationPolicy('seekri1', hashalg='sha512')
+ authz_policy = ACLAuthorizationPolicy()
+ config.set_authentication_policy(authn_policy)
+ config.set_authorization_policy(authz_policy)
+ config.set_default_permission('a')
+ config.add_route('foo', '/foo')
+ config.add_route('bar', '/bar')
+ config.scan('tests.pkgs.forbiddenview')
diff --git a/tests/pkgs/hybridapp/__init__.py b/tests/pkgs/hybridapp/__init__.py
new file mode 100644
index 000000000..001e1b882
--- /dev/null
+++ b/tests/pkgs/hybridapp/__init__.py
@@ -0,0 +1,46 @@
+def includeme(config):
+ # <!-- we want this view to "win" -->
+ config.add_route('route', 'abc')
+ config.add_view('.views.route_view', route_name='route')
+ # <!-- .. even though this one has a more specific context -->
+ config.add_view(
+ '.views.global_view', context='pyramid.traversal.DefaultRootFactory'
+ )
+ config.add_view(
+ '.views.global2_view',
+ context='pyramid.traversal.DefaultRootFactory',
+ name='global2',
+ )
+ config.add_route('route2', 'def')
+ # <!-- we want this view to win for route2 even though global view with
+ # context is more specific -->
+ config.add_view('.views.route2_view', route_name='route2')
+
+ # <!-- the global view should be found for this route -->
+ config.add_route('route3', 'ghi', use_global_views=True)
+ # <!-- the global view should not be found for this route -->
+ config.add_route('route4', 'jkl')
+ # <!-- the global view should not be found for this route (/global2) -->
+ config.add_route('route5', 'mno/*traverse')
+ # <!-- the global view should be found for this route (/global2) -->
+ config.add_route('route6', 'pqr/*traverse', use_global_views=True)
+ config.add_route('route7', 'error')
+ config.add_view('.views.erroneous_view', route_name='route7')
+ config.add_route('route8', 'error2')
+ config.add_view('.views.erroneous_view', route_name='route8')
+ # <!-- we want this view to "win" for route7 as exception view -->
+ config.add_view('.views.exception_view', context=RuntimeError)
+ # <!-- we want this view to "win" for route8 as exception view-->
+ config.add_view(
+ '.views.exception2_view', context=RuntimeError, route_name='route8'
+ )
+ config.add_route('route9', 'error_sub')
+ config.add_view('.views.erroneous_sub_view', route_name='route9')
+ # <!-- we want this view to "win" for route9 as exception view... -->
+ config.add_view(
+ '.views.exception2_view',
+ context='.views.SuperException',
+ route_name='route9',
+ )
+ # <!-- ...even if we have more context-specialized view for exception -->
+ config.add_view('.views.exception_view', context='.views.SubException')
diff --git a/tests/pkgs/hybridapp/views.py b/tests/pkgs/hybridapp/views.py
new file mode 100644
index 000000000..695a79531
--- /dev/null
+++ b/tests/pkgs/hybridapp/views.py
@@ -0,0 +1,49 @@
+from webob import Response
+
+
+def route_view(request):
+ """ """
+ return Response('route')
+
+
+def global_view(request):
+ """ """
+ return Response('global')
+
+
+def global2_view(request):
+ """ """
+ return Response('global2')
+
+
+def route2_view(request):
+ """ """
+ return Response('route2')
+
+
+def exception_view(request):
+ """ """
+ return Response('supressed')
+
+
+def exception2_view(request):
+ """ """
+ return Response('supressed2')
+
+
+def erroneous_view(request):
+ """ """
+ raise RuntimeError()
+
+
+def erroneous_sub_view(request):
+ """ """
+ raise SubException()
+
+
+class SuperException(Exception):
+ """ """
+
+
+class SubException(SuperException):
+ """ """
diff --git a/tests/pkgs/includeapp1/__init__.py b/tests/pkgs/includeapp1/__init__.py
new file mode 100644
index 000000000..eaeeb7ef6
--- /dev/null
+++ b/tests/pkgs/includeapp1/__init__.py
@@ -0,0 +1 @@
+# include app
diff --git a/tests/pkgs/includeapp1/root.py b/tests/pkgs/includeapp1/root.py
new file mode 100644
index 000000000..369ab9f38
--- /dev/null
+++ b/tests/pkgs/includeapp1/root.py
@@ -0,0 +1,11 @@
+from pyramid.response import Response
+
+
+def aview(request):
+ return Response('root')
+
+
+def configure(config):
+ config.add_view(aview)
+ config.include('tests.pkgs.includeapp1.two.configure')
+ config.commit()
diff --git a/tests/pkgs/includeapp1/three.py b/tests/pkgs/includeapp1/three.py
new file mode 100644
index 000000000..b8d881244
--- /dev/null
+++ b/tests/pkgs/includeapp1/three.py
@@ -0,0 +1,11 @@
+from pyramid.response import Response
+
+
+def aview(request):
+ return Response('three')
+
+
+def configure(config):
+ config.add_view(aview, name='three')
+ config.include('tests.pkgs.includeapp1.two.configure') # should not cycle
+ config.add_view(aview) # will be overridden by root when resolved
diff --git a/tests/pkgs/includeapp1/two.py b/tests/pkgs/includeapp1/two.py
new file mode 100644
index 000000000..727161c8e
--- /dev/null
+++ b/tests/pkgs/includeapp1/two.py
@@ -0,0 +1,11 @@
+from pyramid.response import Response
+
+
+def aview(request):
+ return Response('two')
+
+
+def configure(config):
+ config.add_view(aview, name='two')
+ config.include('tests.pkgs.includeapp1.three.configure')
+ config.add_view(aview) # will be overridden by root when resolved
diff --git a/tests/pkgs/localeapp/__init__.py b/tests/pkgs/localeapp/__init__.py
new file mode 100644
index 000000000..1a35cdb4a
--- /dev/null
+++ b/tests/pkgs/localeapp/__init__.py
@@ -0,0 +1 @@
+# a file
diff --git a/tests/pkgs/localeapp/locale/GARBAGE b/tests/pkgs/localeapp/locale/GARBAGE
new file mode 100644
index 000000000..032c55584
--- /dev/null
+++ b/tests/pkgs/localeapp/locale/GARBAGE
@@ -0,0 +1 @@
+Garbage file.
diff --git a/tests/pkgs/localeapp/locale/be/LC_MESSAGES b/tests/pkgs/localeapp/locale/be/LC_MESSAGES
new file mode 100644
index 000000000..909cf6a3b
--- /dev/null
+++ b/tests/pkgs/localeapp/locale/be/LC_MESSAGES
@@ -0,0 +1 @@
+busted.
diff --git a/tests/pkgs/localeapp/locale/de/LC_MESSAGES/deformsite.mo b/tests/pkgs/localeapp/locale/de/LC_MESSAGES/deformsite.mo
new file mode 100644
index 000000000..2924a5eb5
--- /dev/null
+++ b/tests/pkgs/localeapp/locale/de/LC_MESSAGES/deformsite.mo
Binary files differ
diff --git a/tests/pkgs/localeapp/locale/de/LC_MESSAGES/deformsite.po b/tests/pkgs/localeapp/locale/de/LC_MESSAGES/deformsite.po
new file mode 100644
index 000000000..17f87bc19
--- /dev/null
+++ b/tests/pkgs/localeapp/locale/de/LC_MESSAGES/deformsite.po
@@ -0,0 +1,31 @@
+# German translations for deformsite.
+# Copyright (C) 2010 ORGANIZATION
+# This file is distributed under the same license as the deformsite project.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2010.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: deformsite 0.0\n"
+"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
+"POT-Creation-Date: 2010-04-22 14:17+0400\n"
+"PO-Revision-Date: 2010-04-22 14:17-0400\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: de <LL@li.org>\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: Babel 0.9.5\n"
+
+#: deformsite/__init__.py:458
+msgid "Approve"
+msgstr "Genehmigen"
+
+#: deformsite/__init__.py:459
+msgid "Show approval"
+msgstr "Zeigen Genehmigung"
+
+#: deformsite/__init__.py:466
+msgid "Submit"
+msgstr "Beugen"
+
diff --git a/tests/pkgs/localeapp/locale/de_DE/LC_MESSAGES/deformsite.mo b/tests/pkgs/localeapp/locale/de_DE/LC_MESSAGES/deformsite.mo
new file mode 100644
index 000000000..e3b2b0881
--- /dev/null
+++ b/tests/pkgs/localeapp/locale/de_DE/LC_MESSAGES/deformsite.mo
Binary files differ
diff --git a/tests/pkgs/localeapp/locale/de_DE/LC_MESSAGES/deformsite.po b/tests/pkgs/localeapp/locale/de_DE/LC_MESSAGES/deformsite.po
new file mode 100644
index 000000000..be055bed9
--- /dev/null
+++ b/tests/pkgs/localeapp/locale/de_DE/LC_MESSAGES/deformsite.po
@@ -0,0 +1,26 @@
+# German translations for deformsite.
+# Copyright (C) 2010 ORGANIZATION
+# This file is distributed under the same license as the deformsite project.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2010.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: deformsite 0.0\n"
+"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
+"POT-Creation-Date: 2010-04-22 14:17+0400\n"
+"PO-Revision-Date: 2010-04-22 14:17-0400\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: de <LL@li.org>\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: Babel 0.9.5\n"
+
+#: deformsite/__init__.py:459
+msgid "Show approval"
+msgstr "Zeigen Genehmigung"
+
+#: deformsite/__init__.py:466
+msgid "Submit"
+msgstr "different"
diff --git a/tests/pkgs/localeapp/locale/en/LC_MESSAGES/deformsite.mo b/tests/pkgs/localeapp/locale/en/LC_MESSAGES/deformsite.mo
new file mode 100644
index 000000000..2924a5eb5
--- /dev/null
+++ b/tests/pkgs/localeapp/locale/en/LC_MESSAGES/deformsite.mo
Binary files differ
diff --git a/tests/pkgs/localeapp/locale/en/LC_MESSAGES/deformsite.po b/tests/pkgs/localeapp/locale/en/LC_MESSAGES/deformsite.po
new file mode 100644
index 000000000..17f87bc19
--- /dev/null
+++ b/tests/pkgs/localeapp/locale/en/LC_MESSAGES/deformsite.po
@@ -0,0 +1,31 @@
+# German translations for deformsite.
+# Copyright (C) 2010 ORGANIZATION
+# This file is distributed under the same license as the deformsite project.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2010.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: deformsite 0.0\n"
+"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
+"POT-Creation-Date: 2010-04-22 14:17+0400\n"
+"PO-Revision-Date: 2010-04-22 14:17-0400\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: de <LL@li.org>\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: Babel 0.9.5\n"
+
+#: deformsite/__init__.py:458
+msgid "Approve"
+msgstr "Genehmigen"
+
+#: deformsite/__init__.py:459
+msgid "Show approval"
+msgstr "Zeigen Genehmigung"
+
+#: deformsite/__init__.py:466
+msgid "Submit"
+msgstr "Beugen"
+
diff --git a/tests/pkgs/localeapp/locale2/GARBAGE b/tests/pkgs/localeapp/locale2/GARBAGE
new file mode 100644
index 000000000..032c55584
--- /dev/null
+++ b/tests/pkgs/localeapp/locale2/GARBAGE
@@ -0,0 +1 @@
+Garbage file.
diff --git a/tests/pkgs/localeapp/locale2/be/LC_MESSAGES b/tests/pkgs/localeapp/locale2/be/LC_MESSAGES
new file mode 100644
index 000000000..909cf6a3b
--- /dev/null
+++ b/tests/pkgs/localeapp/locale2/be/LC_MESSAGES
@@ -0,0 +1 @@
+busted.
diff --git a/tests/pkgs/localeapp/locale2/de/LC_MESSAGES/deformsite.mo b/tests/pkgs/localeapp/locale2/de/LC_MESSAGES/deformsite.mo
new file mode 100644
index 000000000..2924a5eb5
--- /dev/null
+++ b/tests/pkgs/localeapp/locale2/de/LC_MESSAGES/deformsite.mo
Binary files differ
diff --git a/tests/pkgs/localeapp/locale2/de/LC_MESSAGES/deformsite.po b/tests/pkgs/localeapp/locale2/de/LC_MESSAGES/deformsite.po
new file mode 100644
index 000000000..17f87bc19
--- /dev/null
+++ b/tests/pkgs/localeapp/locale2/de/LC_MESSAGES/deformsite.po
@@ -0,0 +1,31 @@
+# German translations for deformsite.
+# Copyright (C) 2010 ORGANIZATION
+# This file is distributed under the same license as the deformsite project.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2010.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: deformsite 0.0\n"
+"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
+"POT-Creation-Date: 2010-04-22 14:17+0400\n"
+"PO-Revision-Date: 2010-04-22 14:17-0400\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: de <LL@li.org>\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: Babel 0.9.5\n"
+
+#: deformsite/__init__.py:458
+msgid "Approve"
+msgstr "Genehmigen"
+
+#: deformsite/__init__.py:459
+msgid "Show approval"
+msgstr "Zeigen Genehmigung"
+
+#: deformsite/__init__.py:466
+msgid "Submit"
+msgstr "Beugen"
+
diff --git a/tests/pkgs/localeapp/locale2/en/LC_MESSAGES/deformsite.mo b/tests/pkgs/localeapp/locale2/en/LC_MESSAGES/deformsite.mo
new file mode 100644
index 000000000..2924a5eb5
--- /dev/null
+++ b/tests/pkgs/localeapp/locale2/en/LC_MESSAGES/deformsite.mo
Binary files differ
diff --git a/tests/pkgs/localeapp/locale2/en/LC_MESSAGES/deformsite.po b/tests/pkgs/localeapp/locale2/en/LC_MESSAGES/deformsite.po
new file mode 100644
index 000000000..17f87bc19
--- /dev/null
+++ b/tests/pkgs/localeapp/locale2/en/LC_MESSAGES/deformsite.po
@@ -0,0 +1,31 @@
+# German translations for deformsite.
+# Copyright (C) 2010 ORGANIZATION
+# This file is distributed under the same license as the deformsite project.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2010.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: deformsite 0.0\n"
+"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
+"POT-Creation-Date: 2010-04-22 14:17+0400\n"
+"PO-Revision-Date: 2010-04-22 14:17-0400\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: de <LL@li.org>\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: Babel 0.9.5\n"
+
+#: deformsite/__init__.py:458
+msgid "Approve"
+msgstr "Genehmigen"
+
+#: deformsite/__init__.py:459
+msgid "Show approval"
+msgstr "Zeigen Genehmigung"
+
+#: deformsite/__init__.py:466
+msgid "Submit"
+msgstr "Beugen"
+
diff --git a/tests/pkgs/localeapp/locale3/GARBAGE b/tests/pkgs/localeapp/locale3/GARBAGE
new file mode 100644
index 000000000..032c55584
--- /dev/null
+++ b/tests/pkgs/localeapp/locale3/GARBAGE
@@ -0,0 +1 @@
+Garbage file.
diff --git a/tests/pkgs/localeapp/locale3/be/LC_MESSAGES b/tests/pkgs/localeapp/locale3/be/LC_MESSAGES
new file mode 100644
index 000000000..909cf6a3b
--- /dev/null
+++ b/tests/pkgs/localeapp/locale3/be/LC_MESSAGES
@@ -0,0 +1 @@
+busted.
diff --git a/tests/pkgs/localeapp/locale3/de/LC_MESSAGES/deformsite.mo b/tests/pkgs/localeapp/locale3/de/LC_MESSAGES/deformsite.mo
new file mode 100644
index 000000000..2924a5eb5
--- /dev/null
+++ b/tests/pkgs/localeapp/locale3/de/LC_MESSAGES/deformsite.mo
Binary files differ
diff --git a/tests/pkgs/localeapp/locale3/de/LC_MESSAGES/deformsite.po b/tests/pkgs/localeapp/locale3/de/LC_MESSAGES/deformsite.po
new file mode 100644
index 000000000..17f87bc19
--- /dev/null
+++ b/tests/pkgs/localeapp/locale3/de/LC_MESSAGES/deformsite.po
@@ -0,0 +1,31 @@
+# German translations for deformsite.
+# Copyright (C) 2010 ORGANIZATION
+# This file is distributed under the same license as the deformsite project.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2010.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: deformsite 0.0\n"
+"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
+"POT-Creation-Date: 2010-04-22 14:17+0400\n"
+"PO-Revision-Date: 2010-04-22 14:17-0400\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: de <LL@li.org>\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: Babel 0.9.5\n"
+
+#: deformsite/__init__.py:458
+msgid "Approve"
+msgstr "Genehmigen"
+
+#: deformsite/__init__.py:459
+msgid "Show approval"
+msgstr "Zeigen Genehmigung"
+
+#: deformsite/__init__.py:466
+msgid "Submit"
+msgstr "Beugen"
+
diff --git a/tests/pkgs/localeapp/locale3/en/LC_MESSAGES/deformsite.mo b/tests/pkgs/localeapp/locale3/en/LC_MESSAGES/deformsite.mo
new file mode 100644
index 000000000..2924a5eb5
--- /dev/null
+++ b/tests/pkgs/localeapp/locale3/en/LC_MESSAGES/deformsite.mo
Binary files differ
diff --git a/tests/pkgs/localeapp/locale3/en/LC_MESSAGES/deformsite.po b/tests/pkgs/localeapp/locale3/en/LC_MESSAGES/deformsite.po
new file mode 100644
index 000000000..17f87bc19
--- /dev/null
+++ b/tests/pkgs/localeapp/locale3/en/LC_MESSAGES/deformsite.po
@@ -0,0 +1,31 @@
+# German translations for deformsite.
+# Copyright (C) 2010 ORGANIZATION
+# This file is distributed under the same license as the deformsite project.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2010.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: deformsite 0.0\n"
+"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
+"POT-Creation-Date: 2010-04-22 14:17+0400\n"
+"PO-Revision-Date: 2010-04-22 14:17-0400\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: de <LL@li.org>\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: Babel 0.9.5\n"
+
+#: deformsite/__init__.py:458
+msgid "Approve"
+msgstr "Genehmigen"
+
+#: deformsite/__init__.py:459
+msgid "Show approval"
+msgstr "Zeigen Genehmigung"
+
+#: deformsite/__init__.py:466
+msgid "Submit"
+msgstr "Beugen"
+
diff --git a/tests/pkgs/notfoundview/__init__.py b/tests/pkgs/notfoundview/__init__.py
new file mode 100644
index 000000000..f606ec671
--- /dev/null
+++ b/tests/pkgs/notfoundview/__init__.py
@@ -0,0 +1,35 @@
+from pyramid.view import notfound_view_config, view_config
+from pyramid.response import Response
+
+
+@notfound_view_config(route_name='foo', append_slash=True)
+def foo_notfound(request): # pragma: no cover
+ return Response('foo_notfound')
+
+
+@notfound_view_config(route_name='baz')
+def baz_notfound(request):
+ return Response('baz_notfound')
+
+
+@notfound_view_config(append_slash=True)
+def notfound(request):
+ return Response('generic_notfound')
+
+
+@view_config(route_name='bar')
+def bar(request):
+ return Response('OK bar')
+
+
+@view_config(route_name='foo2')
+def foo2(request):
+ return Response('OK foo2')
+
+
+def includeme(config):
+ config.add_route('foo', '/foo')
+ config.add_route('foo2', '/foo/')
+ config.add_route('bar', '/bar/')
+ config.add_route('baz', '/baz')
+ config.scan('tests.pkgs.notfoundview')
diff --git a/tests/pkgs/permbugapp/__init__.py b/tests/pkgs/permbugapp/__init__.py
new file mode 100644
index 000000000..aedd405f8
--- /dev/null
+++ b/tests/pkgs/permbugapp/__init__.py
@@ -0,0 +1,27 @@
+from pyramid.compat import escape
+from pyramid.security import view_execution_permitted
+from pyramid.response import Response
+
+
+def x_view(request): # pragma: no cover
+ return Response('this is private!')
+
+
+def test(context, request):
+ # should return false
+ msg = 'Allow ./x? %s' % repr(
+ view_execution_permitted(context, request, 'x')
+ )
+ return Response(escape(msg))
+
+
+def includeme(config):
+ from pyramid.authentication import AuthTktAuthenticationPolicy
+ from pyramid.authorization import ACLAuthorizationPolicy
+
+ authn_policy = AuthTktAuthenticationPolicy('seekt1t', hashalg='sha512')
+ authz_policy = ACLAuthorizationPolicy()
+ config.set_authentication_policy(authn_policy)
+ config.set_authorization_policy(authz_policy)
+ config.add_view(test, name='test')
+ config.add_view(x_view, name='x', permission='private')
diff --git a/tests/pkgs/rendererscanapp/__init__.py b/tests/pkgs/rendererscanapp/__init__.py
new file mode 100644
index 000000000..1fc831e66
--- /dev/null
+++ b/tests/pkgs/rendererscanapp/__init__.py
@@ -0,0 +1,10 @@
+from pyramid.view import view_config
+
+
+@view_config(name='one', renderer='json')
+def one(request):
+ return {'name': 'One!'}
+
+
+def includeme(config):
+ config.scan()
diff --git a/tests/pkgs/rendererscanapp/two/__init__.py b/tests/pkgs/rendererscanapp/two/__init__.py
new file mode 100644
index 000000000..7d3990317
--- /dev/null
+++ b/tests/pkgs/rendererscanapp/two/__init__.py
@@ -0,0 +1,6 @@
+from pyramid.view import view_config
+
+
+@view_config(name='two', renderer='json')
+def two(request):
+ return {'nameagain': 'Two!'}
diff --git a/tests/pkgs/restbugapp/__init__.py b/tests/pkgs/restbugapp/__init__.py
new file mode 100644
index 000000000..ae0a80f01
--- /dev/null
+++ b/tests/pkgs/restbugapp/__init__.py
@@ -0,0 +1,19 @@
+def includeme(config):
+ config.add_route('gameactions_pet_get_pets', '/pet', request_method='GET')
+ config.add_route(
+ 'gameactions_pet_care_for_pet', '/pet', request_method='POST'
+ )
+ config.add_view(
+ '.views.PetRESTView',
+ route_name='gameactions_pet_get_pets',
+ attr='GET',
+ permission='view',
+ renderer='json',
+ )
+ config.add_view(
+ '.views.PetRESTView',
+ route_name='gameactions_pet_care_for_pet',
+ attr='POST',
+ permission='view',
+ renderer='json',
+ )
diff --git a/tests/pkgs/restbugapp/views.py b/tests/pkgs/restbugapp/views.py
new file mode 100644
index 000000000..161321aed
--- /dev/null
+++ b/tests/pkgs/restbugapp/views.py
@@ -0,0 +1,17 @@
+from pyramid.response import Response
+
+
+class BaseRESTView(object):
+ def __init__(self, context, request):
+ self.context = context
+ self.request = request
+
+
+class PetRESTView(BaseRESTView):
+ """ REST Controller to control action of an avatar """
+
+ def __init__(self, context, request):
+ super(PetRESTView, self).__init__(context, request)
+
+ def GET(self):
+ return Response('gotten')
diff --git a/tests/pkgs/static_abspath/__init__.py b/tests/pkgs/static_abspath/__init__.py
new file mode 100644
index 000000000..0c875b96f
--- /dev/null
+++ b/tests/pkgs/static_abspath/__init__.py
@@ -0,0 +1,7 @@
+import os
+
+
+def includeme(config):
+ here = here = os.path.dirname(__file__)
+ fixtures = os.path.normpath(os.path.join(here, '..', '..', 'fixtures'))
+ config.add_static_view('/', fixtures)
diff --git a/tests/pkgs/static_assetspec/__init__.py b/tests/pkgs/static_assetspec/__init__.py
new file mode 100644
index 000000000..e7d3e9373
--- /dev/null
+++ b/tests/pkgs/static_assetspec/__init__.py
@@ -0,0 +1,2 @@
+def includeme(config):
+ config.add_static_view('/', 'tests:fixtures')
diff --git a/tests/pkgs/static_routeprefix/__init__.py b/tests/pkgs/static_routeprefix/__init__.py
new file mode 100644
index 000000000..f64f31292
--- /dev/null
+++ b/tests/pkgs/static_routeprefix/__init__.py
@@ -0,0 +1,7 @@
+def includeme(config):
+ config.add_static_view('/static', 'tests:fixtures')
+ config.include(includeme2, route_prefix='/prefix')
+
+
+def includeme2(config):
+ config.add_static_view('/static', 'tests:fixtures/static')
diff --git a/tests/pkgs/staticpermapp/__init__.py b/tests/pkgs/staticpermapp/__init__.py
new file mode 100644
index 000000000..ffc87d39a
--- /dev/null
+++ b/tests/pkgs/staticpermapp/__init__.py
@@ -0,0 +1,32 @@
+class RootFactory(object):
+ __acl__ = [('Allow', 'fred', 'view')]
+
+ def __init__(self, request):
+ pass
+
+
+class LocalRootFactory(object):
+ __acl__ = [('Allow', 'bob', 'view')]
+
+ def __init__(self, request):
+ pass
+
+
+def includeme(config):
+ from pyramid.authentication import RemoteUserAuthenticationPolicy
+ from pyramid.authorization import ACLAuthorizationPolicy
+
+ authn_policy = RemoteUserAuthenticationPolicy()
+ authz_policy = ACLAuthorizationPolicy()
+ config._set_authentication_policy(authn_policy)
+ config._set_authorization_policy(authz_policy)
+ config.add_static_view('allowed', 'tests:fixtures/static/')
+ config.add_static_view(
+ 'protected', 'tests:fixtures/static/', permission='view'
+ )
+ config.add_static_view(
+ 'factory_protected',
+ 'tests:fixtures/static/',
+ permission='view',
+ factory=LocalRootFactory,
+ )
diff --git a/tests/pkgs/subrequestapp/__init__.py b/tests/pkgs/subrequestapp/__init__.py
new file mode 100644
index 000000000..177f5637b
--- /dev/null
+++ b/tests/pkgs/subrequestapp/__init__.py
@@ -0,0 +1,58 @@
+from pyramid.config import Configurator
+from pyramid.request import Request
+
+
+def view_one(request):
+ subreq = Request.blank('/view_two')
+ response = request.invoke_subrequest(subreq, use_tweens=False)
+ return response
+
+
+def view_two(request):
+ # check that request.foo is valid for a subrequest
+ return 'This came from view_two, foo=%s' % (request.foo,)
+
+
+def view_three(request):
+ subreq = Request.blank('/view_four')
+ try:
+ return request.invoke_subrequest(subreq, use_tweens=True)
+ except Exception: # pragma: no cover
+ request.response.body = b'Value error raised'
+ return request.response
+
+
+def view_four(request):
+ raise ValueError('foo')
+
+
+def view_five(request):
+ subreq = Request.blank('/view_four')
+ try:
+ return request.invoke_subrequest(subreq, use_tweens=False)
+ except ValueError:
+ request.response.body = b'Value error raised'
+ return request.response
+
+
+def excview(request):
+ request.response.status_int = 500
+ request.response.body = b'Bad stuff happened'
+ return request.response
+
+
+def main():
+ config = Configurator()
+ config.add_route('one', '/view_one')
+ config.add_route('two', '/view_two')
+ config.add_route('three', '/view_three')
+ config.add_route('four', '/view_four')
+ config.add_route('five', '/view_five')
+ config.add_view(excview, context=Exception)
+ config.add_view(view_one, route_name='one')
+ config.add_view(view_two, route_name='two', renderer='string')
+ config.add_view(view_three, route_name='three')
+ config.add_view(view_four, route_name='four')
+ config.add_view(view_five, route_name='five')
+ config.add_request_method(lambda r: 'bar', 'foo', property=True)
+ return config
diff --git a/tests/pkgs/viewdecoratorapp/__init__.py b/tests/pkgs/viewdecoratorapp/__init__.py
new file mode 100644
index 000000000..99b7ea9c7
--- /dev/null
+++ b/tests/pkgs/viewdecoratorapp/__init__.py
@@ -0,0 +1,2 @@
+def includeme(config):
+ config.scan('tests.pkgs.viewdecoratorapp')
diff --git a/tests/pkgs/viewdecoratorapp/views/__init__.py b/tests/pkgs/viewdecoratorapp/views/__init__.py
new file mode 100644
index 000000000..5bb534f79
--- /dev/null
+++ b/tests/pkgs/viewdecoratorapp/views/__init__.py
@@ -0,0 +1 @@
+# package
diff --git a/tests/pkgs/viewdecoratorapp/views/views.py b/tests/pkgs/viewdecoratorapp/views/views.py
new file mode 100644
index 000000000..6879acd2b
--- /dev/null
+++ b/tests/pkgs/viewdecoratorapp/views/views.py
@@ -0,0 +1,11 @@
+from pyramid.view import view_config
+
+
+@view_config(renderer='json', name='first')
+def first(request):
+ return {'result': 'OK1'}
+
+
+@view_config(renderer='json', name='second')
+def second(request):
+ return {'result': 'OK2'}
diff --git a/tests/pkgs/wsgiapp2app/__init__.py b/tests/pkgs/wsgiapp2app/__init__.py
new file mode 100644
index 000000000..f7452f52c
--- /dev/null
+++ b/tests/pkgs/wsgiapp2app/__init__.py
@@ -0,0 +1,20 @@
+from pyramid.view import view_config
+from pyramid.wsgi import wsgiapp2
+
+
+@view_config(name='hello', renderer='string')
+@wsgiapp2
+def hello(environ, start_response):
+ assert environ['PATH_INFO'] == '/'
+ assert environ['SCRIPT_NAME'] == '/hello'
+ response_headers = [('Content-Type', 'text/plain')]
+ start_response('200 OK', response_headers)
+ return [b'Hello!']
+
+
+def main():
+ from pyramid.config import Configurator
+
+ c = Configurator()
+ c.scan()
+ return c
diff --git a/tests/test_asset.py b/tests/test_asset.py
new file mode 100644
index 000000000..55a3c0336
--- /dev/null
+++ b/tests/test_asset.py
@@ -0,0 +1,94 @@
+import unittest
+import os
+
+here = os.path.abspath(os.path.dirname(__file__))
+
+
+class Test_resolve_asset_spec(unittest.TestCase):
+ def _callFUT(self, spec, package_name='__main__'):
+ from pyramid.resource import resolve_asset_spec
+
+ return resolve_asset_spec(spec, package_name)
+
+ def test_abspath(self):
+ package_name, filename = self._callFUT(here, 'apackage')
+ self.assertEqual(filename, here)
+ self.assertEqual(package_name, None)
+
+ def test_rel_spec(self):
+ pkg = 'tests'
+ path = 'test_asset.py'
+ package_name, filename = self._callFUT(path, pkg)
+ self.assertEqual(package_name, 'tests')
+ self.assertEqual(filename, 'test_asset.py')
+
+ def test_abs_spec(self):
+ pkg = 'tests'
+ path = 'pyramid.nottests:test_asset.py'
+ package_name, filename = self._callFUT(path, pkg)
+ self.assertEqual(package_name, 'pyramid.nottests')
+ self.assertEqual(filename, 'test_asset.py')
+
+ def test_package_name_is_None(self):
+ pkg = None
+ path = 'test_asset.py'
+ package_name, filename = self._callFUT(path, pkg)
+ self.assertEqual(package_name, None)
+ self.assertEqual(filename, 'test_asset.py')
+
+ def test_package_name_is_package_object(self):
+ import tests
+
+ pkg = tests
+ path = 'test_asset.py'
+ package_name, filename = self._callFUT(path, pkg)
+ self.assertEqual(package_name, 'tests')
+ self.assertEqual(filename, 'test_asset.py')
+
+
+class Test_abspath_from_asset_spec(unittest.TestCase):
+ def _callFUT(self, spec, pname='__main__'):
+ from pyramid.resource import abspath_from_asset_spec
+
+ return abspath_from_asset_spec(spec, pname)
+
+ def test_pname_is_None_before_resolve_asset_spec(self):
+ result = self._callFUT('abc', None)
+ self.assertEqual(result, 'abc')
+
+ def test_pname_is_None_after_resolve_asset_spec(self):
+ result = self._callFUT('/abc', '__main__')
+ self.assertEqual(result, '/abc')
+
+ def test_pkgrelative(self):
+ result = self._callFUT('abc', 'tests')
+ self.assertEqual(result, os.path.join(here, 'abc'))
+
+
+class Test_asset_spec_from_abspath(unittest.TestCase):
+ def _callFUT(self, abspath, package):
+ from pyramid.asset import asset_spec_from_abspath
+
+ return asset_spec_from_abspath(abspath, package)
+
+ def test_package_name_is_main(self):
+ pkg = DummyPackage('__main__')
+ result = self._callFUT('abspath', pkg)
+ self.assertEqual(result, 'abspath')
+
+ def test_abspath_startswith_package_path(self):
+ abspath = os.path.join(here, 'fixtureapp')
+ pkg = DummyPackage('tests')
+ pkg.__file__ = 'file'
+ result = self._callFUT(abspath, pkg)
+ self.assertEqual(result, 'tests:fixtureapp')
+
+ def test_abspath_doesnt_startwith_package_path(self):
+ pkg = DummyPackage('tests')
+ result = self._callFUT(here, pkg)
+ self.assertEqual(result, here)
+
+
+class DummyPackage:
+ def __init__(self, name):
+ self.__name__ = name
diff --git a/tests/test_authentication.py b/tests/test_authentication.py
new file mode 100644
index 000000000..fc3e60587
--- /dev/null
+++ b/tests/test_authentication.py
@@ -0,0 +1,2034 @@
+import unittest
+import warnings
+from pyramid import testing
+from pyramid.compat import text_, bytes_
+
+
+class TestCallbackAuthenticationPolicyDebugging(unittest.TestCase):
+ def setUp(self):
+ from pyramid.interfaces import IDebugLogger
+
+ self.config = testing.setUp()
+ self.config.registry.registerUtility(self, IDebugLogger)
+ self.messages = []
+
+ def tearDown(self):
+ del self.config
+
+ def debug(self, msg):
+ self.messages.append(msg)
+
+ def _makeOne(self, userid=None, callback=None):
+ from pyramid.authentication import CallbackAuthenticationPolicy
+
+ class MyAuthenticationPolicy(CallbackAuthenticationPolicy):
+ def unauthenticated_userid(self, request):
+ return userid
+
+ policy = MyAuthenticationPolicy()
+ policy.debug = True
+ policy.callback = callback
+ return policy
+
+ def test_authenticated_userid_no_unauthenticated_userid(self):
+ request = DummyRequest(registry=self.config.registry)
+ policy = self._makeOne()
+ self.assertEqual(policy.authenticated_userid(request), None)
+ self.assertEqual(len(self.messages), 1)
+ self.assertEqual(
+ self.messages[0],
+ 'tests.test_authentication.MyAuthenticationPolicy.'
+ 'authenticated_userid: call to unauthenticated_userid returned '
+ 'None; returning None',
+ )
+
+ def test_authenticated_userid_no_callback(self):
+ request = DummyRequest(registry=self.config.registry)
+ policy = self._makeOne(userid='fred')
+ self.assertEqual(policy.authenticated_userid(request), 'fred')
+ self.assertEqual(len(self.messages), 1)
+ self.assertEqual(
+ self.messages[0],
+ "tests.test_authentication.MyAuthenticationPolicy."
+ "authenticated_userid: there was no groupfinder callback; "
+ "returning 'fred'",
+ )
+
+ def test_authenticated_userid_with_callback_fail(self):
+ request = DummyRequest(registry=self.config.registry)
+
+ def callback(userid, request):
+ return None
+
+ policy = self._makeOne(userid='fred', callback=callback)
+ self.assertEqual(policy.authenticated_userid(request), None)
+ self.assertEqual(len(self.messages), 1)
+ self.assertEqual(
+ self.messages[0],
+ 'tests.test_authentication.MyAuthenticationPolicy.'
+ 'authenticated_userid: groupfinder callback returned None; '
+ 'returning None',
+ )
+
+ def test_authenticated_userid_with_callback_success(self):
+ request = DummyRequest(registry=self.config.registry)
+
+ def callback(userid, request):
+ return []
+
+ policy = self._makeOne(userid='fred', callback=callback)
+ self.assertEqual(policy.authenticated_userid(request), 'fred')
+ self.assertEqual(len(self.messages), 1)
+ self.assertEqual(
+ self.messages[0],
+ "tests.test_authentication.MyAuthenticationPolicy."
+ "authenticated_userid: groupfinder callback returned []; "
+ "returning 'fred'",
+ )
+
+ def test_authenticated_userid_fails_cleaning_as_Authenticated(self):
+ request = DummyRequest(registry=self.config.registry)
+ policy = self._makeOne(userid='system.Authenticated')
+ self.assertEqual(policy.authenticated_userid(request), None)
+ self.assertEqual(len(self.messages), 1)
+ self.assertEqual(
+ self.messages[0],
+ "tests.test_authentication.MyAuthenticationPolicy."
+ "authenticated_userid: use of userid 'system.Authenticated' is "
+ "disallowed by any built-in Pyramid security policy, returning "
+ "None",
+ )
+
+ def test_authenticated_userid_fails_cleaning_as_Everyone(self):
+ request = DummyRequest(registry=self.config.registry)
+ policy = self._makeOne(userid='system.Everyone')
+ self.assertEqual(policy.authenticated_userid(request), None)
+ self.assertEqual(len(self.messages), 1)
+ self.assertEqual(
+ self.messages[0],
+ "tests.test_authentication.MyAuthenticationPolicy."
+ "authenticated_userid: use of userid 'system.Everyone' is "
+ "disallowed by any built-in Pyramid security policy, returning "
+ "None",
+ )
+
+ def test_effective_principals_no_unauthenticated_userid(self):
+ request = DummyRequest(registry=self.config.registry)
+ policy = self._makeOne()
+ self.assertEqual(
+ policy.effective_principals(request), ['system.Everyone']
+ )
+ self.assertEqual(len(self.messages), 1)
+ self.assertEqual(
+ self.messages[0],
+ "tests.test_authentication.MyAuthenticationPolicy."
+ "effective_principals: unauthenticated_userid returned None; "
+ "returning ['system.Everyone']",
+ )
+
+ def test_effective_principals_no_callback(self):
+ request = DummyRequest(registry=self.config.registry)
+ policy = self._makeOne(userid='fred')
+ self.assertEqual(
+ policy.effective_principals(request),
+ ['system.Everyone', 'system.Authenticated', 'fred'],
+ )
+ self.assertEqual(len(self.messages), 2)
+ self.assertEqual(
+ self.messages[0],
+ 'tests.test_authentication.MyAuthenticationPolicy.'
+ 'effective_principals: groupfinder callback is None, so groups '
+ 'is []',
+ )
+ self.assertEqual(
+ self.messages[1],
+ "tests.test_authentication.MyAuthenticationPolicy."
+ "effective_principals: returning effective principals: "
+ "['system.Everyone', 'system.Authenticated', 'fred']",
+ )
+
+ def test_effective_principals_with_callback_fail(self):
+ request = DummyRequest(registry=self.config.registry)
+
+ def callback(userid, request):
+ return None
+
+ policy = self._makeOne(userid='fred', callback=callback)
+ self.assertEqual(
+ policy.effective_principals(request), ['system.Everyone']
+ )
+ self.assertEqual(len(self.messages), 2)
+ self.assertEqual(
+ self.messages[0],
+ 'tests.test_authentication.MyAuthenticationPolicy.'
+ 'effective_principals: groupfinder callback returned None as '
+ 'groups',
+ )
+ self.assertEqual(
+ self.messages[1],
+ "tests.test_authentication.MyAuthenticationPolicy."
+ "effective_principals: returning effective principals: "
+ "['system.Everyone']",
+ )
+
+ def test_effective_principals_with_callback_success(self):
+ request = DummyRequest(registry=self.config.registry)
+
+ def callback(userid, request):
+ return []
+
+ policy = self._makeOne(userid='fred', callback=callback)
+ self.assertEqual(
+ policy.effective_principals(request),
+ ['system.Everyone', 'system.Authenticated', 'fred'],
+ )
+ self.assertEqual(len(self.messages), 2)
+ self.assertEqual(
+ self.messages[0],
+ 'tests.test_authentication.MyAuthenticationPolicy.'
+ 'effective_principals: groupfinder callback returned [] as groups',
+ )
+ self.assertEqual(
+ self.messages[1],
+ "tests.test_authentication.MyAuthenticationPolicy."
+ "effective_principals: returning effective principals: "
+ "['system.Everyone', 'system.Authenticated', 'fred']",
+ )
+
+ def test_effective_principals_with_unclean_principal_Authenticated(self):
+ request = DummyRequest(registry=self.config.registry)
+ policy = self._makeOne(userid='system.Authenticated')
+ self.assertEqual(
+ policy.effective_principals(request), ['system.Everyone']
+ )
+ self.assertEqual(len(self.messages), 1)
+ self.assertEqual(
+ self.messages[0],
+ "tests.test_authentication.MyAuthenticationPolicy."
+ "effective_principals: unauthenticated_userid returned disallowed "
+ "'system.Authenticated'; returning ['system.Everyone'] as if it "
+ "was None",
+ )
+
+ def test_effective_principals_with_unclean_principal_Everyone(self):
+ request = DummyRequest(registry=self.config.registry)
+ policy = self._makeOne(userid='system.Everyone')
+ self.assertEqual(
+ policy.effective_principals(request), ['system.Everyone']
+ )
+ self.assertEqual(len(self.messages), 1)
+ self.assertEqual(
+ self.messages[0],
+ "tests.test_authentication.MyAuthenticationPolicy."
+ "effective_principals: unauthenticated_userid returned disallowed "
+ "'system.Everyone'; returning ['system.Everyone'] as if it "
+ "was None",
+ )
+
+
+class TestRepozeWho1AuthenticationPolicy(unittest.TestCase):
+ def _getTargetClass(self):
+ from pyramid.authentication import RepozeWho1AuthenticationPolicy
+
+ return RepozeWho1AuthenticationPolicy
+
+ def _makeOne(self, identifier_name='auth_tkt', callback=None):
+ return self._getTargetClass()(identifier_name, callback)
+
+ def test_class_implements_IAuthenticationPolicy(self):
+ from zope.interface.verify import verifyClass
+ from pyramid.interfaces import IAuthenticationPolicy
+
+ verifyClass(IAuthenticationPolicy, self._getTargetClass())
+
+ def test_instance_implements_IAuthenticationPolicy(self):
+ from zope.interface.verify import verifyObject
+ from pyramid.interfaces import IAuthenticationPolicy
+
+ verifyObject(IAuthenticationPolicy, self._makeOne())
+
+ def test_unauthenticated_userid_returns_None(self):
+ request = DummyRequest({})
+ policy = self._makeOne()
+ self.assertEqual(policy.unauthenticated_userid(request), None)
+
+ def test_unauthenticated_userid(self):
+ request = DummyRequest(
+ {'repoze.who.identity': {'repoze.who.userid': 'fred'}}
+ )
+ policy = self._makeOne()
+ self.assertEqual(policy.unauthenticated_userid(request), 'fred')
+
+ def test_authenticated_userid_None(self):
+ request = DummyRequest({})
+ policy = self._makeOne()
+ self.assertEqual(policy.authenticated_userid(request), None)
+
+ def test_authenticated_userid(self):
+ request = DummyRequest(
+ {'repoze.who.identity': {'repoze.who.userid': 'fred'}}
+ )
+ policy = self._makeOne()
+ self.assertEqual(policy.authenticated_userid(request), 'fred')
+
+ def test_authenticated_userid_repoze_who_userid_is_None(self):
+ request = DummyRequest(
+ {'repoze.who.identity': {'repoze.who.userid': None}}
+ )
+ policy = self._makeOne()
+ self.assertEqual(policy.authenticated_userid(request), None)
+
+ def test_authenticated_userid_with_callback_returns_None(self):
+ request = DummyRequest(
+ {'repoze.who.identity': {'repoze.who.userid': 'fred'}}
+ )
+
+ def callback(identity, request):
+ return None
+
+ policy = self._makeOne(callback=callback)
+ self.assertEqual(policy.authenticated_userid(request), None)
+
+ def test_authenticated_userid_with_callback_returns_something(self):
+ request = DummyRequest(
+ {'repoze.who.identity': {'repoze.who.userid': 'fred'}}
+ )
+
+ def callback(identity, request):
+ return ['agroup']
+
+ policy = self._makeOne(callback=callback)
+ self.assertEqual(policy.authenticated_userid(request), 'fred')
+
+ def test_authenticated_userid_unclean_principal_Authenticated(self):
+ request = DummyRequest(
+ {
+ 'repoze.who.identity': {
+ 'repoze.who.userid': 'system.Authenticated'
+ }
+ }
+ )
+ policy = self._makeOne()
+ self.assertEqual(policy.authenticated_userid(request), None)
+
+ def test_authenticated_userid_unclean_principal_Everyone(self):
+ request = DummyRequest(
+ {'repoze.who.identity': {'repoze.who.userid': 'system.Everyone'}}
+ )
+ policy = self._makeOne()
+ self.assertEqual(policy.authenticated_userid(request), None)
+
+ def test_effective_principals_None(self):
+ from pyramid.security import Everyone
+
+ request = DummyRequest({})
+ policy = self._makeOne()
+ self.assertEqual(policy.effective_principals(request), [Everyone])
+
+ def test_effective_principals_userid_only(self):
+ from pyramid.security import Everyone
+ from pyramid.security import Authenticated
+
+ request = DummyRequest(
+ {'repoze.who.identity': {'repoze.who.userid': 'fred'}}
+ )
+ policy = self._makeOne()
+ self.assertEqual(
+ policy.effective_principals(request),
+ [Everyone, Authenticated, 'fred'],
+ )
+
+ def test_effective_principals_userid_and_groups(self):
+ from pyramid.security import Everyone
+ from pyramid.security import Authenticated
+
+ request = DummyRequest(
+ {
+ 'repoze.who.identity': {
+ 'repoze.who.userid': 'fred',
+ 'groups': ['quux', 'biz'],
+ }
+ }
+ )
+
+ def callback(identity, request):
+ return identity['groups']
+
+ policy = self._makeOne(callback=callback)
+ self.assertEqual(
+ policy.effective_principals(request),
+ [Everyone, Authenticated, 'fred', 'quux', 'biz'],
+ )
+
+ def test_effective_principals_userid_callback_returns_None(self):
+ from pyramid.security import Everyone
+
+ request = DummyRequest(
+ {
+ 'repoze.who.identity': {
+ 'repoze.who.userid': 'fred',
+ 'groups': ['quux', 'biz'],
+ }
+ }
+ )
+
+ def callback(identity, request):
+ return None
+
+ policy = self._makeOne(callback=callback)
+ self.assertEqual(policy.effective_principals(request), [Everyone])
+
+ def test_effective_principals_repoze_who_userid_is_None(self):
+ from pyramid.security import Everyone
+
+ request = DummyRequest(
+ {'repoze.who.identity': {'repoze.who.userid': None}}
+ )
+ policy = self._makeOne()
+ self.assertEqual(policy.effective_principals(request), [Everyone])
+
+ def test_effective_principals_repoze_who_userid_is_unclean_Everyone(self):
+ from pyramid.security import Everyone
+
+ request = DummyRequest(
+ {'repoze.who.identity': {'repoze.who.userid': 'system.Everyone'}}
+ )
+ policy = self._makeOne()
+ self.assertEqual(policy.effective_principals(request), [Everyone])
+
+ def test_effective_principals_repoze_who_userid_is_unclean_Authenticated(
+ self
+ ):
+ from pyramid.security import Everyone
+
+ request = DummyRequest(
+ {
+ 'repoze.who.identity': {
+ 'repoze.who.userid': 'system.Authenticated'
+ }
+ }
+ )
+ policy = self._makeOne()
+ self.assertEqual(policy.effective_principals(request), [Everyone])
+
+ def test_remember_no_plugins(self):
+ request = DummyRequest({})
+ policy = self._makeOne()
+ result = policy.remember(request, 'fred')
+ self.assertEqual(result, [])
+
+ def test_remember(self):
+ authtkt = DummyWhoPlugin()
+ request = DummyRequest({'repoze.who.plugins': {'auth_tkt': authtkt}})
+ policy = self._makeOne()
+ result = policy.remember(request, 'fred')
+ self.assertEqual(result[0], request.environ)
+ self.assertEqual(result[1], {'repoze.who.userid': 'fred'})
+
+ def test_remember_kwargs(self):
+ authtkt = DummyWhoPlugin()
+ request = DummyRequest({'repoze.who.plugins': {'auth_tkt': authtkt}})
+ policy = self._makeOne()
+ result = policy.remember(request, 'fred', max_age=23)
+ self.assertEqual(
+ result[1], {'repoze.who.userid': 'fred', 'max_age': 23}
+ )
+
+ def test_forget_no_plugins(self):
+ request = DummyRequest({})
+ policy = self._makeOne()
+ result = policy.forget(request)
+ self.assertEqual(result, [])
+
+ def test_forget(self):
+ authtkt = DummyWhoPlugin()
+ request = DummyRequest(
+ {
+ 'repoze.who.plugins': {'auth_tkt': authtkt},
+ 'repoze.who.identity': {'repoze.who.userid': 'fred'},
+ }
+ )
+ policy = self._makeOne()
+ result = policy.forget(request)
+ self.assertEqual(result[0], request.environ)
+ self.assertEqual(result[1], request.environ['repoze.who.identity'])
+
+
+class TestRemoteUserAuthenticationPolicy(unittest.TestCase):
+ def _getTargetClass(self):
+ from pyramid.authentication import RemoteUserAuthenticationPolicy
+
+ return RemoteUserAuthenticationPolicy
+
+ def _makeOne(self, environ_key='REMOTE_USER', callback=None):
+ return self._getTargetClass()(environ_key, callback)
+
+ def test_class_implements_IAuthenticationPolicy(self):
+ from zope.interface.verify import verifyClass
+ from pyramid.interfaces import IAuthenticationPolicy
+
+ verifyClass(IAuthenticationPolicy, self._getTargetClass())
+
+ def test_instance_implements_IAuthenticationPolicy(self):
+ from zope.interface.verify import verifyObject
+ from pyramid.interfaces import IAuthenticationPolicy
+
+ verifyObject(IAuthenticationPolicy, self._makeOne())
+
+ def test_unauthenticated_userid_returns_None(self):
+ request = DummyRequest({})
+ policy = self._makeOne()
+ self.assertEqual(policy.unauthenticated_userid(request), None)
+
+ def test_unauthenticated_userid(self):
+ request = DummyRequest({'REMOTE_USER': 'fred'})
+ policy = self._makeOne()
+ self.assertEqual(policy.unauthenticated_userid(request), 'fred')
+
+ def test_authenticated_userid_None(self):
+ request = DummyRequest({})
+ policy = self._makeOne()
+ self.assertEqual(policy.authenticated_userid(request), None)
+
+ def test_authenticated_userid(self):
+ request = DummyRequest({'REMOTE_USER': 'fred'})
+ policy = self._makeOne()
+ self.assertEqual(policy.authenticated_userid(request), 'fred')
+
+ def test_effective_principals_None(self):
+ from pyramid.security import Everyone
+
+ request = DummyRequest({})
+ policy = self._makeOne()
+ self.assertEqual(policy.effective_principals(request), [Everyone])
+
+ def test_effective_principals(self):
+ from pyramid.security import Everyone
+ from pyramid.security import Authenticated
+
+ request = DummyRequest({'REMOTE_USER': 'fred'})
+ policy = self._makeOne()
+ self.assertEqual(
+ policy.effective_principals(request),
+ [Everyone, Authenticated, 'fred'],
+ )
+
+ def test_remember(self):
+ request = DummyRequest({'REMOTE_USER': 'fred'})
+ policy = self._makeOne()
+ result = policy.remember(request, 'fred')
+ self.assertEqual(result, [])
+
+ def test_forget(self):
+ request = DummyRequest({'REMOTE_USER': 'fred'})
+ policy = self._makeOne()
+ result = policy.forget(request)
+ self.assertEqual(result, [])
+
+
+class TestAuthTktAuthenticationPolicy(unittest.TestCase):
+ def _getTargetClass(self):
+ from pyramid.authentication import AuthTktAuthenticationPolicy
+
+ return AuthTktAuthenticationPolicy
+
+ def _makeOne(self, callback, cookieidentity, **kw):
+ inst = self._getTargetClass()('secret', callback, **kw)
+ inst.cookie = DummyCookieHelper(cookieidentity)
+ return inst
+
+ def setUp(self):
+ self.warnings = warnings.catch_warnings()
+ self.warnings.__enter__()
+ warnings.simplefilter('ignore', DeprecationWarning)
+
+ def tearDown(self):
+ self.warnings.__exit__(None, None, None)
+
+ def test_allargs(self):
+ # pass all known args
+ inst = self._getTargetClass()(
+ 'secret',
+ callback=None,
+ cookie_name=None,
+ secure=False,
+ include_ip=False,
+ timeout=None,
+ reissue_time=None,
+ hashalg='sha512',
+ samesite=None,
+ )
+ self.assertEqual(inst.callback, None)
+
+ def test_hashalg_override(self):
+ # important to ensure hashalg is passed to cookie helper
+ inst = self._getTargetClass()('secret', hashalg='sha512')
+ self.assertEqual(inst.cookie.hashalg, 'sha512')
+
+ def test_unauthenticated_userid_returns_None(self):
+ request = DummyRequest({})
+ policy = self._makeOne(None, None)
+ self.assertEqual(policy.unauthenticated_userid(request), None)
+
+ def test_unauthenticated_userid(self):
+ request = DummyRequest({'REMOTE_USER': 'fred'})
+ policy = self._makeOne(None, {'userid': 'fred'})
+ self.assertEqual(policy.unauthenticated_userid(request), 'fred')
+
+ def test_authenticated_userid_no_cookie_identity(self):
+ request = DummyRequest({})
+ policy = self._makeOne(None, None)
+ self.assertEqual(policy.authenticated_userid(request), None)
+
+ def test_authenticated_userid_callback_returns_None(self):
+ request = DummyRequest({})
+
+ def callback(userid, request):
+ return None
+
+ policy = self._makeOne(callback, {'userid': 'fred'})
+ self.assertEqual(policy.authenticated_userid(request), None)
+
+ def test_authenticated_userid(self):
+ request = DummyRequest({})
+
+ def callback(userid, request):
+ return True
+
+ policy = self._makeOne(callback, {'userid': 'fred'})
+ self.assertEqual(policy.authenticated_userid(request), 'fred')
+
+ def test_effective_principals_no_cookie_identity(self):
+ from pyramid.security import Everyone
+
+ request = DummyRequest({})
+ policy = self._makeOne(None, None)
+ self.assertEqual(policy.effective_principals(request), [Everyone])
+
+ def test_effective_principals_callback_returns_None(self):
+ from pyramid.security import Everyone
+
+ request = DummyRequest({})
+
+ def callback(userid, request):
+ return None
+
+ policy = self._makeOne(callback, {'userid': 'fred'})
+ self.assertEqual(policy.effective_principals(request), [Everyone])
+
+ def test_effective_principals(self):
+ from pyramid.security import Everyone
+ from pyramid.security import Authenticated
+
+ request = DummyRequest({})
+
+ def callback(userid, request):
+ return ['group.foo']
+
+ policy = self._makeOne(callback, {'userid': 'fred'})
+ self.assertEqual(
+ policy.effective_principals(request),
+ [Everyone, Authenticated, 'fred', 'group.foo'],
+ )
+
+ def test_remember(self):
+ request = DummyRequest({})
+ policy = self._makeOne(None, None)
+ result = policy.remember(request, 'fred')
+ self.assertEqual(result, [])
+
+ def test_remember_with_extra_kargs(self):
+ request = DummyRequest({})
+ policy = self._makeOne(None, None)
+ result = policy.remember(request, 'fred', a=1, b=2)
+ self.assertEqual(policy.cookie.kw, {'a': 1, 'b': 2})
+ self.assertEqual(result, [])
+
+ def test_forget(self):
+ request = DummyRequest({})
+ policy = self._makeOne(None, None)
+ result = policy.forget(request)
+ self.assertEqual(result, [])
+
+ def test_class_implements_IAuthenticationPolicy(self):
+ from zope.interface.verify import verifyClass
+ from pyramid.interfaces import IAuthenticationPolicy
+
+ verifyClass(IAuthenticationPolicy, self._getTargetClass())
+
+ def test_instance_implements_IAuthenticationPolicy(self):
+ from zope.interface.verify import verifyObject
+ from pyramid.interfaces import IAuthenticationPolicy
+
+ verifyObject(IAuthenticationPolicy, self._makeOne(None, None))
+
+
+class TestAuthTktCookieHelper(unittest.TestCase):
+ def _getTargetClass(self):
+ from pyramid.authentication import AuthTktCookieHelper
+
+ return AuthTktCookieHelper
+
+ def _makeOne(self, *arg, **kw):
+ helper = self._getTargetClass()(*arg, **kw)
+ # laziness after moving auth_tkt classes and funcs into
+ # authentication module
+ auth_tkt = DummyAuthTktModule()
+ helper.auth_tkt = auth_tkt
+ helper.AuthTicket = auth_tkt.AuthTicket
+ helper.parse_ticket = auth_tkt.parse_ticket
+ helper.BadTicket = auth_tkt.BadTicket
+ return helper
+
+ def _makeRequest(self, cookie=None, ipv6=False):
+ environ = {'wsgi.version': (1, 0)}
+
+ if ipv6 is False:
+ environ['REMOTE_ADDR'] = '1.1.1.1'
+ else:
+ environ['REMOTE_ADDR'] = '::1'
+ environ['SERVER_NAME'] = 'localhost'
+ return DummyRequest(environ, cookie=cookie)
+
+ def _cookieValue(self, cookie):
+ items = cookie.value.split('/')
+ D = {}
+ for item in items:
+ k, v = item.split('=', 1)
+ D[k] = v
+ return D
+
+ def _parseHeaders(self, headers):
+ return [self._parseHeader(header) for header in headers]
+
+ def _parseHeader(self, header):
+ cookie = self._parseCookie(header[1])
+ return cookie
+
+ def _parseCookie(self, cookie):
+ from pyramid.compat import SimpleCookie
+
+ cookies = SimpleCookie()
+ cookies.load(cookie)
+ return cookies.get('auth_tkt')
+
+ def test_init_cookie_str_reissue_invalid(self):
+ self.assertRaises(
+ ValueError, self._makeOne, 'secret', reissue_time='invalid value'
+ )
+
+ def test_init_cookie_str_timeout_invalid(self):
+ self.assertRaises(
+ ValueError, self._makeOne, 'secret', timeout='invalid value'
+ )
+
+ def test_init_cookie_str_max_age_invalid(self):
+ self.assertRaises(
+ ValueError, self._makeOne, 'secret', max_age='invalid value'
+ )
+
+ def test_identify_nocookie(self):
+ helper = self._makeOne('secret')
+ request = self._makeRequest()
+ result = helper.identify(request)
+ self.assertEqual(result, None)
+
+ def test_identify_cookie_value_is_None(self):
+ helper = self._makeOne('secret')
+ request = self._makeRequest(None)
+ result = helper.identify(request)
+ self.assertEqual(result, None)
+
+ def test_identify_good_cookie_include_ip(self):
+ helper = self._makeOne('secret', include_ip=True)
+ request = self._makeRequest('ticket')
+ result = helper.identify(request)
+ self.assertEqual(len(result), 4)
+ self.assertEqual(result['tokens'], ())
+ self.assertEqual(result['userid'], 'userid')
+ self.assertEqual(result['userdata'], '')
+ self.assertEqual(result['timestamp'], 0)
+ self.assertEqual(helper.auth_tkt.value, 'ticket')
+ self.assertEqual(helper.auth_tkt.remote_addr, '1.1.1.1')
+ self.assertEqual(helper.auth_tkt.secret, 'secret')
+ environ = request.environ
+ self.assertEqual(environ['REMOTE_USER_TOKENS'], ())
+ self.assertEqual(environ['REMOTE_USER_DATA'], '')
+ self.assertEqual(environ['AUTH_TYPE'], 'cookie')
+
+ def test_identify_good_cookie_include_ipv6(self):
+ helper = self._makeOne('secret', include_ip=True)
+ request = self._makeRequest('ticket', ipv6=True)
+ result = helper.identify(request)
+ self.assertEqual(len(result), 4)
+ self.assertEqual(result['tokens'], ())
+ self.assertEqual(result['userid'], 'userid')
+ self.assertEqual(result['userdata'], '')
+ self.assertEqual(result['timestamp'], 0)
+ self.assertEqual(helper.auth_tkt.value, 'ticket')
+ self.assertEqual(helper.auth_tkt.remote_addr, '::1')
+ self.assertEqual(helper.auth_tkt.secret, 'secret')
+ environ = request.environ
+ self.assertEqual(environ['REMOTE_USER_TOKENS'], ())
+ self.assertEqual(environ['REMOTE_USER_DATA'], '')
+ self.assertEqual(environ['AUTH_TYPE'], 'cookie')
+
+ def test_identify_good_cookie_dont_include_ip(self):
+ helper = self._makeOne('secret', include_ip=False)
+ request = self._makeRequest('ticket')
+ result = helper.identify(request)
+ self.assertEqual(len(result), 4)
+ self.assertEqual(result['tokens'], ())
+ self.assertEqual(result['userid'], 'userid')
+ self.assertEqual(result['userdata'], '')
+ self.assertEqual(result['timestamp'], 0)
+ self.assertEqual(helper.auth_tkt.value, 'ticket')
+ self.assertEqual(helper.auth_tkt.remote_addr, '0.0.0.0')
+ self.assertEqual(helper.auth_tkt.secret, 'secret')
+ environ = request.environ
+ self.assertEqual(environ['REMOTE_USER_TOKENS'], ())
+ self.assertEqual(environ['REMOTE_USER_DATA'], '')
+ self.assertEqual(environ['AUTH_TYPE'], 'cookie')
+
+ def test_identify_good_cookie_int_useridtype(self):
+ helper = self._makeOne('secret', include_ip=False)
+ helper.auth_tkt.userid = '1'
+ helper.auth_tkt.user_data = 'userid_type:int'
+ request = self._makeRequest('ticket')
+ result = helper.identify(request)
+ self.assertEqual(len(result), 4)
+ self.assertEqual(result['tokens'], ())
+ self.assertEqual(result['userid'], 1)
+ self.assertEqual(result['userdata'], 'userid_type:int')
+ self.assertEqual(result['timestamp'], 0)
+ environ = request.environ
+ self.assertEqual(environ['REMOTE_USER_TOKENS'], ())
+ self.assertEqual(environ['REMOTE_USER_DATA'], 'userid_type:int')
+ self.assertEqual(environ['AUTH_TYPE'], 'cookie')
+
+ def test_identify_nonuseridtype_user_data(self):
+ helper = self._makeOne('secret', include_ip=False)
+ helper.auth_tkt.userid = '1'
+ helper.auth_tkt.user_data = 'bogus:int'
+ request = self._makeRequest('ticket')
+ result = helper.identify(request)
+ self.assertEqual(len(result), 4)
+ self.assertEqual(result['tokens'], ())
+ self.assertEqual(result['userid'], '1')
+ self.assertEqual(result['userdata'], 'bogus:int')
+ self.assertEqual(result['timestamp'], 0)
+ environ = request.environ
+ self.assertEqual(environ['REMOTE_USER_TOKENS'], ())
+ self.assertEqual(environ['REMOTE_USER_DATA'], 'bogus:int')
+ self.assertEqual(environ['AUTH_TYPE'], 'cookie')
+
+ def test_identify_good_cookie_unknown_useridtype(self):
+ helper = self._makeOne('secret', include_ip=False)
+ helper.auth_tkt.userid = 'abc'
+ helper.auth_tkt.user_data = 'userid_type:unknown'
+ request = self._makeRequest('ticket')
+ result = helper.identify(request)
+ self.assertEqual(len(result), 4)
+ self.assertEqual(result['tokens'], ())
+ self.assertEqual(result['userid'], 'abc')
+ self.assertEqual(result['userdata'], 'userid_type:unknown')
+ self.assertEqual(result['timestamp'], 0)
+ environ = request.environ
+ self.assertEqual(environ['REMOTE_USER_TOKENS'], ())
+ self.assertEqual(environ['REMOTE_USER_DATA'], 'userid_type:unknown')
+ self.assertEqual(environ['AUTH_TYPE'], 'cookie')
+
+ def test_identify_good_cookie_b64str_useridtype(self):
+ from base64 import b64encode
+
+ helper = self._makeOne('secret', include_ip=False)
+ helper.auth_tkt.userid = b64encode(b'encoded').strip()
+ helper.auth_tkt.user_data = 'userid_type:b64str'
+ request = self._makeRequest('ticket')
+ result = helper.identify(request)
+ self.assertEqual(len(result), 4)
+ self.assertEqual(result['tokens'], ())
+ self.assertEqual(result['userid'], b'encoded')
+ self.assertEqual(result['userdata'], 'userid_type:b64str')
+ self.assertEqual(result['timestamp'], 0)
+ environ = request.environ
+ self.assertEqual(environ['REMOTE_USER_TOKENS'], ())
+ self.assertEqual(environ['REMOTE_USER_DATA'], 'userid_type:b64str')
+ self.assertEqual(environ['AUTH_TYPE'], 'cookie')
+
+ def test_identify_good_cookie_b64unicode_useridtype(self):
+ from base64 import b64encode
+
+ helper = self._makeOne('secret', include_ip=False)
+ helper.auth_tkt.userid = b64encode(b'\xc3\xa9ncoded').strip()
+ helper.auth_tkt.user_data = 'userid_type:b64unicode'
+ request = self._makeRequest('ticket')
+ result = helper.identify(request)
+ self.assertEqual(len(result), 4)
+ self.assertEqual(result['tokens'], ())
+ self.assertEqual(result['userid'], text_(b'\xc3\xa9ncoded', 'utf-8'))
+ self.assertEqual(result['userdata'], 'userid_type:b64unicode')
+ self.assertEqual(result['timestamp'], 0)
+ environ = request.environ
+ self.assertEqual(environ['REMOTE_USER_TOKENS'], ())
+ self.assertEqual(environ['REMOTE_USER_DATA'], 'userid_type:b64unicode')
+ self.assertEqual(environ['AUTH_TYPE'], 'cookie')
+
+ def test_identify_bad_cookie(self):
+ helper = self._makeOne('secret', include_ip=True)
+ helper.auth_tkt.parse_raise = True
+ request = self._makeRequest('ticket')
+ result = helper.identify(request)
+ self.assertEqual(result, None)
+
+ def test_identify_cookie_timeout(self):
+ helper = self._makeOne('secret', timeout=1)
+ self.assertEqual(helper.timeout, 1)
+
+ def test_identify_cookie_str_timeout(self):
+ helper = self._makeOne('secret', timeout='1')
+ self.assertEqual(helper.timeout, 1)
+
+ def test_identify_cookie_timeout_aged(self):
+ import time
+
+ helper = self._makeOne('secret', timeout=10)
+ now = time.time()
+ helper.auth_tkt.timestamp = now - 1
+ helper.now = now + 10
+ helper.auth_tkt.tokens = (text_('a'),)
+ request = self._makeRequest('bogus')
+ result = helper.identify(request)
+ self.assertFalse(result)
+
+ def test_identify_cookie_reissue(self):
+ import time
+
+ helper = self._makeOne('secret', timeout=10, reissue_time=0)
+ now = time.time()
+ helper.auth_tkt.timestamp = now
+ helper.now = now + 1
+ helper.auth_tkt.tokens = (text_('a'),)
+ request = self._makeRequest('bogus')
+ result = helper.identify(request)
+ self.assertTrue(result)
+ self.assertEqual(len(request.callbacks), 1)
+ response = DummyResponse()
+ request.callbacks[0](request, response)
+ self.assertEqual(len(response.headerlist), 3)
+ self.assertEqual(response.headerlist[0][0], 'Set-Cookie')
+
+ def test_identify_cookie_str_reissue(self):
+ import time
+
+ helper = self._makeOne('secret', timeout=10, reissue_time='0')
+ now = time.time()
+ helper.auth_tkt.timestamp = now
+ helper.now = now + 1
+ helper.auth_tkt.tokens = (text_('a'),)
+ request = self._makeRequest('bogus')
+ result = helper.identify(request)
+ self.assertTrue(result)
+ self.assertEqual(len(request.callbacks), 1)
+ response = DummyResponse()
+ request.callbacks[0](request, response)
+ self.assertEqual(len(response.headerlist), 3)
+ self.assertEqual(response.headerlist[0][0], 'Set-Cookie')
+
+ def test_identify_cookie_reissue_already_reissued_this_request(self):
+ import time
+
+ helper = self._makeOne('secret', timeout=10, reissue_time=0)
+ now = time.time()
+ helper.auth_tkt.timestamp = now
+ helper.now = now + 1
+ request = self._makeRequest('bogus')
+ request._authtkt_reissued = True
+ result = helper.identify(request)
+ self.assertTrue(result)
+ self.assertEqual(len(request.callbacks), 0)
+
+ def test_identify_cookie_reissue_notyet(self):
+ import time
+
+ helper = self._makeOne('secret', timeout=10, reissue_time=10)
+ now = time.time()
+ helper.auth_tkt.timestamp = now
+ helper.now = now + 1
+ request = self._makeRequest('bogus')
+ result = helper.identify(request)
+ self.assertTrue(result)
+ self.assertEqual(len(request.callbacks), 0)
+
+ def test_identify_cookie_reissue_revoked_by_forget(self):
+ import time
+
+ helper = self._makeOne('secret', timeout=10, reissue_time=0)
+ now = time.time()
+ helper.auth_tkt.timestamp = now
+ helper.now = now + 1
+ request = self._makeRequest('bogus')
+ result = helper.identify(request)
+ self.assertTrue(result)
+ self.assertEqual(len(request.callbacks), 1)
+ result = helper.forget(request)
+ self.assertTrue(result)
+ self.assertEqual(len(request.callbacks), 1)
+ response = DummyResponse()
+ request.callbacks[0](request, response)
+ self.assertEqual(len(response.headerlist), 0)
+
+ def test_identify_cookie_reissue_revoked_by_remember(self):
+ import time
+
+ helper = self._makeOne('secret', timeout=10, reissue_time=0)
+ now = time.time()
+ helper.auth_tkt.timestamp = now
+ helper.now = now + 1
+ request = self._makeRequest('bogus')
+ result = helper.identify(request)
+ self.assertTrue(result)
+ self.assertEqual(len(request.callbacks), 1)
+ result = helper.remember(request, 'bob')
+ self.assertTrue(result)
+ self.assertEqual(len(request.callbacks), 1)
+ response = DummyResponse()
+ request.callbacks[0](request, response)
+ self.assertEqual(len(response.headerlist), 0)
+
+ def test_identify_cookie_reissue_with_tokens_default(self):
+ # see https://github.com/Pylons/pyramid/issues#issue/108
+ import time
+
+ helper = self._makeOne('secret', timeout=10, reissue_time=0)
+ auth_tkt = DummyAuthTktModule(tokens=[''])
+ helper.auth_tkt = auth_tkt
+ helper.AuthTicket = auth_tkt.AuthTicket
+ helper.parse_ticket = auth_tkt.parse_ticket
+ helper.BadTicket = auth_tkt.BadTicket
+ now = time.time()
+ helper.auth_tkt.timestamp = now
+ helper.now = now + 1
+ request = self._makeRequest('bogus')
+ result = helper.identify(request)
+ self.assertTrue(result)
+ self.assertEqual(len(request.callbacks), 1)
+ response = DummyResponse()
+ request.callbacks[0](None, response)
+ self.assertEqual(len(response.headerlist), 3)
+ self.assertEqual(response.headerlist[0][0], 'Set-Cookie')
+ self.assertTrue("/tokens=/" in response.headerlist[0][1])
+
+ def test_remember(self):
+ helper = self._makeOne('secret')
+ request = self._makeRequest()
+ result = helper.remember(request, 'userid')
+ self.assertEqual(len(result), 3)
+
+ self.assertEqual(result[0][0], 'Set-Cookie')
+ self.assertTrue(result[0][1].endswith('; Path=/; SameSite=Lax'))
+ self.assertTrue(result[0][1].startswith('auth_tkt='))
+
+ self.assertEqual(result[1][0], 'Set-Cookie')
+ self.assertTrue(
+ result[1][1].endswith('; Domain=localhost; Path=/; SameSite=Lax')
+ )
+ self.assertTrue(result[1][1].startswith('auth_tkt='))
+
+ self.assertEqual(result[2][0], 'Set-Cookie')
+ self.assertTrue(
+ result[2][1].endswith('; Domain=.localhost; Path=/; SameSite=Lax')
+ )
+ self.assertTrue(result[2][1].startswith('auth_tkt='))
+
+ def test_remember_nondefault_samesite(self):
+ helper = self._makeOne('secret', samesite='Strict')
+ request = self._makeRequest()
+ result = helper.remember(request, 'userid')
+ self.assertEqual(len(result), 3)
+
+ self.assertEqual(result[0][0], 'Set-Cookie')
+ self.assertTrue(result[0][1].endswith('; Path=/; SameSite=Strict'))
+ self.assertTrue(result[0][1].startswith('auth_tkt='))
+
+ self.assertEqual(result[1][0], 'Set-Cookie')
+ self.assertTrue(
+ result[1][1].endswith(
+ '; Domain=localhost; Path=/; SameSite=Strict'
+ )
+ )
+ self.assertTrue(result[1][1].startswith('auth_tkt='))
+
+ self.assertEqual(result[2][0], 'Set-Cookie')
+ self.assertTrue(
+ result[2][1].endswith(
+ '; Domain=.localhost; Path=/; SameSite=Strict'
+ )
+ )
+ self.assertTrue(result[2][1].startswith('auth_tkt='))
+
+ def test_remember_None_samesite(self):
+ helper = self._makeOne('secret', samesite=None)
+ request = self._makeRequest()
+ result = helper.remember(request, 'userid')
+ self.assertEqual(len(result), 3)
+
+ self.assertEqual(result[0][0], 'Set-Cookie')
+ self.assertTrue(result[0][1].endswith('; Path=/')) # no samesite
+ self.assertTrue(result[0][1].startswith('auth_tkt='))
+
+ self.assertEqual(result[1][0], 'Set-Cookie')
+ self.assertTrue(result[1][1].endswith('; Domain=localhost; Path=/'))
+ self.assertTrue(result[1][1].startswith('auth_tkt='))
+
+ self.assertEqual(result[2][0], 'Set-Cookie')
+ self.assertTrue(result[2][1].endswith('; Domain=.localhost; Path=/'))
+ self.assertTrue(result[2][1].startswith('auth_tkt='))
+
+ def test_remember_include_ip(self):
+ helper = self._makeOne('secret', include_ip=True)
+ request = self._makeRequest()
+ result = helper.remember(request, 'other')
+ self.assertEqual(len(result), 3)
+
+ self.assertEqual(result[0][0], 'Set-Cookie')
+ self.assertTrue(result[0][1].endswith('; Path=/; SameSite=Lax'))
+ self.assertTrue(result[0][1].startswith('auth_tkt='))
+
+ self.assertEqual(result[1][0], 'Set-Cookie')
+ self.assertTrue(
+ result[1][1].endswith('; Domain=localhost; Path=/; SameSite=Lax')
+ )
+ self.assertTrue(result[1][1].startswith('auth_tkt='))
+
+ self.assertEqual(result[2][0], 'Set-Cookie')
+ self.assertTrue(
+ result[2][1].endswith('; Domain=.localhost; Path=/; SameSite=Lax')
+ )
+ self.assertTrue(result[2][1].startswith('auth_tkt='))
+
+ def test_remember_path(self):
+ helper = self._makeOne(
+ 'secret', include_ip=True, path="/cgi-bin/app.cgi/"
+ )
+ request = self._makeRequest()
+ result = helper.remember(request, 'other')
+ self.assertEqual(len(result), 3)
+
+ self.assertEqual(result[0][0], 'Set-Cookie')
+ self.assertTrue(
+ result[0][1].endswith('; Path=/cgi-bin/app.cgi/; SameSite=Lax')
+ )
+ self.assertTrue(result[0][1].startswith('auth_tkt='))
+
+ self.assertEqual(result[1][0], 'Set-Cookie')
+ self.assertTrue(
+ result[1][1].endswith(
+ '; Domain=localhost; Path=/cgi-bin/app.cgi/; SameSite=Lax'
+ )
+ )
+ self.assertTrue(result[1][1].startswith('auth_tkt='))
+
+ self.assertEqual(result[2][0], 'Set-Cookie')
+ self.assertTrue(
+ result[2][1].endswith(
+ '; Domain=.localhost; Path=/cgi-bin/app.cgi/; SameSite=Lax'
+ )
+ )
+ self.assertTrue(result[2][1].startswith('auth_tkt='))
+
+ def test_remember_http_only(self):
+ helper = self._makeOne('secret', include_ip=True, http_only=True)
+ request = self._makeRequest()
+ result = helper.remember(request, 'other')
+ self.assertEqual(len(result), 3)
+
+ self.assertEqual(result[0][0], 'Set-Cookie')
+ self.assertTrue(result[0][1].endswith('; HttpOnly; SameSite=Lax'))
+ self.assertTrue(result[0][1].startswith('auth_tkt='))
+
+ self.assertEqual(result[1][0], 'Set-Cookie')
+ self.assertTrue('; HttpOnly' in result[1][1])
+ self.assertTrue(result[1][1].startswith('auth_tkt='))
+
+ self.assertEqual(result[2][0], 'Set-Cookie')
+ self.assertTrue('; HttpOnly' in result[2][1])
+ self.assertTrue(result[2][1].startswith('auth_tkt='))
+
+ def test_remember_secure(self):
+ helper = self._makeOne('secret', include_ip=True, secure=True)
+ request = self._makeRequest()
+ result = helper.remember(request, 'other')
+ self.assertEqual(len(result), 3)
+
+ self.assertEqual(result[0][0], 'Set-Cookie')
+ self.assertTrue('; secure' in result[0][1])
+ self.assertTrue(result[0][1].startswith('auth_tkt='))
+
+ self.assertEqual(result[1][0], 'Set-Cookie')
+ self.assertTrue('; secure' in result[1][1])
+ self.assertTrue(result[1][1].startswith('auth_tkt='))
+
+ self.assertEqual(result[2][0], 'Set-Cookie')
+ self.assertTrue('; secure' in result[2][1])
+ self.assertTrue(result[2][1].startswith('auth_tkt='))
+
+ def test_remember_wild_domain_disabled(self):
+ helper = self._makeOne('secret', wild_domain=False)
+ request = self._makeRequest()
+ result = helper.remember(request, 'other')
+ self.assertEqual(len(result), 2)
+
+ self.assertEqual(result[0][0], 'Set-Cookie')
+ self.assertTrue(result[0][1].endswith('; Path=/; SameSite=Lax'))
+ self.assertTrue(result[0][1].startswith('auth_tkt='))
+
+ self.assertEqual(result[1][0], 'Set-Cookie')
+ self.assertTrue(
+ result[1][1].endswith('; Domain=localhost; Path=/; SameSite=Lax')
+ )
+ self.assertTrue(result[1][1].startswith('auth_tkt='))
+
+ def test_remember_parent_domain(self):
+ helper = self._makeOne('secret', parent_domain=True)
+ request = self._makeRequest()
+ request.domain = 'www.example.com'
+ result = helper.remember(request, 'other')
+ self.assertEqual(len(result), 1)
+
+ self.assertEqual(result[0][0], 'Set-Cookie')
+ self.assertTrue(
+ result[0][1].endswith(
+ '; Domain=.example.com; Path=/; SameSite=Lax'
+ )
+ )
+ self.assertTrue(result[0][1].startswith('auth_tkt='))
+
+ def test_remember_parent_domain_supercedes_wild_domain(self):
+ helper = self._makeOne('secret', parent_domain=True, wild_domain=True)
+ request = self._makeRequest()
+ request.domain = 'www.example.com'
+ result = helper.remember(request, 'other')
+ self.assertEqual(len(result), 1)
+ self.assertTrue(
+ result[0][1].endswith(
+ '; Domain=.example.com; Path=/; SameSite=Lax'
+ )
+ )
+
+ def test_remember_explicit_domain(self):
+ helper = self._makeOne('secret', domain='pyramid.bazinga')
+ request = self._makeRequest()
+ request.domain = 'www.example.com'
+ result = helper.remember(request, 'other')
+ self.assertEqual(len(result), 1)
+
+ self.assertEqual(result[0][0], 'Set-Cookie')
+ self.assertTrue(
+ result[0][1].endswith(
+ '; Domain=pyramid.bazinga; Path=/; SameSite=Lax'
+ )
+ )
+ self.assertTrue(result[0][1].startswith('auth_tkt='))
+
+ def test_remember_domain_supercedes_parent_and_wild_domain(self):
+ helper = self._makeOne(
+ 'secret',
+ domain='pyramid.bazinga',
+ parent_domain=True,
+ wild_domain=True,
+ )
+ request = self._makeRequest()
+ request.domain = 'www.example.com'
+ result = helper.remember(request, 'other')
+ self.assertEqual(len(result), 1)
+ self.assertTrue(
+ result[0][1].endswith(
+ '; Domain=pyramid.bazinga; Path=/; SameSite=Lax'
+ )
+ )
+
+ def test_remember_binary_userid(self):
+ import base64
+
+ helper = self._makeOne('secret')
+ request = self._makeRequest()
+ result = helper.remember(request, b'userid')
+ values = self._parseHeaders(result)
+ self.assertEqual(len(result), 3)
+ val = self._cookieValue(values[0])
+ self.assertEqual(
+ val['userid'], text_(base64.b64encode(b'userid').strip())
+ )
+ self.assertEqual(val['user_data'], 'userid_type:b64str')
+
+ def test_remember_int_userid(self):
+ helper = self._makeOne('secret')
+ request = self._makeRequest()
+ result = helper.remember(request, 1)
+ values = self._parseHeaders(result)
+ self.assertEqual(len(result), 3)
+ val = self._cookieValue(values[0])
+ self.assertEqual(val['userid'], '1')
+ self.assertEqual(val['user_data'], 'userid_type:int')
+
+ def test_remember_long_userid(self):
+ from pyramid.compat import long
+
+ helper = self._makeOne('secret')
+ request = self._makeRequest()
+ result = helper.remember(request, long(1))
+ values = self._parseHeaders(result)
+ self.assertEqual(len(result), 3)
+ val = self._cookieValue(values[0])
+ self.assertEqual(val['userid'], '1')
+ self.assertEqual(val['user_data'], 'userid_type:int')
+
+ def test_remember_unicode_userid(self):
+ import base64
+
+ helper = self._makeOne('secret')
+ request = self._makeRequest()
+ userid = text_(b'\xc2\xa9', 'utf-8')
+ result = helper.remember(request, userid)
+ values = self._parseHeaders(result)
+ self.assertEqual(len(result), 3)
+ val = self._cookieValue(values[0])
+ self.assertEqual(
+ val['userid'], text_(base64.b64encode(userid.encode('utf-8')))
+ )
+ self.assertEqual(val['user_data'], 'userid_type:b64unicode')
+
+ def test_remember_insane_userid(self):
+ helper = self._makeOne('secret')
+ request = self._makeRequest()
+ userid = object()
+ with warnings.catch_warnings(record=True) as w:
+ warnings.simplefilter('always', RuntimeWarning)
+ result = helper.remember(request, userid)
+ self.assertTrue(str(w[-1].message).startswith('userid is of type'))
+ values = self._parseHeaders(result)
+ self.assertEqual(len(result), 3)
+ value = values[0]
+ self.assertTrue('userid' in value.value)
+
+ def test_remember_max_age(self):
+ helper = self._makeOne('secret')
+ request = self._makeRequest()
+ result = helper.remember(request, 'userid', max_age=500)
+ values = self._parseHeaders(result)
+ self.assertEqual(len(result), 3)
+
+ self.assertEqual(values[0]['max-age'], '500')
+ self.assertTrue(values[0]['expires'])
+
+ def test_remember_str_max_age(self):
+ helper = self._makeOne('secret')
+ request = self._makeRequest()
+ result = helper.remember(request, 'userid', max_age='500')
+ values = self._parseHeaders(result)
+ self.assertEqual(len(result), 3)
+
+ self.assertEqual(values[0]['max-age'], '500')
+ self.assertTrue(values[0]['expires'])
+
+ def test_remember_str_max_age_invalid(self):
+ helper = self._makeOne('secret')
+ request = self._makeRequest()
+ self.assertRaises(
+ ValueError,
+ helper.remember,
+ request,
+ 'userid',
+ max_age='invalid value',
+ )
+
+ def test_remember_tokens(self):
+ helper = self._makeOne('secret')
+ request = self._makeRequest()
+ result = helper.remember(request, 'other', tokens=('foo', 'bar'))
+ self.assertEqual(len(result), 3)
+
+ self.assertEqual(result[0][0], 'Set-Cookie')
+ self.assertTrue("/tokens=foo|bar/" in result[0][1])
+
+ self.assertEqual(result[1][0], 'Set-Cookie')
+ self.assertTrue("/tokens=foo|bar/" in result[1][1])
+
+ self.assertEqual(result[2][0], 'Set-Cookie')
+ self.assertTrue("/tokens=foo|bar/" in result[2][1])
+
+ def test_remember_samesite_nondefault(self):
+ helper = self._makeOne('secret', samesite='Strict')
+ request = self._makeRequest()
+ result = helper.remember(request, 'userid')
+ self.assertEqual(len(result), 3)
+
+ self.assertEqual(result[0][0], 'Set-Cookie')
+ cookieval = result[0][1]
+ self.assertTrue(
+ 'SameSite=Strict' in [x.strip() for x in cookieval.split(';')],
+ cookieval,
+ )
+
+ self.assertEqual(result[1][0], 'Set-Cookie')
+ cookieval = result[1][1]
+ self.assertTrue(
+ 'SameSite=Strict' in [x.strip() for x in cookieval.split(';')],
+ cookieval,
+ )
+
+ self.assertEqual(result[2][0], 'Set-Cookie')
+ cookieval = result[2][1]
+ self.assertTrue(
+ 'SameSite=Strict' in [x.strip() for x in cookieval.split(';')],
+ cookieval,
+ )
+
+ def test_remember_samesite_default(self):
+ helper = self._makeOne('secret')
+ request = self._makeRequest()
+ result = helper.remember(request, 'userid')
+ self.assertEqual(len(result), 3)
+
+ self.assertEqual(result[0][0], 'Set-Cookie')
+ cookieval = result[0][1]
+ self.assertTrue(
+ 'SameSite=Lax' in [x.strip() for x in cookieval.split(';')],
+ cookieval,
+ )
+
+ self.assertEqual(result[1][0], 'Set-Cookie')
+ cookieval = result[1][1]
+ self.assertTrue(
+ 'SameSite=Lax' in [x.strip() for x in cookieval.split(';')],
+ cookieval,
+ )
+
+ self.assertEqual(result[2][0], 'Set-Cookie')
+ cookieval = result[2][1]
+ self.assertTrue(
+ 'SameSite=Lax' in [x.strip() for x in cookieval.split(';')],
+ cookieval,
+ )
+
+ def test_remember_unicode_but_ascii_token(self):
+ helper = self._makeOne('secret')
+ request = self._makeRequest()
+ la = text_(b'foo', 'utf-8')
+ result = helper.remember(request, 'other', tokens=(la,))
+ # tokens must be str type on both Python 2 and 3
+ self.assertTrue("/tokens=foo/" in result[0][1])
+
+ def test_remember_nonascii_token(self):
+ helper = self._makeOne('secret')
+ request = self._makeRequest()
+ la = text_(b'La Pe\xc3\xb1a', 'utf-8')
+ self.assertRaises(
+ ValueError, helper.remember, request, 'other', tokens=(la,)
+ )
+
+ def test_remember_invalid_token_format(self):
+ helper = self._makeOne('secret')
+ request = self._makeRequest()
+ self.assertRaises(
+ ValueError, helper.remember, request, 'other', tokens=('foo bar',)
+ )
+ self.assertRaises(
+ ValueError, helper.remember, request, 'other', tokens=('1bar',)
+ )
+
+ def test_forget(self):
+ helper = self._makeOne('secret')
+ request = self._makeRequest()
+ headers = helper.forget(request)
+ self.assertEqual(len(headers), 3)
+ name, value = headers[0]
+ self.assertEqual(name, 'Set-Cookie')
+ self.assertEqual(
+ value,
+ 'auth_tkt=; Max-Age=0; Path=/; '
+ 'expires=Wed, 31-Dec-97 23:59:59 GMT; SameSite=Lax',
+ )
+ name, value = headers[1]
+ self.assertEqual(name, 'Set-Cookie')
+ self.assertEqual(
+ value,
+ 'auth_tkt=; Domain=localhost; Max-Age=0; Path=/; '
+ 'expires=Wed, 31-Dec-97 23:59:59 GMT; SameSite=Lax',
+ )
+ name, value = headers[2]
+ self.assertEqual(name, 'Set-Cookie')
+ self.assertEqual(
+ value,
+ 'auth_tkt=; Domain=.localhost; Max-Age=0; Path=/; '
+ 'expires=Wed, 31-Dec-97 23:59:59 GMT; SameSite=Lax',
+ )
+
+
+class TestAuthTicket(unittest.TestCase):
+ def _makeOne(self, *arg, **kw):
+ from pyramid.authentication import AuthTicket
+
+ return AuthTicket(*arg, **kw)
+
+ def test_ctor_with_tokens(self):
+ ticket = self._makeOne('secret', 'userid', 'ip', tokens=('a', 'b'))
+ self.assertEqual(ticket.tokens, 'a,b')
+
+ def test_ctor_with_time(self):
+ ticket = self._makeOne('secret', 'userid', 'ip', time='time')
+ self.assertEqual(ticket.time, 'time')
+
+ def test_digest(self):
+ ticket = self._makeOne('secret', 'userid', '0.0.0.0', time=10)
+ result = ticket.digest()
+ self.assertEqual(result, '126fd6224912187ee9ffa80e0b81420c')
+
+ def test_digest_sha512(self):
+ ticket = self._makeOne(
+ 'secret', 'userid', '0.0.0.0', time=10, hashalg='sha512'
+ )
+ result = ticket.digest()
+ self.assertEqual(
+ result,
+ '74770b2e0d5b1a54c2a466ec567a40f7d7823576aa49'
+ '3c65fc3445e9b44097f4a80410319ef8cb256a2e60b9'
+ 'c2002e48a9e33a3e8ee4379352c04ef96d2cb278',
+ )
+
+ def test_cookie_value(self):
+ ticket = self._makeOne(
+ 'secret', 'userid', '0.0.0.0', time=10, tokens=('a', 'b')
+ )
+ result = ticket.cookie_value()
+ self.assertEqual(
+ result, '66f9cc3e423dc57c91df696cf3d1f0d80000000auserid!a,b!'
+ )
+
+ def test_ipv4(self):
+ ticket = self._makeOne(
+ 'secret', 'userid', '198.51.100.1', time=10, hashalg='sha256'
+ )
+ result = ticket.cookie_value()
+ self.assertEqual(
+ result,
+ 'b3e7156db4f8abde4439c4a6499a0668f9e7ffd7fa27b'
+ '798400ecdade8d76c530000000auserid!',
+ )
+
+ def test_ipv6(self):
+ ticket = self._makeOne(
+ 'secret', 'userid', '2001:db8::1', time=10, hashalg='sha256'
+ )
+ result = ticket.cookie_value()
+ self.assertEqual(
+ result,
+ 'd025b601a0f12ca6d008aa35ff3a22b7d8f3d1c1456c8'
+ '5becf8760cd7a2fa4910000000auserid!',
+ )
+
+
+class TestBadTicket(unittest.TestCase):
+ def _makeOne(self, msg, expected=None):
+ from pyramid.authentication import BadTicket
+
+ return BadTicket(msg, expected)
+
+ def test_it(self):
+ exc = self._makeOne('msg', expected=True)
+ self.assertEqual(exc.expected, True)
+ self.assertTrue(isinstance(exc, Exception))
+
+
+class Test_parse_ticket(unittest.TestCase):
+ def _callFUT(self, secret, ticket, ip, hashalg='md5'):
+ from pyramid.authentication import parse_ticket
+
+ return parse_ticket(secret, ticket, ip, hashalg)
+
+ def _assertRaisesBadTicket(self, secret, ticket, ip, hashalg='md5'):
+ from pyramid.authentication import BadTicket
+
+ self.assertRaises(
+ BadTicket, self._callFUT, secret, ticket, ip, hashalg
+ )
+
+ def test_bad_timestamp(self):
+ ticket = 'x' * 64
+ self._assertRaisesBadTicket('secret', ticket, 'ip')
+
+ def test_bad_userid_or_data(self):
+ ticket = 'x' * 32 + '11111111' + 'x' * 10
+ self._assertRaisesBadTicket('secret', ticket, 'ip')
+
+ def test_digest_sig_incorrect(self):
+ ticket = 'x' * 32 + '11111111' + 'a!b!c'
+ self._assertRaisesBadTicket('secret', ticket, '0.0.0.0')
+
+ def test_correct_with_user_data(self):
+ ticket = text_('66f9cc3e423dc57c91df696cf3d1f0d80000000auserid!a,b!')
+ result = self._callFUT('secret', ticket, '0.0.0.0')
+ self.assertEqual(result, (10, 'userid', ['a', 'b'], ''))
+
+ def test_correct_with_user_data_sha512(self):
+ ticket = text_(
+ '7d947cdef99bad55f8e3382a8bd089bb9dd0547f7925b7d189adc1'
+ '160cab0ec0e6888faa41eba641a18522b26f19109f3ffafb769767'
+ 'ba8a26d02aaeae56599a0000000auserid!a,b!'
+ )
+ result = self._callFUT('secret', ticket, '0.0.0.0', 'sha512')
+ self.assertEqual(result, (10, 'userid', ['a', 'b'], ''))
+
+ def test_ipv4(self):
+ ticket = text_(
+ 'b3e7156db4f8abde4439c4a6499a0668f9e7ffd7fa27b798400ecd'
+ 'ade8d76c530000000auserid!'
+ )
+ result = self._callFUT('secret', ticket, '198.51.100.1', 'sha256')
+ self.assertEqual(result, (10, 'userid', [''], ''))
+
+ def test_ipv6(self):
+ ticket = text_(
+ 'd025b601a0f12ca6d008aa35ff3a22b7d8f3d1c1456c85becf8760'
+ 'cd7a2fa4910000000auserid!'
+ )
+ result = self._callFUT('secret', ticket, '2001:db8::1', 'sha256')
+ self.assertEqual(result, (10, 'userid', [''], ''))
+
+
+class TestSessionAuthenticationPolicy(unittest.TestCase):
+ def _getTargetClass(self):
+ from pyramid.authentication import SessionAuthenticationPolicy
+
+ return SessionAuthenticationPolicy
+
+ def _makeOne(self, callback=None, prefix=''):
+ return self._getTargetClass()(prefix=prefix, callback=callback)
+
+ def test_class_implements_IAuthenticationPolicy(self):
+ from zope.interface.verify import verifyClass
+ from pyramid.interfaces import IAuthenticationPolicy
+
+ verifyClass(IAuthenticationPolicy, self._getTargetClass())
+
+ def test_instance_implements_IAuthenticationPolicy(self):
+ from zope.interface.verify import verifyObject
+ from pyramid.interfaces import IAuthenticationPolicy
+
+ verifyObject(IAuthenticationPolicy, self._makeOne())
+
+ def test_unauthenticated_userid_returns_None(self):
+ request = DummyRequest()
+ policy = self._makeOne()
+ self.assertEqual(policy.unauthenticated_userid(request), None)
+
+ def test_unauthenticated_userid(self):
+ request = DummyRequest(session={'userid': 'fred'})
+ policy = self._makeOne()
+ self.assertEqual(policy.unauthenticated_userid(request), 'fred')
+
+ def test_authenticated_userid_no_cookie_identity(self):
+ request = DummyRequest()
+ policy = self._makeOne()
+ self.assertEqual(policy.authenticated_userid(request), None)
+
+ def test_authenticated_userid_callback_returns_None(self):
+ request = DummyRequest(session={'userid': 'fred'})
+
+ def callback(userid, request):
+ return None
+
+ policy = self._makeOne(callback)
+ self.assertEqual(policy.authenticated_userid(request), None)
+
+ def test_authenticated_userid(self):
+ request = DummyRequest(session={'userid': 'fred'})
+
+ def callback(userid, request):
+ return True
+
+ policy = self._makeOne(callback)
+ self.assertEqual(policy.authenticated_userid(request), 'fred')
+
+ def test_effective_principals_no_identity(self):
+ from pyramid.security import Everyone
+
+ request = DummyRequest()
+ policy = self._makeOne()
+ self.assertEqual(policy.effective_principals(request), [Everyone])
+
+ def test_effective_principals_callback_returns_None(self):
+ from pyramid.security import Everyone
+
+ request = DummyRequest(session={'userid': 'fred'})
+
+ def callback(userid, request):
+ return None
+
+ policy = self._makeOne(callback)
+ self.assertEqual(policy.effective_principals(request), [Everyone])
+
+ def test_effective_principals(self):
+ from pyramid.security import Everyone
+ from pyramid.security import Authenticated
+
+ request = DummyRequest(session={'userid': 'fred'})
+
+ def callback(userid, request):
+ return ['group.foo']
+
+ policy = self._makeOne(callback)
+ self.assertEqual(
+ policy.effective_principals(request),
+ [Everyone, Authenticated, 'fred', 'group.foo'],
+ )
+
+ def test_remember(self):
+ request = DummyRequest()
+ policy = self._makeOne()
+ result = policy.remember(request, 'fred')
+ self.assertEqual(request.session.get('userid'), 'fred')
+ self.assertEqual(result, [])
+
+ def test_forget(self):
+ request = DummyRequest(session={'userid': 'fred'})
+ policy = self._makeOne()
+ result = policy.forget(request)
+ self.assertEqual(request.session.get('userid'), None)
+ self.assertEqual(result, [])
+
+ def test_forget_no_identity(self):
+ request = DummyRequest()
+ policy = self._makeOne()
+ result = policy.forget(request)
+ self.assertEqual(request.session.get('userid'), None)
+ self.assertEqual(result, [])
+
+
+class TestBasicAuthAuthenticationPolicy(unittest.TestCase):
+ def _getTargetClass(self):
+ from pyramid.authentication import BasicAuthAuthenticationPolicy as cls
+
+ return cls
+
+ def _makeOne(self, check):
+ return self._getTargetClass()(check, realm='SomeRealm')
+
+ def test_class_implements_IAuthenticationPolicy(self):
+ from zope.interface.verify import verifyClass
+ from pyramid.interfaces import IAuthenticationPolicy
+
+ verifyClass(IAuthenticationPolicy, self._getTargetClass())
+
+ def test_unauthenticated_userid(self):
+ import base64
+
+ request = testing.DummyRequest()
+ request.headers['Authorization'] = 'Basic %s' % base64.b64encode(
+ bytes_('chrisr:password')
+ ).decode('ascii')
+ policy = self._makeOne(None)
+ self.assertEqual(policy.unauthenticated_userid(request), 'chrisr')
+
+ def test_unauthenticated_userid_no_credentials(self):
+ request = testing.DummyRequest()
+ policy = self._makeOne(None)
+ self.assertEqual(policy.unauthenticated_userid(request), None)
+
+ def test_unauthenticated_bad_header(self):
+ request = testing.DummyRequest()
+ request.headers['Authorization'] = '...'
+ policy = self._makeOne(None)
+ self.assertEqual(policy.unauthenticated_userid(request), None)
+
+ def test_unauthenticated_userid_not_basic(self):
+ request = testing.DummyRequest()
+ request.headers['Authorization'] = 'Complicated things'
+ policy = self._makeOne(None)
+ self.assertEqual(policy.unauthenticated_userid(request), None)
+
+ def test_unauthenticated_userid_corrupt_base64(self):
+ request = testing.DummyRequest()
+ request.headers['Authorization'] = 'Basic chrisr:password'
+ policy = self._makeOne(None)
+ self.assertEqual(policy.unauthenticated_userid(request), None)
+
+ def test_authenticated_userid(self):
+ import base64
+
+ request = testing.DummyRequest()
+ request.headers['Authorization'] = 'Basic %s' % base64.b64encode(
+ bytes_('chrisr:password')
+ ).decode('ascii')
+
+ def check(username, password, request):
+ return []
+
+ policy = self._makeOne(check)
+ self.assertEqual(policy.authenticated_userid(request), 'chrisr')
+
+ def test_authenticated_userid_utf8(self):
+ import base64
+
+ request = testing.DummyRequest()
+ inputs = (
+ b'm\xc3\xb6rk\xc3\xb6:' b'm\xc3\xb6rk\xc3\xb6password'
+ ).decode('utf-8')
+ request.headers['Authorization'] = 'Basic %s' % (
+ base64.b64encode(inputs.encode('utf-8')).decode('latin-1')
+ )
+
+ def check(username, password, request):
+ return []
+
+ policy = self._makeOne(check)
+ self.assertEqual(
+ policy.authenticated_userid(request),
+ b'm\xc3\xb6rk\xc3\xb6'.decode('utf-8'),
+ )
+
+ def test_authenticated_userid_latin1(self):
+ import base64
+
+ request = testing.DummyRequest()
+ inputs = (
+ b'm\xc3\xb6rk\xc3\xb6:' b'm\xc3\xb6rk\xc3\xb6password'
+ ).decode('utf-8')
+ request.headers['Authorization'] = 'Basic %s' % (
+ base64.b64encode(inputs.encode('latin-1')).decode('latin-1')
+ )
+
+ def check(username, password, request):
+ return []
+
+ policy = self._makeOne(check)
+ self.assertEqual(
+ policy.authenticated_userid(request),
+ b'm\xc3\xb6rk\xc3\xb6'.decode('utf-8'),
+ )
+
+ def test_unauthenticated_userid_invalid_payload(self):
+ import base64
+
+ request = testing.DummyRequest()
+ request.headers['Authorization'] = 'Basic %s' % base64.b64encode(
+ bytes_('chrisrpassword')
+ ).decode('ascii')
+ policy = self._makeOne(None)
+ self.assertEqual(policy.unauthenticated_userid(request), None)
+
+ def test_remember(self):
+ policy = self._makeOne(None)
+ self.assertEqual(policy.remember(None, None), [])
+
+ def test_forget(self):
+ policy = self._makeOne(None)
+ self.assertEqual(
+ policy.forget(None),
+ [('WWW-Authenticate', 'Basic realm="SomeRealm"')],
+ )
+
+
+class TestExtractHTTPBasicCredentials(unittest.TestCase):
+ def _get_func(self):
+ from pyramid.authentication import extract_http_basic_credentials
+
+ return extract_http_basic_credentials
+
+ def test_no_auth_header(self):
+ request = testing.DummyRequest()
+ fn = self._get_func()
+
+ self.assertIsNone(fn(request))
+
+ def test_invalid_payload(self):
+ import base64
+
+ request = testing.DummyRequest()
+ request.headers['Authorization'] = 'Basic %s' % base64.b64encode(
+ bytes_('chrisrpassword')
+ ).decode('ascii')
+ fn = self._get_func()
+ self.assertIsNone(fn(request))
+
+ def test_not_a_basic_auth_scheme(self):
+ import base64
+
+ request = testing.DummyRequest()
+ request.headers['Authorization'] = 'OtherScheme %s' % base64.b64encode(
+ bytes_('chrisr:password')
+ ).decode('ascii')
+ fn = self._get_func()
+ self.assertIsNone(fn(request))
+
+ def test_no_base64_encoding(self):
+ request = testing.DummyRequest()
+ request.headers['Authorization'] = 'Basic ...'
+ fn = self._get_func()
+ self.assertIsNone(fn(request))
+
+ def test_latin1_payload(self):
+ import base64
+
+ request = testing.DummyRequest()
+ inputs = (
+ b'm\xc3\xb6rk\xc3\xb6:' b'm\xc3\xb6rk\xc3\xb6password'
+ ).decode('utf-8')
+ request.headers['Authorization'] = 'Basic %s' % (
+ base64.b64encode(inputs.encode('latin-1')).decode('latin-1')
+ )
+ fn = self._get_func()
+ self.assertEqual(
+ fn(request),
+ (
+ b'm\xc3\xb6rk\xc3\xb6'.decode('utf-8'),
+ b'm\xc3\xb6rk\xc3\xb6password'.decode('utf-8'),
+ ),
+ )
+
+ def test_utf8_payload(self):
+ import base64
+
+ request = testing.DummyRequest()
+ inputs = (
+ b'm\xc3\xb6rk\xc3\xb6:' b'm\xc3\xb6rk\xc3\xb6password'
+ ).decode('utf-8')
+ request.headers['Authorization'] = 'Basic %s' % (
+ base64.b64encode(inputs.encode('utf-8')).decode('latin-1')
+ )
+ fn = self._get_func()
+ self.assertEqual(
+ fn(request),
+ (
+ b'm\xc3\xb6rk\xc3\xb6'.decode('utf-8'),
+ b'm\xc3\xb6rk\xc3\xb6password'.decode('utf-8'),
+ ),
+ )
+
+ def test_namedtuple_return(self):
+ import base64
+
+ request = testing.DummyRequest()
+ request.headers['Authorization'] = 'Basic %s' % base64.b64encode(
+ bytes_('chrisr:pass')
+ ).decode('ascii')
+ fn = self._get_func()
+ result = fn(request)
+
+ self.assertEqual(result.username, 'chrisr')
+ self.assertEqual(result.password, 'pass')
+
+
+class DummyContext:
+ pass
+
+
+class DummyCookies(object):
+ def __init__(self, cookie):
+ self.cookie = cookie
+
+ def get(self, name):
+ return self.cookie
+
+
+class DummyRequest:
+ domain = 'localhost'
+
+ def __init__(self, environ=None, session=None, registry=None, cookie=None):
+ self.environ = environ or {}
+ self.session = session or {}
+ self.registry = registry
+ self.callbacks = []
+ self.cookies = DummyCookies(cookie)
+
+ def add_response_callback(self, callback):
+ self.callbacks.append(callback)
+
+
+class DummyWhoPlugin:
+ def remember(self, environ, identity):
+ return environ, identity
+
+ def forget(self, environ, identity):
+ return environ, identity
+
+
+class DummyCookieHelper:
+ def __init__(self, result):
+ self.result = result
+
+ def identify(self, *arg, **kw):
+ return self.result
+
+ def remember(self, *arg, **kw):
+ self.kw = kw
+ return []
+
+ def forget(self, *arg):
+ return []
+
+
+class DummyAuthTktModule(object):
+ def __init__(
+ self,
+ timestamp=0,
+ userid='userid',
+ tokens=(),
+ user_data='',
+ parse_raise=False,
+ hashalg="md5",
+ ):
+ self.timestamp = timestamp
+ self.userid = userid
+ self.tokens = tokens
+ self.user_data = user_data
+ self.parse_raise = parse_raise
+ self.hashalg = hashalg
+
+ def parse_ticket(secret, value, remote_addr, hashalg):
+ self.secret = secret
+ self.value = value
+ self.remote_addr = remote_addr
+ if self.parse_raise:
+ raise self.BadTicket()
+ return self.timestamp, self.userid, self.tokens, self.user_data
+
+ self.parse_ticket = parse_ticket
+
+ class AuthTicket(object):
+ def __init__(self, secret, userid, remote_addr, **kw):
+ self.secret = secret
+ self.userid = userid
+ self.remote_addr = remote_addr
+ self.kw = kw
+
+ def cookie_value(self):
+ result = {
+ 'secret': self.secret,
+ 'userid': self.userid,
+ 'remote_addr': self.remote_addr,
+ }
+ result.update(self.kw)
+ tokens = result.pop('tokens', None)
+ if tokens is not None:
+ tokens = '|'.join(tokens)
+ result['tokens'] = tokens
+ items = sorted(result.items())
+ new_items = []
+ for k, v in items:
+ if isinstance(v, bytes):
+ v = text_(v)
+ new_items.append((k, v))
+ result = '/'.join(['%s=%s' % (k, v) for k, v in new_items])
+ return result
+
+ self.AuthTicket = AuthTicket
+
+ class BadTicket(Exception):
+ pass
+
+
+class DummyResponse:
+ def __init__(self):
+ self.headerlist = []
diff --git a/tests/test_authorization.py b/tests/test_authorization.py
new file mode 100644
index 000000000..efb84b203
--- /dev/null
+++ b/tests/test_authorization.py
@@ -0,0 +1,291 @@
+import unittest
+
+from pyramid.testing import cleanUp
+
+
+class TestACLAuthorizationPolicy(unittest.TestCase):
+ def setUp(self):
+ cleanUp()
+
+ def tearDown(self):
+ cleanUp()
+
+ def _getTargetClass(self):
+ from pyramid.authorization import ACLAuthorizationPolicy
+
+ return ACLAuthorizationPolicy
+
+ def _makeOne(self):
+ return self._getTargetClass()()
+
+ def test_class_implements_IAuthorizationPolicy(self):
+ from zope.interface.verify import verifyClass
+ from pyramid.interfaces import IAuthorizationPolicy
+
+ verifyClass(IAuthorizationPolicy, self._getTargetClass())
+
+ def test_instance_implements_IAuthorizationPolicy(self):
+ from zope.interface.verify import verifyObject
+ from pyramid.interfaces import IAuthorizationPolicy
+
+ verifyObject(IAuthorizationPolicy, self._makeOne())
+
+ def test_permits_no_acl(self):
+ context = DummyContext()
+ policy = self._makeOne()
+ self.assertEqual(policy.permits(context, [], 'view'), False)
+
+ def test_permits(self):
+ from pyramid.security import Deny
+ from pyramid.security import Allow
+ from pyramid.security import Everyone
+ from pyramid.security import Authenticated
+ from pyramid.security import ALL_PERMISSIONS
+ from pyramid.security import DENY_ALL
+
+ root = DummyContext()
+ community = DummyContext(__name__='community', __parent__=root)
+ blog = DummyContext(__name__='blog', __parent__=community)
+ root.__acl__ = [(Allow, Authenticated, VIEW)]
+ community.__acl__ = [
+ (Allow, 'fred', ALL_PERMISSIONS),
+ (Allow, 'wilma', VIEW),
+ DENY_ALL,
+ ]
+ blog.__acl__ = [
+ (Allow, 'barney', MEMBER_PERMS),
+ (Allow, 'wilma', VIEW),
+ ]
+
+ policy = self._makeOne()
+
+ result = policy.permits(
+ blog, [Everyone, Authenticated, 'wilma'], 'view'
+ )
+ self.assertEqual(result, True)
+ self.assertEqual(result.context, blog)
+ self.assertEqual(result.ace, (Allow, 'wilma', VIEW))
+ self.assertEqual(result.acl, blog.__acl__)
+
+ result = policy.permits(
+ blog, [Everyone, Authenticated, 'wilma'], 'delete'
+ )
+ self.assertEqual(result, False)
+ self.assertEqual(result.context, community)
+ self.assertEqual(result.ace, (Deny, Everyone, ALL_PERMISSIONS))
+ self.assertEqual(result.acl, community.__acl__)
+
+ result = policy.permits(
+ blog, [Everyone, Authenticated, 'fred'], 'view'
+ )
+ self.assertEqual(result, True)
+ self.assertEqual(result.context, community)
+ self.assertEqual(result.ace, (Allow, 'fred', ALL_PERMISSIONS))
+ result = policy.permits(
+ blog, [Everyone, Authenticated, 'fred'], 'doesntevenexistyet'
+ )
+ self.assertEqual(result, True)
+ self.assertEqual(result.context, community)
+ self.assertEqual(result.ace, (Allow, 'fred', ALL_PERMISSIONS))
+ self.assertEqual(result.acl, community.__acl__)
+
+ result = policy.permits(
+ blog, [Everyone, Authenticated, 'barney'], 'view'
+ )
+ self.assertEqual(result, True)
+ self.assertEqual(result.context, blog)
+ self.assertEqual(result.ace, (Allow, 'barney', MEMBER_PERMS))
+ result = policy.permits(
+ blog, [Everyone, Authenticated, 'barney'], 'administer'
+ )
+ self.assertEqual(result, False)
+ self.assertEqual(result.context, community)
+ self.assertEqual(result.ace, (Deny, Everyone, ALL_PERMISSIONS))
+ self.assertEqual(result.acl, community.__acl__)
+
+ result = policy.permits(
+ root, [Everyone, Authenticated, 'someguy'], 'view'
+ )
+ self.assertEqual(result, True)
+ self.assertEqual(result.context, root)
+ self.assertEqual(result.ace, (Allow, Authenticated, VIEW))
+ result = policy.permits(
+ blog, [Everyone, Authenticated, 'someguy'], 'view'
+ )
+ self.assertEqual(result, False)
+ self.assertEqual(result.context, community)
+ self.assertEqual(result.ace, (Deny, Everyone, ALL_PERMISSIONS))
+ self.assertEqual(result.acl, community.__acl__)
+
+ result = policy.permits(root, [Everyone], 'view')
+ self.assertEqual(result, False)
+ self.assertEqual(result.context, root)
+ self.assertEqual(result.ace, '<default deny>')
+ self.assertEqual(result.acl, root.__acl__)
+
+ context = DummyContext()
+ result = policy.permits(context, [Everyone], 'view')
+ self.assertEqual(result, False)
+ self.assertEqual(result.ace, '<default deny>')
+ self.assertEqual(
+ result.acl, '<No ACL found on any object in resource lineage>'
+ )
+
+ def test_permits_string_permissions_in_acl(self):
+ from pyramid.security import Allow
+
+ root = DummyContext()
+ root.__acl__ = [(Allow, 'wilma', 'view_stuff')]
+
+ policy = self._makeOne()
+
+ result = policy.permits(root, ['wilma'], 'view')
+ # would be True if matching against 'view_stuff' instead of against
+ # ['view_stuff']
+ self.assertEqual(result, False)
+
+ def test_principals_allowed_by_permission_direct(self):
+ from pyramid.security import Allow
+ from pyramid.security import DENY_ALL
+
+ context = DummyContext()
+ acl = [
+ (Allow, 'chrism', ('read', 'write')),
+ DENY_ALL,
+ (Allow, 'other', 'read'),
+ ]
+ context.__acl__ = acl
+ policy = self._makeOne()
+ result = sorted(
+ policy.principals_allowed_by_permission(context, 'read')
+ )
+ self.assertEqual(result, ['chrism'])
+
+ def test_principals_allowed_by_permission_callable_acl(self):
+ from pyramid.security import Allow
+ from pyramid.security import DENY_ALL
+
+ context = DummyContext()
+ acl = lambda: [
+ (Allow, 'chrism', ('read', 'write')),
+ DENY_ALL,
+ (Allow, 'other', 'read'),
+ ]
+ context.__acl__ = acl
+ policy = self._makeOne()
+ result = sorted(
+ policy.principals_allowed_by_permission(context, 'read')
+ )
+ self.assertEqual(result, ['chrism'])
+
+ def test_principals_allowed_by_permission_string_permission(self):
+ from pyramid.security import Allow
+
+ context = DummyContext()
+ acl = [(Allow, 'chrism', 'read_it')]
+ context.__acl__ = acl
+ policy = self._makeOne()
+ result = policy.principals_allowed_by_permission(context, 'read')
+ # would be ['chrism'] if 'read' were compared against 'read_it' instead
+ # of against ['read_it']
+ self.assertEqual(list(result), [])
+
+ def test_principals_allowed_by_permission(self):
+ from pyramid.security import Allow
+ from pyramid.security import Deny
+ from pyramid.security import DENY_ALL
+ from pyramid.security import ALL_PERMISSIONS
+
+ root = DummyContext(__name__='', __parent__=None)
+ community = DummyContext(__name__='community', __parent__=root)
+ blog = DummyContext(__name__='blog', __parent__=community)
+ root.__acl__ = [
+ (Allow, 'chrism', ('read', 'write')),
+ (Allow, 'other', ('read',)),
+ (Allow, 'jim', ALL_PERMISSIONS),
+ ]
+ community.__acl__ = [
+ (Deny, 'flooz', 'read'),
+ (Allow, 'flooz', 'read'),
+ (Allow, 'mork', 'read'),
+ (Deny, 'jim', 'read'),
+ (Allow, 'someguy', 'manage'),
+ ]
+ blog.__acl__ = [(Allow, 'fred', 'read'), DENY_ALL]
+
+ policy = self._makeOne()
+
+ result = sorted(policy.principals_allowed_by_permission(blog, 'read'))
+ self.assertEqual(result, ['fred'])
+ result = sorted(
+ policy.principals_allowed_by_permission(community, 'read')
+ )
+ self.assertEqual(result, ['chrism', 'mork', 'other'])
+ result = sorted(
+ policy.principals_allowed_by_permission(community, 'read')
+ )
+ result = sorted(policy.principals_allowed_by_permission(root, 'read'))
+ self.assertEqual(result, ['chrism', 'jim', 'other'])
+
+ def test_principals_allowed_by_permission_no_acls(self):
+ context = DummyContext()
+ policy = self._makeOne()
+ result = sorted(
+ policy.principals_allowed_by_permission(context, 'read')
+ )
+ self.assertEqual(result, [])
+
+ def test_principals_allowed_by_permission_deny_not_permission_in_acl(self):
+ from pyramid.security import Deny
+ from pyramid.security import Everyone
+
+ context = DummyContext()
+ acl = [(Deny, Everyone, 'write')]
+ context.__acl__ = acl
+ policy = self._makeOne()
+ result = sorted(
+ policy.principals_allowed_by_permission(context, 'read')
+ )
+ self.assertEqual(result, [])
+
+ def test_principals_allowed_by_permission_deny_permission_in_acl(self):
+ from pyramid.security import Deny
+ from pyramid.security import Everyone
+
+ context = DummyContext()
+ acl = [(Deny, Everyone, 'read')]
+ context.__acl__ = acl
+ policy = self._makeOne()
+ result = sorted(
+ policy.principals_allowed_by_permission(context, 'read')
+ )
+ self.assertEqual(result, [])
+
+ def test_callable_acl(self):
+ from pyramid.security import Allow
+
+ context = DummyContext()
+ fn = lambda self: [(Allow, 'bob', 'read')]
+ context.__acl__ = fn.__get__(context, context.__class__)
+ policy = self._makeOne()
+ result = policy.permits(context, ['bob'], 'read')
+ self.assertTrue(result)
+
+
+class DummyContext:
+ def __init__(self, *arg, **kw):
+ self.__dict__.update(kw)
+
+
+VIEW = 'view'
+EDIT = 'edit'
+CREATE = 'create'
+DELETE = 'delete'
+MODERATE = 'moderate'
+ADMINISTER = 'administer'
+COMMENT = 'comment'
+
+GUEST_PERMS = (VIEW, COMMENT)
+MEMBER_PERMS = GUEST_PERMS + (EDIT, CREATE, DELETE)
+MODERATOR_PERMS = MEMBER_PERMS + (MODERATE,)
+ADMINISTRATOR_PERMS = MODERATOR_PERMS + (ADMINISTER,)
diff --git a/tests/test_compat.py b/tests/test_compat.py
new file mode 100644
index 000000000..4a14caedf
--- /dev/null
+++ b/tests/test_compat.py
@@ -0,0 +1,32 @@
+import unittest
+from pyramid.compat import is_unbound_method
+
+
+class TestUnboundMethods(unittest.TestCase):
+ def test_old_style_bound(self):
+ self.assertFalse(is_unbound_method(OldStyle().run))
+
+ def test_new_style_bound(self):
+ self.assertFalse(is_unbound_method(NewStyle().run))
+
+ def test_old_style_unbound(self):
+ self.assertTrue(is_unbound_method(OldStyle.run))
+
+ def test_new_style_unbound(self):
+ self.assertTrue(is_unbound_method(NewStyle.run))
+
+ def test_normal_func_unbound(self):
+ def func(): # pragma: no cover
+ return 'OK'
+
+ self.assertFalse(is_unbound_method(func))
+
+
+class OldStyle:
+ def run(self): # pragma: no cover
+ return 'OK'
+
+
+class NewStyle(object):
+ def run(self): # pragma: no cover
+ return 'OK'
diff --git a/tests/test_config/__init__.py b/tests/test_config/__init__.py
new file mode 100644
index 000000000..ac1f19667
--- /dev/null
+++ b/tests/test_config/__init__.py
@@ -0,0 +1,70 @@
+# package
+from functools import partial
+from zope.interface import implementer
+from zope.interface import Interface
+
+
+class IFactory(Interface):
+ pass
+
+
+def dummy_tween_factory(handler, registry): # pragma: no cover
+ pass
+
+
+def dummy_tween_factory2(handler, registry): # pragma: no cover
+ pass
+
+
+def dummy_include(config):
+ config.registry.included = True
+ config.action('discrim', None, config.package)
+
+
+def dummy_include2(config):
+ config.registry.also_included = True
+ config.action('discrim', None, config.package)
+
+
+includeme = dummy_include
+
+
+class DummyContext:
+ pass
+
+
+@implementer(IFactory)
+class DummyFactory(object):
+ def __call__(self):
+ """ """
+
+
+def dummyfactory(request):
+ """ """
+
+
+class IDummy(Interface):
+ pass
+
+
+def dummy_view(request):
+ return 'OK'
+
+
+def dummy_extend(config, discrim):
+ config.action(discrim, None, config.package)
+
+
+def dummy_extend2(config, discrim):
+ config.action(discrim, None, config.registry)
+
+
+dummy_partial = partial(dummy_extend, discrim='partial')
+
+
+class DummyCallable(object):
+ def __call__(self, config, discrim):
+ config.action(discrim, None, config.package)
+
+
+dummy_callable = DummyCallable()
diff --git a/tests/test_config/files/assets/dummy.txt b/tests/test_config/files/assets/dummy.txt
new file mode 100644
index 000000000..18832d351
--- /dev/null
+++ b/tests/test_config/files/assets/dummy.txt
@@ -0,0 +1 @@
+Hello.
diff --git a/tests/test_config/files/minimal.txt b/tests/test_config/files/minimal.txt
new file mode 100644
index 000000000..19fe66dfa
--- /dev/null
+++ b/tests/test_config/files/minimal.txt
@@ -0,0 +1 @@
+<div clas="header"></div>
diff --git a/tests/test_config/path/scanerror/__init__.py b/tests/test_config/path/scanerror/__init__.py
new file mode 100644
index 000000000..934d6d3ad
--- /dev/null
+++ b/tests/test_config/path/scanerror/__init__.py
@@ -0,0 +1 @@
+# scan error package
diff --git a/tests/test_config/path/scanerror/will_raise_error.py b/tests/test_config/path/scanerror/will_raise_error.py
new file mode 100644
index 000000000..9098ff1fe
--- /dev/null
+++ b/tests/test_config/path/scanerror/will_raise_error.py
@@ -0,0 +1 @@
+import wont.exist
diff --git a/tests/test_config/pkgs/__init__.py b/tests/test_config/pkgs/__init__.py
new file mode 100644
index 000000000..5bb534f79
--- /dev/null
+++ b/tests/test_config/pkgs/__init__.py
@@ -0,0 +1 @@
+# package
diff --git a/tests/test_config/pkgs/asset/__init__.py b/tests/test_config/pkgs/asset/__init__.py
new file mode 100644
index 000000000..5bb534f79
--- /dev/null
+++ b/tests/test_config/pkgs/asset/__init__.py
@@ -0,0 +1 @@
+# package
diff --git a/tests/test_config/pkgs/asset/subpackage/__init__.py b/tests/test_config/pkgs/asset/subpackage/__init__.py
new file mode 100644
index 000000000..5bb534f79
--- /dev/null
+++ b/tests/test_config/pkgs/asset/subpackage/__init__.py
@@ -0,0 +1 @@
+# package
diff --git a/tests/test_config/pkgs/asset/subpackage/templates/bar.pt b/tests/test_config/pkgs/asset/subpackage/templates/bar.pt
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/test_config/pkgs/asset/subpackage/templates/bar.pt
diff --git a/tests/test_config/pkgs/scanextrakw/__init__.py b/tests/test_config/pkgs/scanextrakw/__init__.py
new file mode 100644
index 000000000..ddda504e1
--- /dev/null
+++ b/tests/test_config/pkgs/scanextrakw/__init__.py
@@ -0,0 +1,17 @@
+import venusian
+
+
+def foo(wrapped):
+ def bar(scanner, name, wrapped):
+ scanner.config.a = scanner.a
+
+ venusian.attach(wrapped, bar)
+ return wrapped
+
+
+@foo
+def hello():
+ pass
+
+
+hello() # appease coverage
diff --git a/tests/test_config/pkgs/scannable/__init__.py b/tests/test_config/pkgs/scannable/__init__.py
new file mode 100644
index 000000000..585f4357b
--- /dev/null
+++ b/tests/test_config/pkgs/scannable/__init__.py
@@ -0,0 +1,117 @@
+from pyramid.view import view_config
+from pyramid.renderers import null_renderer
+
+
+@view_config(renderer=null_renderer)
+def grokked(context, request):
+ return 'grokked'
+
+
+@view_config(request_method='POST', renderer=null_renderer)
+def grokked_post(context, request):
+ return 'grokked_post'
+
+
+@view_config(name='stacked2', renderer=null_renderer)
+@view_config(name='stacked1', renderer=null_renderer)
+def stacked(context, request):
+ return 'stacked'
+
+
+class stacked_class(object):
+ def __init__(self, context, request):
+ self.context = context
+ self.request = request
+
+ def __call__(self):
+ return 'stacked_class'
+
+
+stacked_class = view_config(name='stacked_class1', renderer=null_renderer)(
+ stacked_class
+)
+stacked_class = view_config(name='stacked_class2', renderer=null_renderer)(
+ stacked_class
+)
+
+
+class oldstyle_grokked_class:
+ def __init__(self, context, request):
+ self.context = context
+ self.request = request
+
+ def __call__(self):
+ return 'oldstyle_grokked_class'
+
+
+oldstyle_grokked_class = view_config(
+ name='oldstyle_grokked_class', renderer=null_renderer
+)(oldstyle_grokked_class)
+
+
+class grokked_class(object):
+ def __init__(self, context, request):
+ self.context = context
+ self.request = request
+
+ def __call__(self):
+ return 'grokked_class'
+
+
+grokked_class = view_config(name='grokked_class', renderer=null_renderer)(
+ grokked_class
+)
+
+
+class Foo(object):
+ def __call__(self, context, request):
+ return 'grokked_instance'
+
+
+grokked_instance = Foo()
+grokked_instance = view_config(
+ name='grokked_instance', renderer=null_renderer
+)(grokked_instance)
+
+
+class Base(object):
+ @view_config(name='basemethod', renderer=null_renderer)
+ def basemethod(self):
+ """ """
+
+
+class MethodViews(Base):
+ def __init__(self, context, request):
+ self.context = context
+ self.request = request
+
+ @view_config(name='method1', renderer=null_renderer)
+ def method1(self):
+ return 'method1'
+
+ @view_config(name='method2', renderer=null_renderer)
+ def method2(self):
+ return 'method2'
+
+ @view_config(name='stacked_method2', renderer=null_renderer)
+ @view_config(name='stacked_method1', renderer=null_renderer)
+ def stacked(self):
+ return 'stacked_method'
+
+
+# ungrokkable
+
+A = 1
+B = {}
+
+
+def stuff():
+ """ """
+
+
+class Whatever(object):
+ pass
+
+
+class Whatever2:
+ pass
diff --git a/tests/test_config/pkgs/scannable/another.py b/tests/test_config/pkgs/scannable/another.py
new file mode 100644
index 000000000..e8b71e5e3
--- /dev/null
+++ b/tests/test_config/pkgs/scannable/another.py
@@ -0,0 +1,83 @@
+from pyramid.view import view_config
+from pyramid.renderers import null_renderer
+
+
+@view_config(name='another', renderer=null_renderer)
+def grokked(context, request):
+ return 'another_grokked'
+
+
+@view_config(request_method='POST', name='another', renderer=null_renderer)
+def grokked_post(context, request):
+ return 'another_grokked_post'
+
+
+@view_config(name='another_stacked2', renderer=null_renderer)
+@view_config(name='another_stacked1', renderer=null_renderer)
+def stacked(context, request):
+ return 'another_stacked'
+
+
+class stacked_class(object):
+ def __init__(self, context, request):
+ self.context = context
+ self.request = request
+
+ def __call__(self):
+ return 'another_stacked_class'
+
+
+stacked_class = view_config(
+ name='another_stacked_class1', renderer=null_renderer
+)(stacked_class)
+stacked_class = view_config(
+ name='another_stacked_class2', renderer=null_renderer
+)(stacked_class)
+
+
+class oldstyle_grokked_class:
+ def __init__(self, context, request):
+ self.context = context
+ self.request = request
+
+ def __call__(self):
+ return 'another_oldstyle_grokked_class'
+
+
+oldstyle_grokked_class = view_config(
+ name='another_oldstyle_grokked_class', renderer=null_renderer
+)(oldstyle_grokked_class)
+
+
+class grokked_class(object):
+ def __init__(self, context, request):
+ self.context = context
+ self.request = request
+
+ def __call__(self):
+ return 'another_grokked_class'
+
+
+grokked_class = view_config(
+ name='another_grokked_class', renderer=null_renderer
+)(grokked_class)
+
+
+class Foo(object):
+ def __call__(self, context, request):
+ return 'another_grokked_instance'
+
+
+grokked_instance = Foo()
+grokked_instance = view_config(
+ name='another_grokked_instance', renderer=null_renderer
+)(grokked_instance)
+
+# ungrokkable
+
+A = 1
+B = {}
+
+
+def stuff():
+ """ """
diff --git a/tests/test_config/pkgs/scannable/pod/notinit.py b/tests/test_config/pkgs/scannable/pod/notinit.py
new file mode 100644
index 000000000..03c93857f
--- /dev/null
+++ b/tests/test_config/pkgs/scannable/pod/notinit.py
@@ -0,0 +1,7 @@
+from pyramid.view import view_config
+from pyramid.renderers import null_renderer
+
+
+@view_config(name='pod_notinit', renderer=null_renderer)
+def subpackage_notinit(context, request):
+ return 'pod_notinit'
diff --git a/tests/test_config/pkgs/scannable/subpackage/__init__.py b/tests/test_config/pkgs/scannable/subpackage/__init__.py
new file mode 100644
index 000000000..f89ca33f7
--- /dev/null
+++ b/tests/test_config/pkgs/scannable/subpackage/__init__.py
@@ -0,0 +1,7 @@
+from pyramid.view import view_config
+from pyramid.renderers import null_renderer
+
+
+@view_config(name='subpackage_init', renderer=null_renderer)
+def subpackage_init(context, request):
+ return 'subpackage_init'
diff --git a/tests/test_config/pkgs/scannable/subpackage/notinit.py b/tests/test_config/pkgs/scannable/subpackage/notinit.py
new file mode 100644
index 000000000..65c2a4929
--- /dev/null
+++ b/tests/test_config/pkgs/scannable/subpackage/notinit.py
@@ -0,0 +1,7 @@
+from pyramid.view import view_config
+from pyramid.renderers import null_renderer
+
+
+@view_config(name='subpackage_notinit', renderer=null_renderer)
+def subpackage_notinit(context, request):
+ return 'subpackage_notinit'
diff --git a/tests/test_config/pkgs/scannable/subpackage/subsubpackage/__init__.py b/tests/test_config/pkgs/scannable/subpackage/subsubpackage/__init__.py
new file mode 100644
index 000000000..ec4bab818
--- /dev/null
+++ b/tests/test_config/pkgs/scannable/subpackage/subsubpackage/__init__.py
@@ -0,0 +1,7 @@
+from pyramid.view import view_config
+from pyramid.renderers import null_renderer
+
+
+@view_config(name='subsubpackage_init', renderer=null_renderer)
+def subpackage_init(context, request):
+ return 'subsubpackage_init'
diff --git a/tests/test_config/pkgs/selfscan/__init__.py b/tests/test_config/pkgs/selfscan/__init__.py
new file mode 100644
index 000000000..8bc8761ca
--- /dev/null
+++ b/tests/test_config/pkgs/selfscan/__init__.py
@@ -0,0 +1,14 @@
+from pyramid.view import view_config
+
+
+@view_config(renderer='string')
+def abc(request):
+ return 'root'
+
+
+def main():
+ from pyramid.config import Configurator
+
+ c = Configurator()
+ c.scan()
+ return c
diff --git a/tests/test_config/pkgs/selfscan/another.py b/tests/test_config/pkgs/selfscan/another.py
new file mode 100644
index 000000000..79e0b08de
--- /dev/null
+++ b/tests/test_config/pkgs/selfscan/another.py
@@ -0,0 +1,6 @@
+from pyramid.view import view_config
+
+
+@view_config(name='two', renderer='string')
+def two(request):
+ return 'two'
diff --git a/tests/test_config/test_actions.py b/tests/test_config/test_actions.py
new file mode 100644
index 000000000..a72d0d7b1
--- /dev/null
+++ b/tests/test_config/test_actions.py
@@ -0,0 +1,1090 @@
+import unittest
+
+from pyramid.exceptions import ConfigurationConflictError
+from pyramid.exceptions import ConfigurationExecutionError
+
+from pyramid.interfaces import IRequest
+
+
+class ActionConfiguratorMixinTests(unittest.TestCase):
+ def _makeOne(self, *arg, **kw):
+ from pyramid.config import Configurator
+
+ config = Configurator(*arg, **kw)
+ return config
+
+ def _getViewCallable(
+ self,
+ config,
+ ctx_iface=None,
+ request_iface=None,
+ name='',
+ exception_view=False,
+ ):
+ from zope.interface import Interface
+ from pyramid.interfaces import IView
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IExceptionViewClassifier
+
+ if exception_view: # pragma: no cover
+ classifier = IExceptionViewClassifier
+ else:
+ classifier = IViewClassifier
+ if ctx_iface is None:
+ ctx_iface = Interface
+ if request_iface is None:
+ request_iface = IRequest
+ return config.registry.adapters.lookup(
+ (classifier, request_iface, ctx_iface),
+ IView,
+ name=name,
+ default=None,
+ )
+
+ def test_action_branching_kw_is_None(self):
+ config = self._makeOne(autocommit=True)
+ self.assertEqual(config.action('discrim'), None)
+
+ def test_action_branching_kw_is_not_None(self):
+ config = self._makeOne(autocommit=True)
+ self.assertEqual(config.action('discrim', kw={'a': 1}), None)
+
+ def test_action_autocommit_with_introspectables(self):
+ from pyramid.config.actions import ActionInfo
+
+ config = self._makeOne(autocommit=True)
+ intr = DummyIntrospectable()
+ config.action('discrim', introspectables=(intr,))
+ self.assertEqual(len(intr.registered), 1)
+ self.assertEqual(intr.registered[0][0], config.introspector)
+ self.assertEqual(intr.registered[0][1].__class__, ActionInfo)
+
+ def test_action_autocommit_with_introspectables_introspection_off(self):
+ config = self._makeOne(autocommit=True)
+ config.introspection = False
+ intr = DummyIntrospectable()
+ config.action('discrim', introspectables=(intr,))
+ self.assertEqual(len(intr.registered), 0)
+
+ def test_action_branching_nonautocommit_with_config_info(self):
+ config = self._makeOne(autocommit=False)
+ config.info = 'abc'
+ state = DummyActionState()
+ state.autocommit = False
+ config.action_state = state
+ config.action('discrim', kw={'a': 1})
+ self.assertEqual(
+ state.actions,
+ [
+ (
+ (),
+ {
+ 'args': (),
+ 'callable': None,
+ 'discriminator': 'discrim',
+ 'includepath': (),
+ 'info': 'abc',
+ 'introspectables': (),
+ 'kw': {'a': 1},
+ 'order': 0,
+ },
+ )
+ ],
+ )
+
+ def test_action_branching_nonautocommit_without_config_info(self):
+ config = self._makeOne(autocommit=False)
+ config.info = ''
+ config._ainfo = ['z']
+ state = DummyActionState()
+ config.action_state = state
+ state.autocommit = False
+ config.action('discrim', kw={'a': 1})
+ self.assertEqual(
+ state.actions,
+ [
+ (
+ (),
+ {
+ 'args': (),
+ 'callable': None,
+ 'discriminator': 'discrim',
+ 'includepath': (),
+ 'info': 'z',
+ 'introspectables': (),
+ 'kw': {'a': 1},
+ 'order': 0,
+ },
+ )
+ ],
+ )
+
+ def test_action_branching_nonautocommit_with_introspectables(self):
+ config = self._makeOne(autocommit=False)
+ config.info = ''
+ config._ainfo = []
+ state = DummyActionState()
+ config.action_state = state
+ state.autocommit = False
+ intr = DummyIntrospectable()
+ config.action('discrim', introspectables=(intr,))
+ self.assertEqual(state.actions[0][1]['introspectables'], (intr,))
+
+ def test_action_nonautocommit_with_introspectables_introspection_off(self):
+ config = self._makeOne(autocommit=False)
+ config.info = ''
+ config._ainfo = []
+ config.introspection = False
+ state = DummyActionState()
+ config.action_state = state
+ state.autocommit = False
+ intr = DummyIntrospectable()
+ config.action('discrim', introspectables=(intr,))
+ self.assertEqual(state.actions[0][1]['introspectables'], ())
+
+ def test_commit_conflict_simple(self):
+ config = self._makeOne()
+
+ def view1(request): # pragma: no cover
+ pass
+
+ def view2(request): # pragma: no cover
+ pass
+
+ config.add_view(view1)
+ config.add_view(view2)
+ self.assertRaises(ConfigurationConflictError, config.commit)
+
+ def test_commit_conflict_resolved_with_include(self):
+ config = self._makeOne()
+
+ def view1(request): # pragma: no cover
+ pass
+
+ def view2(request): # pragma: no cover
+ pass
+
+ def includeme(config):
+ config.add_view(view2)
+
+ config.add_view(view1)
+ config.include(includeme)
+ config.commit()
+ registeredview = self._getViewCallable(config)
+ self.assertEqual(registeredview.__name__, 'view1')
+
+ def test_commit_conflict_with_two_includes(self):
+ config = self._makeOne()
+
+ def view1(request): # pragma: no cover
+ pass
+
+ def view2(request): # pragma: no cover
+ pass
+
+ def includeme1(config):
+ config.add_view(view1)
+
+ def includeme2(config):
+ config.add_view(view2)
+
+ config.include(includeme1)
+ config.include(includeme2)
+ try:
+ config.commit()
+ except ConfigurationConflictError as why:
+ c1, c2 = _conflictFunctions(why)
+ self.assertEqual(c1, 'includeme1')
+ self.assertEqual(c2, 'includeme2')
+ else: # pragma: no cover
+ raise AssertionError
+
+ def test_commit_conflict_resolved_with_two_includes_and_local(self):
+ config = self._makeOne()
+
+ def view1(request): # pragma: no cover
+ pass
+
+ def view2(request): # pragma: no cover
+ pass
+
+ def view3(request): # pragma: no cover
+ pass
+
+ def includeme1(config):
+ config.add_view(view1)
+
+ def includeme2(config):
+ config.add_view(view2)
+
+ config.include(includeme1)
+ config.include(includeme2)
+ config.add_view(view3)
+ config.commit()
+ registeredview = self._getViewCallable(config)
+ self.assertEqual(registeredview.__name__, 'view3')
+
+ def test_autocommit_no_conflicts(self):
+ from pyramid.renderers import null_renderer
+
+ config = self._makeOne(autocommit=True)
+
+ def view1(request): # pragma: no cover
+ pass
+
+ def view2(request): # pragma: no cover
+ pass
+
+ def view3(request): # pragma: no cover
+ pass
+
+ config.add_view(view1, renderer=null_renderer)
+ config.add_view(view2, renderer=null_renderer)
+ config.add_view(view3, renderer=null_renderer)
+ config.commit()
+ registeredview = self._getViewCallable(config)
+ self.assertEqual(registeredview.__name__, 'view3')
+
+ def test_conflict_set_notfound_view(self):
+ config = self._makeOne()
+
+ def view1(request): # pragma: no cover
+ pass
+
+ def view2(request): # pragma: no cover
+ pass
+
+ config.set_notfound_view(view1)
+ config.set_notfound_view(view2)
+ try:
+ config.commit()
+ except ConfigurationConflictError as why:
+ c1, c2 = _conflictFunctions(why)
+ self.assertEqual(c1, 'test_conflict_set_notfound_view')
+ self.assertEqual(c2, 'test_conflict_set_notfound_view')
+ else: # pragma: no cover
+ raise AssertionError
+
+ def test_conflict_set_forbidden_view(self):
+ config = self._makeOne()
+
+ def view1(request): # pragma: no cover
+ pass
+
+ def view2(request): # pragma: no cover
+ pass
+
+ config.set_forbidden_view(view1)
+ config.set_forbidden_view(view2)
+ try:
+ config.commit()
+ except ConfigurationConflictError as why:
+ c1, c2 = _conflictFunctions(why)
+ self.assertEqual(c1, 'test_conflict_set_forbidden_view')
+ self.assertEqual(c2, 'test_conflict_set_forbidden_view')
+ else: # pragma: no cover
+ raise AssertionError
+
+
+class TestActionState(unittest.TestCase):
+ def _makeOne(self):
+ from pyramid.config.actions import ActionState
+
+ return ActionState()
+
+ def test_it(self):
+ c = self._makeOne()
+ self.assertEqual(c.actions, [])
+
+ def test_action_simple(self):
+ from . import dummyfactory as f
+
+ c = self._makeOne()
+ c.actions = []
+ c.action(1, f, (1,), {'x': 1})
+ self.assertEqual(
+ c.actions,
+ [
+ {
+ 'args': (1,),
+ 'callable': f,
+ 'discriminator': 1,
+ 'includepath': (),
+ 'info': None,
+ 'introspectables': (),
+ 'kw': {'x': 1},
+ 'order': 0,
+ }
+ ],
+ )
+ c.action(None)
+ self.assertEqual(
+ c.actions,
+ [
+ {
+ 'args': (1,),
+ 'callable': f,
+ 'discriminator': 1,
+ 'includepath': (),
+ 'info': None,
+ 'introspectables': (),
+ 'kw': {'x': 1},
+ 'order': 0,
+ },
+ {
+ 'args': (),
+ 'callable': None,
+ 'discriminator': None,
+ 'includepath': (),
+ 'info': None,
+ 'introspectables': (),
+ 'kw': {},
+ 'order': 0,
+ },
+ ],
+ )
+
+ def test_action_with_includepath(self):
+ c = self._makeOne()
+ c.actions = []
+ c.action(None, includepath=('abc',))
+ self.assertEqual(
+ c.actions,
+ [
+ {
+ 'args': (),
+ 'callable': None,
+ 'discriminator': None,
+ 'includepath': ('abc',),
+ 'info': None,
+ 'introspectables': (),
+ 'kw': {},
+ 'order': 0,
+ }
+ ],
+ )
+
+ def test_action_with_info(self):
+ c = self._makeOne()
+ c.action(None, info='abc')
+ self.assertEqual(
+ c.actions,
+ [
+ {
+ 'args': (),
+ 'callable': None,
+ 'discriminator': None,
+ 'includepath': (),
+ 'info': 'abc',
+ 'introspectables': (),
+ 'kw': {},
+ 'order': 0,
+ }
+ ],
+ )
+
+ def test_action_with_includepath_and_info(self):
+ c = self._makeOne()
+ c.action(None, includepath=('spec',), info='bleh')
+ self.assertEqual(
+ c.actions,
+ [
+ {
+ 'args': (),
+ 'callable': None,
+ 'discriminator': None,
+ 'includepath': ('spec',),
+ 'info': 'bleh',
+ 'introspectables': (),
+ 'kw': {},
+ 'order': 0,
+ }
+ ],
+ )
+
+ def test_action_with_order(self):
+ c = self._makeOne()
+ c.actions = []
+ c.action(None, order=99999)
+ self.assertEqual(
+ c.actions,
+ [
+ {
+ 'args': (),
+ 'callable': None,
+ 'discriminator': None,
+ 'includepath': (),
+ 'info': None,
+ 'introspectables': (),
+ 'kw': {},
+ 'order': 99999,
+ }
+ ],
+ )
+
+ def test_action_with_introspectables(self):
+ c = self._makeOne()
+ c.actions = []
+ intr = DummyIntrospectable()
+ c.action(None, introspectables=(intr,))
+ self.assertEqual(
+ c.actions,
+ [
+ {
+ 'args': (),
+ 'callable': None,
+ 'discriminator': None,
+ 'includepath': (),
+ 'info': None,
+ 'introspectables': (intr,),
+ 'kw': {},
+ 'order': 0,
+ }
+ ],
+ )
+
+ def test_processSpec(self):
+ c = self._makeOne()
+ self.assertTrue(c.processSpec('spec'))
+ self.assertFalse(c.processSpec('spec'))
+
+ def test_execute_actions_tuples(self):
+ output = []
+
+ def f(*a, **k):
+ output.append((a, k))
+
+ c = self._makeOne()
+ c.actions = [
+ (1, f, (1,)),
+ (1, f, (11,), {}, ('x',)),
+ (2, f, (2,)),
+ (None, None),
+ ]
+ c.execute_actions()
+ self.assertEqual(output, [((1,), {}), ((2,), {})])
+
+ def test_execute_actions_dicts(self):
+ output = []
+
+ def f(*a, **k):
+ output.append((a, k))
+
+ c = self._makeOne()
+ c.actions = [
+ {
+ 'discriminator': 1,
+ 'callable': f,
+ 'args': (1,),
+ 'kw': {},
+ 'order': 0,
+ 'includepath': (),
+ 'info': None,
+ 'introspectables': (),
+ },
+ {
+ 'discriminator': 1,
+ 'callable': f,
+ 'args': (11,),
+ 'kw': {},
+ 'includepath': ('x',),
+ 'order': 0,
+ 'info': None,
+ 'introspectables': (),
+ },
+ {
+ 'discriminator': 2,
+ 'callable': f,
+ 'args': (2,),
+ 'kw': {},
+ 'order': 0,
+ 'includepath': (),
+ 'info': None,
+ 'introspectables': (),
+ },
+ {
+ 'discriminator': None,
+ 'callable': None,
+ 'args': (),
+ 'kw': {},
+ 'order': 0,
+ 'includepath': (),
+ 'info': None,
+ 'introspectables': (),
+ },
+ ]
+ c.execute_actions()
+ self.assertEqual(output, [((1,), {}), ((2,), {})])
+
+ def test_execute_actions_with_introspectables(self):
+ output = []
+
+ def f(*a, **k):
+ output.append((a, k))
+
+ c = self._makeOne()
+ intr = DummyIntrospectable()
+ c.actions = [
+ {
+ 'discriminator': 1,
+ 'callable': f,
+ 'args': (1,),
+ 'kw': {},
+ 'order': 0,
+ 'includepath': (),
+ 'info': None,
+ 'introspectables': (intr,),
+ }
+ ]
+ introspector = object()
+ c.execute_actions(introspector=introspector)
+ self.assertEqual(output, [((1,), {})])
+ self.assertEqual(intr.registered, [(introspector, None)])
+
+ def test_execute_actions_with_introspectable_no_callable(self):
+ c = self._makeOne()
+ intr = DummyIntrospectable()
+ c.actions = [
+ {
+ 'discriminator': 1,
+ 'callable': None,
+ 'args': (1,),
+ 'kw': {},
+ 'order': 0,
+ 'includepath': (),
+ 'info': None,
+ 'introspectables': (intr,),
+ }
+ ]
+ introspector = object()
+ c.execute_actions(introspector=introspector)
+ self.assertEqual(intr.registered, [(introspector, None)])
+
+ def test_execute_actions_error(self):
+ output = []
+
+ def f(*a, **k):
+ output.append(('f', a, k))
+
+ def bad():
+ raise NotImplementedError
+
+ c = self._makeOne()
+ c.actions = [
+ (1, f, (1,)),
+ (1, f, (11,), {}, ('x',)),
+ (2, f, (2,)),
+ (3, bad, (), {}, (), 'oops'),
+ ]
+ self.assertRaises(ConfigurationExecutionError, c.execute_actions)
+ self.assertEqual(output, [('f', (1,), {}), ('f', (2,), {})])
+
+ def test_reentrant_action(self):
+ output = []
+ c = self._makeOne()
+
+ def f(*a, **k):
+ output.append(('f', a, k))
+ c.actions.append((3, g, (8,), {}))
+
+ def g(*a, **k):
+ output.append(('g', a, k))
+
+ c.actions = [(1, f, (1,))]
+ c.execute_actions()
+ self.assertEqual(output, [('f', (1,), {}), ('g', (8,), {})])
+
+ def test_reentrant_action_with_deferred_discriminator(self):
+ # see https://github.com/Pylons/pyramid/issues/2697
+ from pyramid.registry import Deferred
+
+ output = []
+ c = self._makeOne()
+
+ def f(*a, **k):
+ output.append(('f', a, k))
+ c.actions.append((4, g, (4,), {}, (), None, 2))
+
+ def g(*a, **k):
+ output.append(('g', a, k))
+
+ def h(*a, **k):
+ output.append(('h', a, k))
+
+ def discrim():
+ self.assertEqual(output, [('f', (1,), {}), ('g', (2,), {})])
+ return 3
+
+ d = Deferred(discrim)
+ c.actions = [
+ (d, h, (3,), {}, (), None, 1), # order 1
+ (1, f, (1,)), # order 0
+ (2, g, (2,)), # order 0
+ ]
+ c.execute_actions()
+ self.assertEqual(
+ output,
+ [
+ ('f', (1,), {}),
+ ('g', (2,), {}),
+ ('h', (3,), {}),
+ ('g', (4,), {}),
+ ],
+ )
+
+ def test_reentrant_action_error(self):
+ from pyramid.exceptions import ConfigurationError
+
+ c = self._makeOne()
+
+ def f(*a, **k):
+ c.actions.append((3, g, (8,), {}, (), None, -1))
+
+ def g(*a, **k): # pragma: no cover
+ pass
+
+ c.actions = [(1, f, (1,))]
+ self.assertRaises(ConfigurationError, c.execute_actions)
+
+ def test_reentrant_action_without_clear(self):
+ c = self._makeOne()
+
+ def f(*a, **k):
+ c.actions.append((3, g, (8,)))
+
+ def g(*a, **k):
+ pass
+
+ c.actions = [(1, f, (1,))]
+ c.execute_actions(clear=False)
+ self.assertEqual(c.actions, [(1, f, (1,)), (3, g, (8,))])
+
+ def test_executing_conflicting_action_across_orders(self):
+ from pyramid.exceptions import ConfigurationConflictError
+
+ c = self._makeOne()
+
+ def f(*a, **k):
+ pass
+
+ def g(*a, **k): # pragma: no cover
+ pass
+
+ c.actions = [(1, f, (1,), {}, (), None, -1), (1, g, (2,))]
+ self.assertRaises(ConfigurationConflictError, c.execute_actions)
+
+ def test_executing_conflicting_action_across_reentrant_orders(self):
+ from pyramid.exceptions import ConfigurationConflictError
+
+ c = self._makeOne()
+
+ def f(*a, **k):
+ c.actions.append((1, g, (8,)))
+
+ def g(*a, **k): # pragma: no cover
+ pass
+
+ c.actions = [(1, f, (1,), {}, (), None, -1)]
+ self.assertRaises(ConfigurationConflictError, c.execute_actions)
+
+
+class Test_reentrant_action_functional(unittest.TestCase):
+ def _makeConfigurator(self, *arg, **kw):
+ from pyramid.config import Configurator
+
+ config = Configurator(*arg, **kw)
+ return config
+
+ def test_functional(self):
+ def add_auto_route(config, name, view):
+ def register():
+ config.add_view(route_name=name, view=view)
+ config.add_route(name, '/' + name)
+
+ config.action(('auto route', name), register, order=-30)
+
+ config = self._makeConfigurator()
+ config.add_directive('add_auto_route', add_auto_route)
+
+ def my_view(request): # pragma: no cover
+ return request.response
+
+ config.add_auto_route('foo', my_view)
+ config.commit()
+ from pyramid.interfaces import IRoutesMapper
+
+ mapper = config.registry.getUtility(IRoutesMapper)
+ routes = mapper.get_routes()
+ route = routes[0]
+ self.assertEqual(len(routes), 1)
+ self.assertEqual(route.name, 'foo')
+ self.assertEqual(route.path, '/foo')
+
+ def test_deferred_discriminator(self):
+ # see https://github.com/Pylons/pyramid/issues/2697
+ from pyramid.config import PHASE0_CONFIG
+
+ config = self._makeConfigurator()
+
+ def deriver(view, info):
+ return view
+
+ deriver.options = ('foo',)
+ config.add_view_deriver(deriver, 'foo_view')
+ # add_view uses a deferred discriminator and will fail if executed
+ # prior to add_view_deriver executing its action
+ config.add_view(lambda r: r.response, name='', foo=1)
+
+ def dummy_action():
+ # trigger a re-entrant action
+ config.action(None, lambda: None)
+
+ config.action(None, dummy_action, order=PHASE0_CONFIG)
+ config.commit()
+
+
+class Test_resolveConflicts(unittest.TestCase):
+ def _callFUT(self, actions):
+ from pyramid.config.actions import resolveConflicts
+
+ return resolveConflicts(actions)
+
+ def test_it_success_tuples(self):
+ from . import dummyfactory as f
+
+ result = self._callFUT(
+ [
+ (None, f),
+ (1, f, (1,), {}, (), 'first'),
+ (1, f, (2,), {}, ('x',), 'second'),
+ (1, f, (3,), {}, ('y',), 'third'),
+ (4, f, (4,), {}, ('y',), 'should be last', 99999),
+ (3, f, (3,), {}, ('y',)),
+ (None, f, (5,), {}, ('y',)),
+ ]
+ )
+ result = list(result)
+ self.assertEqual(
+ result,
+ [
+ {
+ 'info': None,
+ 'args': (),
+ 'callable': f,
+ 'introspectables': (),
+ 'kw': {},
+ 'discriminator': None,
+ 'includepath': (),
+ 'order': 0,
+ },
+ {
+ 'info': 'first',
+ 'args': (1,),
+ 'callable': f,
+ 'introspectables': (),
+ 'kw': {},
+ 'discriminator': 1,
+ 'includepath': (),
+ 'order': 0,
+ },
+ {
+ 'info': None,
+ 'args': (3,),
+ 'callable': f,
+ 'introspectables': (),
+ 'kw': {},
+ 'discriminator': 3,
+ 'includepath': ('y',),
+ 'order': 0,
+ },
+ {
+ 'info': None,
+ 'args': (5,),
+ 'callable': f,
+ 'introspectables': (),
+ 'kw': {},
+ 'discriminator': None,
+ 'includepath': ('y',),
+ 'order': 0,
+ },
+ {
+ 'info': 'should be last',
+ 'args': (4,),
+ 'callable': f,
+ 'introspectables': (),
+ 'kw': {},
+ 'discriminator': 4,
+ 'includepath': ('y',),
+ 'order': 99999,
+ },
+ ],
+ )
+
+ def test_it_success_dicts(self):
+ from . import dummyfactory as f
+
+ result = self._callFUT(
+ [
+ (None, f),
+ (1, f, (1,), {}, (), 'first'),
+ (1, f, (2,), {}, ('x',), 'second'),
+ (1, f, (3,), {}, ('y',), 'third'),
+ (4, f, (4,), {}, ('y',), 'should be last', 99999),
+ (3, f, (3,), {}, ('y',)),
+ (None, f, (5,), {}, ('y',)),
+ ]
+ )
+ result = list(result)
+ self.assertEqual(
+ result,
+ [
+ {
+ 'info': None,
+ 'args': (),
+ 'callable': f,
+ 'introspectables': (),
+ 'kw': {},
+ 'discriminator': None,
+ 'includepath': (),
+ 'order': 0,
+ },
+ {
+ 'info': 'first',
+ 'args': (1,),
+ 'callable': f,
+ 'introspectables': (),
+ 'kw': {},
+ 'discriminator': 1,
+ 'includepath': (),
+ 'order': 0,
+ },
+ {
+ 'info': None,
+ 'args': (3,),
+ 'callable': f,
+ 'introspectables': (),
+ 'kw': {},
+ 'discriminator': 3,
+ 'includepath': ('y',),
+ 'order': 0,
+ },
+ {
+ 'info': None,
+ 'args': (5,),
+ 'callable': f,
+ 'introspectables': (),
+ 'kw': {},
+ 'discriminator': None,
+ 'includepath': ('y',),
+ 'order': 0,
+ },
+ {
+ 'info': 'should be last',
+ 'args': (4,),
+ 'callable': f,
+ 'introspectables': (),
+ 'kw': {},
+ 'discriminator': 4,
+ 'includepath': ('y',),
+ 'order': 99999,
+ },
+ ],
+ )
+
+ def test_it_conflict(self):
+ from . import dummyfactory as f
+
+ result = self._callFUT(
+ [
+ (None, f),
+ (1, f, (2,), {}, ('x',), 'eek'), # will conflict
+ (1, f, (3,), {}, ('y',), 'ack'), # will conflict
+ (4, f, (4,), {}, ('y',)),
+ (3, f, (3,), {}, ('y',)),
+ (None, f, (5,), {}, ('y',)),
+ ]
+ )
+ self.assertRaises(ConfigurationConflictError, list, result)
+
+ def test_it_with_actions_grouped_by_order(self):
+ from . import dummyfactory as f
+
+ result = self._callFUT(
+ [
+ (None, f), # X
+ (1, f, (1,), {}, (), 'third', 10), # X
+ (1, f, (2,), {}, ('x',), 'fourth', 10),
+ (1, f, (3,), {}, ('y',), 'fifth', 10),
+ (2, f, (1,), {}, (), 'sixth', 10), # X
+ (3, f, (1,), {}, (), 'seventh', 10), # X
+ (5, f, (4,), {}, ('y',), 'eighth', 99999), # X
+ (4, f, (3,), {}, (), 'first', 5), # X
+ (4, f, (5,), {}, ('y',), 'second', 5),
+ ]
+ )
+ result = list(result)
+ self.assertEqual(len(result), 6)
+ # resolved actions should be grouped by (order, i)
+ self.assertEqual(
+ result,
+ [
+ {
+ 'info': None,
+ 'args': (),
+ 'callable': f,
+ 'introspectables': (),
+ 'kw': {},
+ 'discriminator': None,
+ 'includepath': (),
+ 'order': 0,
+ },
+ {
+ 'info': 'first',
+ 'args': (3,),
+ 'callable': f,
+ 'introspectables': (),
+ 'kw': {},
+ 'discriminator': 4,
+ 'includepath': (),
+ 'order': 5,
+ },
+ {
+ 'info': 'third',
+ 'args': (1,),
+ 'callable': f,
+ 'introspectables': (),
+ 'kw': {},
+ 'discriminator': 1,
+ 'includepath': (),
+ 'order': 10,
+ },
+ {
+ 'info': 'sixth',
+ 'args': (1,),
+ 'callable': f,
+ 'introspectables': (),
+ 'kw': {},
+ 'discriminator': 2,
+ 'includepath': (),
+ 'order': 10,
+ },
+ {
+ 'info': 'seventh',
+ 'args': (1,),
+ 'callable': f,
+ 'introspectables': (),
+ 'kw': {},
+ 'discriminator': 3,
+ 'includepath': (),
+ 'order': 10,
+ },
+ {
+ 'info': 'eighth',
+ 'args': (4,),
+ 'callable': f,
+ 'introspectables': (),
+ 'kw': {},
+ 'discriminator': 5,
+ 'includepath': ('y',),
+ 'order': 99999,
+ },
+ ],
+ )
+
+ def test_override_success_across_orders(self):
+ from . import dummyfactory as f
+
+ result = self._callFUT(
+ [
+ (1, f, (2,), {}, ('x',), 'eek', 0),
+ (1, f, (3,), {}, ('x', 'y'), 'ack', 10),
+ ]
+ )
+ result = list(result)
+ self.assertEqual(
+ result,
+ [
+ {
+ 'info': 'eek',
+ 'args': (2,),
+ 'callable': f,
+ 'introspectables': (),
+ 'kw': {},
+ 'discriminator': 1,
+ 'includepath': ('x',),
+ 'order': 0,
+ }
+ ],
+ )
+
+ def test_conflicts_across_orders(self):
+ from . import dummyfactory as f
+
+ result = self._callFUT(
+ [
+ (1, f, (2,), {}, ('x', 'y'), 'eek', 0),
+ (1, f, (3,), {}, ('x'), 'ack', 10),
+ ]
+ )
+ self.assertRaises(ConfigurationConflictError, list, result)
+
+
+class TestActionInfo(unittest.TestCase):
+ def _getTargetClass(self):
+ from pyramid.config.actions import ActionInfo
+
+ return ActionInfo
+
+ def _makeOne(self, filename, lineno, function, linerepr):
+ return self._getTargetClass()(filename, lineno, function, linerepr)
+
+ def test_class_conforms(self):
+ from zope.interface.verify import verifyClass
+ from pyramid.interfaces import IActionInfo
+
+ verifyClass(IActionInfo, self._getTargetClass())
+
+ def test_instance_conforms(self):
+ from zope.interface.verify import verifyObject
+ from pyramid.interfaces import IActionInfo
+
+ verifyObject(IActionInfo, self._makeOne('f', 0, 'f', 'f'))
+
+ def test_ctor(self):
+ inst = self._makeOne('filename', 10, 'function', 'src')
+ self.assertEqual(inst.file, 'filename')
+ self.assertEqual(inst.line, 10)
+ self.assertEqual(inst.function, 'function')
+ self.assertEqual(inst.src, 'src')
+
+ def test___str__(self):
+ inst = self._makeOne('filename', 0, 'function', ' linerepr ')
+ self.assertEqual(
+ str(inst), "Line 0 of file filename:\n linerepr "
+ )
+
+
+def _conflictFunctions(e):
+ conflicts = e._conflicts.values()
+ for conflict in conflicts:
+ for confinst in conflict:
+ yield confinst.function
+
+
+class DummyActionState(object):
+ autocommit = False
+ info = ''
+
+ def __init__(self):
+ self.actions = []
+
+ def action(self, *arg, **kw):
+ self.actions.append((arg, kw))
+
+
+class DummyIntrospectable(object):
+ def __init__(self):
+ self.registered = []
+
+ def register(self, introspector, action_info):
+ self.registered.append((introspector, action_info))
diff --git a/tests/test_config/test_adapters.py b/tests/test_config/test_adapters.py
new file mode 100644
index 000000000..d871e8825
--- /dev/null
+++ b/tests/test_config/test_adapters.py
@@ -0,0 +1,431 @@
+import unittest
+
+from pyramid.compat import PY2
+from . import IDummy
+
+
+class AdaptersConfiguratorMixinTests(unittest.TestCase):
+ def _makeOne(self, *arg, **kw):
+ from pyramid.config import Configurator
+
+ config = Configurator(*arg, **kw)
+ return config
+
+ def test_add_subscriber_defaults(self):
+ from zope.interface import implementer
+ from zope.interface import Interface
+
+ class IEvent(Interface):
+ pass
+
+ @implementer(IEvent)
+ class Event:
+ pass
+
+ L = []
+
+ def subscriber(event):
+ L.append(event)
+
+ config = self._makeOne(autocommit=True)
+ config.add_subscriber(subscriber)
+ event = Event()
+ config.registry.notify(event)
+ self.assertEqual(len(L), 1)
+ self.assertEqual(L[0], event)
+ config.registry.notify(object())
+ self.assertEqual(len(L), 2)
+
+ def test_add_subscriber_iface_specified(self):
+ from zope.interface import implementer
+ from zope.interface import Interface
+
+ class IEvent(Interface):
+ pass
+
+ @implementer(IEvent)
+ class Event:
+ pass
+
+ L = []
+
+ def subscriber(event):
+ L.append(event)
+
+ config = self._makeOne(autocommit=True)
+ config.add_subscriber(subscriber, IEvent)
+ event = Event()
+ config.registry.notify(event)
+ self.assertEqual(len(L), 1)
+ self.assertEqual(L[0], event)
+ config.registry.notify(object())
+ self.assertEqual(len(L), 1)
+
+ def test_add_subscriber_dottednames(self):
+ import tests.test_config
+ from pyramid.interfaces import INewRequest
+
+ config = self._makeOne(autocommit=True)
+ config.add_subscriber(
+ 'tests.test_config', 'pyramid.interfaces.INewRequest'
+ )
+ handlers = list(config.registry.registeredHandlers())
+ self.assertEqual(len(handlers), 1)
+ handler = handlers[0]
+ self.assertEqual(handler.handler, tests.test_config)
+ self.assertEqual(handler.required, (INewRequest,))
+
+ def test_add_object_event_subscriber(self):
+ from zope.interface import implementer
+ from zope.interface import Interface
+
+ class IEvent(Interface):
+ pass
+
+ @implementer(IEvent)
+ class Event:
+ object = 'foo'
+
+ event = Event()
+ L = []
+
+ def subscriber(object, event):
+ L.append(event)
+
+ config = self._makeOne(autocommit=True)
+ config.add_subscriber(subscriber, (Interface, IEvent))
+ config.registry.subscribers((event.object, event), None)
+ self.assertEqual(len(L), 1)
+ self.assertEqual(L[0], event)
+ config.registry.subscribers((event.object, IDummy), None)
+ self.assertEqual(len(L), 1)
+
+ def test_add_subscriber_with_specific_type_and_predicates_True(self):
+ from zope.interface import implementer
+ from zope.interface import Interface
+
+ class IEvent(Interface):
+ pass
+
+ @implementer(IEvent)
+ class Event:
+ pass
+
+ L = []
+
+ def subscriber(event):
+ L.append(event)
+
+ config = self._makeOne(autocommit=True)
+ predlist = config.get_predlist('subscriber')
+ jam_predicate = predicate_maker('jam')
+ jim_predicate = predicate_maker('jim')
+ predlist.add('jam', jam_predicate)
+ predlist.add('jim', jim_predicate)
+ config.add_subscriber(subscriber, IEvent, jam=True, jim=True)
+ event = Event()
+ event.jam = True
+ event.jim = True
+ config.registry.notify(event)
+ self.assertEqual(len(L), 1)
+ self.assertEqual(L[0], event)
+ config.registry.notify(object())
+ self.assertEqual(len(L), 1)
+
+ def test_add_subscriber_with_default_type_predicates_True(self):
+ from zope.interface import implementer
+ from zope.interface import Interface
+
+ class IEvent(Interface):
+ pass
+
+ @implementer(IEvent)
+ class Event:
+ pass
+
+ L = []
+
+ def subscriber(event):
+ L.append(event)
+
+ config = self._makeOne(autocommit=True)
+ predlist = config.get_predlist('subscriber')
+ jam_predicate = predicate_maker('jam')
+ jim_predicate = predicate_maker('jim')
+ predlist.add('jam', jam_predicate)
+ predlist.add('jim', jim_predicate)
+ config.add_subscriber(subscriber, jam=True, jim=True)
+ event = Event()
+ event.jam = True
+ event.jim = True
+ config.registry.notify(event)
+ self.assertEqual(len(L), 1)
+ self.assertEqual(L[0], event)
+ config.registry.notify(object())
+ self.assertEqual(len(L), 1)
+
+ def test_add_subscriber_with_specific_type_and_predicates_False(self):
+ from zope.interface import implementer
+ from zope.interface import Interface
+
+ class IEvent(Interface):
+ pass
+
+ @implementer(IEvent)
+ class Event:
+ pass
+
+ L = []
+
+ def subscriber(event): # pragma: no cover
+ L.append(event)
+
+ config = self._makeOne(autocommit=True)
+ predlist = config.get_predlist('subscriber')
+ jam_predicate = predicate_maker('jam')
+ jim_predicate = predicate_maker('jim')
+ predlist.add('jam', jam_predicate)
+ predlist.add('jim', jim_predicate)
+ config.add_subscriber(subscriber, IEvent, jam=True, jim=True)
+ event = Event()
+ event.jam = True
+ event.jim = False
+ config.registry.notify(event)
+ self.assertEqual(len(L), 0)
+
+ def test_add_subscriber_with_default_type_predicates_False(self):
+ from zope.interface import implementer
+ from zope.interface import Interface
+
+ class IEvent(Interface):
+ pass
+
+ @implementer(IEvent)
+ class Event:
+ pass
+
+ L = []
+
+ def subscriber(event): # pragma: no cover
+ L.append(event)
+
+ config = self._makeOne(autocommit=True)
+ predlist = config.get_predlist('subscriber')
+ jam_predicate = predicate_maker('jam')
+ jim_predicate = predicate_maker('jim')
+ predlist.add('jam', jam_predicate)
+ predlist.add('jim', jim_predicate)
+ config.add_subscriber(subscriber, jam=True, jim=True)
+ event = Event()
+ event.jam = False
+ event.jim = True
+ config.registry.notify(event)
+ self.assertEqual(len(L), 0)
+
+ def test_add_subscriber_predicate(self):
+ config = self._makeOne()
+ L = []
+
+ def add_predicate(
+ type, name, factory, weighs_less_than=None, weighs_more_than=None
+ ):
+ self.assertEqual(type, 'subscriber')
+ self.assertEqual(name, 'name')
+ self.assertEqual(factory, 'factory')
+ self.assertEqual(weighs_more_than, 1)
+ self.assertEqual(weighs_less_than, 2)
+ L.append(1)
+
+ config._add_predicate = add_predicate
+ config.add_subscriber_predicate('name', 'factory', 1, 2)
+ self.assertTrue(L)
+
+ def test_add_response_adapter(self):
+ from pyramid.interfaces import IResponse
+
+ config = self._makeOne(autocommit=True)
+
+ class Adapter(object):
+ def __init__(self, other):
+ self.other = other
+
+ config.add_response_adapter(Adapter, str)
+ result = config.registry.queryAdapter('foo', IResponse)
+ self.assertTrue(result.other, 'foo')
+
+ def test_add_response_adapter_self(self):
+ from pyramid.interfaces import IResponse
+
+ config = self._makeOne(autocommit=True)
+
+ class Adapter(object):
+ pass
+
+ config.add_response_adapter(None, Adapter)
+ adapter = Adapter()
+ result = config.registry.queryAdapter(adapter, IResponse)
+ self.assertTrue(result is adapter)
+
+ def test_add_response_adapter_dottednames(self):
+ from pyramid.interfaces import IResponse
+
+ config = self._makeOne(autocommit=True)
+ if PY2:
+ str_name = '__builtin__.str'
+ else:
+ str_name = 'builtins.str'
+ config.add_response_adapter('pyramid.response.Response', str_name)
+ result = config.registry.queryAdapter('foo', IResponse)
+ self.assertTrue(result.body, b'foo')
+
+ def test_add_traverser_dotted_names(self):
+ from pyramid.interfaces import ITraverser
+
+ config = self._makeOne(autocommit=True)
+ config.add_traverser(
+ 'tests.test_config.test_adapters.DummyTraverser',
+ 'tests.test_config.test_adapters.DummyIface',
+ )
+ iface = DummyIface()
+ traverser = config.registry.getAdapter(iface, ITraverser)
+ self.assertEqual(traverser.__class__, DummyTraverser)
+ self.assertEqual(traverser.root, iface)
+
+ def test_add_traverser_default_iface_means_Interface(self):
+ from pyramid.interfaces import ITraverser
+
+ config = self._makeOne(autocommit=True)
+ config.add_traverser(DummyTraverser)
+ traverser = config.registry.getAdapter(None, ITraverser)
+ self.assertEqual(traverser.__class__, DummyTraverser)
+
+ def test_add_traverser_nondefault_iface(self):
+ from pyramid.interfaces import ITraverser
+
+ config = self._makeOne(autocommit=True)
+ config.add_traverser(DummyTraverser, DummyIface)
+ iface = DummyIface()
+ traverser = config.registry.getAdapter(iface, ITraverser)
+ self.assertEqual(traverser.__class__, DummyTraverser)
+ self.assertEqual(traverser.root, iface)
+
+ def test_add_traverser_introspectables(self):
+ config = self._makeOne()
+ config.add_traverser(DummyTraverser, DummyIface)
+ actions = config.action_state.actions
+ self.assertEqual(len(actions), 1)
+ intrs = actions[0]['introspectables']
+ self.assertEqual(len(intrs), 1)
+ intr = intrs[0]
+ self.assertEqual(intr.type_name, 'traverser')
+ self.assertEqual(intr.discriminator, ('traverser', DummyIface))
+ self.assertEqual(intr.category_name, 'traversers')
+ self.assertEqual(intr.title, 'traverser for %r' % DummyIface)
+ self.assertEqual(intr['adapter'], DummyTraverser)
+ self.assertEqual(intr['iface'], DummyIface)
+
+ def test_add_resource_url_adapter_dotted_names(self):
+ from pyramid.interfaces import IResourceURL
+
+ config = self._makeOne(autocommit=True)
+ config.add_resource_url_adapter(
+ 'tests.test_config.test_adapters.DummyResourceURL',
+ 'tests.test_config.test_adapters.DummyIface',
+ )
+ iface = DummyIface()
+ adapter = config.registry.getMultiAdapter((iface, iface), IResourceURL)
+ self.assertEqual(adapter.__class__, DummyResourceURL)
+ self.assertEqual(adapter.resource, iface)
+ self.assertEqual(adapter.request, iface)
+
+ def test_add_resource_url_default_resource_iface_means_Interface(self):
+ from pyramid.interfaces import IResourceURL
+
+ config = self._makeOne(autocommit=True)
+ config.add_resource_url_adapter(DummyResourceURL)
+ iface = DummyIface()
+ adapter = config.registry.getMultiAdapter((iface, iface), IResourceURL)
+ self.assertEqual(adapter.__class__, DummyResourceURL)
+ self.assertEqual(adapter.resource, iface)
+ self.assertEqual(adapter.request, iface)
+
+ def test_add_resource_url_nodefault_resource_iface(self):
+ from zope.interface import Interface
+ from pyramid.interfaces import IResourceURL
+
+ config = self._makeOne(autocommit=True)
+ config.add_resource_url_adapter(DummyResourceURL, DummyIface)
+ iface = DummyIface()
+ adapter = config.registry.getMultiAdapter((iface, iface), IResourceURL)
+ self.assertEqual(adapter.__class__, DummyResourceURL)
+ self.assertEqual(adapter.resource, iface)
+ self.assertEqual(adapter.request, iface)
+ bad_result = config.registry.queryMultiAdapter(
+ (Interface, Interface), IResourceURL
+ )
+ self.assertEqual(bad_result, None)
+
+ def test_add_resource_url_adapter_introspectables(self):
+ config = self._makeOne()
+ config.add_resource_url_adapter(DummyResourceURL, DummyIface)
+ actions = config.action_state.actions
+ self.assertEqual(len(actions), 1)
+ intrs = actions[0]['introspectables']
+ self.assertEqual(len(intrs), 1)
+ intr = intrs[0]
+ self.assertEqual(intr.type_name, 'resource url adapter')
+ self.assertEqual(
+ intr.discriminator, ('resource url adapter', DummyIface)
+ )
+ self.assertEqual(intr.category_name, 'resource url adapters')
+ self.assertEqual(
+ intr.title,
+ "resource url adapter for resource iface "
+ "<class 'tests.test_config.test_adapters.DummyIface'>",
+ )
+ self.assertEqual(intr['adapter'], DummyResourceURL)
+ self.assertEqual(intr['resource_iface'], DummyIface)
+
+
+class Test_eventonly(unittest.TestCase):
+ def _callFUT(self, callee):
+ from pyramid.config.adapters import eventonly
+
+ return eventonly(callee)
+
+ def test_defaults(self):
+ def acallable(event, a=1, b=2): # pragma: no cover
+ pass
+
+ self.assertTrue(self._callFUT(acallable))
+
+
+class DummyTraverser(object):
+ def __init__(self, root):
+ self.root = root
+
+
+class DummyIface(object):
+ pass
+
+
+class DummyResourceURL(object):
+ def __init__(self, resource, request):
+ self.resource = resource
+ self.request = request
+
+
+def predicate_maker(name):
+ class Predicate(object):
+ def __init__(self, val, config):
+ self.val = val
+
+ def phash(self):
+ return 'phash'
+
+ text = phash
+
+ def __call__(self, event):
+ return getattr(event, name, None) == self.val
+
+ return Predicate
diff --git a/tests/test_config/test_assets.py b/tests/test_config/test_assets.py
new file mode 100644
index 000000000..875846dbd
--- /dev/null
+++ b/tests/test_config/test_assets.py
@@ -0,0 +1,1081 @@
+import os.path
+import unittest
+from pyramid.testing import cleanUp
+
+# we use this folder
+here = os.path.dirname(os.path.abspath(__file__))
+
+
+class TestAssetsConfiguratorMixin(unittest.TestCase):
+ def _makeOne(self, *arg, **kw):
+ from pyramid.config import Configurator
+
+ config = Configurator(*arg, **kw)
+ return config
+
+ def test_override_asset_samename(self):
+ from pyramid.exceptions import ConfigurationError
+
+ config = self._makeOne()
+ self.assertRaises(ConfigurationError, config.override_asset, 'a', 'a')
+
+ def test_override_asset_directory_with_file(self):
+ from pyramid.exceptions import ConfigurationError
+
+ config = self._makeOne()
+ self.assertRaises(
+ ConfigurationError,
+ config.override_asset,
+ 'a:foo/',
+ 'tests.test_config.pkgs.asset:foo.pt',
+ )
+
+ def test_override_asset_file_with_directory(self):
+ from pyramid.exceptions import ConfigurationError
+
+ config = self._makeOne()
+ self.assertRaises(
+ ConfigurationError,
+ config.override_asset,
+ 'a:foo.pt',
+ 'tests.test_config.pkgs.asset:templates/',
+ )
+
+ def test_override_asset_file_with_package(self):
+ from pyramid.exceptions import ConfigurationError
+
+ config = self._makeOne()
+ self.assertRaises(
+ ConfigurationError,
+ config.override_asset,
+ 'a:foo.pt',
+ 'tests.test_config.pkgs.asset',
+ )
+
+ def test_override_asset_file_with_file(self):
+ from pyramid.config.assets import PackageAssetSource
+
+ config = self._makeOne(autocommit=True)
+ override = DummyUnderOverride()
+ config.override_asset(
+ 'tests.test_config.pkgs.asset:templates/foo.pt',
+ 'tests.test_config.pkgs.asset.subpackage:templates/bar.pt',
+ _override=override,
+ )
+ from tests.test_config.pkgs import asset
+ from tests.test_config.pkgs.asset import subpackage
+
+ self.assertEqual(override.package, asset)
+ self.assertEqual(override.path, 'templates/foo.pt')
+ source = override.source
+ self.assertTrue(isinstance(source, PackageAssetSource))
+ self.assertEqual(source.package, subpackage)
+ self.assertEqual(source.prefix, 'templates/bar.pt')
+
+ resource_name = ''
+ expected = os.path.join(
+ here, 'pkgs', 'asset', 'subpackage', 'templates', 'bar.pt'
+ )
+ self.assertEqual(override.source.get_filename(resource_name), expected)
+
+ def test_override_asset_package_with_package(self):
+ from pyramid.config.assets import PackageAssetSource
+
+ config = self._makeOne(autocommit=True)
+ override = DummyUnderOverride()
+ config.override_asset(
+ 'tests.test_config.pkgs.asset',
+ 'tests.test_config.pkgs.asset.subpackage',
+ _override=override,
+ )
+ from tests.test_config.pkgs import asset
+ from tests.test_config.pkgs.asset import subpackage
+
+ self.assertEqual(override.package, asset)
+ self.assertEqual(override.path, '')
+ source = override.source
+ self.assertTrue(isinstance(source, PackageAssetSource))
+ self.assertEqual(source.package, subpackage)
+ self.assertEqual(source.prefix, '')
+
+ resource_name = 'templates/bar.pt'
+ expected = os.path.join(
+ here, 'pkgs', 'asset', 'subpackage', 'templates', 'bar.pt'
+ )
+ self.assertEqual(override.source.get_filename(resource_name), expected)
+
+ def test_override_asset_directory_with_directory(self):
+ from pyramid.config.assets import PackageAssetSource
+
+ config = self._makeOne(autocommit=True)
+ override = DummyUnderOverride()
+ config.override_asset(
+ 'tests.test_config.pkgs.asset:templates/',
+ 'tests.test_config.pkgs.asset.subpackage:templates/',
+ _override=override,
+ )
+ from tests.test_config.pkgs import asset
+ from tests.test_config.pkgs.asset import subpackage
+
+ self.assertEqual(override.package, asset)
+ self.assertEqual(override.path, 'templates/')
+ source = override.source
+ self.assertTrue(isinstance(source, PackageAssetSource))
+ self.assertEqual(source.package, subpackage)
+ self.assertEqual(source.prefix, 'templates/')
+
+ resource_name = 'bar.pt'
+ expected = os.path.join(
+ here, 'pkgs', 'asset', 'subpackage', 'templates', 'bar.pt'
+ )
+ self.assertEqual(override.source.get_filename(resource_name), expected)
+
+ def test_override_asset_directory_with_package(self):
+ from pyramid.config.assets import PackageAssetSource
+
+ config = self._makeOne(autocommit=True)
+ override = DummyUnderOverride()
+ config.override_asset(
+ 'tests.test_config.pkgs.asset:templates/',
+ 'tests.test_config.pkgs.asset.subpackage',
+ _override=override,
+ )
+ from tests.test_config.pkgs import asset
+ from tests.test_config.pkgs.asset import subpackage
+
+ self.assertEqual(override.package, asset)
+ self.assertEqual(override.path, 'templates/')
+ source = override.source
+ self.assertTrue(isinstance(source, PackageAssetSource))
+ self.assertEqual(source.package, subpackage)
+ self.assertEqual(source.prefix, '')
+
+ resource_name = 'templates/bar.pt'
+ expected = os.path.join(
+ here, 'pkgs', 'asset', 'subpackage', 'templates', 'bar.pt'
+ )
+ self.assertEqual(override.source.get_filename(resource_name), expected)
+
+ def test_override_asset_package_with_directory(self):
+ from pyramid.config.assets import PackageAssetSource
+
+ config = self._makeOne(autocommit=True)
+ override = DummyUnderOverride()
+ config.override_asset(
+ 'tests.test_config.pkgs.asset',
+ 'tests.test_config.pkgs.asset.subpackage:templates/',
+ _override=override,
+ )
+ from tests.test_config.pkgs import asset
+ from tests.test_config.pkgs.asset import subpackage
+
+ self.assertEqual(override.package, asset)
+ self.assertEqual(override.path, '')
+ source = override.source
+ self.assertTrue(isinstance(source, PackageAssetSource))
+ self.assertEqual(source.package, subpackage)
+ self.assertEqual(source.prefix, 'templates/')
+
+ resource_name = 'bar.pt'
+ expected = os.path.join(
+ here, 'pkgs', 'asset', 'subpackage', 'templates', 'bar.pt'
+ )
+ self.assertEqual(override.source.get_filename(resource_name), expected)
+
+ def test_override_asset_directory_with_absfile(self):
+ from pyramid.exceptions import ConfigurationError
+
+ config = self._makeOne()
+ self.assertRaises(
+ ConfigurationError,
+ config.override_asset,
+ 'a:foo/',
+ os.path.join(here, 'pkgs', 'asset', 'foo.pt'),
+ )
+
+ def test_override_asset_file_with_absdirectory(self):
+ from pyramid.exceptions import ConfigurationError
+
+ config = self._makeOne()
+ abspath = os.path.join(
+ here, 'pkgs', 'asset', 'subpackage', 'templates'
+ )
+ self.assertRaises(
+ ConfigurationError, config.override_asset, 'a:foo.pt', abspath
+ )
+
+ def test_override_asset_file_with_missing_abspath(self):
+ from pyramid.exceptions import ConfigurationError
+
+ config = self._makeOne()
+ self.assertRaises(
+ ConfigurationError,
+ config.override_asset,
+ 'a:foo.pt',
+ os.path.join(here, 'wont_exist'),
+ )
+
+ def test_override_asset_file_with_absfile(self):
+ from pyramid.config.assets import FSAssetSource
+
+ config = self._makeOne(autocommit=True)
+ override = DummyUnderOverride()
+ abspath = os.path.join(
+ here, 'pkgs', 'asset', 'subpackage', 'templates', 'bar.pt'
+ )
+ config.override_asset(
+ 'tests.test_config.pkgs.asset:templates/foo.pt',
+ abspath,
+ _override=override,
+ )
+ from tests.test_config.pkgs import asset
+
+ self.assertEqual(override.package, asset)
+ self.assertEqual(override.path, 'templates/foo.pt')
+ source = override.source
+ self.assertTrue(isinstance(source, FSAssetSource))
+ self.assertEqual(source.prefix, abspath)
+
+ resource_name = ''
+ expected = os.path.join(
+ here, 'pkgs', 'asset', 'subpackage', 'templates', 'bar.pt'
+ )
+ self.assertEqual(override.source.get_filename(resource_name), expected)
+
+ def test_override_asset_directory_with_absdirectory(self):
+ from pyramid.config.assets import FSAssetSource
+
+ config = self._makeOne(autocommit=True)
+ override = DummyUnderOverride()
+ abspath = os.path.join(
+ here, 'pkgs', 'asset', 'subpackage', 'templates'
+ )
+ config.override_asset(
+ 'tests.test_config.pkgs.asset:templates/',
+ abspath,
+ _override=override,
+ )
+ from tests.test_config.pkgs import asset
+
+ self.assertEqual(override.package, asset)
+ self.assertEqual(override.path, 'templates/')
+ source = override.source
+ self.assertTrue(isinstance(source, FSAssetSource))
+ self.assertEqual(source.prefix, abspath)
+
+ resource_name = 'bar.pt'
+ expected = os.path.join(
+ here, 'pkgs', 'asset', 'subpackage', 'templates', 'bar.pt'
+ )
+ self.assertEqual(override.source.get_filename(resource_name), expected)
+
+ def test_override_asset_package_with_absdirectory(self):
+ from pyramid.config.assets import FSAssetSource
+
+ config = self._makeOne(autocommit=True)
+ override = DummyUnderOverride()
+ abspath = os.path.join(
+ here, 'pkgs', 'asset', 'subpackage', 'templates'
+ )
+ config.override_asset(
+ 'tests.test_config.pkgs.asset', abspath, _override=override
+ )
+ from tests.test_config.pkgs import asset
+
+ self.assertEqual(override.package, asset)
+ self.assertEqual(override.path, '')
+ source = override.source
+ self.assertTrue(isinstance(source, FSAssetSource))
+ self.assertEqual(source.prefix, abspath)
+
+ resource_name = 'bar.pt'
+ expected = os.path.join(
+ here, 'pkgs', 'asset', 'subpackage', 'templates', 'bar.pt'
+ )
+ self.assertEqual(override.source.get_filename(resource_name), expected)
+
+ def test__override_not_yet_registered(self):
+ from pyramid.interfaces import IPackageOverrides
+
+ package = DummyPackage('package')
+ source = DummyAssetSource()
+ config = self._makeOne()
+ config._override(
+ package, 'path', source, PackageOverrides=DummyPackageOverrides
+ )
+ overrides = config.registry.queryUtility(
+ IPackageOverrides, name='package'
+ )
+ self.assertEqual(overrides.inserted, [('path', source)])
+ self.assertEqual(overrides.package, package)
+
+ def test__override_already_registered(self):
+ from pyramid.interfaces import IPackageOverrides
+
+ package = DummyPackage('package')
+ source = DummyAssetSource()
+ overrides = DummyPackageOverrides(package)
+ config = self._makeOne()
+ config.registry.registerUtility(
+ overrides, IPackageOverrides, name='package'
+ )
+ config._override(
+ package, 'path', source, PackageOverrides=DummyPackageOverrides
+ )
+ self.assertEqual(overrides.inserted, [('path', source)])
+ self.assertEqual(overrides.package, package)
+
+
+class TestOverrideProvider(unittest.TestCase):
+ def setUp(self):
+ cleanUp()
+
+ def tearDown(self):
+ cleanUp()
+
+ def _getTargetClass(self):
+ from pyramid.config.assets import OverrideProvider
+
+ return OverrideProvider
+
+ def _makeOne(self, module):
+ klass = self._getTargetClass()
+ return klass(module)
+
+ def _registerOverrides(self, overrides, name='tests.test_config'):
+ from pyramid.interfaces import IPackageOverrides
+ from pyramid.threadlocal import get_current_registry
+
+ reg = get_current_registry()
+ reg.registerUtility(overrides, IPackageOverrides, name=name)
+
+ def test_get_resource_filename_no_overrides(self):
+ resource_name = 'test_assets.py'
+ import tests.test_config
+
+ provider = self._makeOne(tests.test_config)
+ expected = os.path.join(here, resource_name)
+ result = provider.get_resource_filename(None, resource_name)
+ self.assertEqual(result, expected)
+
+ def test_get_resource_stream_no_overrides(self):
+ resource_name = 'test_assets.py'
+ import tests.test_config
+
+ provider = self._makeOne(tests.test_config)
+ with provider.get_resource_stream(None, resource_name) as result:
+ _assertBody(result.read(), os.path.join(here, resource_name))
+
+ def test_get_resource_string_no_overrides(self):
+ resource_name = 'test_assets.py'
+ import tests.test_config
+
+ provider = self._makeOne(tests.test_config)
+ result = provider.get_resource_string(None, resource_name)
+ _assertBody(result, os.path.join(here, resource_name))
+
+ def test_has_resource_no_overrides(self):
+ resource_name = 'test_assets.py'
+ import tests.test_config
+
+ provider = self._makeOne(tests.test_config)
+ result = provider.has_resource(resource_name)
+ self.assertEqual(result, True)
+
+ def test_resource_isdir_no_overrides(self):
+ file_resource_name = 'test_assets.py'
+ directory_resource_name = 'files'
+ import tests.test_config
+
+ provider = self._makeOne(tests.test_config)
+ result = provider.resource_isdir(file_resource_name)
+ self.assertEqual(result, False)
+ result = provider.resource_isdir(directory_resource_name)
+ self.assertEqual(result, True)
+
+ def test_resource_listdir_no_overrides(self):
+ resource_name = 'files'
+ import tests.test_config
+
+ provider = self._makeOne(tests.test_config)
+ result = provider.resource_listdir(resource_name)
+ self.assertTrue(result)
+
+ def test_get_resource_filename_override_returns_None(self):
+ overrides = DummyOverrides(None)
+ self._registerOverrides(overrides)
+ resource_name = 'test_assets.py'
+ import tests.test_config
+
+ provider = self._makeOne(tests.test_config)
+ expected = os.path.join(here, resource_name)
+ result = provider.get_resource_filename(None, resource_name)
+ self.assertEqual(result, expected)
+
+ def test_get_resource_stream_override_returns_None(self):
+ overrides = DummyOverrides(None)
+ self._registerOverrides(overrides)
+ resource_name = 'test_assets.py'
+ import tests.test_config
+
+ provider = self._makeOne(tests.test_config)
+ with provider.get_resource_stream(None, resource_name) as result:
+ _assertBody(result.read(), os.path.join(here, resource_name))
+
+ def test_get_resource_string_override_returns_None(self):
+ overrides = DummyOverrides(None)
+ self._registerOverrides(overrides)
+ resource_name = 'test_assets.py'
+ import tests.test_config
+
+ provider = self._makeOne(tests.test_config)
+ result = provider.get_resource_string(None, resource_name)
+ _assertBody(result, os.path.join(here, resource_name))
+
+ def test_has_resource_override_returns_None(self):
+ overrides = DummyOverrides(None)
+ self._registerOverrides(overrides)
+ resource_name = 'test_assets.py'
+ import tests.test_config
+
+ provider = self._makeOne(tests.test_config)
+ result = provider.has_resource(resource_name)
+ self.assertEqual(result, True)
+
+ def test_resource_isdir_override_returns_None(self):
+ overrides = DummyOverrides(None)
+ self._registerOverrides(overrides)
+ resource_name = 'files'
+ import tests.test_config
+
+ provider = self._makeOne(tests.test_config)
+ result = provider.resource_isdir(resource_name)
+ self.assertEqual(result, True)
+
+ def test_resource_listdir_override_returns_None(self):
+ overrides = DummyOverrides(None)
+ self._registerOverrides(overrides)
+ resource_name = 'files'
+ import tests.test_config
+
+ provider = self._makeOne(tests.test_config)
+ result = provider.resource_listdir(resource_name)
+ self.assertTrue(result)
+
+ def test_get_resource_filename_override_returns_value(self):
+ overrides = DummyOverrides('value')
+ import tests.test_config
+
+ self._registerOverrides(overrides)
+ provider = self._makeOne(tests.test_config)
+ result = provider.get_resource_filename(None, 'test_assets.py')
+ self.assertEqual(result, 'value')
+
+ def test_get_resource_stream_override_returns_value(self):
+ from io import BytesIO
+
+ overrides = DummyOverrides(BytesIO(b'value'))
+ import tests.test_config
+
+ self._registerOverrides(overrides)
+ provider = self._makeOne(tests.test_config)
+ with provider.get_resource_stream(None, 'test_assets.py') as stream:
+ self.assertEqual(stream.getvalue(), b'value')
+
+ def test_get_resource_string_override_returns_value(self):
+ overrides = DummyOverrides('value')
+ import tests.test_config
+
+ self._registerOverrides(overrides)
+ provider = self._makeOne(tests.test_config)
+ result = provider.get_resource_string(None, 'test_assets.py')
+ self.assertEqual(result, 'value')
+
+ def test_has_resource_override_returns_True(self):
+ overrides = DummyOverrides(True)
+ import tests.test_config
+
+ self._registerOverrides(overrides)
+ provider = self._makeOne(tests.test_config)
+ result = provider.has_resource('test_assets.py')
+ self.assertEqual(result, True)
+
+ def test_resource_isdir_override_returns_False(self):
+ overrides = DummyOverrides(False)
+ import tests.test_config
+
+ self._registerOverrides(overrides)
+ provider = self._makeOne(tests.test_config)
+ result = provider.resource_isdir('files')
+ self.assertEqual(result, False)
+
+ def test_resource_listdir_override_returns_values(self):
+ overrides = DummyOverrides(['a'])
+ import tests.test_config
+
+ self._registerOverrides(overrides)
+ provider = self._makeOne(tests.test_config)
+ result = provider.resource_listdir('files')
+ self.assertEqual(result, ['a'])
+
+
+class TestPackageOverrides(unittest.TestCase):
+ def _getTargetClass(self):
+ from pyramid.config.assets import PackageOverrides
+
+ return PackageOverrides
+
+ def _makeOne(self, package=None, pkg_resources=None):
+ if package is None:
+ package = DummyPackage('package')
+ klass = self._getTargetClass()
+ if pkg_resources is None:
+ pkg_resources = DummyPkgResources()
+ return klass(package, pkg_resources=pkg_resources)
+
+ def test_class_conforms_to_IPackageOverrides(self):
+ from zope.interface.verify import verifyClass
+ from pyramid.interfaces import IPackageOverrides
+
+ verifyClass(IPackageOverrides, self._getTargetClass())
+
+ def test_instance_conforms_to_IPackageOverrides(self):
+ from zope.interface.verify import verifyObject
+ from pyramid.interfaces import IPackageOverrides
+
+ verifyObject(IPackageOverrides, self._makeOne())
+
+ def test_class_conforms_to_IPEP302Loader(self):
+ from zope.interface.verify import verifyClass
+ from pyramid.interfaces import IPEP302Loader
+
+ verifyClass(IPEP302Loader, self._getTargetClass())
+
+ def test_instance_conforms_to_IPEP302Loader(self):
+ from zope.interface.verify import verifyObject
+ from pyramid.interfaces import IPEP302Loader
+
+ verifyObject(IPEP302Loader, self._makeOne())
+
+ def test_ctor_package_already_has_loader_of_different_type(self):
+ package = DummyPackage('package')
+ loader = package.__loader__ = DummyLoader()
+ po = self._makeOne(package)
+ self.assertTrue(package.__loader__ is po)
+ self.assertTrue(po.real_loader is loader)
+
+ def test_ctor_package_already_has_loader_of_same_type(self):
+ package = DummyPackage('package')
+ package.__loader__ = self._makeOne(package)
+ po = self._makeOne(package)
+ self.assertEqual(package.__loader__, po)
+
+ def test_ctor_sets_loader(self):
+ package = DummyPackage('package')
+ po = self._makeOne(package)
+ self.assertEqual(package.__loader__, po)
+
+ def test_ctor_registers_loader_type(self):
+ from pyramid.config.assets import OverrideProvider
+
+ dummy_pkg_resources = DummyPkgResources()
+ package = DummyPackage('package')
+ po = self._makeOne(package, dummy_pkg_resources)
+ self.assertEqual(
+ dummy_pkg_resources.registered, [(po.__class__, OverrideProvider)]
+ )
+
+ def test_ctor_sets_local_state(self):
+ package = DummyPackage('package')
+ po = self._makeOne(package)
+ self.assertEqual(po.overrides, [])
+ self.assertEqual(po.overridden_package_name, 'package')
+
+ def test_insert_directory(self):
+ from pyramid.config.assets import DirectoryOverride
+
+ package = DummyPackage('package')
+ po = self._makeOne(package)
+ po.overrides = [None]
+ po.insert('foo/', DummyAssetSource())
+ self.assertEqual(len(po.overrides), 2)
+ override = po.overrides[0]
+ self.assertEqual(override.__class__, DirectoryOverride)
+
+ def test_insert_file(self):
+ from pyramid.config.assets import FileOverride
+
+ package = DummyPackage('package')
+ po = self._makeOne(package)
+ po.overrides = [None]
+ po.insert('foo.pt', DummyAssetSource())
+ self.assertEqual(len(po.overrides), 2)
+ override = po.overrides[0]
+ self.assertEqual(override.__class__, FileOverride)
+
+ def test_insert_emptystring(self):
+ # XXX is this a valid case for a directory?
+ from pyramid.config.assets import DirectoryOverride
+
+ package = DummyPackage('package')
+ po = self._makeOne(package)
+ po.overrides = [None]
+ source = DummyAssetSource()
+ po.insert('', source)
+ self.assertEqual(len(po.overrides), 2)
+ override = po.overrides[0]
+ self.assertEqual(override.__class__, DirectoryOverride)
+
+ def test_filtered_sources(self):
+ overrides = [DummyOverride(None), DummyOverride('foo')]
+ package = DummyPackage('package')
+ po = self._makeOne(package)
+ po.overrides = overrides
+ self.assertEqual(list(po.filtered_sources('whatever')), ['foo'])
+
+ def test_get_filename(self):
+ source = DummyAssetSource(filename='foo.pt')
+ overrides = [DummyOverride(None), DummyOverride((source, ''))]
+ package = DummyPackage('package')
+ po = self._makeOne(package)
+ po.overrides = overrides
+ result = po.get_filename('whatever')
+ self.assertEqual(result, 'foo.pt')
+ self.assertEqual(source.resource_name, '')
+
+ def test_get_filename_file_doesnt_exist(self):
+ source = DummyAssetSource(filename=None)
+ overrides = [
+ DummyOverride(None),
+ DummyOverride((source, 'wont_exist')),
+ ]
+ package = DummyPackage('package')
+ po = self._makeOne(package)
+ po.overrides = overrides
+ self.assertEqual(po.get_filename('whatever'), None)
+ self.assertEqual(source.resource_name, 'wont_exist')
+
+ def test_get_stream(self):
+ source = DummyAssetSource(stream='a stream?')
+ overrides = [DummyOverride(None), DummyOverride((source, 'foo.pt'))]
+ package = DummyPackage('package')
+ po = self._makeOne(package)
+ po.overrides = overrides
+ self.assertEqual(po.get_stream('whatever'), 'a stream?')
+ self.assertEqual(source.resource_name, 'foo.pt')
+
+ def test_get_stream_file_doesnt_exist(self):
+ source = DummyAssetSource(stream=None)
+ overrides = [
+ DummyOverride(None),
+ DummyOverride((source, 'wont_exist')),
+ ]
+ package = DummyPackage('package')
+ po = self._makeOne(package)
+ po.overrides = overrides
+ self.assertEqual(po.get_stream('whatever'), None)
+ self.assertEqual(source.resource_name, 'wont_exist')
+
+ def test_get_string(self):
+ source = DummyAssetSource(string='a string')
+ overrides = [DummyOverride(None), DummyOverride((source, 'foo.pt'))]
+ package = DummyPackage('package')
+ po = self._makeOne(package)
+ po.overrides = overrides
+ self.assertEqual(po.get_string('whatever'), 'a string')
+ self.assertEqual(source.resource_name, 'foo.pt')
+
+ def test_get_string_file_doesnt_exist(self):
+ source = DummyAssetSource(string=None)
+ overrides = [
+ DummyOverride(None),
+ DummyOverride((source, 'wont_exist')),
+ ]
+ package = DummyPackage('package')
+ po = self._makeOne(package)
+ po.overrides = overrides
+ self.assertEqual(po.get_string('whatever'), None)
+ self.assertEqual(source.resource_name, 'wont_exist')
+
+ def test_has_resource(self):
+ source = DummyAssetSource(exists=True)
+ overrides = [DummyOverride(None), DummyOverride((source, 'foo.pt'))]
+ package = DummyPackage('package')
+ po = self._makeOne(package)
+ po.overrides = overrides
+ self.assertEqual(po.has_resource('whatever'), True)
+ self.assertEqual(source.resource_name, 'foo.pt')
+
+ def test_has_resource_file_doesnt_exist(self):
+ source = DummyAssetSource(exists=None)
+ overrides = [
+ DummyOverride(None),
+ DummyOverride((source, 'wont_exist')),
+ ]
+ package = DummyPackage('package')
+ po = self._makeOne(package)
+ po.overrides = overrides
+ self.assertEqual(po.has_resource('whatever'), None)
+ self.assertEqual(source.resource_name, 'wont_exist')
+
+ def test_isdir_false(self):
+ source = DummyAssetSource(isdir=False)
+ overrides = [DummyOverride(None), DummyOverride((source, 'foo.pt'))]
+ package = DummyPackage('package')
+ po = self._makeOne(package)
+ po.overrides = overrides
+ self.assertEqual(po.isdir('whatever'), False)
+ self.assertEqual(source.resource_name, 'foo.pt')
+
+ def test_isdir_true(self):
+ source = DummyAssetSource(isdir=True)
+ overrides = [DummyOverride(None), DummyOverride((source, 'foo.pt'))]
+ package = DummyPackage('package')
+ po = self._makeOne(package)
+ po.overrides = overrides
+ self.assertEqual(po.isdir('whatever'), True)
+ self.assertEqual(source.resource_name, 'foo.pt')
+
+ def test_isdir_doesnt_exist(self):
+ source = DummyAssetSource(isdir=None)
+ overrides = [
+ DummyOverride(None),
+ DummyOverride((source, 'wont_exist')),
+ ]
+ package = DummyPackage('package')
+ po = self._makeOne(package)
+ po.overrides = overrides
+ self.assertEqual(po.isdir('whatever'), None)
+ self.assertEqual(source.resource_name, 'wont_exist')
+
+ def test_listdir(self):
+ source = DummyAssetSource(listdir=True)
+ overrides = [DummyOverride(None), DummyOverride((source, 'foo.pt'))]
+ package = DummyPackage('package')
+ po = self._makeOne(package)
+ po.overrides = overrides
+ self.assertEqual(po.listdir('whatever'), True)
+ self.assertEqual(source.resource_name, 'foo.pt')
+
+ def test_listdir_doesnt_exist(self):
+ source = DummyAssetSource(listdir=None)
+ overrides = [
+ DummyOverride(None),
+ DummyOverride((source, 'wont_exist')),
+ ]
+ package = DummyPackage('package')
+ po = self._makeOne(package)
+ po.overrides = overrides
+ self.assertEqual(po.listdir('whatever'), None)
+ self.assertEqual(source.resource_name, 'wont_exist')
+
+ # PEP 302 __loader__ extensions: use the "real" __loader__, if present.
+ def test_get_data_pkg_has_no___loader__(self):
+ package = DummyPackage('package')
+ po = self._makeOne(package)
+ self.assertRaises(NotImplementedError, po.get_data, 'whatever')
+
+ def test_get_data_pkg_has___loader__(self):
+ package = DummyPackage('package')
+ loader = package.__loader__ = DummyLoader()
+ po = self._makeOne(package)
+ self.assertEqual(po.get_data('whatever'), b'DEADBEEF')
+ self.assertEqual(loader._got_data, 'whatever')
+
+ def test_is_package_pkg_has_no___loader__(self):
+ package = DummyPackage('package')
+ po = self._makeOne(package)
+ self.assertRaises(NotImplementedError, po.is_package, 'whatever')
+
+ def test_is_package_pkg_has___loader__(self):
+ package = DummyPackage('package')
+ loader = package.__loader__ = DummyLoader()
+ po = self._makeOne(package)
+ self.assertTrue(po.is_package('whatever'))
+ self.assertEqual(loader._is_package, 'whatever')
+
+ def test_get_code_pkg_has_no___loader__(self):
+ package = DummyPackage('package')
+ po = self._makeOne(package)
+ self.assertRaises(NotImplementedError, po.get_code, 'whatever')
+
+ def test_get_code_pkg_has___loader__(self):
+ package = DummyPackage('package')
+ loader = package.__loader__ = DummyLoader()
+ po = self._makeOne(package)
+ self.assertEqual(po.get_code('whatever'), b'DEADBEEF')
+ self.assertEqual(loader._got_code, 'whatever')
+
+ def test_get_source_pkg_has_no___loader__(self):
+ package = DummyPackage('package')
+ po = self._makeOne(package)
+ self.assertRaises(NotImplementedError, po.get_source, 'whatever')
+
+ def test_get_source_pkg_has___loader__(self):
+ package = DummyPackage('package')
+ loader = package.__loader__ = DummyLoader()
+ po = self._makeOne(package)
+ self.assertEqual(po.get_source('whatever'), 'def foo():\n pass')
+ self.assertEqual(loader._got_source, 'whatever')
+
+
+class AssetSourceIntegrationTests(object):
+ def test_get_filename(self):
+ source = self._makeOne('')
+ self.assertEqual(
+ source.get_filename('test_assets.py'),
+ os.path.join(here, 'test_assets.py'),
+ )
+
+ def test_get_filename_with_prefix(self):
+ source = self._makeOne('test_assets.py')
+ self.assertEqual(
+ source.get_filename(''), os.path.join(here, 'test_assets.py')
+ )
+
+ def test_get_filename_file_doesnt_exist(self):
+ source = self._makeOne('')
+ self.assertEqual(source.get_filename('wont_exist'), None)
+
+ def test_get_stream(self):
+ source = self._makeOne('')
+ with source.get_stream('test_assets.py') as stream:
+ _assertBody(stream.read(), os.path.join(here, 'test_assets.py'))
+
+ def test_get_stream_with_prefix(self):
+ source = self._makeOne('test_assets.py')
+ with source.get_stream('') as stream:
+ _assertBody(stream.read(), os.path.join(here, 'test_assets.py'))
+
+ def test_get_stream_file_doesnt_exist(self):
+ source = self._makeOne('')
+ self.assertEqual(source.get_stream('wont_exist'), None)
+
+ def test_get_string(self):
+ source = self._makeOne('')
+ _assertBody(
+ source.get_string('test_assets.py'),
+ os.path.join(here, 'test_assets.py'),
+ )
+
+ def test_get_string_with_prefix(self):
+ source = self._makeOne('test_assets.py')
+ _assertBody(
+ source.get_string(''), os.path.join(here, 'test_assets.py')
+ )
+
+ def test_get_string_file_doesnt_exist(self):
+ source = self._makeOne('')
+ self.assertEqual(source.get_string('wont_exist'), None)
+
+ def test_exists(self):
+ source = self._makeOne('')
+ self.assertEqual(source.exists('test_assets.py'), True)
+
+ def test_exists_with_prefix(self):
+ source = self._makeOne('test_assets.py')
+ self.assertEqual(source.exists(''), True)
+
+ def test_exists_file_doesnt_exist(self):
+ source = self._makeOne('')
+ self.assertEqual(source.exists('wont_exist'), None)
+
+ def test_isdir_false(self):
+ source = self._makeOne('')
+ self.assertEqual(source.isdir('test_assets.py'), False)
+
+ def test_isdir_true(self):
+ source = self._makeOne('')
+ self.assertEqual(source.isdir('files'), True)
+
+ def test_isdir_doesnt_exist(self):
+ source = self._makeOne('')
+ self.assertEqual(source.isdir('wont_exist'), None)
+
+ def test_listdir(self):
+ source = self._makeOne('')
+ self.assertTrue(source.listdir('files'))
+
+ def test_listdir_doesnt_exist(self):
+ source = self._makeOne('')
+ self.assertEqual(source.listdir('wont_exist'), None)
+
+
+class TestPackageAssetSource(AssetSourceIntegrationTests, unittest.TestCase):
+ def _getTargetClass(self):
+ from pyramid.config.assets import PackageAssetSource
+
+ return PackageAssetSource
+
+ def _makeOne(self, prefix, package='tests.test_config'):
+ klass = self._getTargetClass()
+ return klass(package, prefix)
+
+
+class TestFSAssetSource(AssetSourceIntegrationTests, unittest.TestCase):
+ def _getTargetClass(self):
+ from pyramid.config.assets import FSAssetSource
+
+ return FSAssetSource
+
+ def _makeOne(self, prefix, base_prefix=here):
+ klass = self._getTargetClass()
+ return klass(os.path.join(base_prefix, prefix))
+
+
+class TestDirectoryOverride(unittest.TestCase):
+ def _getTargetClass(self):
+ from pyramid.config.assets import DirectoryOverride
+
+ return DirectoryOverride
+
+ def _makeOne(self, path, source):
+ klass = self._getTargetClass()
+ return klass(path, source)
+
+ def test_it_match(self):
+ source = DummyAssetSource()
+ o = self._makeOne('foo/', source)
+ result = o('foo/something.pt')
+ self.assertEqual(result, (source, 'something.pt'))
+
+ def test_it_no_match(self):
+ source = DummyAssetSource()
+ o = self._makeOne('foo/', source)
+ result = o('baz/notfound.pt')
+ self.assertEqual(result, None)
+
+
+class TestFileOverride(unittest.TestCase):
+ def _getTargetClass(self):
+ from pyramid.config.assets import FileOverride
+
+ return FileOverride
+
+ def _makeOne(self, path, source):
+ klass = self._getTargetClass()
+ return klass(path, source)
+
+ def test_it_match(self):
+ source = DummyAssetSource()
+ o = self._makeOne('foo.pt', source)
+ result = o('foo.pt')
+ self.assertEqual(result, (source, ''))
+
+ def test_it_no_match(self):
+ source = DummyAssetSource()
+ o = self._makeOne('foo.pt', source)
+ result = o('notfound.pt')
+ self.assertEqual(result, None)
+
+
+class DummyOverride:
+ def __init__(self, result):
+ self.result = result
+
+ def __call__(self, resource_name):
+ return self.result
+
+
+class DummyOverrides:
+ def __init__(self, result):
+ self.result = result
+
+ def get_filename(self, resource_name):
+ return self.result
+
+ listdir = isdir = has_resource = get_stream = get_string = get_filename
+
+
+class DummyPackageOverrides:
+ def __init__(self, package):
+ self.package = package
+ self.inserted = []
+
+ def insert(self, path, source):
+ self.inserted.append((path, source))
+
+
+class DummyPkgResources:
+ def __init__(self):
+ self.registered = []
+
+ def register_loader_type(self, typ, inst):
+ self.registered.append((typ, inst))
+
+
+class DummyPackage:
+ def __init__(self, name):
+ self.__name__ = name
+
+
+class DummyAssetSource:
+ def __init__(self, **kw):
+ self.kw = kw
+
+ def get_filename(self, resource_name):
+ self.resource_name = resource_name
+ return self.kw['filename']
+
+ def get_stream(self, resource_name):
+ self.resource_name = resource_name
+ return self.kw['stream']
+
+ def get_string(self, resource_name):
+ self.resource_name = resource_name
+ return self.kw['string']
+
+ def exists(self, resource_name):
+ self.resource_name = resource_name
+ return self.kw['exists']
+
+ def isdir(self, resource_name):
+ self.resource_name = resource_name
+ return self.kw['isdir']
+
+ def listdir(self, resource_name):
+ self.resource_name = resource_name
+ return self.kw['listdir']
+
+
+class DummyLoader:
+ _got_data = _is_package = None
+
+ def get_data(self, path):
+ self._got_data = path
+ return b'DEADBEEF'
+
+ def is_package(self, fullname):
+ self._is_package = fullname
+ return True
+
+ def get_code(self, fullname):
+ self._got_code = fullname
+ return b'DEADBEEF'
+
+ def get_source(self, fullname):
+ self._got_source = fullname
+ return 'def foo():\n pass'
+
+
+class DummyUnderOverride:
+ def __call__(self, package, path, source, _info=''):
+ self.package = package
+ self.path = path
+ self.source = source
+
+
+def read_(src):
+ with open(src, 'rb') as f:
+ contents = f.read()
+ return contents
+
+
+def _assertBody(body, filename):
+ # strip both \n and \r for windows
+ body = body.replace(b'\r', b'')
+ body = body.replace(b'\n', b'')
+ data = read_(filename)
+ data = data.replace(b'\r', b'')
+ data = data.replace(b'\n', b'')
+ assert body == data
diff --git a/tests/test_config/test_factories.py b/tests/test_config/test_factories.py
new file mode 100644
index 000000000..c03d3f68b
--- /dev/null
+++ b/tests/test_config/test_factories.py
@@ -0,0 +1,203 @@
+import unittest
+
+from . import dummyfactory
+
+
+class TestFactoriesMixin(unittest.TestCase):
+ def _makeOne(self, *arg, **kw):
+ from pyramid.config import Configurator
+
+ config = Configurator(*arg, **kw)
+ return config
+
+ def test_set_request_factory(self):
+ from pyramid.interfaces import IRequestFactory
+
+ config = self._makeOne(autocommit=True)
+ factory = object()
+ config.set_request_factory(factory)
+ self.assertEqual(config.registry.getUtility(IRequestFactory), factory)
+
+ def test_set_request_factory_dottedname(self):
+ from pyramid.interfaces import IRequestFactory
+
+ config = self._makeOne(autocommit=True)
+ config.set_request_factory('tests.test_config.dummyfactory')
+ self.assertEqual(
+ config.registry.getUtility(IRequestFactory), dummyfactory
+ )
+
+ def test_set_response_factory(self):
+ from pyramid.interfaces import IResponseFactory
+
+ config = self._makeOne(autocommit=True)
+ factory = lambda r: object()
+ config.set_response_factory(factory)
+ self.assertEqual(config.registry.getUtility(IResponseFactory), factory)
+
+ def test_set_response_factory_dottedname(self):
+ from pyramid.interfaces import IResponseFactory
+
+ config = self._makeOne(autocommit=True)
+ config.set_response_factory('tests.test_config.dummyfactory')
+ self.assertEqual(
+ config.registry.getUtility(IResponseFactory), dummyfactory
+ )
+
+ def test_set_root_factory(self):
+ from pyramid.interfaces import IRootFactory
+
+ config = self._makeOne()
+ config.set_root_factory(dummyfactory)
+ self.assertEqual(config.registry.queryUtility(IRootFactory), None)
+ config.commit()
+ self.assertEqual(
+ config.registry.getUtility(IRootFactory), dummyfactory
+ )
+
+ def test_set_root_factory_as_None(self):
+ from pyramid.interfaces import IRootFactory
+ from pyramid.traversal import DefaultRootFactory
+
+ config = self._makeOne()
+ config.set_root_factory(None)
+ self.assertEqual(config.registry.queryUtility(IRootFactory), None)
+ config.commit()
+ self.assertEqual(
+ config.registry.getUtility(IRootFactory), DefaultRootFactory
+ )
+
+ def test_set_root_factory_dottedname(self):
+ from pyramid.interfaces import IRootFactory
+
+ config = self._makeOne()
+ config.set_root_factory('tests.test_config.dummyfactory')
+ self.assertEqual(config.registry.queryUtility(IRootFactory), None)
+ config.commit()
+ self.assertEqual(
+ config.registry.getUtility(IRootFactory), dummyfactory
+ )
+
+ def test_set_session_factory(self):
+ from pyramid.interfaces import ISessionFactory
+
+ config = self._makeOne()
+ config.set_session_factory(dummyfactory)
+ self.assertEqual(config.registry.queryUtility(ISessionFactory), None)
+ config.commit()
+ self.assertEqual(
+ config.registry.getUtility(ISessionFactory), dummyfactory
+ )
+
+ def test_set_session_factory_dottedname(self):
+ from pyramid.interfaces import ISessionFactory
+
+ config = self._makeOne()
+ config.set_session_factory('tests.test_config.dummyfactory')
+ self.assertEqual(config.registry.queryUtility(ISessionFactory), None)
+ config.commit()
+ self.assertEqual(
+ config.registry.getUtility(ISessionFactory), dummyfactory
+ )
+
+ def test_add_request_method_with_callable(self):
+ from pyramid.interfaces import IRequestExtensions
+
+ config = self._makeOne(autocommit=True)
+ callable = lambda x: None
+ config.add_request_method(callable, name='foo')
+ exts = config.registry.getUtility(IRequestExtensions)
+ self.assertTrue('foo' in exts.methods)
+
+ def test_add_request_method_with_unnamed_callable(self):
+ from pyramid.interfaces import IRequestExtensions
+
+ config = self._makeOne(autocommit=True)
+
+ def foo(self): # pragma: no cover
+ pass
+
+ config.add_request_method(foo)
+ exts = config.registry.getUtility(IRequestExtensions)
+ self.assertTrue('foo' in exts.methods)
+
+ def test_set_multiple_request_methods_conflict(self):
+ from pyramid.exceptions import ConfigurationConflictError
+
+ config = self._makeOne()
+
+ def foo(self): # pragma: no cover
+ pass
+
+ def bar(self): # pragma: no cover
+ pass
+
+ config.add_request_method(foo, name='bar')
+ config.add_request_method(bar, name='bar')
+ self.assertRaises(ConfigurationConflictError, config.commit)
+
+ def test_add_request_method_with_None_callable(self):
+ from pyramid.interfaces import IRequestExtensions
+
+ config = self._makeOne(autocommit=True)
+ config.add_request_method(name='foo')
+ exts = config.registry.queryUtility(IRequestExtensions)
+ self.assertTrue(exts is None)
+
+ def test_add_request_method_with_None_callable_conflict(self):
+ from pyramid.exceptions import ConfigurationConflictError
+
+ config = self._makeOne()
+
+ def bar(self): # pragma: no cover
+ pass
+
+ config.add_request_method(name='foo')
+ config.add_request_method(bar, name='foo')
+ self.assertRaises(ConfigurationConflictError, config.commit)
+
+ def test_add_request_method_with_None_callable_and_no_name(self):
+ config = self._makeOne(autocommit=True)
+ self.assertRaises(AttributeError, config.add_request_method)
+
+ def test_add_request_method_with_text_type_name(self):
+ from pyramid.compat import text_, PY2
+ from pyramid.exceptions import ConfigurationError
+
+ config = self._makeOne(autocommit=True)
+
+ def boomshaka(r): # pragma: no cover
+ pass
+
+ def get_bad_name():
+ if PY2:
+ name = text_(b'La Pe\xc3\xb1a', 'utf-8')
+ else:
+ name = b'La Pe\xc3\xb1a'
+
+ config.add_request_method(boomshaka, name=name)
+
+ self.assertRaises(ConfigurationError, get_bad_name)
+
+ def test_set_execution_policy(self):
+ from pyramid.interfaces import IExecutionPolicy
+
+ config = self._makeOne(autocommit=True)
+
+ def dummy_policy(environ, router): # pragma: no cover
+ pass
+
+ config.set_execution_policy(dummy_policy)
+ registry = config.registry
+ result = registry.queryUtility(IExecutionPolicy)
+ self.assertEqual(result, dummy_policy)
+
+ def test_set_execution_policy_to_None(self):
+ from pyramid.interfaces import IExecutionPolicy
+ from pyramid.router import default_execution_policy
+
+ config = self._makeOne(autocommit=True)
+ config.set_execution_policy(None)
+ registry = config.registry
+ result = registry.queryUtility(IExecutionPolicy)
+ self.assertEqual(result, default_execution_policy)
diff --git a/tests/test_config/test_i18n.py b/tests/test_config/test_i18n.py
new file mode 100644
index 000000000..b840c1976
--- /dev/null
+++ b/tests/test_config/test_i18n.py
@@ -0,0 +1,171 @@
+import os
+import unittest
+
+from . import dummyfactory
+
+here = os.path.dirname(__file__)
+locale = os.path.abspath(
+ os.path.join(here, '..', 'pkgs', 'localeapp', 'locale')
+)
+locale2 = os.path.abspath(
+ os.path.join(here, '..', 'pkgs', 'localeapp', 'locale2')
+)
+locale3 = os.path.abspath(
+ os.path.join(here, '..', 'pkgs', 'localeapp', 'locale3')
+)
+
+
+class TestI18NConfiguratorMixin(unittest.TestCase):
+ def _makeOne(self, *arg, **kw):
+ from pyramid.config import Configurator
+
+ config = Configurator(*arg, **kw)
+ return config
+
+ def test_set_locale_negotiator(self):
+ from pyramid.interfaces import ILocaleNegotiator
+
+ config = self._makeOne(autocommit=True)
+
+ def negotiator(request): # pragma: no cover
+ pass
+
+ config.set_locale_negotiator(negotiator)
+ self.assertEqual(
+ config.registry.getUtility(ILocaleNegotiator), negotiator
+ )
+
+ def test_set_locale_negotiator_dottedname(self):
+ from pyramid.interfaces import ILocaleNegotiator
+
+ config = self._makeOne(autocommit=True)
+ config.set_locale_negotiator('tests.test_config.dummyfactory')
+ self.assertEqual(
+ config.registry.getUtility(ILocaleNegotiator), dummyfactory
+ )
+
+ def test_add_translation_dirs_missing_dir(self):
+ from pyramid.exceptions import ConfigurationError
+
+ config = self._makeOne()
+ config.add_translation_dirs('/wont/exist/on/my/system')
+ self.assertRaises(ConfigurationError, config.commit)
+
+ def test_add_translation_dirs_no_specs(self):
+ from pyramid.interfaces import ITranslationDirectories
+
+ config = self._makeOne()
+ config.add_translation_dirs()
+ self.assertEqual(
+ config.registry.queryUtility(ITranslationDirectories), None
+ )
+
+ def test_add_translation_dirs_asset_spec(self):
+ from pyramid.interfaces import ITranslationDirectories
+
+ config = self._makeOne(autocommit=True)
+ config.add_translation_dirs('tests.pkgs.localeapp:locale')
+ self.assertEqual(
+ config.registry.getUtility(ITranslationDirectories), [locale]
+ )
+
+ def test_add_translation_dirs_asset_spec_existing_translation_dirs(self):
+ from pyramid.interfaces import ITranslationDirectories
+
+ config = self._makeOne(autocommit=True)
+ directories = ['abc']
+ config.registry.registerUtility(directories, ITranslationDirectories)
+ config.add_translation_dirs('tests.pkgs.localeapp:locale')
+ result = config.registry.getUtility(ITranslationDirectories)
+ self.assertEqual(result, [locale, 'abc'])
+
+ def test_add_translation_dirs_multiple_specs(self):
+ from pyramid.interfaces import ITranslationDirectories
+
+ config = self._makeOne(autocommit=True)
+ config.add_translation_dirs(
+ 'tests.pkgs.localeapp:locale', 'tests.pkgs.localeapp:locale2'
+ )
+ self.assertEqual(
+ config.registry.getUtility(ITranslationDirectories),
+ [locale, locale2],
+ )
+
+ def test_add_translation_dirs_multiple_specs_multiple_calls(self):
+ from pyramid.interfaces import ITranslationDirectories
+
+ config = self._makeOne(autocommit=True)
+ config.add_translation_dirs(
+ 'tests.pkgs.localeapp:locale', 'tests.pkgs.localeapp:locale2'
+ )
+ config.add_translation_dirs('tests.pkgs.localeapp:locale3')
+ self.assertEqual(
+ config.registry.getUtility(ITranslationDirectories),
+ [locale3, locale, locale2],
+ )
+
+ def test_add_translation_dirs_override_multiple_specs_multiple_calls(self):
+ from pyramid.interfaces import ITranslationDirectories
+
+ config = self._makeOne(autocommit=True)
+ config.add_translation_dirs(
+ 'tests.pkgs.localeapp:locale', 'tests.pkgs.localeapp:locale2'
+ )
+ config.add_translation_dirs(
+ 'tests.pkgs.localeapp:locale3', override=True
+ )
+ self.assertEqual(
+ config.registry.getUtility(ITranslationDirectories),
+ [locale, locale2, locale3],
+ )
+
+ def test_add_translation_dirs_invalid_kwargs(self):
+ config = self._makeOne(autocommit=True)
+ with self.assertRaises(TypeError):
+ config.add_translation_dirs('tests.pkgs.localeapp:locale', foo=1)
+
+ def test_add_translation_dirs_abspath(self):
+ from pyramid.interfaces import ITranslationDirectories
+
+ config = self._makeOne(autocommit=True)
+ config.add_translation_dirs(locale)
+ self.assertEqual(
+ config.registry.getUtility(ITranslationDirectories), [locale]
+ )
+
+ def test_add_translation_dirs_uses_override_out_of_order(self):
+ from pyramid.interfaces import ITranslationDirectories
+
+ config = self._makeOne()
+ config.add_translation_dirs('tests.pkgs.localeapp:locale')
+ config.override_asset(
+ 'tests.pkgs.localeapp:locale/', 'tests.pkgs.localeapp:locale2/'
+ )
+ config.commit()
+ self.assertEqual(
+ config.registry.getUtility(ITranslationDirectories), [locale2]
+ )
+
+ def test_add_translation_dirs_doesnt_use_override_w_autocommit(self):
+ from pyramid.interfaces import ITranslationDirectories
+
+ config = self._makeOne(autocommit=True)
+ config.add_translation_dirs('tests.pkgs.localeapp:locale')
+ config.override_asset(
+ 'tests.pkgs.localeapp:locale/', 'tests.pkgs.localeapp:locale2/'
+ )
+ self.assertEqual(
+ config.registry.getUtility(ITranslationDirectories), [locale]
+ )
+
+ def test_add_translation_dirs_uses_override_w_autocommit(self):
+ from pyramid.interfaces import ITranslationDirectories
+
+ config = self._makeOne(autocommit=True)
+ config.override_asset(
+ 'tests.pkgs.localeapp:locale/', 'tests.pkgs.localeapp:locale2/'
+ )
+ config.add_translation_dirs('tests.pkgs.localeapp:locale')
+ self.assertEqual(
+ config.registry.getUtility(ITranslationDirectories), [locale2]
+ )
diff --git a/tests/test_config/test_init.py b/tests/test_config/test_init.py
new file mode 100644
index 000000000..811672fb3
--- /dev/null
+++ b/tests/test_config/test_init.py
@@ -0,0 +1,1455 @@
+import os
+import unittest
+
+from pyramid.compat import im_func
+from pyramid.testing import skip_on
+
+from . import dummy_tween_factory
+from . import dummy_include
+from . import dummy_extend
+from . import dummy_extend2
+from . import DummyContext
+
+from pyramid.exceptions import ConfigurationExecutionError
+from pyramid.exceptions import ConfigurationConflictError
+
+from pyramid.interfaces import IRequest
+
+
+class ConfiguratorTests(unittest.TestCase):
+ def _makeOne(self, *arg, **kw):
+ from pyramid.config import Configurator
+
+ config = Configurator(*arg, **kw)
+ return config
+
+ def _getViewCallable(
+ self,
+ config,
+ ctx_iface=None,
+ request_iface=None,
+ name='',
+ exception_view=False,
+ ):
+ from pyramid.interfaces import IView
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IExceptionViewClassifier
+
+ if exception_view: # pragma: no cover
+ classifier = IExceptionViewClassifier
+ else:
+ classifier = IViewClassifier
+ return config.registry.adapters.lookup(
+ (classifier, request_iface, ctx_iface),
+ IView,
+ name=name,
+ default=None,
+ )
+
+ def _registerEventListener(self, config, event_iface=None):
+ if event_iface is None: # pragma: no cover
+ from zope.interface import Interface
+
+ event_iface = Interface
+ L = []
+
+ def subscriber(*event):
+ L.extend(event)
+
+ config.registry.registerHandler(subscriber, (event_iface,))
+ return L
+
+ def _makeRequest(self, config):
+ request = DummyRequest()
+ request.registry = config.registry
+ return request
+
+ def test_ctor_no_registry(self):
+ import sys
+ from pyramid.interfaces import ISettings
+ from pyramid.config import Configurator
+ from pyramid.interfaces import IRendererFactory
+
+ config = Configurator()
+ this_pkg = sys.modules['tests.test_config']
+ self.assertTrue(config.registry.getUtility(ISettings))
+ self.assertEqual(config.package, this_pkg)
+ config.commit()
+ self.assertTrue(config.registry.getUtility(IRendererFactory, 'json'))
+ self.assertTrue(config.registry.getUtility(IRendererFactory, 'string'))
+
+ def test_begin(self):
+ from pyramid.config import Configurator
+
+ config = Configurator()
+ manager = DummyThreadLocalManager()
+ config.manager = manager
+ config.begin()
+ self.assertEqual(
+ manager.pushed, {'registry': config.registry, 'request': None}
+ )
+ self.assertEqual(manager.popped, False)
+
+ def test_begin_with_request(self):
+ from pyramid.config import Configurator
+
+ config = Configurator()
+ request = object()
+ manager = DummyThreadLocalManager()
+ config.manager = manager
+ config.begin(request=request)
+ self.assertEqual(
+ manager.pushed, {'registry': config.registry, 'request': request}
+ )
+ self.assertEqual(manager.popped, False)
+
+ def test_begin_overrides_request(self):
+ from pyramid.config import Configurator
+
+ config = Configurator()
+ manager = DummyThreadLocalManager()
+ req = object()
+ # set it up for auto-propagation
+ pushed = {'registry': config.registry, 'request': None}
+ manager.pushed = pushed
+ config.manager = manager
+ config.begin(req)
+ self.assertTrue(manager.pushed is not pushed)
+ self.assertEqual(manager.pushed['request'], req)
+ self.assertEqual(manager.pushed['registry'], config.registry)
+
+ def test_begin_propagates_request_for_same_registry(self):
+ from pyramid.config import Configurator
+
+ config = Configurator()
+ manager = DummyThreadLocalManager()
+ req = object()
+ pushed = {'registry': config.registry, 'request': req}
+ manager.pushed = pushed
+ config.manager = manager
+ config.begin()
+ self.assertTrue(manager.pushed is not pushed)
+ self.assertEqual(manager.pushed['request'], req)
+ self.assertEqual(manager.pushed['registry'], config.registry)
+
+ def test_begin_does_not_propagate_request_for_diff_registry(self):
+ from pyramid.config import Configurator
+
+ config = Configurator()
+ manager = DummyThreadLocalManager()
+ req = object()
+ pushed = {'registry': object(), 'request': req}
+ manager.pushed = pushed
+ config.manager = manager
+ config.begin()
+ self.assertTrue(manager.pushed is not pushed)
+ self.assertEqual(manager.pushed['request'], None)
+ self.assertEqual(manager.pushed['registry'], config.registry)
+
+ def test_end(self):
+ from pyramid.config import Configurator
+
+ config = Configurator()
+ manager = DummyThreadLocalManager()
+ pushed = manager.pushed
+ config.manager = manager
+ config.end()
+ self.assertEqual(manager.pushed, pushed)
+ self.assertEqual(manager.popped, True)
+
+ def test_context_manager(self):
+ from pyramid.config import Configurator
+
+ config = Configurator()
+ manager = DummyThreadLocalManager()
+ config.manager = manager
+ view = lambda r: None
+ with config as ctx:
+ self.assertTrue(config is ctx)
+ self.assertEqual(
+ manager.pushed, {'registry': config.registry, 'request': None}
+ )
+ self.assertFalse(manager.popped)
+ config.add_view(view)
+ self.assertTrue(manager.popped)
+ config.add_view(view) # did not raise a conflict because of commit
+ config.commit()
+
+ def test_ctor_with_package_registry(self):
+ import sys
+ from pyramid.config import Configurator
+
+ pkg = sys.modules['pyramid']
+ config = Configurator(package=pkg)
+ self.assertEqual(config.package, pkg)
+
+ def test_ctor_noreg_custom_settings(self):
+ from pyramid.interfaces import ISettings
+
+ settings = {'reload_templates': True, 'mysetting': True}
+ config = self._makeOne(settings=settings)
+ settings = config.registry.getUtility(ISettings)
+ self.assertEqual(settings['reload_templates'], True)
+ self.assertEqual(settings['debug_authorization'], False)
+ self.assertEqual(settings['mysetting'], True)
+
+ def test_ctor_noreg_debug_logger_None_default(self):
+ from pyramid.interfaces import IDebugLogger
+
+ config = self._makeOne()
+ logger = config.registry.getUtility(IDebugLogger)
+ self.assertEqual(logger.name, 'tests.test_config')
+
+ def test_ctor_noreg_debug_logger_non_None(self):
+ from pyramid.interfaces import IDebugLogger
+
+ logger = object()
+ config = self._makeOne(debug_logger=logger)
+ result = config.registry.getUtility(IDebugLogger)
+ self.assertEqual(logger, result)
+
+ def test_ctor_authentication_policy(self):
+ from pyramid.interfaces import IAuthenticationPolicy
+
+ policy = object()
+ config = self._makeOne(authentication_policy=policy)
+ config.commit()
+ result = config.registry.getUtility(IAuthenticationPolicy)
+ self.assertEqual(policy, result)
+
+ def test_ctor_authorization_policy_only(self):
+ policy = object()
+ config = self._makeOne(authorization_policy=policy)
+ self.assertRaises(ConfigurationExecutionError, config.commit)
+
+ def test_ctor_no_root_factory(self):
+ from pyramid.interfaces import IRootFactory
+
+ config = self._makeOne()
+ self.assertEqual(config.registry.queryUtility(IRootFactory), None)
+ config.commit()
+ self.assertEqual(config.registry.queryUtility(IRootFactory), None)
+
+ def test_ctor_with_root_factory(self):
+ from pyramid.interfaces import IRootFactory
+
+ factory = object()
+ config = self._makeOne(root_factory=factory)
+ self.assertEqual(config.registry.queryUtility(IRootFactory), None)
+ config.commit()
+ self.assertEqual(config.registry.queryUtility(IRootFactory), factory)
+
+ def test_ctor_alternate_renderers(self):
+ from pyramid.interfaces import IRendererFactory
+
+ renderer = object()
+ config = self._makeOne(renderers=[('yeah', renderer)])
+ config.commit()
+ self.assertEqual(
+ config.registry.getUtility(IRendererFactory, 'yeah'), renderer
+ )
+
+ def test_ctor_default_renderers(self):
+ from pyramid.interfaces import IRendererFactory
+ from pyramid.renderers import json_renderer_factory
+
+ config = self._makeOne()
+ self.assertEqual(
+ config.registry.getUtility(IRendererFactory, 'json'),
+ json_renderer_factory,
+ )
+
+ def test_ctor_default_permission(self):
+ from pyramid.interfaces import IDefaultPermission
+
+ config = self._makeOne(default_permission='view')
+ config.commit()
+ self.assertEqual(
+ config.registry.getUtility(IDefaultPermission), 'view'
+ )
+
+ def test_ctor_session_factory(self):
+ from pyramid.interfaces import ISessionFactory
+
+ factory = object()
+ config = self._makeOne(session_factory=factory)
+ self.assertEqual(config.registry.queryUtility(ISessionFactory), None)
+ config.commit()
+ self.assertEqual(config.registry.getUtility(ISessionFactory), factory)
+
+ def test_ctor_default_view_mapper(self):
+ from pyramid.interfaces import IViewMapperFactory
+
+ mapper = object()
+ config = self._makeOne(default_view_mapper=mapper)
+ config.commit()
+ self.assertEqual(
+ config.registry.getUtility(IViewMapperFactory), mapper
+ )
+
+ def test_ctor_httpexception_view_default(self):
+ from pyramid.interfaces import IExceptionResponse
+ from pyramid.httpexceptions import default_exceptionresponse_view
+
+ config = self._makeOne()
+ view = self._getViewCallable(
+ config, ctx_iface=IExceptionResponse, request_iface=IRequest
+ )
+ self.assertTrue(view.__wraps__ is default_exceptionresponse_view)
+
+ def test_ctor_exceptionresponse_view_None(self):
+ from pyramid.interfaces import IExceptionResponse
+
+ config = self._makeOne(exceptionresponse_view=None)
+ view = self._getViewCallable(
+ config, ctx_iface=IExceptionResponse, request_iface=IRequest
+ )
+ self.assertTrue(view is None)
+
+ def test_ctor_exceptionresponse_view_custom(self):
+ from pyramid.interfaces import IExceptionResponse
+
+ def exceptionresponse_view(context, request): # pragma: no cover
+ pass
+
+ config = self._makeOne(exceptionresponse_view=exceptionresponse_view)
+ view = self._getViewCallable(
+ config, ctx_iface=IExceptionResponse, request_iface=IRequest
+ )
+ self.assertTrue(view.__wraps__ is exceptionresponse_view)
+
+ def test_ctor_with_introspection(self):
+ config = self._makeOne(introspection=False)
+ self.assertEqual(config.introspection, False)
+
+ def test_ctor_default_webob_response_adapter_registered(self):
+ from webob import Response as WebobResponse
+
+ response = WebobResponse()
+ from pyramid.interfaces import IResponse
+
+ config = self._makeOne(autocommit=True)
+ result = config.registry.queryAdapter(response, IResponse)
+ self.assertEqual(result, response)
+
+ def test_with_package_module(self):
+ from . import test_init
+
+ config = self._makeOne()
+ newconfig = config.with_package(test_init)
+ import tests.test_config
+
+ self.assertEqual(newconfig.package, tests.test_config)
+
+ def test_with_package_package(self):
+ from tests import test_config
+
+ config = self._makeOne()
+ newconfig = config.with_package(test_config)
+ self.assertEqual(newconfig.package, test_config)
+
+ def test_with_package(self):
+ import tests
+
+ config = self._makeOne()
+ config.basepath = 'basepath'
+ config.info = 'info'
+ config.includepath = ('spec',)
+ config.autocommit = True
+ config.route_prefix = 'prefix'
+ newconfig = config.with_package(tests)
+ self.assertEqual(newconfig.package, tests)
+ self.assertEqual(newconfig.registry, config.registry)
+ self.assertEqual(newconfig.autocommit, True)
+ self.assertEqual(newconfig.route_prefix, 'prefix')
+ self.assertEqual(newconfig.info, 'info')
+ self.assertEqual(newconfig.basepath, 'basepath')
+ self.assertEqual(newconfig.includepath, ('spec',))
+
+ def test_maybe_dotted_string_success(self):
+ import tests.test_config
+
+ config = self._makeOne()
+ result = config.maybe_dotted('tests.test_config')
+ self.assertEqual(result, tests.test_config)
+
+ def test_maybe_dotted_string_fail(self):
+ config = self._makeOne()
+ self.assertRaises(ImportError, config.maybe_dotted, 'cant.be.found')
+
+ def test_maybe_dotted_notstring_success(self):
+ import tests.test_config
+
+ config = self._makeOne()
+ result = config.maybe_dotted(tests.test_config)
+ self.assertEqual(result, tests.test_config)
+
+ def test_absolute_asset_spec_already_absolute(self):
+ import tests.test_config
+
+ config = self._makeOne(package=tests.test_config)
+ result = config.absolute_asset_spec('already:absolute')
+ self.assertEqual(result, 'already:absolute')
+
+ def test_absolute_asset_spec_notastring(self):
+ import tests.test_config
+
+ config = self._makeOne(package=tests.test_config)
+ result = config.absolute_asset_spec(None)
+ self.assertEqual(result, None)
+
+ def test_absolute_asset_spec_relative(self):
+ import tests.test_config
+
+ config = self._makeOne(package=tests.test_config)
+ result = config.absolute_asset_spec('files')
+ self.assertEqual(result, 'tests.test_config:files')
+
+ def test__fix_registry_has_listeners(self):
+ reg = DummyRegistry()
+ config = self._makeOne(reg)
+ config._fix_registry()
+ self.assertEqual(reg.has_listeners, True)
+
+ def test__fix_registry_notify(self):
+ reg = DummyRegistry()
+ config = self._makeOne(reg)
+ config._fix_registry()
+ self.assertEqual(reg.notify(1), None)
+ self.assertEqual(reg.events, (1,))
+
+ def test__fix_registry_queryAdapterOrSelf(self):
+ from zope.interface import Interface
+ from zope.interface import implementer
+
+ class IFoo(Interface):
+ pass
+
+ @implementer(IFoo)
+ class Foo(object):
+ pass
+
+ class Bar(object):
+ pass
+
+ adaptation = ()
+ foo = Foo()
+ bar = Bar()
+ reg = DummyRegistry(adaptation)
+ config = self._makeOne(reg)
+ config._fix_registry()
+ self.assertTrue(reg.queryAdapterOrSelf(foo, IFoo) is foo)
+ self.assertTrue(reg.queryAdapterOrSelf(bar, IFoo) is adaptation)
+
+ def test__fix_registry_registerSelfAdapter(self):
+ reg = DummyRegistry()
+ config = self._makeOne(reg)
+ config._fix_registry()
+ reg.registerSelfAdapter('required', 'provided', name='abc')
+ self.assertEqual(len(reg.adapters), 1)
+ args, kw = reg.adapters[0]
+ self.assertEqual(args[0]('abc'), 'abc')
+ self.assertEqual(
+ kw,
+ {
+ 'info': '',
+ 'provided': 'provided',
+ 'required': 'required',
+ 'name': 'abc',
+ 'event': True,
+ },
+ )
+
+ def test__fix_registry_adds__lock(self):
+ reg = DummyRegistry()
+ config = self._makeOne(reg)
+ config._fix_registry()
+ self.assertTrue(hasattr(reg, '_lock'))
+
+ def test__fix_registry_adds_clear_view_lookup_cache(self):
+ reg = DummyRegistry()
+ config = self._makeOne(reg)
+ self.assertFalse(hasattr(reg, '_clear_view_lookup_cache'))
+ config._fix_registry()
+ self.assertFalse(hasattr(reg, '_view_lookup_cache'))
+ reg._clear_view_lookup_cache()
+ self.assertEqual(reg._view_lookup_cache, {})
+
+ def test_setup_registry_calls_fix_registry(self):
+ reg = DummyRegistry()
+ config = self._makeOne(reg)
+ config.add_view = lambda *arg, **kw: False
+ config._add_tween = lambda *arg, **kw: False
+ config.setup_registry()
+ self.assertEqual(reg.has_listeners, True)
+
+ def test_setup_registry_registers_default_exceptionresponse_views(self):
+ from webob.exc import WSGIHTTPException
+ from pyramid.interfaces import IExceptionResponse
+ from pyramid.view import default_exceptionresponse_view
+
+ reg = DummyRegistry()
+ config = self._makeOne(reg)
+ views = []
+ config.add_view = lambda *arg, **kw: views.append((arg, kw))
+ config.add_default_view_predicates = lambda *arg: None
+ config._add_tween = lambda *arg, **kw: False
+ config.setup_registry()
+ self.assertEqual(
+ views[0],
+ (
+ (default_exceptionresponse_view,),
+ {'context': IExceptionResponse},
+ ),
+ )
+ self.assertEqual(
+ views[1],
+ (
+ (default_exceptionresponse_view,),
+ {'context': WSGIHTTPException},
+ ),
+ )
+
+ def test_setup_registry_registers_default_view_predicates(self):
+ reg = DummyRegistry()
+ config = self._makeOne(reg)
+ vp_called = []
+ config.add_view = lambda *arg, **kw: None
+ config.add_default_view_predicates = lambda *arg: vp_called.append(
+ True
+ )
+ config._add_tween = lambda *arg, **kw: False
+ config.setup_registry()
+ self.assertTrue(vp_called)
+
+ def test_setup_registry_registers_default_webob_iresponse_adapter(self):
+ from webob import Response
+ from pyramid.interfaces import IResponse
+
+ config = self._makeOne()
+ config.setup_registry()
+ response = Response()
+ self.assertTrue(
+ config.registry.queryAdapter(response, IResponse) is response
+ )
+
+ def test_setup_registry_explicit_notfound_trumps_iexceptionresponse(self):
+ from pyramid.renderers import null_renderer
+ from zope.interface import implementedBy
+ from pyramid.httpexceptions import HTTPNotFound
+ from pyramid.registry import Registry
+
+ reg = Registry()
+ config = self._makeOne(reg, autocommit=True)
+ config.setup_registry() # registers IExceptionResponse default view
+
+ def myview(context, request):
+ return 'OK'
+
+ config.add_view(myview, context=HTTPNotFound, renderer=null_renderer)
+ request = self._makeRequest(config)
+ view = self._getViewCallable(
+ config,
+ ctx_iface=implementedBy(HTTPNotFound),
+ request_iface=IRequest,
+ )
+ result = view(None, request)
+ self.assertEqual(result, 'OK')
+
+ def test_setup_registry_custom_settings(self):
+ from pyramid.registry import Registry
+ from pyramid.interfaces import ISettings
+
+ settings = {'reload_templates': True, 'mysetting': True}
+ reg = Registry()
+ config = self._makeOne(reg)
+ config.setup_registry(settings=settings)
+ settings = reg.getUtility(ISettings)
+ self.assertEqual(settings['reload_templates'], True)
+ self.assertEqual(settings['debug_authorization'], False)
+ self.assertEqual(settings['mysetting'], True)
+
+ def test_setup_registry_debug_logger_None_default(self):
+ from pyramid.registry import Registry
+ from pyramid.interfaces import IDebugLogger
+
+ reg = Registry()
+ config = self._makeOne(reg)
+ config.setup_registry()
+ logger = reg.getUtility(IDebugLogger)
+ self.assertEqual(logger.name, 'tests.test_config')
+
+ def test_setup_registry_debug_logger_non_None(self):
+ from pyramid.registry import Registry
+ from pyramid.interfaces import IDebugLogger
+
+ logger = object()
+ reg = Registry()
+ config = self._makeOne(reg)
+ config.setup_registry(debug_logger=logger)
+ result = reg.getUtility(IDebugLogger)
+ self.assertEqual(logger, result)
+
+ def test_setup_registry_debug_logger_name(self):
+ from pyramid.registry import Registry
+ from pyramid.interfaces import IDebugLogger
+
+ reg = Registry()
+ config = self._makeOne(reg)
+ config.setup_registry(debug_logger='foo')
+ result = reg.getUtility(IDebugLogger)
+ self.assertEqual(result.name, 'foo')
+
+ def test_setup_registry_authentication_policy(self):
+ from pyramid.registry import Registry
+ from pyramid.interfaces import IAuthenticationPolicy
+
+ policy = object()
+ reg = Registry()
+ config = self._makeOne(reg)
+ config.setup_registry(authentication_policy=policy)
+ config.commit()
+ result = reg.getUtility(IAuthenticationPolicy)
+ self.assertEqual(policy, result)
+
+ def test_setup_registry_authentication_policy_dottedname(self):
+ from pyramid.registry import Registry
+ from pyramid.interfaces import IAuthenticationPolicy
+
+ reg = Registry()
+ config = self._makeOne(reg)
+ config.setup_registry(authentication_policy='tests.test_config')
+ config.commit()
+ result = reg.getUtility(IAuthenticationPolicy)
+ import tests.test_config
+
+ self.assertEqual(result, tests.test_config)
+
+ def test_setup_registry_authorization_policy_dottedname(self):
+ from pyramid.registry import Registry
+ from pyramid.interfaces import IAuthorizationPolicy
+
+ reg = Registry()
+ config = self._makeOne(reg)
+ dummy = object()
+ config.setup_registry(
+ authentication_policy=dummy,
+ authorization_policy='tests.test_config',
+ )
+ config.commit()
+ result = reg.getUtility(IAuthorizationPolicy)
+ import tests.test_config
+
+ self.assertEqual(result, tests.test_config)
+
+ def test_setup_registry_authorization_policy_only(self):
+ from pyramid.registry import Registry
+
+ policy = object()
+ reg = Registry()
+ config = self._makeOne(reg)
+ config.setup_registry(authorization_policy=policy)
+ config = self.assertRaises(ConfigurationExecutionError, config.commit)
+
+ def test_setup_registry_no_default_root_factory(self):
+ from pyramid.registry import Registry
+ from pyramid.interfaces import IRootFactory
+
+ reg = Registry()
+ config = self._makeOne(reg)
+ config.setup_registry()
+ config.commit()
+ self.assertEqual(reg.queryUtility(IRootFactory), None)
+
+ def test_setup_registry_dottedname_root_factory(self):
+ from pyramid.registry import Registry
+ from pyramid.interfaces import IRootFactory
+
+ reg = Registry()
+ config = self._makeOne(reg)
+ import tests.test_config
+
+ config.setup_registry(root_factory='tests.test_config')
+ self.assertEqual(reg.queryUtility(IRootFactory), None)
+ config.commit()
+ self.assertEqual(reg.getUtility(IRootFactory), tests.test_config)
+
+ def test_setup_registry_locale_negotiator_dottedname(self):
+ from pyramid.registry import Registry
+ from pyramid.interfaces import ILocaleNegotiator
+
+ reg = Registry()
+ config = self._makeOne(reg)
+ import tests.test_config
+
+ config.setup_registry(locale_negotiator='tests.test_config')
+ self.assertEqual(reg.queryUtility(ILocaleNegotiator), None)
+ config.commit()
+ utility = reg.getUtility(ILocaleNegotiator)
+ self.assertEqual(utility, tests.test_config)
+
+ def test_setup_registry_locale_negotiator(self):
+ from pyramid.registry import Registry
+ from pyramid.interfaces import ILocaleNegotiator
+
+ reg = Registry()
+ config = self._makeOne(reg)
+ negotiator = object()
+ config.setup_registry(locale_negotiator=negotiator)
+ self.assertEqual(reg.queryUtility(ILocaleNegotiator), None)
+ config.commit()
+ utility = reg.getUtility(ILocaleNegotiator)
+ self.assertEqual(utility, negotiator)
+
+ def test_setup_registry_request_factory(self):
+ from pyramid.registry import Registry
+ from pyramid.interfaces import IRequestFactory
+
+ reg = Registry()
+ config = self._makeOne(reg)
+ factory = object()
+ config.setup_registry(request_factory=factory)
+ self.assertEqual(reg.queryUtility(IRequestFactory), None)
+ config.commit()
+ utility = reg.getUtility(IRequestFactory)
+ self.assertEqual(utility, factory)
+
+ def test_setup_registry_response_factory(self):
+ from pyramid.registry import Registry
+ from pyramid.interfaces import IResponseFactory
+
+ reg = Registry()
+ config = self._makeOne(reg)
+ factory = lambda r: object()
+ config.setup_registry(response_factory=factory)
+ self.assertEqual(reg.queryUtility(IResponseFactory), None)
+ config.commit()
+ utility = reg.getUtility(IResponseFactory)
+ self.assertEqual(utility, factory)
+
+ def test_setup_registry_request_factory_dottedname(self):
+ from pyramid.registry import Registry
+ from pyramid.interfaces import IRequestFactory
+
+ reg = Registry()
+ config = self._makeOne(reg)
+ import tests.test_config
+
+ config.setup_registry(request_factory='tests.test_config')
+ self.assertEqual(reg.queryUtility(IRequestFactory), None)
+ config.commit()
+ utility = reg.getUtility(IRequestFactory)
+ self.assertEqual(utility, tests.test_config)
+
+ def test_setup_registry_alternate_renderers(self):
+ from pyramid.registry import Registry
+ from pyramid.interfaces import IRendererFactory
+
+ renderer = object()
+ reg = Registry()
+ config = self._makeOne(reg)
+ config.setup_registry(renderers=[('yeah', renderer)])
+ config.commit()
+ self.assertEqual(reg.getUtility(IRendererFactory, 'yeah'), renderer)
+
+ def test_setup_registry_default_permission(self):
+ from pyramid.registry import Registry
+ from pyramid.interfaces import IDefaultPermission
+
+ reg = Registry()
+ config = self._makeOne(reg)
+ config.setup_registry(default_permission='view')
+ config.commit()
+ self.assertEqual(reg.getUtility(IDefaultPermission), 'view')
+
+ def test_setup_registry_includes(self):
+ from pyramid.registry import Registry
+
+ reg = Registry()
+ config = self._makeOne(reg)
+ settings = {
+ 'pyramid.includes': """tests.test_config.dummy_include
+tests.test_config.dummy_include2"""
+ }
+ config.setup_registry(settings=settings)
+ self.assertTrue(reg.included)
+ self.assertTrue(reg.also_included)
+
+ def test_setup_registry_includes_spaces(self):
+ from pyramid.registry import Registry
+
+ reg = Registry()
+ config = self._makeOne(reg)
+ settings = {
+ 'pyramid.includes': """tests.test_config.dummy_include tests.\
+test_config.dummy_include2"""
+ }
+ config.setup_registry(settings=settings)
+ self.assertTrue(reg.included)
+ self.assertTrue(reg.also_included)
+
+ def test_setup_registry_tweens(self):
+ from pyramid.interfaces import ITweens
+ from pyramid.registry import Registry
+
+ reg = Registry()
+ config = self._makeOne(reg)
+ settings = {'pyramid.tweens': 'tests.test_config.dummy_tween_factory'}
+ config.setup_registry(settings=settings)
+ config.commit()
+ tweens = config.registry.getUtility(ITweens)
+ self.assertEqual(
+ tweens.explicit,
+ [('tests.test_config.dummy_tween_factory', dummy_tween_factory)],
+ )
+
+ def test_introspector_decorator(self):
+ inst = self._makeOne()
+ default = inst.introspector
+ self.assertTrue(hasattr(default, 'add'))
+ self.assertEqual(inst.introspector, inst.registry.introspector)
+ introspector = object()
+ inst.introspector = introspector
+ new = inst.introspector
+ self.assertTrue(new is introspector)
+ self.assertEqual(inst.introspector, inst.registry.introspector)
+ del inst.introspector
+ default = inst.introspector
+ self.assertFalse(default is new)
+ self.assertTrue(hasattr(default, 'add'))
+
+ def test_make_wsgi_app(self):
+ import pyramid.config
+ from pyramid.router import Router
+ from pyramid.interfaces import IApplicationCreated
+
+ manager = DummyThreadLocalManager()
+ config = self._makeOne()
+ subscriber = self._registerEventListener(config, IApplicationCreated)
+ config.manager = manager
+ app = config.make_wsgi_app()
+ self.assertEqual(app.__class__, Router)
+ self.assertEqual(manager.pushed['registry'], config.registry)
+ self.assertEqual(manager.pushed['request'], None)
+ self.assertTrue(manager.popped)
+ self.assertEqual(pyramid.config.global_registries.last, app.registry)
+ self.assertEqual(len(subscriber), 1)
+ self.assertTrue(IApplicationCreated.providedBy(subscriber[0]))
+ pyramid.config.global_registries.empty()
+
+ def test_include_with_dotted_name(self):
+ from tests import test_config
+
+ config = self._makeOne()
+ config.include('tests.test_config.dummy_include')
+ after = config.action_state
+ actions = after.actions
+ self.assertEqual(len(actions), 1)
+ action = after.actions[0]
+ self.assertEqual(action['discriminator'], 'discrim')
+ self.assertEqual(action['callable'], None)
+ self.assertEqual(action['args'], test_config)
+
+ def test_include_with_python_callable(self):
+ from tests import test_config
+
+ config = self._makeOne()
+ config.include(dummy_include)
+ after = config.action_state
+ actions = after.actions
+ self.assertEqual(len(actions), 1)
+ action = actions[0]
+ self.assertEqual(action['discriminator'], 'discrim')
+ self.assertEqual(action['callable'], None)
+ self.assertEqual(action['args'], test_config)
+
+ def test_include_with_module_defaults_to_includeme(self):
+ from tests import test_config
+
+ config = self._makeOne()
+ config.include('tests.test_config')
+ after = config.action_state
+ actions = after.actions
+ self.assertEqual(len(actions), 1)
+ action = actions[0]
+ self.assertEqual(action['discriminator'], 'discrim')
+ self.assertEqual(action['callable'], None)
+ self.assertEqual(action['args'], test_config)
+
+ def test_include_with_module_defaults_to_includeme_missing(self):
+ from pyramid.exceptions import ConfigurationError
+
+ config = self._makeOne()
+ self.assertRaises(ConfigurationError, config.include, 'tests')
+
+ def test_include_with_route_prefix(self):
+ root_config = self._makeOne(autocommit=True)
+
+ def dummy_subapp(config):
+ self.assertEqual(config.route_prefix, 'root')
+
+ root_config.include(dummy_subapp, route_prefix='root')
+
+ def test_include_with_nested_route_prefix(self):
+ root_config = self._makeOne(autocommit=True, route_prefix='root')
+
+ def dummy_subapp2(config):
+ self.assertEqual(config.route_prefix, 'root/nested')
+
+ def dummy_subapp3(config):
+ self.assertEqual(config.route_prefix, 'root/nested/nested2')
+ config.include(dummy_subapp4)
+
+ def dummy_subapp4(config):
+ self.assertEqual(config.route_prefix, 'root/nested/nested2')
+
+ def dummy_subapp(config):
+ self.assertEqual(config.route_prefix, 'root/nested')
+ config.include(dummy_subapp2)
+ config.include(dummy_subapp3, route_prefix='nested2')
+
+ root_config.include(dummy_subapp, route_prefix='nested')
+
+ def test_include_with_missing_source_file(self):
+ from pyramid.exceptions import ConfigurationError
+ import inspect
+
+ config = self._makeOne()
+
+ class DummyInspect(object):
+ def getmodule(self, c):
+ return inspect.getmodule(c)
+
+ def getsourcefile(self, c):
+ return None
+
+ config.inspect = DummyInspect()
+ try:
+ config.include('tests.test_config.dummy_include')
+ except ConfigurationError as e:
+ self.assertEqual(
+ e.args[0],
+ "No source file for module 'tests.test_config' (.py "
+ "file must exist, refusing to use orphan .pyc or .pyo file).",
+ )
+ else: # pragma: no cover
+ raise AssertionError
+
+ def test_include_constant_root_package(self):
+ import tests
+ from tests import test_config
+
+ config = self._makeOne(root_package=tests)
+ results = {}
+
+ def include(config):
+ results['package'] = config.package
+ results['root_package'] = config.root_package
+
+ config.include(include)
+ self.assertEqual(results['root_package'], tests)
+ self.assertEqual(results['package'], test_config)
+
+ def test_include_threadlocals_active(self):
+ from pyramid.threadlocal import get_current_registry
+
+ stack = []
+
+ def include(config):
+ stack.append(get_current_registry())
+
+ config = self._makeOne()
+ config.include(include)
+ self.assertTrue(stack[0] is config.registry)
+
+ def test_scan_integration(self):
+ from zope.interface import alsoProvides
+ from pyramid.view import render_view_to_response
+ import tests.test_config.pkgs.scannable as package
+
+ config = self._makeOne(autocommit=True)
+ config.scan(package)
+
+ ctx = DummyContext()
+ req = DummyRequest()
+ alsoProvides(req, IRequest)
+ req.registry = config.registry
+
+ req.method = 'GET'
+ result = render_view_to_response(ctx, req, '')
+ self.assertEqual(result, 'grokked')
+
+ req.method = 'POST'
+ result = render_view_to_response(ctx, req, '')
+ self.assertEqual(result, 'grokked_post')
+
+ result = render_view_to_response(ctx, req, 'grokked_class')
+ self.assertEqual(result, 'grokked_class')
+
+ result = render_view_to_response(ctx, req, 'grokked_instance')
+ self.assertEqual(result, 'grokked_instance')
+
+ result = render_view_to_response(ctx, req, 'oldstyle_grokked_class')
+ self.assertEqual(result, 'oldstyle_grokked_class')
+
+ req.method = 'GET'
+ result = render_view_to_response(ctx, req, 'another')
+ self.assertEqual(result, 'another_grokked')
+
+ req.method = 'POST'
+ result = render_view_to_response(ctx, req, 'another')
+ self.assertEqual(result, 'another_grokked_post')
+
+ result = render_view_to_response(ctx, req, 'another_grokked_class')
+ self.assertEqual(result, 'another_grokked_class')
+
+ result = render_view_to_response(ctx, req, 'another_grokked_instance')
+ self.assertEqual(result, 'another_grokked_instance')
+
+ result = render_view_to_response(
+ ctx, req, 'another_oldstyle_grokked_class'
+ )
+ self.assertEqual(result, 'another_oldstyle_grokked_class')
+
+ result = render_view_to_response(ctx, req, 'stacked1')
+ self.assertEqual(result, 'stacked')
+
+ result = render_view_to_response(ctx, req, 'stacked2')
+ self.assertEqual(result, 'stacked')
+
+ result = render_view_to_response(ctx, req, 'another_stacked1')
+ self.assertEqual(result, 'another_stacked')
+
+ result = render_view_to_response(ctx, req, 'another_stacked2')
+ self.assertEqual(result, 'another_stacked')
+
+ result = render_view_to_response(ctx, req, 'stacked_class1')
+ self.assertEqual(result, 'stacked_class')
+
+ result = render_view_to_response(ctx, req, 'stacked_class2')
+ self.assertEqual(result, 'stacked_class')
+
+ result = render_view_to_response(ctx, req, 'another_stacked_class1')
+ self.assertEqual(result, 'another_stacked_class')
+
+ result = render_view_to_response(ctx, req, 'another_stacked_class2')
+ self.assertEqual(result, 'another_stacked_class')
+
+ # NB: on Jython, a class without an __init__ apparently accepts
+ # any number of arguments without raising a TypeError, so the next
+ # assertion may fail there. We don't support Jython at the moment,
+ # this is just a note to a future self.
+
+ self.assertRaises(
+ TypeError, render_view_to_response, ctx, req, 'basemethod'
+ )
+
+ result = render_view_to_response(ctx, req, 'method1')
+ self.assertEqual(result, 'method1')
+
+ result = render_view_to_response(ctx, req, 'method2')
+ self.assertEqual(result, 'method2')
+
+ result = render_view_to_response(ctx, req, 'stacked_method1')
+ self.assertEqual(result, 'stacked_method')
+
+ result = render_view_to_response(ctx, req, 'stacked_method2')
+ self.assertEqual(result, 'stacked_method')
+
+ result = render_view_to_response(ctx, req, 'subpackage_init')
+ self.assertEqual(result, 'subpackage_init')
+
+ result = render_view_to_response(ctx, req, 'subpackage_notinit')
+ self.assertEqual(result, 'subpackage_notinit')
+
+ result = render_view_to_response(ctx, req, 'subsubpackage_init')
+ self.assertEqual(result, 'subsubpackage_init')
+
+ result = render_view_to_response(ctx, req, 'pod_notinit')
+ self.assertEqual(result, None)
+
+ def test_scan_integration_with_ignore(self):
+ from zope.interface import alsoProvides
+ from pyramid.view import render_view_to_response
+ import tests.test_config.pkgs.scannable as package
+
+ config = self._makeOne(autocommit=True)
+ config.scan(package, ignore='tests.test_config.pkgs.scannable.another')
+
+ ctx = DummyContext()
+ req = DummyRequest()
+ alsoProvides(req, IRequest)
+ req.registry = config.registry
+
+ req.method = 'GET'
+ result = render_view_to_response(ctx, req, '')
+ self.assertEqual(result, 'grokked')
+
+ # ignored
+ v = render_view_to_response(ctx, req, 'another_stacked_class2')
+ self.assertEqual(v, None)
+
+ def test_scan_integration_dottedname_package(self):
+ from zope.interface import alsoProvides
+ from pyramid.view import render_view_to_response
+
+ config = self._makeOne(autocommit=True)
+ config.scan('tests.test_config.pkgs.scannable')
+
+ ctx = DummyContext()
+ req = DummyRequest()
+ alsoProvides(req, IRequest)
+ req.registry = config.registry
+
+ req.method = 'GET'
+ result = render_view_to_response(ctx, req, '')
+ self.assertEqual(result, 'grokked')
+
+ def test_scan_integration_with_extra_kw(self):
+ config = self._makeOne(autocommit=True)
+ config.scan('tests.test_config.pkgs.scanextrakw', a=1)
+ self.assertEqual(config.a, 1)
+
+ def test_scan_integration_with_onerror(self):
+ # fancy sys.path manipulation here to appease "setup.py test" which
+ # fails miserably when it can't import something in the package
+ import sys
+
+ try:
+ here = os.path.dirname(__file__)
+ path = os.path.join(here, 'path')
+ sys.path.append(path)
+ config = self._makeOne(autocommit=True)
+
+ class FooException(Exception):
+ pass
+
+ def onerror(name):
+ raise FooException
+
+ self.assertRaises(
+ FooException, config.scan, 'scanerror', onerror=onerror
+ )
+ finally:
+ sys.path.remove(path)
+
+ def test_scan_integration_conflict(self):
+ from tests.test_config.pkgs import selfscan
+ from pyramid.config import Configurator
+
+ c = Configurator()
+ c.scan(selfscan)
+ c.scan(selfscan)
+ try:
+ c.commit()
+ except ConfigurationConflictError as why:
+
+ def scanconflicts(e):
+ conflicts = e._conflicts.values()
+ for conflict in conflicts:
+ for confinst in conflict:
+ yield confinst.src
+
+ which = list(scanconflicts(why))
+ self.assertEqual(len(which), 4)
+ self.assertTrue("@view_config(renderer='string')" in which)
+ self.assertTrue(
+ "@view_config(name='two', renderer='string')" in which
+ )
+
+ @skip_on('py3')
+ def test_hook_zca(self):
+ from zope.component import getSiteManager
+
+ def foo():
+ '123'
+
+ try:
+ config = self._makeOne()
+ config.hook_zca()
+ config.begin()
+ sm = getSiteManager()
+ self.assertEqual(sm, config.registry)
+ finally:
+ getSiteManager.reset()
+
+ @skip_on('py3')
+ def test_unhook_zca(self):
+ from zope.component import getSiteManager
+
+ def foo():
+ '123'
+
+ try:
+ getSiteManager.sethook(foo)
+ config = self._makeOne()
+ config.unhook_zca()
+ sm = getSiteManager()
+ self.assertNotEqual(sm, '123')
+ finally:
+ getSiteManager.reset()
+
+ def test___getattr__missing_when_directives_exist(self):
+ config = self._makeOne()
+ directives = {}
+ config.registry._directives = directives
+ self.assertRaises(AttributeError, config.__getattr__, 'wontexist')
+
+ def test___getattr__missing_when_directives_dont_exist(self):
+ config = self._makeOne()
+ self.assertRaises(AttributeError, config.__getattr__, 'wontexist')
+
+ def test___getattr__matches(self):
+ config = self._makeOne()
+
+ def foo(config): # pragma: no cover
+ pass
+
+ directives = {'foo': (foo, True)}
+ config.registry._directives = directives
+ foo_meth = config.foo
+ self.assertTrue(getattr(foo_meth, im_func).__docobj__ is foo)
+
+ def test___getattr__matches_no_action_wrap(self):
+ config = self._makeOne()
+
+ def foo(config): # pragma: no cover
+ pass
+
+ directives = {'foo': (foo, False)}
+ config.registry._directives = directives
+ foo_meth = config.foo
+ self.assertTrue(getattr(foo_meth, im_func) is foo)
+
+
+class TestConfigurator_add_directive(unittest.TestCase):
+ def setUp(self):
+ from pyramid.config import Configurator
+
+ self.config = Configurator()
+
+ def test_extend_with_dotted_name(self):
+ from tests import test_config
+
+ config = self.config
+ config.add_directive('dummy_extend', 'tests.test_config.dummy_extend')
+ self.assertTrue(hasattr(config, 'dummy_extend'))
+ config.dummy_extend('discrim')
+ after = config.action_state
+ action = after.actions[-1]
+ self.assertEqual(action['discriminator'], 'discrim')
+ self.assertEqual(action['callable'], None)
+ self.assertEqual(action['args'], test_config)
+
+ def test_add_directive_with_partial(self):
+ from tests import test_config
+
+ config = self.config
+ config.add_directive(
+ 'dummy_partial', 'tests.test_config.dummy_partial'
+ )
+ self.assertTrue(hasattr(config, 'dummy_partial'))
+ config.dummy_partial()
+ after = config.action_state
+ action = after.actions[-1]
+ self.assertEqual(action['discriminator'], 'partial')
+ self.assertEqual(action['callable'], None)
+ self.assertEqual(action['args'], test_config)
+
+ def test_add_directive_with_custom_callable(self):
+ from tests import test_config
+
+ config = self.config
+ config.add_directive(
+ 'dummy_callable', 'tests.test_config.dummy_callable'
+ )
+ self.assertTrue(hasattr(config, 'dummy_callable'))
+ config.dummy_callable('discrim')
+ after = config.action_state
+ action = after.actions[-1]
+ self.assertEqual(action['discriminator'], 'discrim')
+ self.assertEqual(action['callable'], None)
+ self.assertEqual(action['args'], test_config)
+
+ def test_extend_with_python_callable(self):
+ from tests import test_config
+
+ config = self.config
+ config.add_directive('dummy_extend', dummy_extend)
+ self.assertTrue(hasattr(config, 'dummy_extend'))
+ config.dummy_extend('discrim')
+ after = config.action_state
+ action = after.actions[-1]
+ self.assertEqual(action['discriminator'], 'discrim')
+ self.assertEqual(action['callable'], None)
+ self.assertEqual(action['args'], test_config)
+
+ def test_extend_same_name_doesnt_conflict(self):
+ config = self.config
+ config.add_directive('dummy_extend', dummy_extend)
+ config.add_directive('dummy_extend', dummy_extend2)
+ self.assertTrue(hasattr(config, 'dummy_extend'))
+ config.dummy_extend('discrim')
+ after = config.action_state
+ action = after.actions[-1]
+ self.assertEqual(action['discriminator'], 'discrim')
+ self.assertEqual(action['callable'], None)
+ self.assertEqual(action['args'], config.registry)
+
+ def test_extend_action_method_successful(self):
+ config = self.config
+ config.add_directive('dummy_extend', dummy_extend)
+ config.dummy_extend('discrim')
+ config.dummy_extend('discrim')
+ self.assertRaises(ConfigurationConflictError, config.commit)
+
+ def test_directive_persists_across_configurator_creations(self):
+ config = self.config
+ config.add_directive('dummy_extend', dummy_extend)
+ config2 = config.with_package('tests')
+ config2.dummy_extend('discrim')
+ after = config2.action_state
+ actions = after.actions
+ self.assertEqual(len(actions), 1)
+ action = actions[0]
+ self.assertEqual(action['discriminator'], 'discrim')
+ self.assertEqual(action['callable'], None)
+ self.assertEqual(action['args'], config2.package)
+
+
+class TestConfigurator__add_predicate(unittest.TestCase):
+ def _makeOne(self):
+ from pyramid.config import Configurator
+
+ return Configurator()
+
+ def test_factory_as_object(self):
+ config = self._makeOne()
+
+ def _fakeAction(
+ discriminator,
+ callable=None,
+ args=(),
+ kw=None,
+ order=0,
+ introspectables=(),
+ **extra
+ ):
+ self.assertEqual(len(introspectables), 1)
+ self.assertEqual(introspectables[0]['name'], 'testing')
+ self.assertEqual(introspectables[0]['factory'], DummyPredicate)
+
+ config.action = _fakeAction
+ config._add_predicate('route', 'testing', DummyPredicate)
+
+ def test_factory_as_dotted_name(self):
+ config = self._makeOne()
+
+ def _fakeAction(
+ discriminator,
+ callable=None,
+ args=(),
+ kw=None,
+ order=0,
+ introspectables=(),
+ **extra
+ ):
+ self.assertEqual(len(introspectables), 1)
+ self.assertEqual(introspectables[0]['name'], 'testing')
+ self.assertEqual(introspectables[0]['factory'], DummyPredicate)
+
+ config.action = _fakeAction
+ config._add_predicate(
+ 'route', 'testing', 'tests.test_config.test_init.DummyPredicate'
+ )
+
+
+class TestGlobalRegistriesIntegration(unittest.TestCase):
+ def setUp(self):
+ from pyramid.config import global_registries
+
+ global_registries.empty()
+
+ tearDown = setUp
+
+ def _makeConfigurator(self, *arg, **kw):
+ from pyramid.config import Configurator
+
+ config = Configurator(*arg, **kw)
+ return config
+
+ def test_global_registries_empty(self):
+ from pyramid.config import global_registries
+
+ self.assertEqual(global_registries.last, None)
+
+ def test_global_registries(self):
+ from pyramid.config import global_registries
+
+ config1 = self._makeConfigurator()
+ config1.make_wsgi_app()
+ self.assertEqual(global_registries.last, config1.registry)
+ config2 = self._makeConfigurator()
+ config2.make_wsgi_app()
+ self.assertEqual(global_registries.last, config2.registry)
+ self.assertEqual(
+ list(global_registries), [config1.registry, config2.registry]
+ )
+ global_registries.remove(config2.registry)
+ self.assertEqual(global_registries.last, config1.registry)
+
+
+class DummyRequest:
+ subpath = ()
+ matchdict = None
+ request_iface = IRequest
+
+ def __init__(self, environ=None):
+ if environ is None:
+ environ = {}
+ self.environ = environ
+ self.params = {}
+ self.cookies = {}
+
+
+class DummyThreadLocalManager(object):
+ def __init__(self):
+ self.pushed = {'registry': None, 'request': None}
+ self.popped = False
+
+ def push(self, d):
+ self.pushed = d
+
+ def get(self):
+ return self.pushed
+
+ def pop(self):
+ self.popped = True
+
+
+class DummyRegistry(object):
+ def __init__(self, adaptation=None, util=None):
+ self.utilities = []
+ self.adapters = []
+ self.adaptation = adaptation
+ self.util = util
+
+ def subscribers(self, events, name):
+ self.events = events
+ return events
+
+ def registerUtility(self, *arg, **kw):
+ self.utilities.append((arg, kw))
+
+ def registerAdapter(self, *arg, **kw):
+ self.adapters.append((arg, kw))
+
+ def queryAdapter(self, *arg, **kw):
+ return self.adaptation
+
+ def queryUtility(self, *arg, **kw):
+ return self.util
+
+
+class DummyPredicate(object):
+ pass
diff --git a/tests/test_config/test_predicates.py b/tests/test_config/test_predicates.py
new file mode 100644
index 000000000..079652b39
--- /dev/null
+++ b/tests/test_config/test_predicates.py
@@ -0,0 +1,480 @@
+import unittest
+
+from pyramid.compat import text_
+
+
+class TestPredicateList(unittest.TestCase):
+ def _makeOne(self):
+ from pyramid.config.predicates import PredicateList
+ from pyramid import predicates
+
+ inst = PredicateList()
+ for name, factory in (
+ ('xhr', predicates.XHRPredicate),
+ ('request_method', predicates.RequestMethodPredicate),
+ ('path_info', predicates.PathInfoPredicate),
+ ('request_param', predicates.RequestParamPredicate),
+ ('header', predicates.HeaderPredicate),
+ ('accept', predicates.AcceptPredicate),
+ ('containment', predicates.ContainmentPredicate),
+ ('request_type', predicates.RequestTypePredicate),
+ ('match_param', predicates.MatchParamPredicate),
+ ('custom', predicates.CustomPredicate),
+ ('traverse', predicates.TraversePredicate),
+ ):
+ inst.add(name, factory)
+ return inst
+
+ def _callFUT(self, **kw):
+ inst = self._makeOne()
+ config = DummyConfigurator()
+ return inst.make(config, **kw)
+
+ def test_ordering_xhr_and_request_method_trump_only_containment(self):
+ order1, _, _ = self._callFUT(xhr=True, request_method='GET')
+ order2, _, _ = self._callFUT(containment=True)
+ self.assertTrue(order1 < order2)
+
+ def test_ordering_number_of_predicates(self):
+ from pyramid.config.predicates import predvalseq
+
+ order1, _, _ = self._callFUT(
+ xhr='xhr',
+ request_method='request_method',
+ path_info='path_info',
+ request_param='param',
+ match_param='foo=bar',
+ header='header',
+ accept='accept',
+ containment='containment',
+ request_type='request_type',
+ custom=predvalseq([DummyCustomPredicate()]),
+ )
+ order2, _, _ = self._callFUT(
+ xhr='xhr',
+ request_method='request_method',
+ path_info='path_info',
+ request_param='param',
+ match_param='foo=bar',
+ header='header',
+ accept='accept',
+ containment='containment',
+ request_type='request_type',
+ custom=predvalseq([DummyCustomPredicate()]),
+ )
+ order3, _, _ = self._callFUT(
+ xhr='xhr',
+ request_method='request_method',
+ path_info='path_info',
+ request_param='param',
+ match_param='foo=bar',
+ header='header',
+ accept='accept',
+ containment='containment',
+ request_type='request_type',
+ )
+ order4, _, _ = self._callFUT(
+ xhr='xhr',
+ request_method='request_method',
+ path_info='path_info',
+ request_param='param',
+ match_param='foo=bar',
+ header='header',
+ accept='accept',
+ containment='containment',
+ )
+ order5, _, _ = self._callFUT(
+ xhr='xhr',
+ request_method='request_method',
+ path_info='path_info',
+ request_param='param',
+ match_param='foo=bar',
+ header='header',
+ accept='accept',
+ )
+ order6, _, _ = self._callFUT(
+ xhr='xhr',
+ request_method='request_method',
+ path_info='path_info',
+ request_param='param',
+ match_param='foo=bar',
+ header='header',
+ )
+ order7, _, _ = self._callFUT(
+ xhr='xhr',
+ request_method='request_method',
+ path_info='path_info',
+ request_param='param',
+ match_param='foo=bar',
+ )
+ order8, _, _ = self._callFUT(
+ xhr='xhr',
+ request_method='request_method',
+ path_info='path_info',
+ request_param='param',
+ )
+ order9, _, _ = self._callFUT(
+ xhr='xhr', request_method='request_method', path_info='path_info'
+ )
+ order10, _, _ = self._callFUT(
+ xhr='xhr', request_method='request_method'
+ )
+ order11, _, _ = self._callFUT(xhr='xhr')
+ order12, _, _ = self._callFUT()
+ self.assertEqual(order1, order2)
+ self.assertTrue(order3 > order2)
+ self.assertTrue(order4 > order3)
+ self.assertTrue(order5 > order4)
+ self.assertTrue(order6 > order5)
+ self.assertTrue(order7 > order6)
+ self.assertTrue(order8 > order7)
+ self.assertTrue(order9 > order8)
+ self.assertTrue(order10 > order9)
+ self.assertTrue(order11 > order10)
+ self.assertTrue(order12 > order10)
+
+ def test_ordering_importance_of_predicates(self):
+ from pyramid.config.predicates import predvalseq
+
+ order1, _, _ = self._callFUT(xhr='xhr')
+ order2, _, _ = self._callFUT(request_method='request_method')
+ order3, _, _ = self._callFUT(path_info='path_info')
+ order4, _, _ = self._callFUT(request_param='param')
+ order5, _, _ = self._callFUT(header='header')
+ order6, _, _ = self._callFUT(accept='accept')
+ order7, _, _ = self._callFUT(containment='containment')
+ order8, _, _ = self._callFUT(request_type='request_type')
+ order9, _, _ = self._callFUT(match_param='foo=bar')
+ order10, _, _ = self._callFUT(
+ custom=predvalseq([DummyCustomPredicate()])
+ )
+ self.assertTrue(order1 > order2)
+ self.assertTrue(order2 > order3)
+ self.assertTrue(order3 > order4)
+ self.assertTrue(order4 > order5)
+ self.assertTrue(order5 > order6)
+ self.assertTrue(order6 > order7)
+ self.assertTrue(order7 > order8)
+ self.assertTrue(order8 > order9)
+ self.assertTrue(order9 > order10)
+
+ def test_ordering_importance_and_number(self):
+ from pyramid.config.predicates import predvalseq
+
+ order1, _, _ = self._callFUT(
+ xhr='xhr', request_method='request_method'
+ )
+ order2, _, _ = self._callFUT(
+ custom=predvalseq([DummyCustomPredicate()])
+ )
+ self.assertTrue(order1 < order2)
+
+ order1, _, _ = self._callFUT(
+ xhr='xhr', request_method='request_method'
+ )
+ order2, _, _ = self._callFUT(
+ request_method='request_method',
+ custom=predvalseq([DummyCustomPredicate()]),
+ )
+ self.assertTrue(order1 > order2)
+
+ order1, _, _ = self._callFUT(
+ xhr='xhr', request_method='request_method', path_info='path_info'
+ )
+ order2, _, _ = self._callFUT(
+ request_method='request_method',
+ custom=predvalseq([DummyCustomPredicate()]),
+ )
+ self.assertTrue(order1 < order2)
+
+ order1, _, _ = self._callFUT(
+ xhr='xhr', request_method='request_method', path_info='path_info'
+ )
+ order2, _, _ = self._callFUT(
+ xhr='xhr',
+ request_method='request_method',
+ custom=predvalseq([DummyCustomPredicate()]),
+ )
+ self.assertTrue(order1 > order2)
+
+ def test_different_custom_predicates_with_same_hash(self):
+ from pyramid.config.predicates import predvalseq
+
+ class PredicateWithHash(object):
+ def __hash__(self):
+ return 1
+
+ a = PredicateWithHash()
+ b = PredicateWithHash()
+ _, _, a_phash = self._callFUT(custom=predvalseq([a]))
+ _, _, b_phash = self._callFUT(custom=predvalseq([b]))
+ self.assertEqual(a_phash, b_phash)
+
+ def test_traverse_has_remainder_already(self):
+ order, predicates, phash = self._callFUT(traverse='/1/:a/:b')
+ self.assertEqual(len(predicates), 1)
+ pred = predicates[0]
+ info = {'traverse': 'abc'}
+ request = DummyRequest()
+ result = pred(info, request)
+ self.assertEqual(result, True)
+ self.assertEqual(info, {'traverse': 'abc'})
+
+ def test_traverse_matches(self):
+ order, predicates, phash = self._callFUT(traverse='/1/:a/:b')
+ self.assertEqual(len(predicates), 1)
+ pred = predicates[0]
+ info = {'match': {'a': 'a', 'b': 'b'}}
+ request = DummyRequest()
+ result = pred(info, request)
+ self.assertEqual(result, True)
+ self.assertEqual(
+ info, {'match': {'a': 'a', 'b': 'b', 'traverse': ('1', 'a', 'b')}}
+ )
+
+ def test_traverse_matches_with_highorder_chars(self):
+ order, predicates, phash = self._callFUT(
+ traverse=text_(b'/La Pe\xc3\xb1a/{x}', 'utf-8')
+ )
+ self.assertEqual(len(predicates), 1)
+ pred = predicates[0]
+ info = {'match': {'x': text_(b'Qu\xc3\xa9bec', 'utf-8')}}
+ request = DummyRequest()
+ result = pred(info, request)
+ self.assertEqual(result, True)
+ self.assertEqual(
+ info['match']['traverse'],
+ (
+ text_(b'La Pe\xc3\xb1a', 'utf-8'),
+ text_(b'Qu\xc3\xa9bec', 'utf-8'),
+ ),
+ )
+
+ def test_custom_predicates_can_affect_traversal(self):
+ from pyramid.config.predicates import predvalseq
+
+ def custom(info, request):
+ m = info['match']
+ m['dummy'] = 'foo'
+ return True
+
+ _, predicates, _ = self._callFUT(
+ custom=predvalseq([custom]), traverse='/1/:dummy/:a'
+ )
+ self.assertEqual(len(predicates), 2)
+ info = {'match': {'a': 'a'}}
+ request = DummyRequest()
+ self.assertTrue(all([p(info, request) for p in predicates]))
+ self.assertEqual(
+ info,
+ {
+ 'match': {
+ 'a': 'a',
+ 'dummy': 'foo',
+ 'traverse': ('1', 'foo', 'a'),
+ }
+ },
+ )
+
+ def test_predicate_text_is_correct(self):
+ from pyramid.config.predicates import predvalseq
+
+ _, predicates, _ = self._callFUT(
+ xhr='xhr',
+ request_method='request_method',
+ path_info='path_info',
+ request_param='param',
+ header='header',
+ accept='accept',
+ containment='containment',
+ request_type='request_type',
+ custom=predvalseq(
+ [
+ DummyCustomPredicate(),
+ DummyCustomPredicate.classmethod_predicate,
+ DummyCustomPredicate.classmethod_predicate_no_text,
+ ]
+ ),
+ match_param='foo=bar',
+ )
+ self.assertEqual(predicates[0].text(), 'xhr = True')
+ self.assertEqual(
+ predicates[1].text(), "request_method = request_method"
+ )
+ self.assertEqual(predicates[2].text(), 'path_info = path_info')
+ self.assertEqual(predicates[3].text(), 'request_param param')
+ self.assertEqual(predicates[4].text(), 'header header')
+ self.assertEqual(predicates[5].text(), 'accept = accept')
+ self.assertEqual(predicates[6].text(), 'containment = containment')
+ self.assertEqual(predicates[7].text(), 'request_type = request_type')
+ self.assertEqual(predicates[8].text(), "match_param foo=bar")
+ self.assertEqual(predicates[9].text(), 'custom predicate')
+ self.assertEqual(predicates[10].text(), 'classmethod predicate')
+ self.assertTrue(predicates[11].text().startswith('custom predicate'))
+
+ def test_match_param_from_string(self):
+ _, predicates, _ = self._callFUT(match_param='foo=bar')
+ request = DummyRequest()
+ request.matchdict = {'foo': 'bar', 'baz': 'bum'}
+ self.assertTrue(predicates[0](Dummy(), request))
+
+ def test_match_param_from_string_fails(self):
+ _, predicates, _ = self._callFUT(match_param='foo=bar')
+ request = DummyRequest()
+ request.matchdict = {'foo': 'bum', 'baz': 'bum'}
+ self.assertFalse(predicates[0](Dummy(), request))
+
+ def test_match_param_from_dict(self):
+ _, predicates, _ = self._callFUT(match_param=('foo=bar', 'baz=bum'))
+ request = DummyRequest()
+ request.matchdict = {'foo': 'bar', 'baz': 'bum'}
+ self.assertTrue(predicates[0](Dummy(), request))
+
+ def test_match_param_from_dict_fails(self):
+ _, predicates, _ = self._callFUT(match_param=('foo=bar', 'baz=bum'))
+ request = DummyRequest()
+ request.matchdict = {'foo': 'bar', 'baz': 'foo'}
+ self.assertFalse(predicates[0](Dummy(), request))
+
+ def test_request_method_sequence(self):
+ _, predicates, _ = self._callFUT(request_method=('GET', 'HEAD'))
+ request = DummyRequest()
+ request.method = 'HEAD'
+ self.assertTrue(predicates[0](Dummy(), request))
+ request.method = 'GET'
+ self.assertTrue(predicates[0](Dummy(), request))
+ request.method = 'POST'
+ self.assertFalse(predicates[0](Dummy(), request))
+
+ def test_request_method_ordering_hashes_same(self):
+ hash1, _, __ = self._callFUT(request_method=('GET', 'HEAD'))
+ hash2, _, __ = self._callFUT(request_method=('HEAD', 'GET'))
+ self.assertEqual(hash1, hash2)
+ hash1, _, __ = self._callFUT(request_method=('GET',))
+ hash2, _, __ = self._callFUT(request_method='GET')
+ self.assertEqual(hash1, hash2)
+
+ def test_unknown_predicate(self):
+ from pyramid.exceptions import ConfigurationError
+
+ self.assertRaises(ConfigurationError, self._callFUT, unknown=1)
+
+ def test_predicate_close_matches(self):
+ from pyramid.exceptions import ConfigurationError
+
+ with self.assertRaises(ConfigurationError) as context:
+ self._callFUT(method='GET')
+ expected_msg = (
+ "Unknown predicate values: {'method': 'GET'} "
+ "(did you mean request_method)"
+ )
+ self.assertEqual(context.exception.args[0], expected_msg)
+
+ def test_notted(self):
+ from pyramid.config import not_
+ from pyramid.testing import DummyRequest
+
+ request = DummyRequest()
+ _, predicates, _ = self._callFUT(
+ xhr='xhr', request_method=not_('POST'), header=not_('header')
+ )
+ self.assertEqual(predicates[0].text(), 'xhr = True')
+ self.assertEqual(predicates[1].text(), "!request_method = POST")
+ self.assertEqual(predicates[2].text(), '!header header')
+ self.assertEqual(predicates[1](None, request), True)
+ self.assertEqual(predicates[2](None, request), True)
+
+
+class Test_sort_accept_offers(unittest.TestCase):
+ def _callFUT(self, offers, order=None):
+ from pyramid.config.predicates import sort_accept_offers
+
+ return sort_accept_offers(offers, order)
+
+ def test_default_specificities(self):
+ result = self._callFUT(['text/html', 'text/html;charset=utf8'])
+ self.assertEqual(result, ['text/html;charset=utf8', 'text/html'])
+
+ def test_specific_type_order(self):
+ result = self._callFUT(
+ [
+ 'text/html',
+ 'application/json',
+ 'text/html;charset=utf8',
+ 'text/plain',
+ ],
+ ['application/json', 'text/html'],
+ )
+ self.assertEqual(
+ result,
+ [
+ 'application/json',
+ 'text/html;charset=utf8',
+ 'text/html',
+ 'text/plain',
+ ],
+ )
+
+ def test_params_order(self):
+ result = self._callFUT(
+ [
+ 'text/html;charset=utf8',
+ 'text/html;charset=latin1',
+ 'text/html;foo=bar',
+ ],
+ ['text/html;charset=latin1', 'text/html;charset=utf8'],
+ )
+ self.assertEqual(
+ result,
+ [
+ 'text/html;charset=latin1',
+ 'text/html;charset=utf8',
+ 'text/html;foo=bar',
+ ],
+ )
+
+ def test_params_inherit_type_prefs(self):
+ result = self._callFUT(
+ ['text/html;charset=utf8', 'text/plain;charset=latin1'],
+ ['text/plain', 'text/html'],
+ )
+ self.assertEqual(
+ result, ['text/plain;charset=latin1', 'text/html;charset=utf8']
+ )
+
+
+class DummyCustomPredicate(object):
+ def __init__(self):
+ self.__text__ = 'custom predicate'
+
+ def classmethod_predicate(*args): # pragma: no cover
+ pass
+
+ classmethod_predicate.__text__ = 'classmethod predicate'
+ classmethod_predicate = classmethod(classmethod_predicate)
+
+ @classmethod
+ def classmethod_predicate_no_text(*args):
+ pass # pragma: no cover
+
+
+class Dummy(object):
+ def __init__(self, **kw):
+ self.__dict__.update(**kw)
+
+
+class DummyRequest:
+ subpath = ()
+ matchdict = None
+
+ def __init__(self, environ=None):
+ if environ is None:
+ environ = {}
+ self.environ = environ
+ self.params = {}
+ self.cookies = {}
+
+
+class DummyConfigurator(object):
+ def maybe_dotted(self, thing):
+ return thing
diff --git a/tests/test_config/test_rendering.py b/tests/test_config/test_rendering.py
new file mode 100644
index 000000000..a33977c28
--- /dev/null
+++ b/tests/test_config/test_rendering.py
@@ -0,0 +1,43 @@
+import unittest
+
+
+class TestRenderingConfiguratorMixin(unittest.TestCase):
+ def _makeOne(self, *arg, **kw):
+ from pyramid.config import Configurator
+
+ config = Configurator(*arg, **kw)
+ return config
+
+ def test_add_default_renderers(self):
+ from pyramid.config.rendering import DEFAULT_RENDERERS
+ from pyramid.interfaces import IRendererFactory
+
+ config = self._makeOne(autocommit=True)
+ config.add_default_renderers()
+ for name, impl in DEFAULT_RENDERERS:
+ self.assertTrue(
+ config.registry.queryUtility(IRendererFactory, name)
+ is not None
+ )
+
+ def test_add_renderer(self):
+ from pyramid.interfaces import IRendererFactory
+
+ config = self._makeOne(autocommit=True)
+ renderer = object()
+ config.add_renderer('name', renderer)
+ self.assertEqual(
+ config.registry.getUtility(IRendererFactory, 'name'), renderer
+ )
+
+ def test_add_renderer_dottedname_factory(self):
+ from pyramid.interfaces import IRendererFactory
+
+ config = self._makeOne(autocommit=True)
+ import tests.test_config
+
+ config.add_renderer('name', 'tests.test_config')
+ self.assertEqual(
+ config.registry.getUtility(IRendererFactory, 'name'),
+ tests.test_config,
+ )
diff --git a/tests/test_config/test_routes.py b/tests/test_config/test_routes.py
new file mode 100644
index 000000000..1c1ed6700
--- /dev/null
+++ b/tests/test_config/test_routes.py
@@ -0,0 +1,322 @@
+import unittest
+
+from . import dummyfactory
+from . import DummyContext
+from pyramid.compat import text_
+
+
+class RoutesConfiguratorMixinTests(unittest.TestCase):
+ def _makeOne(self, *arg, **kw):
+ from pyramid.config import Configurator
+
+ config = Configurator(*arg, **kw)
+ return config
+
+ def _assertRoute(self, config, name, path, num_predicates=0):
+ from pyramid.interfaces import IRoutesMapper
+
+ mapper = config.registry.getUtility(IRoutesMapper)
+ routes = mapper.get_routes()
+ route = routes[0]
+ self.assertEqual(len(routes), 1)
+ self.assertEqual(route.name, name)
+ self.assertEqual(route.path, path)
+ self.assertEqual(len(routes[0].predicates), num_predicates)
+ return route
+
+ def _makeRequest(self, config):
+ request = DummyRequest()
+ request.registry = config.registry
+ return request
+
+ def test_get_routes_mapper_not_yet_registered(self):
+ config = self._makeOne()
+ mapper = config.get_routes_mapper()
+ self.assertEqual(mapper.routelist, [])
+
+ def test_get_routes_mapper_already_registered(self):
+ from pyramid.interfaces import IRoutesMapper
+
+ config = self._makeOne()
+ mapper = object()
+ config.registry.registerUtility(mapper, IRoutesMapper)
+ result = config.get_routes_mapper()
+ self.assertEqual(result, mapper)
+
+ def test_add_route_defaults(self):
+ config = self._makeOne(autocommit=True)
+ config.add_route('name', 'path')
+ self._assertRoute(config, 'name', 'path')
+
+ def test_add_route_with_route_prefix(self):
+ config = self._makeOne(autocommit=True)
+ config.route_prefix = 'root'
+ config.add_route('name', 'path')
+ self._assertRoute(config, 'name', 'root/path')
+
+ def test_add_route_with_empty_string_with_route_prefix(self):
+ config = self._makeOne(autocommit=True)
+ config.route_prefix = 'root'
+ config.add_route('name', '')
+ self._assertRoute(config, 'name', 'root')
+
+ def test_add_route_with_root_slash_with_route_prefix(self):
+ config = self._makeOne(autocommit=True)
+ config.route_prefix = 'root'
+ config.add_route('name', '/')
+ self._assertRoute(config, 'name', 'root/')
+
+ def test_add_route_discriminator(self):
+ config = self._makeOne()
+ config.add_route('name', 'path')
+ self.assertEqual(
+ config.action_state.actions[-1]['discriminator'], ('route', 'name')
+ )
+
+ def test_add_route_with_factory(self):
+ config = self._makeOne(autocommit=True)
+ factory = object()
+ config.add_route('name', 'path', factory=factory)
+ route = self._assertRoute(config, 'name', 'path')
+ self.assertEqual(route.factory, factory)
+
+ def test_add_route_with_static(self):
+ config = self._makeOne(autocommit=True)
+ config.add_route('name', 'path/{foo}', static=True)
+ mapper = config.get_routes_mapper()
+ self.assertEqual(len(mapper.get_routes()), 0)
+ self.assertEqual(mapper.generate('name', {"foo": "a"}), '/path/a')
+
+ def test_add_route_with_factory_dottedname(self):
+ config = self._makeOne(autocommit=True)
+ config.add_route(
+ 'name', 'path', factory='tests.test_config.dummyfactory'
+ )
+ route = self._assertRoute(config, 'name', 'path')
+ self.assertEqual(route.factory, dummyfactory)
+
+ def test_add_route_with_xhr(self):
+ config = self._makeOne(autocommit=True)
+ config.add_route('name', 'path', xhr=True)
+ route = self._assertRoute(config, 'name', 'path', 1)
+ predicate = route.predicates[0]
+ request = self._makeRequest(config)
+ request.is_xhr = True
+ self.assertEqual(predicate(None, request), True)
+ request = self._makeRequest(config)
+ request.is_xhr = False
+ self.assertEqual(predicate(None, request), False)
+
+ def test_add_route_with_request_method(self):
+ config = self._makeOne(autocommit=True)
+ config.add_route('name', 'path', request_method='GET')
+ route = self._assertRoute(config, 'name', 'path', 1)
+ predicate = route.predicates[0]
+ request = self._makeRequest(config)
+ request.method = 'GET'
+ self.assertEqual(predicate(None, request), True)
+ request = self._makeRequest(config)
+ request.method = 'POST'
+ self.assertEqual(predicate(None, request), False)
+
+ def test_add_route_with_path_info(self):
+ config = self._makeOne(autocommit=True)
+ config.add_route('name', 'path', path_info='/foo')
+ route = self._assertRoute(config, 'name', 'path', 1)
+ predicate = route.predicates[0]
+ request = self._makeRequest(config)
+ request.upath_info = '/foo'
+ self.assertEqual(predicate(None, request), True)
+ request = self._makeRequest(config)
+ request.upath_info = '/'
+ self.assertEqual(predicate(None, request), False)
+
+ def test_add_route_with_path_info_highorder(self):
+ config = self._makeOne(autocommit=True)
+ config.add_route(
+ 'name', 'path', path_info=text_(b'/La Pe\xc3\xb1a', 'utf-8')
+ )
+ route = self._assertRoute(config, 'name', 'path', 1)
+ predicate = route.predicates[0]
+ request = self._makeRequest(config)
+ request.upath_info = text_(b'/La Pe\xc3\xb1a', 'utf-8')
+ self.assertEqual(predicate(None, request), True)
+ request = self._makeRequest(config)
+ request.upath_info = text_('/')
+ self.assertEqual(predicate(None, request), False)
+
+ def test_add_route_with_path_info_regex(self):
+ config = self._makeOne(autocommit=True)
+ config.add_route(
+ 'name', 'path', path_info=text_(br'/La Pe\w*', 'utf-8')
+ )
+ route = self._assertRoute(config, 'name', 'path', 1)
+ predicate = route.predicates[0]
+ request = self._makeRequest(config)
+ request.upath_info = text_(b'/La Pe\xc3\xb1a', 'utf-8')
+ self.assertEqual(predicate(None, request), True)
+ request = self._makeRequest(config)
+ request.upath_info = text_('/')
+ self.assertEqual(predicate(None, request), False)
+
+ def test_add_route_with_request_param(self):
+ config = self._makeOne(autocommit=True)
+ config.add_route('name', 'path', request_param='abc')
+ route = self._assertRoute(config, 'name', 'path', 1)
+ predicate = route.predicates[0]
+ request = self._makeRequest(config)
+ request.params = {'abc': '123'}
+ self.assertEqual(predicate(None, request), True)
+ request = self._makeRequest(config)
+ request.params = {}
+ self.assertEqual(predicate(None, request), False)
+
+ def test_add_route_with_custom_predicates(self):
+ import warnings
+
+ config = self._makeOne(autocommit=True)
+
+ def pred1(context, request): # pragma: no cover
+ pass
+
+ def pred2(context, request): # pragma: no cover
+ pass
+
+ with warnings.catch_warnings(record=True) as w:
+ warnings.filterwarnings('always')
+ config.add_route('name', 'path', custom_predicates=(pred1, pred2))
+ self.assertEqual(len(w), 1)
+ route = self._assertRoute(config, 'name', 'path', 2)
+ self.assertEqual(len(route.predicates), 2)
+
+ def test_add_route_with_header(self):
+ config = self._makeOne(autocommit=True)
+ config.add_route('name', 'path', header='Host')
+ route = self._assertRoute(config, 'name', 'path', 1)
+ predicate = route.predicates[0]
+ request = self._makeRequest(config)
+ request.headers = {'Host': 'example.com'}
+ self.assertEqual(predicate(None, request), True)
+ request = self._makeRequest(config)
+ request.headers = {}
+ self.assertEqual(predicate(None, request), False)
+
+ def test_add_route_with_accept(self):
+ config = self._makeOne(autocommit=True)
+ config.add_route('name', 'path', accept='text/xml')
+ route = self._assertRoute(config, 'name', 'path', 1)
+ predicate = route.predicates[0]
+ request = self._makeRequest(config)
+ request.accept = DummyAccept('text/xml')
+ self.assertEqual(predicate(None, request), True)
+ request = self._makeRequest(config)
+ request.accept = DummyAccept('text/html')
+ self.assertEqual(predicate(None, request), False)
+
+ def test_add_route_with_accept_list(self):
+ config = self._makeOne(autocommit=True)
+ config.add_route('name', 'path', accept=['text/xml', 'text/plain'])
+ route = self._assertRoute(config, 'name', 'path', 1)
+ predicate = route.predicates[0]
+ request = self._makeRequest(config)
+ request.accept = DummyAccept('text/xml')
+ self.assertEqual(predicate(None, request), True)
+ request = self._makeRequest(config)
+ request.accept = DummyAccept('text/plain')
+ self.assertEqual(predicate(None, request), True)
+ request = self._makeRequest(config)
+ request.accept = DummyAccept('text/html')
+ self.assertEqual(predicate(None, request), False)
+
+ def test_add_route_with_wildcard_accept_raises(self):
+ config = self._makeOne(autocommit=True)
+ self.assertRaises(
+ ValueError,
+ lambda: config.add_route('name', 'path', accept='text/*'),
+ )
+
+ def test_add_route_no_pattern_with_path(self):
+ config = self._makeOne(autocommit=True)
+ config.add_route('name', path='path')
+ self._assertRoute(config, 'name', 'path')
+
+ def test_add_route_no_path_no_pattern(self):
+ from pyramid.exceptions import ConfigurationError
+
+ config = self._makeOne()
+ self.assertRaises(ConfigurationError, config.add_route, 'name')
+
+ def test_add_route_with_pregenerator(self):
+ config = self._makeOne(autocommit=True)
+ config.add_route('name', 'pattern', pregenerator='123')
+ route = self._assertRoute(config, 'name', 'pattern')
+ self.assertEqual(route.pregenerator, '123')
+
+ def test_add_route_no_view_with_view_attr(self):
+ config = self._makeOne(autocommit=True)
+ from pyramid.exceptions import ConfigurationError
+
+ try:
+ config.add_route('name', '/pattern', view_attr='abc')
+ except ConfigurationError:
+ pass
+ else: # pragma: no cover
+ raise AssertionError
+
+ def test_add_route_no_view_with_view_context(self):
+ config = self._makeOne(autocommit=True)
+ from pyramid.exceptions import ConfigurationError
+
+ try:
+ config.add_route('name', '/pattern', view_context=DummyContext)
+ except ConfigurationError:
+ pass
+ else: # pragma: no cover
+ raise AssertionError
+
+ def test_add_route_no_view_with_view_permission(self):
+ config = self._makeOne(autocommit=True)
+ from pyramid.exceptions import ConfigurationError
+
+ try:
+ config.add_route('name', '/pattern', view_permission='edit')
+ except ConfigurationError:
+ pass
+ else: # pragma: no cover
+ raise AssertionError
+
+ def test_add_route_no_view_with_view_renderer(self):
+ config = self._makeOne(autocommit=True)
+ from pyramid.exceptions import ConfigurationError
+
+ try:
+ config.add_route('name', '/pattern', view_renderer='json')
+ except ConfigurationError:
+ pass
+ else: # pragma: no cover
+ raise AssertionError
+
+
+class DummyRequest:
+ subpath = ()
+ matchdict = None
+
+ def __init__(self, environ=None):
+ if environ is None:
+ environ = {}
+ self.environ = environ
+ self.params = {}
+ self.cookies = {}
+
+
+class DummyAccept(object):
+ def __init__(self, *matches, **kw):
+ self.matches = list(matches)
+ self.contains = kw.pop('contains', False)
+
+ def acceptable_offers(self, offers):
+ results = []
+ for match in self.matches:
+ if match in offers:
+ results.append((match, 1.0))
+ return results
diff --git a/tests/test_config/test_security.py b/tests/test_config/test_security.py
new file mode 100644
index 000000000..5ebd78f8d
--- /dev/null
+++ b/tests/test_config/test_security.py
@@ -0,0 +1,151 @@
+import unittest
+
+from pyramid.exceptions import ConfigurationExecutionError
+from pyramid.exceptions import ConfigurationError
+
+
+class ConfiguratorSecurityMethodsTests(unittest.TestCase):
+ def _makeOne(self, *arg, **kw):
+ from pyramid.config import Configurator
+
+ config = Configurator(*arg, **kw)
+ return config
+
+ def test_set_authentication_policy_no_authz_policy(self):
+ config = self._makeOne()
+ policy = object()
+ config.set_authentication_policy(policy)
+ self.assertRaises(ConfigurationExecutionError, config.commit)
+
+ def test_set_authentication_policy_no_authz_policy_autocommit(self):
+ config = self._makeOne(autocommit=True)
+ policy = object()
+ self.assertRaises(
+ ConfigurationError, config.set_authentication_policy, policy
+ )
+
+ def test_set_authentication_policy_with_authz_policy(self):
+ from pyramid.interfaces import IAuthenticationPolicy
+ from pyramid.interfaces import IAuthorizationPolicy
+
+ config = self._makeOne()
+ authn_policy = object()
+ authz_policy = object()
+ config.registry.registerUtility(authz_policy, IAuthorizationPolicy)
+ config.set_authentication_policy(authn_policy)
+ config.commit()
+ self.assertEqual(
+ config.registry.getUtility(IAuthenticationPolicy), authn_policy
+ )
+
+ def test_set_authentication_policy_with_authz_policy_autocommit(self):
+ from pyramid.interfaces import IAuthenticationPolicy
+ from pyramid.interfaces import IAuthorizationPolicy
+
+ config = self._makeOne(autocommit=True)
+ authn_policy = object()
+ authz_policy = object()
+ config.registry.registerUtility(authz_policy, IAuthorizationPolicy)
+ config.set_authentication_policy(authn_policy)
+ config.commit()
+ self.assertEqual(
+ config.registry.getUtility(IAuthenticationPolicy), authn_policy
+ )
+
+ def test_set_authorization_policy_no_authn_policy(self):
+ config = self._makeOne()
+ policy = object()
+ config.set_authorization_policy(policy)
+ self.assertRaises(ConfigurationExecutionError, config.commit)
+
+ def test_set_authorization_policy_no_authn_policy_autocommit(self):
+ from pyramid.interfaces import IAuthorizationPolicy
+
+ config = self._makeOne(autocommit=True)
+ policy = object()
+ config.set_authorization_policy(policy)
+ self.assertEqual(
+ config.registry.getUtility(IAuthorizationPolicy), policy
+ )
+
+ def test_set_authorization_policy_with_authn_policy(self):
+ from pyramid.interfaces import IAuthorizationPolicy
+ from pyramid.interfaces import IAuthenticationPolicy
+
+ config = self._makeOne()
+ authn_policy = object()
+ authz_policy = object()
+ config.registry.registerUtility(authn_policy, IAuthenticationPolicy)
+ config.set_authorization_policy(authz_policy)
+ config.commit()
+ self.assertEqual(
+ config.registry.getUtility(IAuthorizationPolicy), authz_policy
+ )
+
+ def test_set_authorization_policy_with_authn_policy_autocommit(self):
+ from pyramid.interfaces import IAuthorizationPolicy
+ from pyramid.interfaces import IAuthenticationPolicy
+
+ config = self._makeOne(autocommit=True)
+ authn_policy = object()
+ authz_policy = object()
+ config.registry.registerUtility(authn_policy, IAuthenticationPolicy)
+ config.set_authorization_policy(authz_policy)
+ self.assertEqual(
+ config.registry.getUtility(IAuthorizationPolicy), authz_policy
+ )
+
+ def test_set_default_permission(self):
+ from pyramid.interfaces import IDefaultPermission
+
+ config = self._makeOne(autocommit=True)
+ config.set_default_permission('view')
+ self.assertEqual(
+ config.registry.getUtility(IDefaultPermission), 'view'
+ )
+
+ def test_add_permission(self):
+ config = self._makeOne(autocommit=True)
+ config.add_permission('perm')
+ cat = config.registry.introspector.get_category('permissions')
+ self.assertEqual(len(cat), 1)
+ D = cat[0]
+ intr = D['introspectable']
+ self.assertEqual(intr['value'], 'perm')
+
+ def test_set_default_csrf_options(self):
+ from pyramid.interfaces import IDefaultCSRFOptions
+
+ config = self._makeOne(autocommit=True)
+ config.set_default_csrf_options()
+ result = config.registry.getUtility(IDefaultCSRFOptions)
+ self.assertEqual(result.require_csrf, True)
+ self.assertEqual(result.token, 'csrf_token')
+ self.assertEqual(result.header, 'X-CSRF-Token')
+ self.assertEqual(
+ list(sorted(result.safe_methods)),
+ ['GET', 'HEAD', 'OPTIONS', 'TRACE'],
+ )
+ self.assertTrue(result.callback is None)
+
+ def test_changing_set_default_csrf_options(self):
+ from pyramid.interfaces import IDefaultCSRFOptions
+
+ config = self._makeOne(autocommit=True)
+
+ def callback(request): # pragma: no cover
+ return True
+
+ config.set_default_csrf_options(
+ require_csrf=False,
+ token='DUMMY',
+ header=None,
+ safe_methods=('PUT',),
+ callback=callback,
+ )
+ result = config.registry.getUtility(IDefaultCSRFOptions)
+ self.assertEqual(result.require_csrf, False)
+ self.assertEqual(result.token, 'DUMMY')
+ self.assertEqual(result.header, None)
+ self.assertEqual(list(sorted(result.safe_methods)), ['PUT'])
+ self.assertTrue(result.callback is callback)
diff --git a/tests/test_config/test_settings.py b/tests/test_config/test_settings.py
new file mode 100644
index 000000000..2fe769add
--- /dev/null
+++ b/tests/test_config/test_settings.py
@@ -0,0 +1,635 @@
+import unittest
+
+
+class TestSettingsConfiguratorMixin(unittest.TestCase):
+ def _makeOne(self, *arg, **kw):
+ from pyramid.config import Configurator
+
+ config = Configurator(*arg, **kw)
+ return config
+
+ def test__set_settings_as_None(self):
+ config = self._makeOne()
+ settings = config._set_settings(None)
+ self.assertTrue(settings)
+
+ def test__set_settings_does_not_uses_original_dict(self):
+ config = self._makeOne()
+ dummy = {}
+ result = config._set_settings(dummy)
+ self.assertTrue(dummy is not result)
+ self.assertNotIn('pyramid.debug_all', dummy)
+
+ def test__set_settings_as_dictwithvalues(self):
+ config = self._makeOne()
+ settings = config._set_settings({'a': '1'})
+ self.assertEqual(settings['a'], '1')
+
+ def test_get_settings_nosettings(self):
+ from pyramid.registry import Registry
+
+ reg = Registry()
+ config = self._makeOne(reg)
+ self.assertEqual(config.get_settings(), None)
+
+ def test_get_settings_withsettings(self):
+ settings = {'a': 1}
+ config = self._makeOne()
+ config.registry.settings = settings
+ self.assertEqual(config.get_settings(), settings)
+
+ def test_add_settings_settings_already_registered(self):
+ from pyramid.registry import Registry
+
+ reg = Registry()
+ config = self._makeOne(reg)
+ config._set_settings({'a': 1})
+ config.add_settings({'b': 2})
+ settings = reg.settings
+ self.assertEqual(settings['a'], 1)
+ self.assertEqual(settings['b'], 2)
+
+ def test_add_settings_settings_not_yet_registered(self):
+ from pyramid.registry import Registry
+ from pyramid.interfaces import ISettings
+
+ reg = Registry()
+ config = self._makeOne(reg)
+ config.add_settings({'a': 1})
+ settings = reg.getUtility(ISettings)
+ self.assertEqual(settings['a'], 1)
+
+ def test_add_settings_settings_None(self):
+ from pyramid.registry import Registry
+ from pyramid.interfaces import ISettings
+
+ reg = Registry()
+ config = self._makeOne(reg)
+ config.add_settings(None, a=1)
+ settings = reg.getUtility(ISettings)
+ self.assertEqual(settings['a'], 1)
+
+ def test_settings_parameter_dict_is_never_updated(self):
+ class ReadOnlyDict(dict):
+ def __readonly__(self, *args, **kwargs): # pragma: no cover
+ raise RuntimeError("Cannot modify ReadOnlyDict")
+
+ __setitem__ = __readonly__
+ __delitem__ = __readonly__
+ pop = __readonly__
+ popitem = __readonly__
+ clear = __readonly__
+ update = __readonly__
+ setdefault = __readonly__
+ del __readonly__
+
+ initial = ReadOnlyDict()
+ config = self._makeOne(settings=initial)
+ config._set_settings({'a': '1'})
+
+
+class TestSettings(unittest.TestCase):
+ def _getTargetClass(self):
+ from pyramid.config.settings import Settings
+
+ return Settings
+
+ def _makeOne(self, d=None, environ=None):
+ if environ is None:
+ environ = {}
+ klass = self._getTargetClass()
+ return klass(d, _environ_=environ)
+
+ def test_noargs(self):
+ settings = self._makeOne()
+ self.assertEqual(settings['debug_authorization'], False)
+ self.assertEqual(settings['debug_notfound'], False)
+ self.assertEqual(settings['debug_routematch'], False)
+ self.assertEqual(settings['reload_templates'], False)
+ self.assertEqual(settings['reload_resources'], False)
+
+ self.assertEqual(settings['pyramid.debug_authorization'], False)
+ self.assertEqual(settings['pyramid.debug_notfound'], False)
+ self.assertEqual(settings['pyramid.debug_routematch'], False)
+ self.assertEqual(settings['pyramid.reload_templates'], False)
+ self.assertEqual(settings['pyramid.reload_resources'], False)
+
+ def test_prevent_http_cache(self):
+ settings = self._makeOne({})
+ self.assertEqual(settings['prevent_http_cache'], False)
+ self.assertEqual(settings['pyramid.prevent_http_cache'], False)
+ result = self._makeOne({'prevent_http_cache': 'false'})
+ self.assertEqual(result['prevent_http_cache'], False)
+ self.assertEqual(result['pyramid.prevent_http_cache'], False)
+ result = self._makeOne({'prevent_http_cache': 't'})
+ self.assertEqual(result['prevent_http_cache'], True)
+ self.assertEqual(result['pyramid.prevent_http_cache'], True)
+ result = self._makeOne({'prevent_http_cache': '1'})
+ self.assertEqual(result['prevent_http_cache'], True)
+ self.assertEqual(result['pyramid.prevent_http_cache'], True)
+ result = self._makeOne({'pyramid.prevent_http_cache': 't'})
+ self.assertEqual(result['prevent_http_cache'], True)
+ self.assertEqual(result['pyramid.prevent_http_cache'], True)
+ result = self._makeOne({}, {'PYRAMID_PREVENT_HTTP_CACHE': '1'})
+ self.assertEqual(result['prevent_http_cache'], True)
+ self.assertEqual(result['pyramid.prevent_http_cache'], True)
+ result = self._makeOne(
+ {'prevent_http_cache': 'false', 'pyramid.prevent_http_cache': '1'}
+ )
+ self.assertEqual(result['prevent_http_cache'], True)
+ self.assertEqual(result['pyramid.prevent_http_cache'], True)
+ result = self._makeOne(
+ {'prevent_http_cache': 'false', 'pyramid.prevent_http_cache': 'f'},
+ {'PYRAMID_PREVENT_HTTP_CACHE': '1'},
+ )
+ self.assertEqual(result['prevent_http_cache'], True)
+ self.assertEqual(result['pyramid.prevent_http_cache'], True)
+
+ def test_prevent_cachebust(self):
+ settings = self._makeOne({})
+ self.assertEqual(settings['prevent_cachebust'], False)
+ self.assertEqual(settings['pyramid.prevent_cachebust'], False)
+ result = self._makeOne({'prevent_cachebust': 'false'})
+ self.assertEqual(result['prevent_cachebust'], False)
+ self.assertEqual(result['pyramid.prevent_cachebust'], False)
+ result = self._makeOne({'prevent_cachebust': 't'})
+ self.assertEqual(result['prevent_cachebust'], True)
+ self.assertEqual(result['pyramid.prevent_cachebust'], True)
+ result = self._makeOne({'prevent_cachebust': '1'})
+ self.assertEqual(result['prevent_cachebust'], True)
+ self.assertEqual(result['pyramid.prevent_cachebust'], True)
+ result = self._makeOne({'pyramid.prevent_cachebust': 't'})
+ self.assertEqual(result['prevent_cachebust'], True)
+ self.assertEqual(result['pyramid.prevent_cachebust'], True)
+ result = self._makeOne({}, {'PYRAMID_PREVENT_CACHEBUST': '1'})
+ self.assertEqual(result['prevent_cachebust'], True)
+ self.assertEqual(result['pyramid.prevent_cachebust'], True)
+ result = self._makeOne(
+ {'prevent_cachebust': 'false', 'pyramid.prevent_cachebust': '1'}
+ )
+ self.assertEqual(result['prevent_cachebust'], True)
+ self.assertEqual(result['pyramid.prevent_cachebust'], True)
+ result = self._makeOne(
+ {'prevent_cachebust': 'false', 'pyramid.prevent_cachebust': 'f'},
+ {'PYRAMID_PREVENT_CACHEBUST': '1'},
+ )
+ self.assertEqual(result['prevent_cachebust'], True)
+ self.assertEqual(result['pyramid.prevent_cachebust'], True)
+
+ def test_reload_templates(self):
+ settings = self._makeOne({})
+ self.assertEqual(settings['reload_templates'], False)
+ self.assertEqual(settings['pyramid.reload_templates'], False)
+ result = self._makeOne({'reload_templates': 'false'})
+ self.assertEqual(result['reload_templates'], False)
+ self.assertEqual(result['pyramid.reload_templates'], False)
+ result = self._makeOne({'reload_templates': 't'})
+ self.assertEqual(result['reload_templates'], True)
+ self.assertEqual(result['pyramid.reload_templates'], True)
+ result = self._makeOne({'reload_templates': '1'})
+ self.assertEqual(result['reload_templates'], True)
+ self.assertEqual(result['pyramid.reload_templates'], True)
+ result = self._makeOne({'pyramid.reload_templates': '1'})
+ self.assertEqual(result['reload_templates'], True)
+ self.assertEqual(result['pyramid.reload_templates'], True)
+ result = self._makeOne({}, {'PYRAMID_RELOAD_TEMPLATES': '1'})
+ self.assertEqual(result['reload_templates'], True)
+ self.assertEqual(result['pyramid.reload_templates'], True)
+ result = self._makeOne(
+ {'reload_templates': 'false', 'pyramid.reload_templates': '1'}
+ )
+ self.assertEqual(result['reload_templates'], True)
+ self.assertEqual(result['pyramid.reload_templates'], True)
+ result = self._makeOne(
+ {'reload_templates': 'false'}, {'PYRAMID_RELOAD_TEMPLATES': '1'}
+ )
+ self.assertEqual(result['reload_templates'], True)
+ self.assertEqual(result['pyramid.reload_templates'], True)
+
+ def test_reload_resources(self):
+ # alias for reload_assets
+ result = self._makeOne({})
+ self.assertEqual(result['reload_resources'], False)
+ self.assertEqual(result['reload_assets'], False)
+ self.assertEqual(result['pyramid.reload_resources'], False)
+ self.assertEqual(result['pyramid.reload_assets'], False)
+ result = self._makeOne({'reload_resources': 'false'})
+ self.assertEqual(result['reload_resources'], False)
+ self.assertEqual(result['reload_assets'], False)
+ self.assertEqual(result['pyramid.reload_resources'], False)
+ self.assertEqual(result['pyramid.reload_assets'], False)
+ result = self._makeOne({'reload_resources': 't'})
+ self.assertEqual(result['reload_resources'], True)
+ self.assertEqual(result['reload_assets'], True)
+ self.assertEqual(result['pyramid.reload_resources'], True)
+ self.assertEqual(result['pyramid.reload_assets'], True)
+ result = self._makeOne({'reload_resources': '1'})
+ self.assertEqual(result['reload_resources'], True)
+ self.assertEqual(result['reload_assets'], True)
+ self.assertEqual(result['pyramid.reload_resources'], True)
+ self.assertEqual(result['pyramid.reload_assets'], True)
+ result = self._makeOne({'pyramid.reload_resources': '1'})
+ self.assertEqual(result['reload_resources'], True)
+ self.assertEqual(result['reload_assets'], True)
+ self.assertEqual(result['pyramid.reload_resources'], True)
+ self.assertEqual(result['pyramid.reload_assets'], True)
+ result = self._makeOne({}, {'PYRAMID_RELOAD_RESOURCES': '1'})
+ self.assertEqual(result['reload_resources'], True)
+ self.assertEqual(result['reload_assets'], True)
+ self.assertEqual(result['pyramid.reload_resources'], True)
+ self.assertEqual(result['pyramid.reload_assets'], True)
+ result = self._makeOne(
+ {'reload_resources': 'false', 'pyramid.reload_resources': '1'}
+ )
+ self.assertEqual(result['reload_resources'], True)
+ self.assertEqual(result['reload_assets'], True)
+ self.assertEqual(result['pyramid.reload_resources'], True)
+ self.assertEqual(result['pyramid.reload_assets'], True)
+ result = self._makeOne(
+ {'reload_resources': 'false', 'pyramid.reload_resources': 'false'},
+ {'PYRAMID_RELOAD_RESOURCES': '1'},
+ )
+ self.assertEqual(result['reload_resources'], True)
+ self.assertEqual(result['reload_assets'], True)
+ self.assertEqual(result['pyramid.reload_resources'], True)
+ self.assertEqual(result['pyramid.reload_assets'], True)
+
+ def test_reload_assets(self):
+ # alias for reload_resources
+ result = self._makeOne({})
+ self.assertEqual(result['reload_assets'], False)
+ self.assertEqual(result['reload_resources'], False)
+ self.assertEqual(result['pyramid.reload_assets'], False)
+ self.assertEqual(result['pyramid.reload_resources'], False)
+ result = self._makeOne({'reload_assets': 'false'})
+ self.assertEqual(result['reload_resources'], False)
+ self.assertEqual(result['reload_assets'], False)
+ self.assertEqual(result['pyramid.reload_assets'], False)
+ self.assertEqual(result['pyramid.reload_resources'], False)
+ result = self._makeOne({'reload_assets': 't'})
+ self.assertEqual(result['reload_assets'], True)
+ self.assertEqual(result['reload_resources'], True)
+ self.assertEqual(result['pyramid.reload_assets'], True)
+ self.assertEqual(result['pyramid.reload_resources'], True)
+ result = self._makeOne({'reload_assets': '1'})
+ self.assertEqual(result['reload_assets'], True)
+ self.assertEqual(result['reload_resources'], True)
+ self.assertEqual(result['pyramid.reload_assets'], True)
+ self.assertEqual(result['pyramid.reload_resources'], True)
+ result = self._makeOne({'pyramid.reload_assets': '1'})
+ self.assertEqual(result['reload_assets'], True)
+ self.assertEqual(result['reload_resources'], True)
+ self.assertEqual(result['pyramid.reload_assets'], True)
+ self.assertEqual(result['pyramid.reload_resources'], True)
+ result = self._makeOne({}, {'PYRAMID_RELOAD_ASSETS': '1'})
+ self.assertEqual(result['reload_assets'], True)
+ self.assertEqual(result['reload_resources'], True)
+ self.assertEqual(result['pyramid.reload_assets'], True)
+ self.assertEqual(result['pyramid.reload_resources'], True)
+ result = self._makeOne(
+ {'reload_assets': 'false', 'pyramid.reload_assets': '1'}
+ )
+ self.assertEqual(result['reload_assets'], True)
+ self.assertEqual(result['reload_resources'], True)
+ self.assertEqual(result['pyramid.reload_assets'], True)
+ self.assertEqual(result['pyramid.reload_resources'], True)
+ result = self._makeOne(
+ {'reload_assets': 'false', 'pyramid.reload_assets': 'false'},
+ {'PYRAMID_RELOAD_ASSETS': '1'},
+ )
+ self.assertEqual(result['reload_assets'], True)
+ self.assertEqual(result['reload_resources'], True)
+ self.assertEqual(result['pyramid.reload_assets'], True)
+ self.assertEqual(result['pyramid.reload_resources'], True)
+
+ def test_reload_all(self):
+ result = self._makeOne({})
+ self.assertEqual(result['reload_templates'], False)
+ self.assertEqual(result['reload_resources'], False)
+ self.assertEqual(result['reload_assets'], False)
+ self.assertEqual(result['pyramid.reload_templates'], False)
+ self.assertEqual(result['pyramid.reload_resources'], False)
+ self.assertEqual(result['pyramid.reload_assets'], False)
+ result = self._makeOne({'reload_all': 'false'})
+ self.assertEqual(result['reload_templates'], False)
+ self.assertEqual(result['reload_resources'], False)
+ self.assertEqual(result['reload_assets'], False)
+ self.assertEqual(result['pyramid.reload_templates'], False)
+ self.assertEqual(result['pyramid.reload_resources'], False)
+ self.assertEqual(result['pyramid.reload_assets'], False)
+ result = self._makeOne({'reload_all': 't'})
+ self.assertEqual(result['reload_templates'], True)
+ self.assertEqual(result['reload_resources'], True)
+ self.assertEqual(result['reload_assets'], True)
+ self.assertEqual(result['pyramid.reload_templates'], True)
+ self.assertEqual(result['pyramid.reload_resources'], True)
+ self.assertEqual(result['pyramid.reload_assets'], True)
+ result = self._makeOne({'reload_all': '1'})
+ self.assertEqual(result['reload_templates'], True)
+ self.assertEqual(result['reload_resources'], True)
+ self.assertEqual(result['reload_assets'], True)
+ self.assertEqual(result['pyramid.reload_templates'], True)
+ self.assertEqual(result['pyramid.reload_resources'], True)
+ self.assertEqual(result['pyramid.reload_assets'], True)
+ result = self._makeOne({'pyramid.reload_all': '1'})
+ self.assertEqual(result['reload_templates'], True)
+ self.assertEqual(result['reload_resources'], True)
+ self.assertEqual(result['reload_assets'], True)
+ self.assertEqual(result['pyramid.reload_templates'], True)
+ self.assertEqual(result['pyramid.reload_resources'], True)
+ self.assertEqual(result['pyramid.reload_assets'], True)
+ result = self._makeOne({}, {'PYRAMID_RELOAD_ALL': '1'})
+ self.assertEqual(result['reload_templates'], True)
+ self.assertEqual(result['reload_resources'], True)
+ self.assertEqual(result['reload_assets'], True)
+ self.assertEqual(result['pyramid.reload_templates'], True)
+ self.assertEqual(result['pyramid.reload_resources'], True)
+ self.assertEqual(result['pyramid.reload_assets'], True)
+ result = self._makeOne(
+ {'reload_all': 'false', 'pyramid.reload_all': '1'}
+ )
+ self.assertEqual(result['reload_templates'], True)
+ self.assertEqual(result['reload_resources'], True)
+ self.assertEqual(result['reload_assets'], True)
+ self.assertEqual(result['pyramid.reload_templates'], True)
+ self.assertEqual(result['pyramid.reload_resources'], True)
+ self.assertEqual(result['pyramid.reload_assets'], True)
+ result = self._makeOne(
+ {'reload_all': 'false', 'pyramid.reload_all': 'false'},
+ {'PYRAMID_RELOAD_ALL': '1'},
+ )
+ self.assertEqual(result['reload_templates'], True)
+ self.assertEqual(result['reload_resources'], True)
+ self.assertEqual(result['reload_assets'], True)
+ self.assertEqual(result['pyramid.reload_templates'], True)
+ self.assertEqual(result['pyramid.reload_resources'], True)
+ self.assertEqual(result['pyramid.reload_assets'], True)
+
+ def test_debug_authorization(self):
+ result = self._makeOne({})
+ self.assertEqual(result['debug_authorization'], False)
+ self.assertEqual(result['pyramid.debug_authorization'], False)
+ result = self._makeOne({'debug_authorization': 'false'})
+ self.assertEqual(result['debug_authorization'], False)
+ self.assertEqual(result['pyramid.debug_authorization'], False)
+ result = self._makeOne({'debug_authorization': 't'})
+ self.assertEqual(result['debug_authorization'], True)
+ self.assertEqual(result['pyramid.debug_authorization'], True)
+ result = self._makeOne({'debug_authorization': '1'})
+ self.assertEqual(result['debug_authorization'], True)
+ self.assertEqual(result['pyramid.debug_authorization'], True)
+ result = self._makeOne({'pyramid.debug_authorization': '1'})
+ self.assertEqual(result['debug_authorization'], True)
+ self.assertEqual(result['pyramid.debug_authorization'], True)
+ result = self._makeOne({}, {'PYRAMID_DEBUG_AUTHORIZATION': '1'})
+ self.assertEqual(result['debug_authorization'], True)
+ self.assertEqual(result['pyramid.debug_authorization'], True)
+ result = self._makeOne(
+ {
+ 'debug_authorization': 'false',
+ 'pyramid.debug_authorization': '1',
+ }
+ )
+ self.assertEqual(result['debug_authorization'], True)
+ self.assertEqual(result['pyramid.debug_authorization'], True)
+ result = self._makeOne(
+ {
+ 'debug_authorization': 'false',
+ 'pyramid.debug_authorization': 'false',
+ },
+ {'PYRAMID_DEBUG_AUTHORIZATION': '1'},
+ )
+ self.assertEqual(result['debug_authorization'], True)
+ self.assertEqual(result['pyramid.debug_authorization'], True)
+
+ def test_debug_notfound(self):
+ result = self._makeOne({})
+ self.assertEqual(result['debug_notfound'], False)
+ self.assertEqual(result['pyramid.debug_notfound'], False)
+ result = self._makeOne({'debug_notfound': 'false'})
+ self.assertEqual(result['debug_notfound'], False)
+ self.assertEqual(result['pyramid.debug_notfound'], False)
+ result = self._makeOne({'debug_notfound': 't'})
+ self.assertEqual(result['debug_notfound'], True)
+ self.assertEqual(result['pyramid.debug_notfound'], True)
+ result = self._makeOne({'debug_notfound': '1'})
+ self.assertEqual(result['debug_notfound'], True)
+ self.assertEqual(result['pyramid.debug_notfound'], True)
+ result = self._makeOne({'pyramid.debug_notfound': '1'})
+ self.assertEqual(result['debug_notfound'], True)
+ self.assertEqual(result['pyramid.debug_notfound'], True)
+ result = self._makeOne({}, {'PYRAMID_DEBUG_NOTFOUND': '1'})
+ self.assertEqual(result['debug_notfound'], True)
+ self.assertEqual(result['pyramid.debug_notfound'], True)
+ result = self._makeOne(
+ {'debug_notfound': 'false', 'pyramid.debug_notfound': '1'}
+ )
+ self.assertEqual(result['debug_notfound'], True)
+ self.assertEqual(result['pyramid.debug_notfound'], True)
+ result = self._makeOne(
+ {'debug_notfound': 'false', 'pyramid.debug_notfound': 'false'},
+ {'PYRAMID_DEBUG_NOTFOUND': '1'},
+ )
+ self.assertEqual(result['debug_notfound'], True)
+ self.assertEqual(result['pyramid.debug_notfound'], True)
+
+ def test_debug_routematch(self):
+ result = self._makeOne({})
+ self.assertEqual(result['debug_routematch'], False)
+ self.assertEqual(result['pyramid.debug_routematch'], False)
+ result = self._makeOne({'debug_routematch': 'false'})
+ self.assertEqual(result['debug_routematch'], False)
+ self.assertEqual(result['pyramid.debug_routematch'], False)
+ result = self._makeOne({'debug_routematch': 't'})
+ self.assertEqual(result['debug_routematch'], True)
+ self.assertEqual(result['pyramid.debug_routematch'], True)
+ result = self._makeOne({'debug_routematch': '1'})
+ self.assertEqual(result['debug_routematch'], True)
+ self.assertEqual(result['pyramid.debug_routematch'], True)
+ result = self._makeOne({'pyramid.debug_routematch': '1'})
+ self.assertEqual(result['debug_routematch'], True)
+ self.assertEqual(result['pyramid.debug_routematch'], True)
+ result = self._makeOne({}, {'PYRAMID_DEBUG_ROUTEMATCH': '1'})
+ self.assertEqual(result['debug_routematch'], True)
+ self.assertEqual(result['pyramid.debug_routematch'], True)
+ result = self._makeOne(
+ {'debug_routematch': 'false', 'pyramid.debug_routematch': '1'}
+ )
+ self.assertEqual(result['debug_routematch'], True)
+ self.assertEqual(result['pyramid.debug_routematch'], True)
+ result = self._makeOne(
+ {'debug_routematch': 'false', 'pyramid.debug_routematch': 'false'},
+ {'PYRAMID_DEBUG_ROUTEMATCH': '1'},
+ )
+ self.assertEqual(result['debug_routematch'], True)
+ self.assertEqual(result['pyramid.debug_routematch'], True)
+
+ def test_debug_templates(self):
+ result = self._makeOne({})
+ self.assertEqual(result['debug_templates'], False)
+ self.assertEqual(result['pyramid.debug_templates'], False)
+ result = self._makeOne({'debug_templates': 'false'})
+ self.assertEqual(result['debug_templates'], False)
+ self.assertEqual(result['pyramid.debug_templates'], False)
+ result = self._makeOne({'debug_templates': 't'})
+ self.assertEqual(result['debug_templates'], True)
+ self.assertEqual(result['pyramid.debug_templates'], True)
+ result = self._makeOne({'debug_templates': '1'})
+ self.assertEqual(result['debug_templates'], True)
+ self.assertEqual(result['pyramid.debug_templates'], True)
+ result = self._makeOne({'pyramid.debug_templates': '1'})
+ self.assertEqual(result['debug_templates'], True)
+ self.assertEqual(result['pyramid.debug_templates'], True)
+ result = self._makeOne({}, {'PYRAMID_DEBUG_TEMPLATES': '1'})
+ self.assertEqual(result['debug_templates'], True)
+ self.assertEqual(result['pyramid.debug_templates'], True)
+ result = self._makeOne(
+ {'debug_templates': 'false', 'pyramid.debug_templates': '1'}
+ )
+ self.assertEqual(result['debug_templates'], True)
+ self.assertEqual(result['pyramid.debug_templates'], True)
+ result = self._makeOne(
+ {'debug_templates': 'false', 'pyramid.debug_templates': 'false'},
+ {'PYRAMID_DEBUG_TEMPLATES': '1'},
+ )
+ self.assertEqual(result['debug_templates'], True)
+ self.assertEqual(result['pyramid.debug_templates'], True)
+
+ def test_debug_all(self):
+ result = self._makeOne({})
+ self.assertEqual(result['debug_notfound'], False)
+ self.assertEqual(result['debug_routematch'], False)
+ self.assertEqual(result['debug_authorization'], False)
+ self.assertEqual(result['debug_templates'], False)
+ self.assertEqual(result['pyramid.debug_notfound'], False)
+ self.assertEqual(result['pyramid.debug_routematch'], False)
+ self.assertEqual(result['pyramid.debug_authorization'], False)
+ self.assertEqual(result['pyramid.debug_templates'], False)
+ result = self._makeOne({'debug_all': 'false'})
+ self.assertEqual(result['debug_notfound'], False)
+ self.assertEqual(result['debug_routematch'], False)
+ self.assertEqual(result['debug_authorization'], False)
+ self.assertEqual(result['debug_templates'], False)
+ self.assertEqual(result['pyramid.debug_notfound'], False)
+ self.assertEqual(result['pyramid.debug_routematch'], False)
+ self.assertEqual(result['pyramid.debug_authorization'], False)
+ self.assertEqual(result['pyramid.debug_templates'], False)
+ result = self._makeOne({'debug_all': 't'})
+ self.assertEqual(result['debug_notfound'], True)
+ self.assertEqual(result['debug_routematch'], True)
+ self.assertEqual(result['debug_authorization'], True)
+ self.assertEqual(result['debug_templates'], True)
+ self.assertEqual(result['pyramid.debug_notfound'], True)
+ self.assertEqual(result['pyramid.debug_routematch'], True)
+ self.assertEqual(result['pyramid.debug_authorization'], True)
+ self.assertEqual(result['pyramid.debug_templates'], True)
+ result = self._makeOne({'debug_all': '1'})
+ self.assertEqual(result['debug_notfound'], True)
+ self.assertEqual(result['debug_routematch'], True)
+ self.assertEqual(result['debug_authorization'], True)
+ self.assertEqual(result['debug_templates'], True)
+ self.assertEqual(result['pyramid.debug_notfound'], True)
+ self.assertEqual(result['pyramid.debug_routematch'], True)
+ self.assertEqual(result['pyramid.debug_authorization'], True)
+ self.assertEqual(result['pyramid.debug_templates'], True)
+ result = self._makeOne({'pyramid.debug_all': '1'})
+ self.assertEqual(result['debug_notfound'], True)
+ self.assertEqual(result['debug_routematch'], True)
+ self.assertEqual(result['debug_authorization'], True)
+ self.assertEqual(result['debug_templates'], True)
+ self.assertEqual(result['pyramid.debug_notfound'], True)
+ self.assertEqual(result['pyramid.debug_routematch'], True)
+ self.assertEqual(result['pyramid.debug_authorization'], True)
+ self.assertEqual(result['pyramid.debug_templates'], True)
+ result = self._makeOne({}, {'PYRAMID_DEBUG_ALL': '1'})
+ self.assertEqual(result['debug_notfound'], True)
+ self.assertEqual(result['debug_routematch'], True)
+ self.assertEqual(result['debug_authorization'], True)
+ self.assertEqual(result['debug_templates'], True)
+ self.assertEqual(result['pyramid.debug_notfound'], True)
+ self.assertEqual(result['pyramid.debug_routematch'], True)
+ self.assertEqual(result['pyramid.debug_authorization'], True)
+ self.assertEqual(result['pyramid.debug_templates'], True)
+ result = self._makeOne(
+ {'debug_all': 'false', 'pyramid.debug_all': '1'}
+ )
+ self.assertEqual(result['debug_notfound'], True)
+ self.assertEqual(result['debug_routematch'], True)
+ self.assertEqual(result['debug_authorization'], True)
+ self.assertEqual(result['debug_templates'], True)
+ self.assertEqual(result['pyramid.debug_notfound'], True)
+ self.assertEqual(result['pyramid.debug_routematch'], True)
+ self.assertEqual(result['pyramid.debug_authorization'], True)
+ self.assertEqual(result['pyramid.debug_templates'], True)
+ result = self._makeOne(
+ {'debug_all': 'false', 'pyramid.debug_all': 'false'},
+ {'PYRAMID_DEBUG_ALL': '1'},
+ )
+ self.assertEqual(result['debug_notfound'], True)
+ self.assertEqual(result['debug_routematch'], True)
+ self.assertEqual(result['debug_authorization'], True)
+ self.assertEqual(result['debug_templates'], True)
+ self.assertEqual(result['pyramid.debug_notfound'], True)
+ self.assertEqual(result['pyramid.debug_routematch'], True)
+ self.assertEqual(result['pyramid.debug_authorization'], True)
+ self.assertEqual(result['pyramid.debug_templates'], True)
+
+ def test_default_locale_name(self):
+ result = self._makeOne({})
+ self.assertEqual(result['default_locale_name'], 'en')
+ self.assertEqual(result['pyramid.default_locale_name'], 'en')
+ result = self._makeOne({'default_locale_name': 'abc'})
+ self.assertEqual(result['default_locale_name'], 'abc')
+ self.assertEqual(result['pyramid.default_locale_name'], 'abc')
+ result = self._makeOne({'pyramid.default_locale_name': 'abc'})
+ self.assertEqual(result['default_locale_name'], 'abc')
+ self.assertEqual(result['pyramid.default_locale_name'], 'abc')
+ result = self._makeOne({}, {'PYRAMID_DEFAULT_LOCALE_NAME': 'abc'})
+ self.assertEqual(result['default_locale_name'], 'abc')
+ self.assertEqual(result['pyramid.default_locale_name'], 'abc')
+ result = self._makeOne(
+ {
+ 'default_locale_name': 'def',
+ 'pyramid.default_locale_name': 'abc',
+ }
+ )
+ self.assertEqual(result['default_locale_name'], 'abc')
+ self.assertEqual(result['pyramid.default_locale_name'], 'abc')
+ result = self._makeOne(
+ {
+ 'default_locale_name': 'def',
+ 'pyramid.default_locale_name': 'ghi',
+ },
+ {'PYRAMID_DEFAULT_LOCALE_NAME': 'abc'},
+ )
+ self.assertEqual(result['default_locale_name'], 'abc')
+ self.assertEqual(result['pyramid.default_locale_name'], 'abc')
+
+ def test_csrf_trusted_origins(self):
+ result = self._makeOne({})
+ self.assertEqual(result['pyramid.csrf_trusted_origins'], [])
+ result = self._makeOne({'pyramid.csrf_trusted_origins': 'example.com'})
+ self.assertEqual(
+ result['pyramid.csrf_trusted_origins'], ['example.com']
+ )
+ result = self._makeOne(
+ {'pyramid.csrf_trusted_origins': ['example.com']}
+ )
+ self.assertEqual(
+ result['pyramid.csrf_trusted_origins'], ['example.com']
+ )
+ result = self._makeOne(
+ {
+ 'pyramid.csrf_trusted_origins': (
+ 'example.com foo.example.com\nasdf.example.com'
+ )
+ }
+ )
+ self.assertEqual(
+ result['pyramid.csrf_trusted_origins'],
+ ['example.com', 'foo.example.com', 'asdf.example.com'],
+ )
+
+ def test_originals_kept(self):
+ result = self._makeOne({'a': 'i am so a'})
+ self.assertEqual(result['a'], 'i am so a')
diff --git a/tests/test_config/test_testing.py b/tests/test_config/test_testing.py
new file mode 100644
index 000000000..ede31e1b6
--- /dev/null
+++ b/tests/test_config/test_testing.py
@@ -0,0 +1,235 @@
+import unittest
+from zope.interface import implementer
+
+from pyramid.compat import text_
+from pyramid.security import AuthenticationAPIMixin, AuthorizationAPIMixin
+from . import IDummy
+
+
+class TestingConfiguratorMixinTests(unittest.TestCase):
+ def _makeOne(self, *arg, **kw):
+ from pyramid.config import Configurator
+
+ config = Configurator(*arg, **kw)
+ return config
+
+ def test_testing_securitypolicy(self):
+ from pyramid.testing import DummySecurityPolicy
+
+ config = self._makeOne(autocommit=True)
+ config.testing_securitypolicy(
+ 'user', ('group1', 'group2'), permissive=False
+ )
+ from pyramid.interfaces import IAuthenticationPolicy
+ from pyramid.interfaces import IAuthorizationPolicy
+
+ ut = config.registry.getUtility(IAuthenticationPolicy)
+ self.assertTrue(isinstance(ut, DummySecurityPolicy))
+ ut = config.registry.getUtility(IAuthorizationPolicy)
+ self.assertEqual(ut.userid, 'user')
+ self.assertEqual(ut.groupids, ('group1', 'group2'))
+ self.assertEqual(ut.permissive, False)
+
+ def test_testing_securitypolicy_remember_result(self):
+ from pyramid.security import remember
+
+ config = self._makeOne(autocommit=True)
+ pol = config.testing_securitypolicy(
+ 'user',
+ ('group1', 'group2'),
+ permissive=False,
+ remember_result=True,
+ )
+ request = DummyRequest()
+ request.registry = config.registry
+ val = remember(request, 'fred')
+ self.assertEqual(pol.remembered, 'fred')
+ self.assertEqual(val, True)
+
+ def test_testing_securitypolicy_forget_result(self):
+ from pyramid.security import forget
+
+ config = self._makeOne(autocommit=True)
+ pol = config.testing_securitypolicy(
+ 'user', ('group1', 'group2'), permissive=False, forget_result=True
+ )
+ request = DummyRequest()
+ request.registry = config.registry
+ val = forget(request)
+ self.assertEqual(pol.forgotten, True)
+ self.assertEqual(val, True)
+
+ def test_testing_resources(self):
+ from pyramid.traversal import find_resource
+ from pyramid.interfaces import ITraverser
+
+ ob1 = object()
+ ob2 = object()
+ resources = {'/ob1': ob1, '/ob2': ob2}
+ config = self._makeOne(autocommit=True)
+ config.testing_resources(resources)
+ adapter = config.registry.getAdapter(None, ITraverser)
+ result = adapter(DummyRequest({'PATH_INFO': '/ob1'}))
+ self.assertEqual(result['context'], ob1)
+ self.assertEqual(result['view_name'], '')
+ self.assertEqual(result['subpath'], ())
+ self.assertEqual(result['traversed'], (text_('ob1'),))
+ self.assertEqual(result['virtual_root'], ob1)
+ self.assertEqual(result['virtual_root_path'], ())
+ result = adapter(DummyRequest({'PATH_INFO': '/ob2'}))
+ self.assertEqual(result['context'], ob2)
+ self.assertEqual(result['view_name'], '')
+ self.assertEqual(result['subpath'], ())
+ self.assertEqual(result['traversed'], (text_('ob2'),))
+ self.assertEqual(result['virtual_root'], ob2)
+ self.assertEqual(result['virtual_root_path'], ())
+ self.assertRaises(
+ KeyError, adapter, DummyRequest({'PATH_INFO': '/ob3'})
+ )
+ try:
+ config.begin()
+ self.assertEqual(find_resource(None, '/ob1'), ob1)
+ finally:
+ config.end()
+
+ def test_testing_add_subscriber_single(self):
+ config = self._makeOne(autocommit=True)
+ L = config.testing_add_subscriber(IDummy)
+ event = DummyEvent()
+ config.registry.notify(event)
+ self.assertEqual(len(L), 1)
+ self.assertEqual(L[0], event)
+ config.registry.notify(object())
+ self.assertEqual(len(L), 1)
+
+ def test_testing_add_subscriber_dottedname(self):
+ config = self._makeOne(autocommit=True)
+ L = config.testing_add_subscriber('tests.test_config.IDummy')
+ event = DummyEvent()
+ config.registry.notify(event)
+ self.assertEqual(len(L), 1)
+ self.assertEqual(L[0], event)
+ config.registry.notify(object())
+ self.assertEqual(len(L), 1)
+
+ def test_testing_add_subscriber_multiple(self):
+ from zope.interface import Interface
+
+ config = self._makeOne(autocommit=True)
+ L = config.testing_add_subscriber((Interface, IDummy))
+ event = DummyEvent()
+ event.object = 'foo'
+ # the below is the equivalent of z.c.event.objectEventNotify(event)
+ config.registry.subscribers((event.object, event), None)
+ self.assertEqual(len(L), 2)
+ self.assertEqual(L[0], 'foo')
+ self.assertEqual(L[1], event)
+
+ def test_testing_add_subscriber_defaults(self):
+ config = self._makeOne(autocommit=True)
+ L = config.testing_add_subscriber()
+ event = object()
+ config.registry.notify(event)
+ self.assertEqual(L[-1], event)
+ event2 = object()
+ config.registry.notify(event2)
+ self.assertEqual(L[-1], event2)
+
+ def test_testing_add_renderer(self):
+ config = self._makeOne(autocommit=True)
+ renderer = config.testing_add_renderer('templates/foo.pt')
+ from pyramid.testing import DummyTemplateRenderer
+
+ self.assertTrue(isinstance(renderer, DummyTemplateRenderer))
+ from pyramid.renderers import render_to_response
+
+ # must provide request to pass in registry (this is a functest)
+ request = DummyRequest()
+ request.registry = config.registry
+ render_to_response(
+ 'templates/foo.pt', {'foo': 1, 'bar': 2}, request=request
+ )
+ renderer.assert_(foo=1)
+ renderer.assert_(bar=2)
+ renderer.assert_(request=request)
+
+ def test_testing_add_renderer_twice(self):
+ config = self._makeOne(autocommit=True)
+ renderer1 = config.testing_add_renderer('templates/foo.pt')
+ renderer2 = config.testing_add_renderer('templates/bar.pt')
+ from pyramid.testing import DummyTemplateRenderer
+
+ self.assertTrue(isinstance(renderer1, DummyTemplateRenderer))
+ self.assertTrue(isinstance(renderer2, DummyTemplateRenderer))
+ from pyramid.renderers import render_to_response
+
+ # must provide request to pass in registry (this is a functest)
+ request = DummyRequest()
+ request.registry = config.registry
+ render_to_response(
+ 'templates/foo.pt', {'foo': 1, 'bar': 2}, request=request
+ )
+ renderer1.assert_(foo=1)
+ renderer1.assert_(bar=2)
+ renderer1.assert_(request=request)
+ render_to_response(
+ 'templates/bar.pt', {'foo': 1, 'bar': 2}, request=request
+ )
+ renderer2.assert_(foo=1)
+ renderer2.assert_(bar=2)
+ renderer2.assert_(request=request)
+
+ def test_testing_add_renderer_explicitrenderer(self):
+ config = self._makeOne(autocommit=True)
+
+ class E(Exception):
+ pass
+
+ def renderer(kw, system):
+ self.assertEqual(kw, {'foo': 1, 'bar': 2})
+ raise E
+
+ renderer = config.testing_add_renderer('templates/foo.pt', renderer)
+ from pyramid.renderers import render_to_response
+
+ # must provide request to pass in registry (this is a functest)
+ request = DummyRequest()
+ request.registry = config.registry
+ try:
+ render_to_response(
+ 'templates/foo.pt', {'foo': 1, 'bar': 2}, request=request
+ )
+ except E:
+ pass
+ else: # pragma: no cover
+ raise AssertionError
+
+ def test_testing_add_template(self):
+ config = self._makeOne(autocommit=True)
+ renderer = config.testing_add_template('templates/foo.pt')
+ from pyramid.testing import DummyTemplateRenderer
+
+ self.assertTrue(isinstance(renderer, DummyTemplateRenderer))
+ from pyramid.renderers import render_to_response
+
+ # must provide request to pass in registry (this is a functest)
+ request = DummyRequest()
+ request.registry = config.registry
+ render_to_response(
+ 'templates/foo.pt', dict(foo=1, bar=2), request=request
+ )
+ renderer.assert_(foo=1)
+ renderer.assert_(bar=2)
+ renderer.assert_(request=request)
+
+
+@implementer(IDummy)
+class DummyEvent:
+ pass
+
+
+class DummyRequest(AuthenticationAPIMixin, AuthorizationAPIMixin):
+ def __init__(self, environ=None):
+ if environ is None:
+ environ = {}
+ self.environ = environ
diff --git a/tests/test_config/test_tweens.py b/tests/test_config/test_tweens.py
new file mode 100644
index 000000000..805310c9a
--- /dev/null
+++ b/tests/test_config/test_tweens.py
@@ -0,0 +1,484 @@
+import unittest
+
+from . import dummy_tween_factory
+from . import dummy_tween_factory2
+
+from pyramid.exceptions import ConfigurationConflictError
+
+
+class TestTweensConfiguratorMixin(unittest.TestCase):
+ def _makeOne(self, *arg, **kw):
+ from pyramid.config import Configurator
+
+ config = Configurator(*arg, **kw)
+ return config
+
+ def test_add_tweens_names_distinct(self):
+ from pyramid.interfaces import ITweens
+ from pyramid.tweens import excview_tween_factory
+
+ def factory1(handler, registry): # pragma: no cover
+ return handler
+
+ def factory2(handler, registry): # pragma: no cover
+ return handler
+
+ config = self._makeOne()
+ config.add_tween('tests.test_config.dummy_tween_factory')
+ config.add_tween('tests.test_config.dummy_tween_factory2')
+ config.commit()
+ tweens = config.registry.queryUtility(ITweens)
+ implicit = tweens.implicit()
+ self.assertEqual(
+ implicit,
+ [
+ (
+ 'tests.test_config.dummy_tween_factory2',
+ dummy_tween_factory2,
+ ),
+ ('tests.test_config.dummy_tween_factory', dummy_tween_factory),
+ (
+ 'pyramid.tweens.excview_tween_factory',
+ excview_tween_factory,
+ ),
+ ],
+ )
+
+ def test_add_tweens_names_with_underover(self):
+ from pyramid.interfaces import ITweens
+ from pyramid.tweens import excview_tween_factory
+ from pyramid.tweens import MAIN
+
+ config = self._makeOne()
+ config.add_tween('tests.test_config.dummy_tween_factory', over=MAIN)
+ config.add_tween(
+ 'tests.test_config.dummy_tween_factory2',
+ over=MAIN,
+ under='tests.test_config.dummy_tween_factory',
+ )
+ config.commit()
+ tweens = config.registry.queryUtility(ITweens)
+ implicit = tweens.implicit()
+ self.assertEqual(
+ implicit,
+ [
+ (
+ 'pyramid.tweens.excview_tween_factory',
+ excview_tween_factory,
+ ),
+ ('tests.test_config.dummy_tween_factory', dummy_tween_factory),
+ (
+ 'tests.test_config.dummy_tween_factory2',
+ dummy_tween_factory2,
+ ),
+ ],
+ )
+
+ def test_add_tweens_names_with_under_nonstringoriter(self):
+ from pyramid.exceptions import ConfigurationError
+
+ config = self._makeOne()
+ self.assertRaises(
+ ConfigurationError,
+ config.add_tween,
+ 'tests.test_config.dummy_tween_factory',
+ under=False,
+ )
+
+ def test_add_tweens_names_with_over_nonstringoriter(self):
+ from pyramid.exceptions import ConfigurationError
+
+ config = self._makeOne()
+ self.assertRaises(
+ ConfigurationError,
+ config.add_tween,
+ 'tests.test_config.dummy_tween_factory',
+ over=False,
+ )
+
+ def test_add_tween_dottedname(self):
+ from pyramid.interfaces import ITweens
+ from pyramid.tweens import excview_tween_factory
+
+ config = self._makeOne()
+ config.add_tween('tests.test_config.dummy_tween_factory')
+ config.commit()
+ tweens = config.registry.queryUtility(ITweens)
+ self.assertEqual(
+ tweens.implicit(),
+ [
+ ('tests.test_config.dummy_tween_factory', dummy_tween_factory),
+ (
+ 'pyramid.tweens.excview_tween_factory',
+ excview_tween_factory,
+ ),
+ ],
+ )
+
+ def test_add_tween_instance(self):
+ from pyramid.exceptions import ConfigurationError
+
+ class ATween(object):
+ pass
+
+ atween = ATween()
+ config = self._makeOne()
+ self.assertRaises(ConfigurationError, config.add_tween, atween)
+
+ def test_add_tween_unsuitable(self):
+ from pyramid.exceptions import ConfigurationError
+ import tests.test_config
+
+ config = self._makeOne()
+ self.assertRaises(
+ ConfigurationError, config.add_tween, tests.test_config
+ )
+
+ def test_add_tween_name_ingress(self):
+ from pyramid.exceptions import ConfigurationError
+ from pyramid.tweens import INGRESS
+
+ config = self._makeOne()
+ self.assertRaises(ConfigurationError, config.add_tween, INGRESS)
+
+ def test_add_tween_name_main(self):
+ from pyramid.exceptions import ConfigurationError
+ from pyramid.tweens import MAIN
+
+ config = self._makeOne()
+ self.assertRaises(ConfigurationError, config.add_tween, MAIN)
+
+ def test_add_tweens_conflict(self):
+ config = self._makeOne()
+ config.add_tween('tests.test_config.dummy_tween_factory')
+ config.add_tween('tests.test_config.dummy_tween_factory')
+ self.assertRaises(ConfigurationConflictError, config.commit)
+
+ def test_add_tween_over_ingress(self):
+ from pyramid.exceptions import ConfigurationError
+ from pyramid.tweens import INGRESS
+
+ config = self._makeOne()
+ self.assertRaises(
+ ConfigurationError,
+ config.add_tween,
+ 'tests.test_config.dummy_tween_factory',
+ over=INGRESS,
+ )
+
+ def test_add_tween_over_ingress_iterable(self):
+ from pyramid.exceptions import ConfigurationError
+ from pyramid.tweens import INGRESS
+
+ config = self._makeOne()
+ self.assertRaises(
+ ConfigurationError,
+ config.add_tween,
+ 'tests.test_config.dummy_tween_factory',
+ over=('a', INGRESS),
+ )
+
+ def test_add_tween_under_main(self):
+ from pyramid.exceptions import ConfigurationError
+ from pyramid.tweens import MAIN
+
+ config = self._makeOne()
+ self.assertRaises(
+ ConfigurationError,
+ config.add_tween,
+ 'tests.test_config.dummy_tween_factory',
+ under=MAIN,
+ )
+
+ def test_add_tween_under_main_iterable(self):
+ from pyramid.exceptions import ConfigurationError
+ from pyramid.tweens import MAIN
+
+ config = self._makeOne()
+ self.assertRaises(
+ ConfigurationError,
+ config.add_tween,
+ 'tests.test_config.dummy_tween_factory',
+ under=('a', MAIN),
+ )
+
+
+class TestTweens(unittest.TestCase):
+ def _makeOne(self):
+ from pyramid.config.tweens import Tweens
+
+ return Tweens()
+
+ def test_add_explicit(self):
+ tweens = self._makeOne()
+ tweens.add_explicit('name', 'factory')
+ self.assertEqual(tweens.explicit, [('name', 'factory')])
+ tweens.add_explicit('name2', 'factory2')
+ self.assertEqual(
+ tweens.explicit, [('name', 'factory'), ('name2', 'factory2')]
+ )
+
+ def test_add_implicit(self):
+ tweens = self._makeOne()
+ tweens.add_implicit('name', 'factory')
+ tweens.add_implicit('name2', 'factory2')
+ self.assertEqual(
+ tweens.sorter.sorted(),
+ [('name2', 'factory2'), ('name', 'factory')],
+ )
+
+ def test___call___explicit(self):
+ tweens = self._makeOne()
+
+ def factory1(handler, registry):
+ return handler
+
+ def factory2(handler, registry):
+ return '123'
+
+ tweens.explicit = [('name', factory1), ('name', factory2)]
+ self.assertEqual(tweens(None, None), '123')
+
+ def test___call___implicit(self):
+ tweens = self._makeOne()
+
+ def factory1(handler, registry):
+ return handler
+
+ def factory2(handler, registry):
+ return '123'
+
+ tweens.add_implicit('name2', factory2)
+ tweens.add_implicit('name1', factory1)
+ self.assertEqual(tweens(None, None), '123')
+
+ def test_implicit_ordering_1(self):
+ tweens = self._makeOne()
+ tweens.add_implicit('name1', 'factory1')
+ tweens.add_implicit('name2', 'factory2')
+ self.assertEqual(
+ tweens.implicit(), [('name2', 'factory2'), ('name1', 'factory1')]
+ )
+
+ def test_implicit_ordering_2(self):
+ from pyramid.tweens import MAIN
+
+ tweens = self._makeOne()
+ tweens.add_implicit('name1', 'factory1')
+ tweens.add_implicit('name2', 'factory2', over=MAIN)
+ self.assertEqual(
+ tweens.implicit(), [('name1', 'factory1'), ('name2', 'factory2')]
+ )
+
+ def test_implicit_ordering_3(self):
+ from pyramid.tweens import MAIN
+
+ tweens = self._makeOne()
+ add = tweens.add_implicit
+ add('auth', 'auth_factory', under='browserid')
+ add('dbt', 'dbt_factory')
+ add('retry', 'retry_factory', over='txnmgr', under='exceptionview')
+ add('browserid', 'browserid_factory')
+ add('txnmgr', 'txnmgr_factory', under='exceptionview')
+ add('exceptionview', 'excview_factory', over=MAIN)
+ self.assertEqual(
+ tweens.implicit(),
+ [
+ ('browserid', 'browserid_factory'),
+ ('auth', 'auth_factory'),
+ ('dbt', 'dbt_factory'),
+ ('exceptionview', 'excview_factory'),
+ ('retry', 'retry_factory'),
+ ('txnmgr', 'txnmgr_factory'),
+ ],
+ )
+
+ def test_implicit_ordering_4(self):
+ from pyramid.tweens import MAIN
+
+ tweens = self._makeOne()
+ add = tweens.add_implicit
+ add('exceptionview', 'excview_factory', over=MAIN)
+ add('auth', 'auth_factory', under='browserid')
+ add('retry', 'retry_factory', over='txnmgr', under='exceptionview')
+ add('browserid', 'browserid_factory')
+ add('txnmgr', 'txnmgr_factory', under='exceptionview')
+ add('dbt', 'dbt_factory')
+ self.assertEqual(
+ tweens.implicit(),
+ [
+ ('dbt', 'dbt_factory'),
+ ('browserid', 'browserid_factory'),
+ ('auth', 'auth_factory'),
+ ('exceptionview', 'excview_factory'),
+ ('retry', 'retry_factory'),
+ ('txnmgr', 'txnmgr_factory'),
+ ],
+ )
+
+ def test_implicit_ordering_5(self):
+ from pyramid.tweens import MAIN, INGRESS
+
+ tweens = self._makeOne()
+ add = tweens.add_implicit
+ add('exceptionview', 'excview_factory', over=MAIN)
+ add('auth', 'auth_factory', under=INGRESS)
+ add('retry', 'retry_factory', over='txnmgr', under='exceptionview')
+ add('browserid', 'browserid_factory', under=INGRESS)
+ add('txnmgr', 'txnmgr_factory', under='exceptionview', over=MAIN)
+ add('dbt', 'dbt_factory')
+ self.assertEqual(
+ tweens.implicit(),
+ [
+ ('dbt', 'dbt_factory'),
+ ('browserid', 'browserid_factory'),
+ ('auth', 'auth_factory'),
+ ('exceptionview', 'excview_factory'),
+ ('retry', 'retry_factory'),
+ ('txnmgr', 'txnmgr_factory'),
+ ],
+ )
+
+ def test_implicit_ordering_missing_over_partial(self):
+ from pyramid.exceptions import ConfigurationError
+
+ tweens = self._makeOne()
+ add = tweens.add_implicit
+ add('dbt', 'dbt_factory')
+ add('auth', 'auth_factory', under='browserid')
+ add('retry', 'retry_factory', over='txnmgr', under='exceptionview')
+ add('browserid', 'browserid_factory')
+ self.assertRaises(ConfigurationError, tweens.implicit)
+
+ def test_implicit_ordering_missing_under_partial(self):
+ from pyramid.exceptions import ConfigurationError
+
+ tweens = self._makeOne()
+ add = tweens.add_implicit
+ add('dbt', 'dbt_factory')
+ add('auth', 'auth_factory', under='txnmgr')
+ add('retry', 'retry_factory', over='dbt', under='exceptionview')
+ add('browserid', 'browserid_factory')
+ self.assertRaises(ConfigurationError, tweens.implicit)
+
+ def test_implicit_ordering_missing_over_and_under_partials(self):
+ from pyramid.exceptions import ConfigurationError
+
+ tweens = self._makeOne()
+ add = tweens.add_implicit
+ add('dbt', 'dbt_factory')
+ add('auth', 'auth_factory', under='browserid')
+ add('retry', 'retry_factory', over='foo', under='txnmgr')
+ add('browserid', 'browserid_factory')
+ self.assertRaises(ConfigurationError, tweens.implicit)
+
+ def test_implicit_ordering_missing_over_partial_with_fallback(self):
+ from pyramid.tweens import MAIN
+
+ tweens = self._makeOne()
+ add = tweens.add_implicit
+ add('exceptionview', 'excview_factory', over=MAIN)
+ add('auth', 'auth_factory', under='browserid')
+ add(
+ 'retry',
+ 'retry_factory',
+ over=('txnmgr', MAIN),
+ under='exceptionview',
+ )
+ add('browserid', 'browserid_factory')
+ add('dbt', 'dbt_factory')
+ self.assertEqual(
+ tweens.implicit(),
+ [
+ ('dbt', 'dbt_factory'),
+ ('browserid', 'browserid_factory'),
+ ('auth', 'auth_factory'),
+ ('exceptionview', 'excview_factory'),
+ ('retry', 'retry_factory'),
+ ],
+ )
+
+ def test_implicit_ordering_missing_under_partial_with_fallback(self):
+ from pyramid.tweens import MAIN
+
+ tweens = self._makeOne()
+ add = tweens.add_implicit
+ add('exceptionview', 'excview_factory', over=MAIN)
+ add('auth', 'auth_factory', under=('txnmgr', 'browserid'))
+ add('retry', 'retry_factory', under='exceptionview')
+ add('browserid', 'browserid_factory')
+ add('dbt', 'dbt_factory')
+ self.assertEqual(
+ tweens.implicit(),
+ [
+ ('dbt', 'dbt_factory'),
+ ('browserid', 'browserid_factory'),
+ ('auth', 'auth_factory'),
+ ('exceptionview', 'excview_factory'),
+ ('retry', 'retry_factory'),
+ ],
+ )
+
+ def test_implicit_ordering_with_partial_fallbacks(self):
+ from pyramid.tweens import MAIN
+
+ tweens = self._makeOne()
+ add = tweens.add_implicit
+ add('exceptionview', 'excview_factory', over=('wontbethere', MAIN))
+ add('retry', 'retry_factory', under='exceptionview')
+ add('browserid', 'browserid_factory', over=('wont2', 'exceptionview'))
+ self.assertEqual(
+ tweens.implicit(),
+ [
+ ('browserid', 'browserid_factory'),
+ ('exceptionview', 'excview_factory'),
+ ('retry', 'retry_factory'),
+ ],
+ )
+
+ def test_implicit_ordering_with_multiple_matching_fallbacks(self):
+ from pyramid.tweens import MAIN
+
+ tweens = self._makeOne()
+ add = tweens.add_implicit
+ add('exceptionview', 'excview_factory', over=MAIN)
+ add('retry', 'retry_factory', under='exceptionview')
+ add('browserid', 'browserid_factory', over=('retry', 'exceptionview'))
+ self.assertEqual(
+ tweens.implicit(),
+ [
+ ('browserid', 'browserid_factory'),
+ ('exceptionview', 'excview_factory'),
+ ('retry', 'retry_factory'),
+ ],
+ )
+
+ def test_implicit_ordering_with_missing_fallbacks(self):
+ from pyramid.exceptions import ConfigurationError
+ from pyramid.tweens import MAIN
+
+ tweens = self._makeOne()
+ add = tweens.add_implicit
+ add('exceptionview', 'excview_factory', over=MAIN)
+ add('retry', 'retry_factory', under='exceptionview')
+ add('browserid', 'browserid_factory', over=('txnmgr', 'auth'))
+ self.assertRaises(ConfigurationError, tweens.implicit)
+
+ def test_implicit_ordering_conflict_direct(self):
+ from pyramid.exceptions import CyclicDependencyError
+
+ tweens = self._makeOne()
+ add = tweens.add_implicit
+ add('browserid', 'browserid_factory')
+ add('auth', 'auth_factory', over='browserid', under='browserid')
+ self.assertRaises(CyclicDependencyError, tweens.implicit)
+
+ def test_implicit_ordering_conflict_indirect(self):
+ from pyramid.exceptions import CyclicDependencyError
+
+ tweens = self._makeOne()
+ add = tweens.add_implicit
+ add('browserid', 'browserid_factory')
+ add('auth', 'auth_factory', over='browserid')
+ add('dbt', 'dbt_factory', under='browserid', over='auth')
+ self.assertRaises(CyclicDependencyError, tweens.implicit)
diff --git a/tests/test_config/test_views.py b/tests/test_config/test_views.py
new file mode 100644
index 000000000..b72b9b36a
--- /dev/null
+++ b/tests/test_config/test_views.py
@@ -0,0 +1,4360 @@
+import os
+import unittest
+from zope.interface import implementer
+
+from pyramid import testing
+from pyramid.compat import im_func, text_
+from pyramid.exceptions import ConfigurationError
+from pyramid.exceptions import ConfigurationExecutionError
+from pyramid.exceptions import ConfigurationConflictError
+from pyramid.interfaces import IResponse, IRequest, IMultiView
+
+from . import IDummy
+from . import dummy_view
+
+
+class TestViewsConfigurationMixin(unittest.TestCase):
+ def _makeOne(self, *arg, **kw):
+ from pyramid.config import Configurator
+
+ config = Configurator(*arg, **kw)
+ config.set_default_csrf_options(require_csrf=False)
+ return config
+
+ def _getViewCallable(
+ self,
+ config,
+ ctx_iface=None,
+ exc_iface=None,
+ request_iface=None,
+ name='',
+ ):
+ from zope.interface import Interface
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IView
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IExceptionViewClassifier
+
+ if exc_iface:
+ classifier = IExceptionViewClassifier
+ ctx_iface = exc_iface
+ else:
+ classifier = IViewClassifier
+ if ctx_iface is None:
+ ctx_iface = Interface
+ if request_iface is None:
+ request_iface = IRequest
+ return config.registry.adapters.lookup(
+ (classifier, request_iface, ctx_iface),
+ IView,
+ name=name,
+ default=None,
+ )
+
+ def _registerRenderer(self, config, name='.txt'):
+ from pyramid.interfaces import IRendererFactory
+
+ class Renderer:
+ def __init__(self, info):
+ self.__class__.info = info
+
+ def __call__(self, *arg):
+ return b'Hello!'
+
+ config.registry.registerUtility(Renderer, IRendererFactory, name=name)
+ return Renderer
+
+ def _makeRequest(self, config):
+ request = DummyRequest()
+ request.registry = config.registry
+ return request
+
+ def _assertNotFound(self, wrapper, *arg):
+ from pyramid.httpexceptions import HTTPNotFound
+
+ self.assertRaises(HTTPNotFound, wrapper, *arg)
+
+ def _getRouteRequestIface(self, config, name):
+ from pyramid.interfaces import IRouteRequest
+
+ iface = config.registry.getUtility(IRouteRequest, name)
+ return iface
+
+ def _assertRoute(self, config, name, path, num_predicates=0):
+ from pyramid.interfaces import IRoutesMapper
+
+ mapper = config.registry.getUtility(IRoutesMapper)
+ routes = mapper.get_routes()
+ route = routes[0]
+ self.assertEqual(len(routes), 1)
+ self.assertEqual(route.name, name)
+ self.assertEqual(route.path, path)
+ self.assertEqual(len(routes[0].predicates), num_predicates)
+ return route
+
+ def test_add_view_view_callable_None_no_renderer(self):
+ config = self._makeOne(autocommit=True)
+ self.assertRaises(ConfigurationError, config.add_view)
+
+ def test_add_view_with_request_type_and_route_name(self):
+ config = self._makeOne(autocommit=True)
+ view = lambda *arg: 'OK'
+ self.assertRaises(
+ ConfigurationError,
+ config.add_view,
+ view,
+ '',
+ None,
+ None,
+ True,
+ True,
+ )
+
+ def test_add_view_with_request_type(self):
+ from pyramid.renderers import null_renderer
+ from zope.interface import directlyProvides
+ from pyramid.interfaces import IRequest
+
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(
+ view=view,
+ request_type='pyramid.interfaces.IRequest',
+ renderer=null_renderer,
+ )
+ wrapper = self._getViewCallable(config)
+ request = DummyRequest()
+ self._assertNotFound(wrapper, None, request)
+ directlyProvides(request, IRequest)
+ result = wrapper(None, request)
+ self.assertEqual(result, 'OK')
+
+ def test_add_view_view_callable_None_with_renderer(self):
+ config = self._makeOne(autocommit=True)
+ self._registerRenderer(config, name='dummy')
+ config.add_view(renderer='dummy')
+ view = self._getViewCallable(config)
+ self.assertTrue(b'Hello!' in view(None, None).body)
+
+ def test_add_view_with_tmpl_renderer_factory_introspector_missing(self):
+ config = self._makeOne(autocommit=True)
+ config.introspection = False
+ config.introspector = None
+ config.add_view(renderer='dummy.pt')
+ view = self._getViewCallable(config)
+ self.assertRaises(ValueError, view, None, None)
+
+ def test_add_view_with_tmpl_renderer_factory_no_renderer_factory(self):
+ config = self._makeOne(autocommit=True)
+ introspector = DummyIntrospector()
+ config.introspector = introspector
+ config.add_view(renderer='dummy.pt')
+ self.assertFalse(
+ ('renderer factories', '.pt') in introspector.related[-1]
+ )
+ view = self._getViewCallable(config)
+ self.assertRaises(ValueError, view, None, None)
+
+ def test_add_view_with_tmpl_renderer_factory_with_renderer_factory(self):
+ config = self._makeOne(autocommit=True)
+ introspector = DummyIntrospector(True)
+ config.introspector = introspector
+
+ def dummy_factory(helper):
+ return lambda val, system_vals: 'Hello!'
+
+ config.add_renderer('.pt', dummy_factory)
+ config.add_view(renderer='dummy.pt')
+ self.assertTrue(
+ ('renderer factories', '.pt') in introspector.related[-1]
+ )
+ view = self._getViewCallable(config)
+ self.assertTrue(b'Hello!' in view(None, None).body)
+
+ def test_add_view_wrapped_view_is_decorated(self):
+ def view(request): # request-only wrapper
+ """ """
+
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view)
+ wrapper = self._getViewCallable(config)
+ self.assertEqual(wrapper.__module__, view.__module__)
+ self.assertEqual(wrapper.__name__, view.__name__)
+ self.assertEqual(wrapper.__doc__, view.__doc__)
+ self.assertEqual(
+ wrapper.__discriminator__(None, None).resolve()[0], 'view'
+ )
+
+ def test_add_view_view_callable_dottedname(self):
+ from pyramid.renderers import null_renderer
+
+ config = self._makeOne(autocommit=True)
+ config.add_view(
+ view='tests.test_config.dummy_view', renderer=null_renderer
+ )
+ wrapper = self._getViewCallable(config)
+ self.assertEqual(wrapper(None, None), 'OK')
+
+ def test_add_view_with_function_callable(self):
+ from pyramid.renderers import null_renderer
+
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, renderer=null_renderer)
+ wrapper = self._getViewCallable(config)
+ result = wrapper(None, None)
+ self.assertEqual(result, 'OK')
+
+ def test_add_view_with_function_callable_requestonly(self):
+ from pyramid.renderers import null_renderer
+
+ def view(request):
+ return 'OK'
+
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, renderer=null_renderer)
+ wrapper = self._getViewCallable(config)
+ result = wrapper(None, None)
+ self.assertEqual(result, 'OK')
+
+ def test_add_view_with_name(self):
+ from pyramid.renderers import null_renderer
+
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, name='abc', renderer=null_renderer)
+ wrapper = self._getViewCallable(config, name='abc')
+ result = wrapper(None, None)
+ self.assertEqual(result, 'OK')
+
+ def test_add_view_with_name_unicode(self):
+ from pyramid.renderers import null_renderer
+
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ name = text_(b'La Pe\xc3\xb1a', 'utf-8')
+ config.add_view(view=view, name=name, renderer=null_renderer)
+ wrapper = self._getViewCallable(config, name=name)
+ result = wrapper(None, None)
+ self.assertEqual(result, 'OK')
+
+ def test_add_view_with_decorator(self):
+ from pyramid.renderers import null_renderer
+
+ def view(request):
+ """ ABC """
+ return 'OK'
+
+ def view_wrapper(fn):
+ def inner(context, request):
+ return fn(context, request)
+
+ return inner
+
+ config = self._makeOne(autocommit=True)
+ config.add_view(
+ view=view, decorator=view_wrapper, renderer=null_renderer
+ )
+ wrapper = self._getViewCallable(config)
+ self.assertFalse(wrapper is view)
+ self.assertEqual(wrapper.__doc__, view.__doc__)
+ result = wrapper(None, None)
+ self.assertEqual(result, 'OK')
+
+ def test_add_view_with_decorator_tuple(self):
+ from pyramid.renderers import null_renderer
+
+ def view(request):
+ """ ABC """
+ return 'OK'
+
+ def view_wrapper1(fn):
+ def inner(context, request):
+ return 'wrapped1' + fn(context, request)
+
+ return inner
+
+ def view_wrapper2(fn):
+ def inner(context, request):
+ return 'wrapped2' + fn(context, request)
+
+ return inner
+
+ config = self._makeOne(autocommit=True)
+ config.add_view(
+ view=view,
+ decorator=(view_wrapper2, view_wrapper1),
+ renderer=null_renderer,
+ )
+ wrapper = self._getViewCallable(config)
+ self.assertFalse(wrapper is view)
+ self.assertEqual(wrapper.__doc__, view.__doc__)
+ result = wrapper(None, None)
+ self.assertEqual(result, 'wrapped2wrapped1OK')
+
+ def test_add_view_with_http_cache(self):
+ import datetime
+ from pyramid.response import Response
+
+ response = Response('OK')
+
+ def view(request):
+ """ ABC """
+ return response
+
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, http_cache=(86400, {'public': True}))
+ wrapper = self._getViewCallable(config)
+ self.assertFalse(wrapper is view)
+ self.assertEqual(wrapper.__doc__, view.__doc__)
+ request = testing.DummyRequest()
+ when = datetime.datetime.utcnow() + datetime.timedelta(days=1)
+ result = wrapper(None, request)
+ self.assertEqual(result, response)
+ headers = dict(response.headerlist)
+ self.assertEqual(headers['Cache-Control'], 'max-age=86400, public')
+ expires = parse_httpdate(headers['Expires'])
+ assert_similar_datetime(expires, when)
+
+ def test_add_view_as_instance(self):
+ from pyramid.renderers import null_renderer
+
+ class AView:
+ def __call__(self, context, request):
+ """ """
+ return 'OK'
+
+ view = AView()
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, renderer=null_renderer)
+ wrapper = self._getViewCallable(config)
+ result = wrapper(None, None)
+ self.assertEqual(result, 'OK')
+
+ def test_add_view_as_instancemethod(self):
+ from pyramid.renderers import null_renderer
+
+ class View:
+ def index(self, context, request):
+ return 'OK'
+
+ view = View()
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view.index, renderer=null_renderer)
+ wrapper = self._getViewCallable(config)
+ result = wrapper(None, None)
+ self.assertEqual(result, 'OK')
+
+ def test_add_view_as_instancemethod_requestonly(self):
+ from pyramid.renderers import null_renderer
+
+ class View:
+ def index(self, request):
+ return 'OK'
+
+ view = View()
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view.index, renderer=null_renderer)
+ wrapper = self._getViewCallable(config)
+ result = wrapper(None, None)
+ self.assertEqual(result, 'OK')
+
+ def test_add_view_as_instance_requestonly(self):
+ from pyramid.renderers import null_renderer
+
+ class AView:
+ def __call__(self, request):
+ """ """
+ return 'OK'
+
+ view = AView()
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, renderer=null_renderer)
+ wrapper = self._getViewCallable(config)
+ result = wrapper(None, None)
+ self.assertEqual(result, 'OK')
+
+ def test_add_view_as_oldstyle_class(self):
+ from pyramid.renderers import null_renderer
+
+ class view:
+ def __init__(self, context, request):
+ self.context = context
+ self.request = request
+
+ def __call__(self):
+ return 'OK'
+
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, renderer=null_renderer)
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ result = wrapper(None, request)
+ self.assertEqual(result, 'OK')
+ self.assertEqual(request.__view__.__class__, view)
+
+ def test_add_view_as_oldstyle_class_requestonly(self):
+ from pyramid.renderers import null_renderer
+
+ class view:
+ def __init__(self, request):
+ self.request = request
+
+ def __call__(self):
+ return 'OK'
+
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, renderer=null_renderer)
+ wrapper = self._getViewCallable(config)
+
+ request = self._makeRequest(config)
+ result = wrapper(None, request)
+ self.assertEqual(result, 'OK')
+ self.assertEqual(request.__view__.__class__, view)
+
+ def test_add_view_context_as_class(self):
+ from pyramid.renderers import null_renderer
+ from zope.interface import implementedBy
+
+ view = lambda *arg: 'OK'
+
+ class Foo:
+ pass
+
+ config = self._makeOne(autocommit=True)
+ config.add_view(context=Foo, view=view, renderer=null_renderer)
+ foo = implementedBy(Foo)
+ wrapper = self._getViewCallable(config, foo)
+ self.assertEqual(wrapper, view)
+
+ def test_add_view_context_as_iface(self):
+ from pyramid.renderers import null_renderer
+
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(context=IDummy, view=view, renderer=null_renderer)
+ wrapper = self._getViewCallable(config, IDummy)
+ self.assertEqual(wrapper, view)
+
+ def test_add_view_context_as_dottedname(self):
+ from pyramid.renderers import null_renderer
+
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(
+ context='tests.test_config.IDummy',
+ view=view,
+ renderer=null_renderer,
+ )
+ wrapper = self._getViewCallable(config, IDummy)
+ self.assertEqual(wrapper, view)
+
+ def test_add_view_for__as_dottedname(self):
+ from pyramid.renderers import null_renderer
+
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(
+ for_='tests.test_config.IDummy', view=view, renderer=null_renderer
+ )
+ wrapper = self._getViewCallable(config, IDummy)
+ self.assertEqual(wrapper, view)
+
+ def test_add_view_for_as_class(self):
+ # ``for_`` is older spelling for ``context``
+ from pyramid.renderers import null_renderer
+ from zope.interface import implementedBy
+
+ view = lambda *arg: 'OK'
+
+ class Foo:
+ pass
+
+ config = self._makeOne(autocommit=True)
+ config.add_view(for_=Foo, view=view, renderer=null_renderer)
+ foo = implementedBy(Foo)
+ wrapper = self._getViewCallable(config, foo)
+ self.assertEqual(wrapper, view)
+
+ def test_add_view_for_as_iface(self):
+ # ``for_`` is older spelling for ``context``
+ from pyramid.renderers import null_renderer
+
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(for_=IDummy, view=view, renderer=null_renderer)
+ wrapper = self._getViewCallable(config, IDummy)
+ self.assertEqual(wrapper, view)
+
+ def test_add_view_context_trumps_for(self):
+ # ``for_`` is older spelling for ``context``
+ from pyramid.renderers import null_renderer
+
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+
+ class Foo:
+ pass
+
+ config.add_view(
+ context=IDummy, for_=Foo, view=view, renderer=null_renderer
+ )
+ wrapper = self._getViewCallable(config, IDummy)
+ self.assertEqual(wrapper, view)
+
+ def test_add_view_register_secured_view(self):
+ from pyramid.renderers import null_renderer
+ from zope.interface import Interface
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import ISecuredView
+ from pyramid.interfaces import IViewClassifier
+
+ view = lambda *arg: 'OK'
+ view.__call_permissive__ = view
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, renderer=null_renderer)
+ wrapper = config.registry.adapters.lookup(
+ (IViewClassifier, IRequest, Interface),
+ ISecuredView,
+ name='',
+ default=None,
+ )
+ self.assertEqual(wrapper, view)
+
+ def test_add_view_exception_register_secured_view(self):
+ from pyramid.renderers import null_renderer
+ from zope.interface import implementedBy
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IView
+ from pyramid.interfaces import IExceptionViewClassifier
+
+ view = lambda *arg: 'OK'
+ view.__call_permissive__ = view
+ config = self._makeOne(autocommit=True)
+ config.add_view(
+ view=view, context=RuntimeError, renderer=null_renderer
+ )
+ wrapper = config.registry.adapters.lookup(
+ (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),
+ IView,
+ name='',
+ default=None,
+ )
+ self.assertEqual(wrapper, view)
+
+ def test_add_view_same_phash_overrides_existing_single_view(self):
+ from pyramid.renderers import null_renderer
+ from hashlib import md5
+ from zope.interface import Interface
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IView
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IMultiView
+
+ phash = md5()
+ phash.update(b'xhr = True')
+ view = lambda *arg: 'NOT OK'
+ view.__phash__ = phash.hexdigest()
+ config = self._makeOne(autocommit=True)
+ config.registry.registerAdapter(
+ view, (IViewClassifier, IRequest, Interface), IView, name=''
+ )
+
+ def newview(context, request):
+ return 'OK'
+
+ config.add_view(view=newview, xhr=True, renderer=null_renderer)
+ wrapper = self._getViewCallable(config)
+ self.assertFalse(IMultiView.providedBy(wrapper))
+ request = DummyRequest()
+ request.is_xhr = True
+ self.assertEqual(wrapper(None, request), 'OK')
+
+ def test_add_view_exc_same_phash_overrides_existing_single_view(self):
+ from pyramid.renderers import null_renderer
+ from hashlib import md5
+ from zope.interface import implementedBy
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IView
+ from pyramid.interfaces import IExceptionViewClassifier
+ from pyramid.interfaces import IMultiView
+
+ phash = md5()
+ phash.update(b'xhr = True')
+ view = lambda *arg: 'NOT OK'
+ view.__phash__ = phash.hexdigest()
+ config = self._makeOne(autocommit=True)
+ config.registry.registerAdapter(
+ view,
+ (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),
+ IView,
+ name='',
+ )
+
+ def newview(context, request):
+ return 'OK'
+
+ config.add_view(
+ view=newview,
+ xhr=True,
+ context=RuntimeError,
+ renderer=null_renderer,
+ )
+ wrapper = self._getViewCallable(
+ config, exc_iface=implementedBy(RuntimeError)
+ )
+ self.assertFalse(IMultiView.providedBy(wrapper))
+ request = DummyRequest()
+ request.is_xhr = True
+ self.assertEqual(wrapper(None, request), 'OK')
+
+ def test_add_view_default_phash_overrides_no_phash(self):
+ from pyramid.renderers import null_renderer
+ from zope.interface import Interface
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IView
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IMultiView
+
+ view = lambda *arg: 'NOT OK'
+ config = self._makeOne(autocommit=True)
+ config.registry.registerAdapter(
+ view, (IViewClassifier, IRequest, Interface), IView, name=''
+ )
+
+ def newview(context, request):
+ return 'OK'
+
+ config.add_view(view=newview, renderer=null_renderer)
+ wrapper = self._getViewCallable(config)
+ self.assertFalse(IMultiView.providedBy(wrapper))
+ request = DummyRequest()
+ request.is_xhr = True
+ self.assertEqual(wrapper(None, request), 'OK')
+
+ def test_add_view_exc_default_phash_overrides_no_phash(self):
+ from pyramid.renderers import null_renderer
+ from zope.interface import implementedBy
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IView
+ from pyramid.interfaces import IExceptionViewClassifier
+ from pyramid.interfaces import IMultiView
+
+ view = lambda *arg: 'NOT OK'
+ config = self._makeOne(autocommit=True)
+ config.registry.registerAdapter(
+ view,
+ (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),
+ IView,
+ name='',
+ )
+
+ def newview(context, request):
+ return 'OK'
+
+ config.add_view(
+ view=newview, context=RuntimeError, renderer=null_renderer
+ )
+ wrapper = self._getViewCallable(
+ config, exc_iface=implementedBy(RuntimeError)
+ )
+ self.assertFalse(IMultiView.providedBy(wrapper))
+ request = DummyRequest()
+ request.is_xhr = True
+ self.assertEqual(wrapper(None, request), 'OK')
+
+ def test_add_view_default_phash_overrides_default_phash(self):
+ from pyramid.config.predicates import DEFAULT_PHASH
+ from pyramid.renderers import null_renderer
+ from zope.interface import Interface
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IView
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IMultiView
+
+ view = lambda *arg: 'NOT OK'
+ view.__phash__ = DEFAULT_PHASH
+ config = self._makeOne(autocommit=True)
+ config.registry.registerAdapter(
+ view, (IViewClassifier, IRequest, Interface), IView, name=''
+ )
+
+ def newview(context, request):
+ return 'OK'
+
+ config.add_view(view=newview, renderer=null_renderer)
+ wrapper = self._getViewCallable(config)
+ self.assertFalse(IMultiView.providedBy(wrapper))
+ request = DummyRequest()
+ request.is_xhr = True
+ self.assertEqual(wrapper(None, request), 'OK')
+
+ def test_add_view_exc_default_phash_overrides_default_phash(self):
+ from pyramid.config.predicates import DEFAULT_PHASH
+ from pyramid.renderers import null_renderer
+ from zope.interface import implementedBy
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IView
+ from pyramid.interfaces import IExceptionViewClassifier
+ from pyramid.interfaces import IMultiView
+
+ view = lambda *arg: 'NOT OK'
+ view.__phash__ = DEFAULT_PHASH
+ config = self._makeOne(autocommit=True)
+ config.registry.registerAdapter(
+ view,
+ (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),
+ IView,
+ name='',
+ )
+
+ def newview(context, request):
+ return 'OK'
+
+ config.add_view(
+ view=newview, context=RuntimeError, renderer=null_renderer
+ )
+ wrapper = self._getViewCallable(
+ config, exc_iface=implementedBy(RuntimeError)
+ )
+ self.assertFalse(IMultiView.providedBy(wrapper))
+ request = DummyRequest()
+ request.is_xhr = True
+ self.assertEqual(wrapper(None, request), 'OK')
+
+ def test_add_view_multiview_replaces_existing_view(self):
+ from pyramid.renderers import null_renderer
+ from zope.interface import Interface
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IView
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IMultiView
+
+ view = lambda *arg: 'OK'
+ view.__phash__ = 'abc'
+ config = self._makeOne(autocommit=True)
+ config.registry.registerAdapter(
+ view, (IViewClassifier, IRequest, Interface), IView, name=''
+ )
+ config.add_view(view=view, renderer=null_renderer)
+ wrapper = self._getViewCallable(config)
+ self.assertTrue(IMultiView.providedBy(wrapper))
+ self.assertEqual(wrapper(None, None), 'OK')
+
+ def test_add_view_exc_multiview_replaces_existing_view(self):
+ from pyramid.renderers import null_renderer
+ from zope.interface import implementedBy
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IView
+ from pyramid.interfaces import IExceptionViewClassifier
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IMultiView
+
+ view = lambda *arg: 'OK'
+ view.__phash__ = 'abc'
+ config = self._makeOne(autocommit=True)
+ config.registry.registerAdapter(
+ view,
+ (IViewClassifier, IRequest, implementedBy(RuntimeError)),
+ IView,
+ name='',
+ )
+ config.registry.registerAdapter(
+ view,
+ (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),
+ IView,
+ name='',
+ )
+ config.add_view(
+ view=view, context=RuntimeError, renderer=null_renderer
+ )
+ wrapper = self._getViewCallable(
+ config, exc_iface=implementedBy(RuntimeError)
+ )
+ self.assertTrue(IMultiView.providedBy(wrapper))
+ self.assertEqual(wrapper(None, None), 'OK')
+
+ def test_add_view_multiview_replaces_existing_securedview(self):
+ from pyramid.renderers import null_renderer
+ from zope.interface import Interface
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import ISecuredView
+ from pyramid.interfaces import IMultiView
+ from pyramid.interfaces import IViewClassifier
+
+ view = lambda *arg: 'OK'
+ view.__phash__ = 'abc'
+ config = self._makeOne(autocommit=True)
+ config.registry.registerAdapter(
+ view, (IViewClassifier, IRequest, Interface), ISecuredView, name=''
+ )
+ config.add_view(view=view, renderer=null_renderer)
+ wrapper = self._getViewCallable(config)
+ self.assertTrue(IMultiView.providedBy(wrapper))
+ self.assertEqual(wrapper(None, None), 'OK')
+
+ def test_add_view_exc_multiview_replaces_existing_securedview(self):
+ from pyramid.renderers import null_renderer
+ from zope.interface import implementedBy
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import ISecuredView
+ from pyramid.interfaces import IMultiView
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IExceptionViewClassifier
+
+ view = lambda *arg: 'OK'
+ view.__phash__ = 'abc'
+ config = self._makeOne(autocommit=True)
+ config.registry.registerAdapter(
+ view,
+ (IViewClassifier, IRequest, implementedBy(RuntimeError)),
+ ISecuredView,
+ name='',
+ )
+ config.registry.registerAdapter(
+ view,
+ (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),
+ ISecuredView,
+ name='',
+ )
+ config.add_view(
+ view=view, context=RuntimeError, renderer=null_renderer
+ )
+ wrapper = self._getViewCallable(
+ config, exc_iface=implementedBy(RuntimeError)
+ )
+ self.assertTrue(IMultiView.providedBy(wrapper))
+ self.assertEqual(wrapper(None, None), 'OK')
+
+ def test_add_view_with_accept_multiview_replaces_existing_view(self):
+ from pyramid.renderers import null_renderer
+ from zope.interface import Interface
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IView
+ from pyramid.interfaces import IMultiView
+ from pyramid.interfaces import IViewClassifier
+
+ def view(context, request):
+ return 'OK'
+
+ def view2(context, request):
+ return 'OK2'
+
+ config = self._makeOne(autocommit=True)
+ config.registry.registerAdapter(
+ view, (IViewClassifier, IRequest, Interface), IView, name=''
+ )
+ config.add_view(view=view2, accept='text/html', renderer=null_renderer)
+ wrapper = self._getViewCallable(config)
+ self.assertTrue(IMultiView.providedBy(wrapper))
+ self.assertEqual(len(wrapper.views), 1)
+ self.assertEqual(len(wrapper.media_views), 1)
+ self.assertEqual(wrapper(None, None), 'OK')
+ request = DummyRequest()
+ request.accept = DummyAccept('text/html', 'text/html')
+ self.assertEqual(wrapper(None, request), 'OK2')
+
+ def test_add_view_mixed_case_replaces_existing_view(self):
+ from pyramid.renderers import null_renderer
+
+ def view(context, request):
+ return 'OK'
+
+ def view2(context, request): # pragma: no cover
+ return 'OK2'
+
+ def view3(context, request):
+ return 'OK3'
+
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, renderer=null_renderer)
+ config.add_view(view=view2, accept='text/html', renderer=null_renderer)
+ config.add_view(view=view3, accept='text/HTML', renderer=null_renderer)
+ wrapper = self._getViewCallable(config)
+ self.assertTrue(IMultiView.providedBy(wrapper))
+ self.assertEqual(len(wrapper.media_views.items()), 1)
+ self.assertFalse('text/HTML' in wrapper.media_views)
+ self.assertEqual(wrapper(None, None), 'OK')
+ request = DummyRequest()
+ request.accept = DummyAccept('text/html', 'text/html')
+ self.assertEqual(wrapper(None, request), 'OK3')
+
+ def test_add_views_with_accept_multiview_replaces_existing(self):
+ from pyramid.renderers import null_renderer
+
+ def view(context, request):
+ return 'OK'
+
+ def view2(context, request): # pragma: no cover
+ return 'OK2'
+
+ def view3(context, request):
+ return 'OK3'
+
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, renderer=null_renderer)
+ config.add_view(view=view2, accept='text/html', renderer=null_renderer)
+ config.add_view(view=view3, accept='text/html', renderer=null_renderer)
+ wrapper = self._getViewCallable(config)
+ self.assertEqual(len(wrapper.media_views['text/html']), 1)
+ self.assertEqual(wrapper(None, None), 'OK')
+ request = DummyRequest()
+ request.accept = DummyAccept('text/html', 'text/html')
+ self.assertEqual(wrapper(None, request), 'OK3')
+
+ def test_add_view_exc_with_accept_multiview_replaces_existing_view(self):
+ from pyramid.renderers import null_renderer
+ from zope.interface import implementedBy
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IView
+ from pyramid.interfaces import IMultiView
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IExceptionViewClassifier
+
+ def view(context, request):
+ return 'OK'
+
+ def view2(context, request):
+ return 'OK2'
+
+ config = self._makeOne(autocommit=True)
+ config.registry.registerAdapter(
+ view,
+ (IViewClassifier, IRequest, implementedBy(RuntimeError)),
+ IView,
+ name='',
+ )
+ config.registry.registerAdapter(
+ view,
+ (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),
+ IView,
+ name='',
+ )
+ config.add_view(
+ view=view2,
+ accept='text/html',
+ context=RuntimeError,
+ renderer=null_renderer,
+ )
+ wrapper = self._getViewCallable(
+ config, exc_iface=implementedBy(RuntimeError)
+ )
+ self.assertTrue(IMultiView.providedBy(wrapper))
+ self.assertEqual(len(wrapper.views), 1)
+ self.assertEqual(len(wrapper.media_views), 1)
+ self.assertEqual(wrapper(None, None), 'OK')
+ request = DummyRequest()
+ request.accept = DummyAccept('text/html', 'text/html')
+ self.assertEqual(wrapper(None, request), 'OK2')
+
+ def test_add_view_multiview_replaces_existing_view_with___accept__(self):
+ from pyramid.renderers import null_renderer
+ from zope.interface import Interface
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IView
+ from pyramid.interfaces import IMultiView
+ from pyramid.interfaces import IViewClassifier
+
+ def view(context, request):
+ return 'OK'
+
+ def view2(context, request):
+ return 'OK2'
+
+ view.__accept__ = 'text/html'
+ view.__phash__ = 'abc'
+ config = self._makeOne(autocommit=True)
+ config.registry.registerAdapter(
+ view, (IViewClassifier, IRequest, Interface), IView, name=''
+ )
+ config.add_view(view=view2, renderer=null_renderer)
+ wrapper = self._getViewCallable(config)
+ self.assertTrue(IMultiView.providedBy(wrapper))
+ self.assertEqual(len(wrapper.views), 1)
+ self.assertEqual(len(wrapper.media_views), 1)
+ self.assertEqual(wrapper(None, None), 'OK2')
+ request = DummyRequest()
+ request.accept = DummyAccept('text/html')
+ self.assertEqual(wrapper(None, request), 'OK')
+
+ def test_add_view_exc_mulview_replaces_existing_view_with___accept__(self):
+ from pyramid.renderers import null_renderer
+ from zope.interface import implementedBy
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IView
+ from pyramid.interfaces import IMultiView
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IExceptionViewClassifier
+
+ def view(context, request):
+ return 'OK'
+
+ def view2(context, request):
+ return 'OK2'
+
+ view.__accept__ = 'text/html'
+ view.__phash__ = 'abc'
+ config = self._makeOne(autocommit=True)
+ config.registry.registerAdapter(
+ view,
+ (IViewClassifier, IRequest, implementedBy(RuntimeError)),
+ IView,
+ name='',
+ )
+ config.registry.registerAdapter(
+ view,
+ (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),
+ IView,
+ name='',
+ )
+ config.add_view(
+ view=view2, context=RuntimeError, renderer=null_renderer
+ )
+ wrapper = self._getViewCallable(
+ config, exc_iface=implementedBy(RuntimeError)
+ )
+ self.assertTrue(IMultiView.providedBy(wrapper))
+ self.assertEqual(len(wrapper.views), 1)
+ self.assertEqual(len(wrapper.media_views), 1)
+ self.assertEqual(wrapper(None, None), 'OK2')
+ request = DummyRequest()
+ request.accept = DummyAccept('text/html')
+ self.assertEqual(wrapper(None, request), 'OK')
+
+ def test_add_view_multiview_replaces_multiview(self):
+ from pyramid.renderers import null_renderer
+ from zope.interface import Interface
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IMultiView
+ from pyramid.interfaces import IViewClassifier
+
+ view = DummyMultiView()
+ config = self._makeOne(autocommit=True)
+ config.registry.registerAdapter(
+ view, (IViewClassifier, IRequest, Interface), IMultiView, name=''
+ )
+ view2 = lambda *arg: 'OK2'
+ config.add_view(view=view2, renderer=null_renderer)
+ wrapper = self._getViewCallable(config)
+ self.assertTrue(IMultiView.providedBy(wrapper))
+ self.assertEqual(
+ [(x[0], x[2]) for x in wrapper.views], [(view2, None)]
+ )
+ self.assertEqual(wrapper(None, None), 'OK1')
+
+ def test_add_view_exc_multiview_replaces_multiviews(self):
+ from pyramid.renderers import null_renderer
+ from zope.interface import implementedBy
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IMultiView
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IExceptionViewClassifier
+
+ hot_view = DummyMultiView()
+ exc_view = DummyMultiView()
+ config = self._makeOne(autocommit=True)
+ config.registry.registerAdapter(
+ hot_view,
+ (IViewClassifier, IRequest, implementedBy(RuntimeError)),
+ IMultiView,
+ name='',
+ )
+ config.registry.registerAdapter(
+ exc_view,
+ (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),
+ IMultiView,
+ name='',
+ )
+ view2 = lambda *arg: 'OK2'
+ config.add_view(
+ view=view2, context=RuntimeError, renderer=null_renderer
+ )
+ hot_wrapper = self._getViewCallable(
+ config, ctx_iface=implementedBy(RuntimeError)
+ )
+ self.assertTrue(IMultiView.providedBy(hot_wrapper))
+ self.assertEqual(
+ [(x[0], x[2]) for x in hot_wrapper.views], [(view2, None)]
+ )
+ self.assertEqual(hot_wrapper(None, None), 'OK1')
+
+ exc_wrapper = self._getViewCallable(
+ config, exc_iface=implementedBy(RuntimeError)
+ )
+ self.assertTrue(IMultiView.providedBy(exc_wrapper))
+ self.assertEqual(
+ [(x[0], x[2]) for x in exc_wrapper.views], [(view2, None)]
+ )
+ self.assertEqual(exc_wrapper(None, None), 'OK1')
+
+ def test_add_view_exc_multiview_replaces_only_exc_multiview(self):
+ from pyramid.renderers import null_renderer
+ from zope.interface import implementedBy
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IMultiView
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IExceptionViewClassifier
+
+ hot_view = DummyMultiView()
+ exc_view = DummyMultiView()
+ config = self._makeOne(autocommit=True)
+ config.registry.registerAdapter(
+ hot_view,
+ (IViewClassifier, IRequest, implementedBy(RuntimeError)),
+ IMultiView,
+ name='',
+ )
+ config.registry.registerAdapter(
+ exc_view,
+ (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),
+ IMultiView,
+ name='',
+ )
+ view2 = lambda *arg: 'OK2'
+ config.add_view(
+ view=view2,
+ context=RuntimeError,
+ exception_only=True,
+ renderer=null_renderer,
+ )
+ hot_wrapper = self._getViewCallable(
+ config, ctx_iface=implementedBy(RuntimeError)
+ )
+ self.assertTrue(IMultiView.providedBy(hot_wrapper))
+ self.assertEqual(len(hot_wrapper.views), 0)
+ self.assertEqual(hot_wrapper(None, None), 'OK1')
+
+ exc_wrapper = self._getViewCallable(
+ config, exc_iface=implementedBy(RuntimeError)
+ )
+ self.assertTrue(IMultiView.providedBy(exc_wrapper))
+ self.assertEqual(
+ [(x[0], x[2]) for x in exc_wrapper.views], [(view2, None)]
+ )
+ self.assertEqual(exc_wrapper(None, None), 'OK1')
+
+ def test_add_view_multiview_context_superclass_then_subclass(self):
+ from pyramid.renderers import null_renderer
+ from zope.interface import Interface
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IView
+ from pyramid.interfaces import IMultiView
+ from pyramid.interfaces import IViewClassifier
+
+ class ISuper(Interface):
+ pass
+
+ class ISub(ISuper):
+ pass
+
+ view = lambda *arg: 'OK'
+ view2 = lambda *arg: 'OK2'
+ config = self._makeOne(autocommit=True)
+ config.registry.registerAdapter(
+ view, (IViewClassifier, IRequest, ISuper), IView, name=''
+ )
+ config.add_view(view=view2, for_=ISub, renderer=null_renderer)
+ wrapper = self._getViewCallable(
+ config, ctx_iface=ISuper, request_iface=IRequest
+ )
+ self.assertFalse(IMultiView.providedBy(wrapper))
+ self.assertEqual(wrapper(None, None), 'OK')
+ wrapper = self._getViewCallable(
+ config, ctx_iface=ISub, request_iface=IRequest
+ )
+ self.assertFalse(IMultiView.providedBy(wrapper))
+ self.assertEqual(wrapper(None, None), 'OK2')
+
+ def test_add_view_multiview_exception_superclass_then_subclass(self):
+ from pyramid.renderers import null_renderer
+ from zope.interface import implementedBy
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IView
+ from pyramid.interfaces import IMultiView
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IExceptionViewClassifier
+
+ class Super(Exception):
+ pass
+
+ class Sub(Super):
+ pass
+
+ view = lambda *arg: 'OK'
+ view2 = lambda *arg: 'OK2'
+ config = self._makeOne(autocommit=True)
+ config.registry.registerAdapter(
+ view, (IViewClassifier, IRequest, Super), IView, name=''
+ )
+ config.registry.registerAdapter(
+ view, (IExceptionViewClassifier, IRequest, Super), IView, name=''
+ )
+ config.add_view(view=view2, for_=Sub, renderer=null_renderer)
+ wrapper = self._getViewCallable(
+ config, ctx_iface=implementedBy(Super), request_iface=IRequest
+ )
+ wrapper_exc_view = self._getViewCallable(
+ config, exc_iface=implementedBy(Super), request_iface=IRequest
+ )
+ self.assertEqual(wrapper_exc_view, wrapper)
+ self.assertFalse(IMultiView.providedBy(wrapper_exc_view))
+ self.assertEqual(wrapper_exc_view(None, None), 'OK')
+ wrapper = self._getViewCallable(
+ config, ctx_iface=implementedBy(Sub), request_iface=IRequest
+ )
+ wrapper_exc_view = self._getViewCallable(
+ config, exc_iface=implementedBy(Sub), request_iface=IRequest
+ )
+ self.assertEqual(wrapper_exc_view, wrapper)
+ self.assertFalse(IMultiView.providedBy(wrapper_exc_view))
+ self.assertEqual(wrapper_exc_view(None, None), 'OK2')
+
+ def test_add_view_multiview_call_ordering(self):
+ from pyramid.renderers import null_renderer as nr
+ from zope.interface import directlyProvides
+
+ def view1(context, request):
+ return 'view1'
+
+ def view2(context, request):
+ return 'view2'
+
+ def view3(context, request):
+ return 'view3'
+
+ def view4(context, request):
+ return 'view4'
+
+ def view5(context, request):
+ return 'view5'
+
+ def view6(context, request):
+ return 'view6'
+
+ def view7(context, request):
+ return 'view7'
+
+ def view8(context, request):
+ return 'view8'
+
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view1, renderer=nr)
+ config.add_view(view=view2, request_method='POST', renderer=nr)
+ config.add_view(view=view3, request_param='param', renderer=nr)
+ config.add_view(view=view4, containment=IDummy, renderer=nr)
+ config.add_view(
+ view=view5,
+ request_method='POST',
+ request_param='param',
+ renderer=nr,
+ )
+ config.add_view(
+ view=view6, request_method='POST', containment=IDummy, renderer=nr
+ )
+ config.add_view(
+ view=view7, request_param='param', containment=IDummy, renderer=nr
+ )
+ config.add_view(
+ view=view8,
+ request_method='POST',
+ request_param='param',
+ containment=IDummy,
+ renderer=nr,
+ )
+
+ wrapper = self._getViewCallable(config)
+
+ ctx = DummyContext()
+ request = self._makeRequest(config)
+ request.method = 'GET'
+ request.params = {}
+ self.assertEqual(wrapper(ctx, request), 'view1')
+
+ ctx = DummyContext()
+ request = self._makeRequest(config)
+ request.params = {}
+ request.method = 'POST'
+ self.assertEqual(wrapper(ctx, request), 'view2')
+
+ ctx = DummyContext()
+ request = self._makeRequest(config)
+ request.params = {'param': '1'}
+ request.method = 'GET'
+ self.assertEqual(wrapper(ctx, request), 'view3')
+
+ ctx = DummyContext()
+ directlyProvides(ctx, IDummy)
+ request = self._makeRequest(config)
+ request.method = 'GET'
+ request.params = {}
+ self.assertEqual(wrapper(ctx, request), 'view4')
+
+ ctx = DummyContext()
+ request = self._makeRequest(config)
+ request.method = 'POST'
+ request.params = {'param': '1'}
+ self.assertEqual(wrapper(ctx, request), 'view5')
+
+ ctx = DummyContext()
+ directlyProvides(ctx, IDummy)
+ request = self._makeRequest(config)
+ request.params = {}
+ request.method = 'POST'
+ self.assertEqual(wrapper(ctx, request), 'view6')
+
+ ctx = DummyContext()
+ directlyProvides(ctx, IDummy)
+ request = self._makeRequest(config)
+ request.method = 'GET'
+ request.params = {'param': '1'}
+ self.assertEqual(wrapper(ctx, request), 'view7')
+
+ ctx = DummyContext()
+ directlyProvides(ctx, IDummy)
+ request = self._makeRequest(config)
+ request.method = 'POST'
+ request.params = {'param': '1'}
+ self.assertEqual(wrapper(ctx, request), 'view8')
+
+ def test_view_with_most_specific_predicate(self):
+ from pyramid.renderers import null_renderer as nr
+ from pyramid.router import Router
+
+ class OtherBase(object):
+ pass
+
+ class Int1(object):
+ pass
+
+ class Int2(object):
+ pass
+
+ class Resource(OtherBase, Int1, Int2):
+ def __init__(self, request):
+ pass
+
+ def unknown(context, request): # pragma: no cover
+ return 'unknown'
+
+ def view(context, request):
+ return 'hello'
+
+ config = self._makeOne(autocommit=True)
+ config.add_route('root', '/', factory=Resource)
+ config.add_view(unknown, route_name='root', renderer=nr)
+ config.add_view(
+ view,
+ renderer=nr,
+ route_name='root',
+ context=Int1,
+ request_method='GET',
+ )
+ config.add_view(
+ view=view,
+ renderer=nr,
+ route_name='root',
+ context=Int2,
+ request_method='POST',
+ )
+ request = self._makeRequest(config)
+ request.method = 'POST'
+ request.params = {}
+ router = Router(config.registry)
+ response = router.handle_request(request)
+ self.assertEqual(response, 'hello')
+
+ def test_view_with_most_specific_predicate_with_mismatch(self):
+ from pyramid.renderers import null_renderer as nr
+ from pyramid.router import Router
+
+ class OtherBase(object):
+ pass
+
+ class Int1(object):
+ pass
+
+ class Int2(object):
+ pass
+
+ class Resource(OtherBase, Int1, Int2):
+ def __init__(self, request):
+ pass
+
+ def unknown(context, request): # pragma: no cover
+ return 'unknown'
+
+ def view(context, request):
+ return 'hello'
+
+ config = self._makeOne(autocommit=True)
+ config.add_route('root', '/', factory=Resource)
+
+ config.add_view(
+ unknown,
+ route_name='root',
+ renderer=nr,
+ request_method=('POST',),
+ xhr=True,
+ )
+
+ config.add_view(
+ view,
+ renderer=nr,
+ route_name='root',
+ context=Int1,
+ request_method='GET',
+ )
+ config.add_view(
+ view=view,
+ renderer=nr,
+ route_name='root',
+ context=Int2,
+ request_method='POST',
+ )
+ request = self._makeRequest(config)
+ request.method = 'POST'
+ request.params = {}
+ router = Router(config.registry)
+ response = router.handle_request(request)
+ self.assertEqual(response, 'hello')
+
+ def test_add_view_multiview___discriminator__(self):
+ from pyramid.renderers import null_renderer
+ from zope.interface import Interface
+
+ class IFoo(Interface):
+ pass
+
+ class IBar(Interface):
+ pass
+
+ @implementer(IFoo)
+ class Foo(object):
+ pass
+
+ @implementer(IBar)
+ class Bar(object):
+ pass
+
+ foo = Foo()
+ bar = Bar()
+
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IView
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IMultiView
+
+ view = lambda *arg: 'OK'
+ view.__phash__ = 'abc'
+ config = self._makeOne(autocommit=True)
+ config.registry.registerAdapter(
+ view, (IViewClassifier, IRequest, Interface), IView, name=''
+ )
+ config.add_view(view=view, renderer=null_renderer, containment=IFoo)
+ config.add_view(view=view, renderer=null_renderer, containment=IBar)
+ wrapper = self._getViewCallable(config)
+ self.assertTrue(IMultiView.providedBy(wrapper))
+ request = self._makeRequest(config)
+ self.assertNotEqual(
+ wrapper.__discriminator__(foo, request),
+ wrapper.__discriminator__(bar, request),
+ )
+
+ def test_add_view_with_template_renderer(self):
+ from tests import test_config
+ from pyramid.interfaces import ISettings
+
+ class view(object):
+ def __init__(self, context, request):
+ self.request = request
+ self.context = context
+
+ def __call__(self):
+ return {'a': '1'}
+
+ config = self._makeOne(autocommit=True)
+ renderer = self._registerRenderer(config)
+ fixture = 'tests.test_config:files/minimal.txt'
+ config.introspection = False
+ config.add_view(view=view, renderer=fixture)
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ result = wrapper(None, request)
+ self.assertEqual(result.body, b'Hello!')
+ settings = config.registry.queryUtility(ISettings)
+ result = renderer.info
+ self.assertEqual(result.registry, config.registry)
+ self.assertEqual(result.type, '.txt')
+ self.assertEqual(result.package, test_config)
+ self.assertEqual(result.name, fixture)
+ self.assertEqual(result.settings, settings)
+
+ def test_add_view_with_default_renderer(self):
+ class view(object):
+ def __init__(self, context, request):
+ self.request = request
+ self.context = context
+
+ def __call__(self):
+ return {'a': '1'}
+
+ config = self._makeOne(autocommit=True)
+
+ class moo(object):
+ def __init__(self, *arg, **kw):
+ pass
+
+ def __call__(self, *arg, **kw):
+ return b'moo'
+
+ config.add_renderer(None, moo)
+ config.add_view(view=view)
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ result = wrapper(None, request)
+ self.assertEqual(result.body, b'moo')
+
+ def test_add_view_with_template_renderer_no_callable(self):
+ from tests import test_config
+ from pyramid.interfaces import ISettings
+
+ config = self._makeOne(autocommit=True)
+ renderer = self._registerRenderer(config)
+ fixture = 'tests.test_config:files/minimal.txt'
+ config.introspection = False
+ config.add_view(view=None, renderer=fixture)
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ result = wrapper(None, request)
+ self.assertEqual(result.body, b'Hello!')
+ settings = config.registry.queryUtility(ISettings)
+ result = renderer.info
+ self.assertEqual(result.registry, config.registry)
+ self.assertEqual(result.type, '.txt')
+ self.assertEqual(result.package, test_config)
+ self.assertEqual(result.name, fixture)
+ self.assertEqual(result.settings, settings)
+
+ def test_add_view_with_request_type_as_iface(self):
+ from pyramid.renderers import null_renderer
+ from zope.interface import directlyProvides
+
+ def view(context, request):
+ return 'OK'
+
+ config = self._makeOne(autocommit=True)
+ config.add_view(request_type=IDummy, view=view, renderer=null_renderer)
+ wrapper = self._getViewCallable(config, None)
+ request = self._makeRequest(config)
+ directlyProvides(request, IDummy)
+ result = wrapper(None, request)
+ self.assertEqual(result, 'OK')
+
+ def test_add_view_with_request_type_as_noniface(self):
+ view = lambda *arg: 'OK'
+ config = self._makeOne()
+ self.assertRaises(
+ ConfigurationError, config.add_view, view, '', None, None, object
+ )
+
+ def test_add_view_with_route_name(self):
+ from pyramid.renderers import null_renderer
+
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_route('foo', '/a/b')
+ config.add_view(view=view, route_name='foo', renderer=null_renderer)
+ request_iface = self._getRouteRequestIface(config, 'foo')
+ self.assertNotEqual(request_iface, None)
+ wrapper = self._getViewCallable(config, request_iface=request_iface)
+ self.assertNotEqual(wrapper, None)
+ self.assertEqual(wrapper(None, None), 'OK')
+
+ def test_add_view_with_nonexistant_route_name(self):
+ from pyramid.renderers import null_renderer
+
+ view = lambda *arg: 'OK'
+ config = self._makeOne()
+ config.add_view(view=view, route_name='foo', renderer=null_renderer)
+ self.assertRaises(ConfigurationExecutionError, config.commit)
+
+ def test_add_view_with_route_name_exception(self):
+ from pyramid.renderers import null_renderer
+ from zope.interface import implementedBy
+
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_route('foo', '/a/b')
+ config.add_view(
+ view=view,
+ route_name='foo',
+ context=RuntimeError,
+ renderer=null_renderer,
+ )
+ request_iface = self._getRouteRequestIface(config, 'foo')
+ wrapper_exc_view = self._getViewCallable(
+ config,
+ exc_iface=implementedBy(RuntimeError),
+ request_iface=request_iface,
+ )
+ self.assertNotEqual(wrapper_exc_view, None)
+ wrapper = self._getViewCallable(
+ config,
+ ctx_iface=implementedBy(RuntimeError),
+ request_iface=request_iface,
+ )
+ self.assertEqual(wrapper_exc_view, wrapper)
+ self.assertEqual(wrapper_exc_view(None, None), 'OK')
+
+ def test_add_view_with_request_method_true(self):
+ from pyramid.renderers import null_renderer
+
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(
+ view=view, request_method='POST', renderer=null_renderer
+ )
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ request.method = 'POST'
+ self.assertEqual(wrapper(None, request), 'OK')
+
+ def test_add_view_with_request_method_false(self):
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, request_method='POST')
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ request.method = 'GET'
+ self._assertNotFound(wrapper, None, request)
+
+ def test_add_view_with_request_method_sequence_true(self):
+ from pyramid.renderers import null_renderer
+
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(
+ view=view, request_method=('POST', 'GET'), renderer=null_renderer
+ )
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ request.method = 'POST'
+ self.assertEqual(wrapper(None, request), 'OK')
+
+ def test_add_view_with_request_method_sequence_conflict(self):
+ from pyramid.renderers import null_renderer
+
+ view = lambda *arg: 'OK'
+ config = self._makeOne()
+ config.add_view(
+ view=view, request_method=('POST', 'GET'), renderer=null_renderer
+ )
+ config.add_view(
+ view=view, request_method=('GET', 'POST'), renderer=null_renderer
+ )
+ self.assertRaises(ConfigurationConflictError, config.commit)
+
+ def test_add_view_with_request_method_sequence_false(self):
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, request_method=('POST', 'HEAD'))
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ request.method = 'GET'
+ self._assertNotFound(wrapper, None, request)
+
+ def test_add_view_with_request_method_get_implies_head(self):
+ from pyramid.renderers import null_renderer
+
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(
+ view=view, request_method='GET', renderer=null_renderer
+ )
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ request.method = 'HEAD'
+ self.assertEqual(wrapper(None, request), 'OK')
+
+ def test_add_view_with_request_param_noval_true(self):
+ from pyramid.renderers import null_renderer
+
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, request_param='abc', renderer=null_renderer)
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ request.params = {'abc': ''}
+ self.assertEqual(wrapper(None, request), 'OK')
+
+ def test_add_view_with_request_param_noval_false(self):
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, request_param='abc')
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ request.params = {}
+ self._assertNotFound(wrapper, None, request)
+
+ def test_add_view_with_request_param_val_true(self):
+ from pyramid.renderers import null_renderer
+
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(
+ view=view, request_param='abc=123', renderer=null_renderer
+ )
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ request.params = {'abc': '123'}
+ self.assertEqual(wrapper(None, request), 'OK')
+
+ def test_add_view_with_request_param_val_false(self):
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, request_param='abc=123')
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ request.params = {'abc': ''}
+ self._assertNotFound(wrapper, None, request)
+
+ def test_add_view_with_xhr_true(self):
+ from pyramid.renderers import null_renderer
+
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, xhr=True, renderer=null_renderer)
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ request.is_xhr = True
+ self.assertEqual(wrapper(None, request), 'OK')
+
+ def test_add_view_with_xhr_false(self):
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, xhr=True)
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ request.is_xhr = False
+ self._assertNotFound(wrapper, None, request)
+
+ def test_add_view_with_header_badregex(self):
+ view = lambda *arg: 'OK'
+ config = self._makeOne()
+ config.add_view(view, header='Host:a\\')
+ self.assertRaises(ConfigurationError, config.commit)
+
+ def test_add_view_with_header_noval_match(self):
+ from pyramid.renderers import null_renderer
+
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, header='Host', renderer=null_renderer)
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ request.headers = {'Host': 'whatever'}
+ self.assertEqual(wrapper(None, request), 'OK')
+
+ def test_add_view_with_header_noval_nomatch(self):
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, header='Host')
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ request.headers = {'NotHost': 'whatever'}
+ self._assertNotFound(wrapper, None, request)
+
+ def test_add_view_with_header_val_match(self):
+ from pyramid.renderers import null_renderer
+
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, header=r'Host:\d', renderer=null_renderer)
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ request.headers = {'Host': '1'}
+ self.assertEqual(wrapper(None, request), 'OK')
+
+ def test_add_view_with_header_val_nomatch(self):
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, header=r'Host:\d')
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ request.headers = {'Host': 'abc'}
+ self._assertNotFound(wrapper, None, request)
+
+ def test_add_view_with_header_val_missing(self):
+ from pyramid.httpexceptions import HTTPNotFound
+
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, header=r'Host:\d')
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ request.headers = {'NoHost': '1'}
+ self.assertRaises(HTTPNotFound, wrapper, None, request)
+
+ def test_add_view_with_accept_match(self):
+ from pyramid.renderers import null_renderer
+
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, accept='text/xml', renderer=null_renderer)
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ request.accept = DummyAccept('text/xml')
+ self.assertEqual(wrapper(None, request), 'OK')
+
+ def test_add_view_with_accept_nomatch(self):
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, accept='text/xml')
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ request.accept = DummyAccept('text/html')
+ self._assertNotFound(wrapper, None, request)
+
+ def test_add_view_with_wildcard_accept_raises(self):
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ self.assertRaises(
+ ValueError, lambda: config.add_view(view=view, accept='text/*')
+ )
+
+ def test_add_view_with_containment_true(self):
+ from pyramid.renderers import null_renderer
+ from zope.interface import directlyProvides
+
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, containment=IDummy, renderer=null_renderer)
+ wrapper = self._getViewCallable(config)
+ context = DummyContext()
+ directlyProvides(context, IDummy)
+ self.assertEqual(wrapper(context, None), 'OK')
+
+ def test_add_view_with_containment_false(self):
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, containment=IDummy)
+ wrapper = self._getViewCallable(config)
+ context = DummyContext()
+ self._assertNotFound(wrapper, context, None)
+
+ def test_add_view_with_containment_dottedname(self):
+ from pyramid.renderers import null_renderer
+ from zope.interface import directlyProvides
+
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(
+ view=view,
+ containment='tests.test_config.IDummy',
+ renderer=null_renderer,
+ )
+ wrapper = self._getViewCallable(config)
+ context = DummyContext()
+ directlyProvides(context, IDummy)
+ self.assertEqual(wrapper(context, None), 'OK')
+
+ def test_add_view_with_path_info_badregex(self):
+ view = lambda *arg: 'OK'
+ config = self._makeOne()
+ config.add_view(view, path_info='\\')
+ self.assertRaises(ConfigurationError, config.commit)
+
+ def test_add_view_with_path_info_match(self):
+ from pyramid.renderers import null_renderer
+
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, path_info='/foo', renderer=null_renderer)
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ request.upath_info = text_(b'/foo')
+ self.assertEqual(wrapper(None, request), 'OK')
+
+ def test_add_view_with_path_info_nomatch(self):
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, path_info='/foo')
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ request.upath_info = text_('/')
+ self._assertNotFound(wrapper, None, request)
+
+ def test_add_view_with_check_csrf_predicates_match(self):
+ import warnings
+ from pyramid.renderers import null_renderer
+
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ with warnings.catch_warnings(record=True) as w:
+ warnings.filterwarnings('always')
+ config.add_view(view=view, check_csrf=True, renderer=null_renderer)
+ self.assertEqual(len(w), 1)
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ request.method = "POST"
+ request.session = DummySession({'csrf_token': 'foo'})
+ request.POST = {'csrf_token': 'foo'}
+ request.headers = {}
+ self.assertEqual(wrapper(None, request), 'OK')
+
+ def test_add_view_with_custom_predicates_match(self):
+ import warnings
+ from pyramid.renderers import null_renderer
+
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+
+ def pred1(context, request):
+ return True
+
+ def pred2(context, request):
+ return True
+
+ predicates = (pred1, pred2)
+ with warnings.catch_warnings(record=True) as w:
+ warnings.filterwarnings('always')
+ config.add_view(
+ view=view, custom_predicates=predicates, renderer=null_renderer
+ )
+ self.assertEqual(len(w), 1)
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ self.assertEqual(wrapper(None, request), 'OK')
+
+ def test_add_view_with_custom_predicates_nomatch(self):
+ import warnings
+
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+
+ def pred1(context, request):
+ return True
+
+ def pred2(context, request):
+ return False
+
+ predicates = (pred1, pred2)
+ with warnings.catch_warnings(record=True) as w:
+ warnings.filterwarnings('always')
+ config.add_view(view=view, custom_predicates=predicates)
+ self.assertEqual(len(w), 1)
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ self._assertNotFound(wrapper, None, request)
+
+ def test_add_view_custom_predicate_bests_standard_predicate(self):
+ import warnings
+ from pyramid.renderers import null_renderer
+
+ view = lambda *arg: 'OK'
+ view2 = lambda *arg: 'NOT OK'
+ config = self._makeOne(autocommit=True)
+
+ def pred1(context, request):
+ return True
+
+ with warnings.catch_warnings(record=True) as w:
+ warnings.filterwarnings('always')
+ config.add_view(
+ view=view, custom_predicates=(pred1,), renderer=null_renderer
+ )
+ config.add_view(
+ view=view2, request_method='GET', renderer=null_renderer
+ )
+ self.assertEqual(len(w), 1)
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ request.method = 'GET'
+ self.assertEqual(wrapper(None, request), 'OK')
+
+ def test_add_view_custom_more_preds_first_bests_fewer_preds_last(self):
+ from pyramid.renderers import null_renderer
+
+ view = lambda *arg: 'OK'
+ view2 = lambda *arg: 'NOT OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(
+ view=view, request_method='GET', xhr=True, renderer=null_renderer
+ )
+ config.add_view(
+ view=view2, request_method='GET', renderer=null_renderer
+ )
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ request.method = 'GET'
+ request.is_xhr = True
+ self.assertEqual(wrapper(None, request), 'OK')
+
+ def test_add_view_same_predicates(self):
+ view2 = lambda *arg: 'second'
+ view1 = lambda *arg: 'first'
+ config = self._makeOne()
+ config.add_view(view=view1)
+ config.add_view(view=view2)
+ self.assertRaises(ConfigurationConflictError, config.commit)
+
+ def test_add_view_with_csrf_param(self):
+ from pyramid.renderers import null_renderer
+
+ def view(request):
+ return 'OK'
+
+ config = self._makeOne(autocommit=True)
+ config.add_view(view, require_csrf='st', renderer=null_renderer)
+ view = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ request.scheme = "http"
+ request.method = 'POST'
+ request.POST = {'st': 'foo'}
+ request.headers = {}
+ request.session = DummySession({'csrf_token': 'foo'})
+ self.assertEqual(view(None, request), 'OK')
+
+ def test_add_view_with_csrf_header(self):
+ from pyramid.renderers import null_renderer
+
+ def view(request):
+ return 'OK'
+
+ config = self._makeOne(autocommit=True)
+ config.add_view(view, require_csrf=True, renderer=null_renderer)
+ view = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ request.scheme = "http"
+ request.method = 'POST'
+ request.POST = {}
+ request.headers = {'X-CSRF-Token': 'foo'}
+ request.session = DummySession({'csrf_token': 'foo'})
+ self.assertEqual(view(None, request), 'OK')
+
+ def test_add_view_with_missing_csrf_header(self):
+ from pyramid.exceptions import BadCSRFToken
+ from pyramid.renderers import null_renderer
+
+ def view(request): # pragma: no cover
+ return 'OK'
+
+ config = self._makeOne(autocommit=True)
+ config.add_view(view, require_csrf=True, renderer=null_renderer)
+ view = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ request.scheme = "http"
+ request.method = 'POST'
+ request.POST = {}
+ request.headers = {}
+ request.session = DummySession({'csrf_token': 'foo'})
+ self.assertRaises(BadCSRFToken, lambda: view(None, request))
+
+ def test_add_view_with_permission(self):
+ from pyramid.renderers import null_renderer
+
+ view1 = lambda *arg: 'OK'
+ outerself = self
+
+ class DummyPolicy(object):
+ def effective_principals(self, r):
+ outerself.assertEqual(r, request)
+ return ['abc']
+
+ def permits(self, context, principals, permission):
+ outerself.assertEqual(context, None)
+ outerself.assertEqual(principals, ['abc'])
+ outerself.assertEqual(permission, 'view')
+ return True
+
+ policy = DummyPolicy()
+ config = self._makeOne(
+ authorization_policy=policy,
+ authentication_policy=policy,
+ autocommit=True,
+ )
+ config.add_view(view=view1, permission='view', renderer=null_renderer)
+ view = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ self.assertEqual(view(None, request), 'OK')
+
+ def test_add_view_with_default_permission_no_explicit_permission(self):
+ from pyramid.renderers import null_renderer
+
+ view1 = lambda *arg: 'OK'
+ outerself = self
+
+ class DummyPolicy(object):
+ def effective_principals(self, r):
+ outerself.assertEqual(r, request)
+ return ['abc']
+
+ def permits(self, context, principals, permission):
+ outerself.assertEqual(context, None)
+ outerself.assertEqual(principals, ['abc'])
+ outerself.assertEqual(permission, 'view')
+ return True
+
+ policy = DummyPolicy()
+ config = self._makeOne(
+ authorization_policy=policy,
+ authentication_policy=policy,
+ default_permission='view',
+ autocommit=True,
+ )
+ config.add_view(view=view1, renderer=null_renderer)
+ view = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ self.assertEqual(view(None, request), 'OK')
+
+ def test_add_view_with_no_default_permission_no_explicit_permission(self):
+ from pyramid.renderers import null_renderer
+
+ view1 = lambda *arg: 'OK'
+
+ class DummyPolicy(object):
+ pass # wont be called
+
+ policy = DummyPolicy()
+ config = self._makeOne(
+ authorization_policy=policy,
+ authentication_policy=policy,
+ autocommit=True,
+ )
+ config.add_view(view=view1, renderer=null_renderer)
+ view = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ self.assertEqual(view(None, request), 'OK')
+
+ def test_add_view_with_mapper(self):
+ from pyramid.renderers import null_renderer
+
+ class Mapper(object):
+ def __init__(self, **kw):
+ self.__class__.kw = kw
+
+ def __call__(self, view):
+ return view
+
+ config = self._makeOne(autocommit=True)
+
+ def view(context, request):
+ return 'OK'
+
+ config.add_view(view=view, mapper=Mapper, renderer=null_renderer)
+ view = self._getViewCallable(config)
+ self.assertEqual(view(None, None), 'OK')
+ self.assertEqual(Mapper.kw['mapper'], Mapper)
+
+ def test_add_view_with_view_defaults(self):
+ from pyramid.renderers import null_renderer
+ from pyramid.exceptions import PredicateMismatch
+ from zope.interface import directlyProvides
+
+ class view(object):
+ __view_defaults__ = {'containment': 'tests.test_config.IDummy'}
+
+ def __init__(self, request):
+ pass
+
+ def __call__(self):
+ return 'OK'
+
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, renderer=null_renderer)
+ wrapper = self._getViewCallable(config)
+ context = DummyContext()
+ directlyProvides(context, IDummy)
+ request = self._makeRequest(config)
+ self.assertEqual(wrapper(context, request), 'OK')
+ context = DummyContext()
+ request = self._makeRequest(config)
+ self.assertRaises(PredicateMismatch, wrapper, context, request)
+
+ def test_add_view_with_view_defaults_viewname_is_dottedname_kwarg(self):
+ from pyramid.renderers import null_renderer
+ from pyramid.exceptions import PredicateMismatch
+ from zope.interface import directlyProvides
+
+ config = self._makeOne(autocommit=True)
+ config.add_view(
+ view='tests.test_config.test_views.DummyViewDefaultsClass',
+ renderer=null_renderer,
+ )
+ wrapper = self._getViewCallable(config)
+ context = DummyContext()
+ directlyProvides(context, IDummy)
+ request = self._makeRequest(config)
+ self.assertEqual(wrapper(context, request), 'OK')
+ context = DummyContext()
+ request = self._makeRequest(config)
+ self.assertRaises(PredicateMismatch, wrapper, context, request)
+
+ def test_add_view_with_view_defaults_viewname_is_dottedname_nonkwarg(self):
+ from pyramid.renderers import null_renderer
+ from pyramid.exceptions import PredicateMismatch
+ from zope.interface import directlyProvides
+
+ config = self._makeOne(autocommit=True)
+ config.add_view(
+ 'tests.test_config.test_views.DummyViewDefaultsClass',
+ renderer=null_renderer,
+ )
+ wrapper = self._getViewCallable(config)
+ context = DummyContext()
+ directlyProvides(context, IDummy)
+ request = self._makeRequest(config)
+ self.assertEqual(wrapper(context, request), 'OK')
+ context = DummyContext()
+ request = self._makeRequest(config)
+ self.assertRaises(PredicateMismatch, wrapper, context, request)
+
+ def test_add_view_with_view_config_and_view_defaults_doesnt_conflict(self):
+ from pyramid.renderers import null_renderer
+
+ class view(object):
+ __view_defaults__ = {'containment': 'tests.test_config.IDummy'}
+
+ class view2(object):
+ __view_defaults__ = {'containment': 'tests.test_config.IFactory'}
+
+ config = self._makeOne(autocommit=False)
+ config.add_view(view=view, renderer=null_renderer)
+ config.add_view(view=view2, renderer=null_renderer)
+ config.commit() # does not raise
+
+ def test_add_view_with_view_config_and_view_defaults_conflicts(self):
+ from pyramid.renderers import null_renderer
+
+ class view(object):
+ __view_defaults__ = {'containment': 'tests.test_config.IDummy'}
+
+ class view2(object):
+ __view_defaults__ = {'containment': 'tests.test_config.IDummy'}
+
+ config = self._makeOne(autocommit=False)
+ config.add_view(view=view, renderer=null_renderer)
+ config.add_view(view=view2, renderer=null_renderer)
+ self.assertRaises(ConfigurationConflictError, config.commit)
+
+ def test_add_view_class_method_no_attr(self):
+ from pyramid.renderers import null_renderer
+ from pyramid.exceptions import ConfigurationError
+
+ config = self._makeOne(autocommit=True)
+
+ class DummyViewClass(object):
+ def run(self): # pragma: no cover
+ pass
+
+ def configure_view():
+ config.add_view(view=DummyViewClass.run, renderer=null_renderer)
+
+ self.assertRaises(ConfigurationError, configure_view)
+
+ def test_add_view_exception_only_no_regular_view(self):
+ from zope.interface import implementedBy
+ from pyramid.renderers import null_renderer
+
+ view1 = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(
+ view=view1,
+ context=Exception,
+ exception_only=True,
+ renderer=null_renderer,
+ )
+ view = self._getViewCallable(
+ config, ctx_iface=implementedBy(Exception)
+ )
+ self.assertTrue(view is None)
+
+ def test_add_view_exception_only(self):
+ from zope.interface import implementedBy
+ from pyramid.renderers import null_renderer
+
+ view1 = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(
+ view=view1,
+ context=Exception,
+ exception_only=True,
+ renderer=null_renderer,
+ )
+ view = self._getViewCallable(
+ config, exc_iface=implementedBy(Exception)
+ )
+ self.assertEqual(view1, view)
+
+ def test_add_view_exception_only_misconfiguration(self):
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+
+ class NotAnException(object):
+ pass
+
+ self.assertRaises(
+ ConfigurationError,
+ config.add_view,
+ view,
+ context=NotAnException,
+ exception_only=True,
+ )
+
+ def test_add_exception_view(self):
+ from zope.interface import implementedBy
+ from pyramid.renderers import null_renderer
+
+ view1 = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_exception_view(view=view1, renderer=null_renderer)
+ wrapper = self._getViewCallable(
+ config, exc_iface=implementedBy(Exception)
+ )
+ context = Exception()
+ request = self._makeRequest(config)
+ self.assertEqual(wrapper(context, request), 'OK')
+
+ def test_add_exception_view_with_subclass(self):
+ from zope.interface import implementedBy
+ from pyramid.renderers import null_renderer
+
+ view1 = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_exception_view(
+ view=view1, context=ValueError, renderer=null_renderer
+ )
+ wrapper = self._getViewCallable(
+ config, exc_iface=implementedBy(ValueError)
+ )
+ context = ValueError()
+ request = self._makeRequest(config)
+ self.assertEqual(wrapper(context, request), 'OK')
+
+ def test_add_exception_view_disallows_name(self):
+ config = self._makeOne(autocommit=True)
+ self.assertRaises(
+ ConfigurationError,
+ config.add_exception_view,
+ context=Exception(),
+ name='foo',
+ )
+
+ def test_add_exception_view_disallows_permission(self):
+ config = self._makeOne(autocommit=True)
+ self.assertRaises(
+ ConfigurationError,
+ config.add_exception_view,
+ context=Exception(),
+ permission='foo',
+ )
+
+ def test_add_exception_view_disallows_require_csrf(self):
+ config = self._makeOne(autocommit=True)
+ self.assertRaises(
+ ConfigurationError,
+ config.add_exception_view,
+ context=Exception(),
+ require_csrf=True,
+ )
+
+ def test_add_exception_view_disallows_for_(self):
+ config = self._makeOne(autocommit=True)
+ self.assertRaises(
+ ConfigurationError,
+ config.add_exception_view,
+ context=Exception(),
+ for_='foo',
+ )
+
+ def test_add_exception_view_disallows_exception_only(self):
+ config = self._makeOne(autocommit=True)
+ self.assertRaises(
+ ConfigurationError,
+ config.add_exception_view,
+ context=Exception(),
+ exception_only=True,
+ )
+
+ def test_add_exception_view_with_view_defaults(self):
+ from pyramid.renderers import null_renderer
+ from pyramid.exceptions import PredicateMismatch
+ from zope.interface import directlyProvides
+ from zope.interface import implementedBy
+
+ class view(object):
+ __view_defaults__ = {'containment': 'tests.test_config.IDummy'}
+
+ def __init__(self, request):
+ pass
+
+ def __call__(self):
+ return 'OK'
+
+ config = self._makeOne(autocommit=True)
+ config.add_exception_view(
+ view=view, context=Exception, renderer=null_renderer
+ )
+ wrapper = self._getViewCallable(
+ config, exc_iface=implementedBy(Exception)
+ )
+ context = DummyContext()
+ directlyProvides(context, IDummy)
+ request = self._makeRequest(config)
+ self.assertEqual(wrapper(context, request), 'OK')
+ context = DummyContext()
+ request = self._makeRequest(config)
+ self.assertRaises(PredicateMismatch, wrapper, context, request)
+
+ def test_derive_view_function(self):
+ from pyramid.renderers import null_renderer
+
+ def view(request):
+ return 'OK'
+
+ config = self._makeOne()
+ result = config.derive_view(view, renderer=null_renderer)
+ self.assertFalse(result is view)
+ self.assertEqual(result(None, None), 'OK')
+
+ def test_derive_view_dottedname(self):
+ from pyramid.renderers import null_renderer
+
+ config = self._makeOne()
+ result = config.derive_view(
+ 'tests.test_config.dummy_view', renderer=null_renderer
+ )
+ self.assertFalse(result is dummy_view)
+ self.assertEqual(result(None, None), 'OK')
+
+ def test_derive_view_with_default_renderer_no_explicit_renderer(self):
+ config = self._makeOne()
+
+ class moo(object):
+ def __init__(self, view):
+ pass
+
+ def __call__(self, *arg, **kw):
+ return 'moo'
+
+ config.add_renderer(None, moo)
+ config.commit()
+
+ def view(request):
+ return 'OK'
+
+ result = config.derive_view(view)
+ self.assertFalse(result is view)
+ self.assertEqual(result(None, None).body, b'moo')
+
+ def test_derive_view_with_default_renderer_with_explicit_renderer(self):
+ class moo(object):
+ pass
+
+ class foo(object):
+ def __init__(self, view):
+ pass
+
+ def __call__(self, *arg, **kw):
+ return b'foo'
+
+ def view(request):
+ return 'OK'
+
+ config = self._makeOne()
+ config.add_renderer(None, moo)
+ config.add_renderer('foo', foo)
+ config.commit()
+ result = config.derive_view(view, renderer='foo')
+ self.assertFalse(result is view)
+ request = self._makeRequest(config)
+ self.assertEqual(result(None, request).body, b'foo')
+
+ def test_add_static_view_here_no_utility_registered(self):
+ from pyramid.renderers import null_renderer
+ from zope.interface import Interface
+ from pyramid.interfaces import IView
+ from pyramid.interfaces import IViewClassifier
+
+ config = self._makeOne(autocommit=True)
+ config.add_static_view('static', 'files', renderer=null_renderer)
+ request_type = self._getRouteRequestIface(config, '__static/')
+ self._assertRoute(config, '__static/', 'static/*subpath')
+ wrapped = config.registry.adapters.lookup(
+ (IViewClassifier, request_type, Interface), IView, name=''
+ )
+ from pyramid.request import Request
+
+ request = Request.blank('/static/minimal.txt')
+ request.subpath = ('minimal.txt',)
+ result = wrapped(None, request)
+ self.assertEqual(result.status, '200 OK')
+ self.assertTrue(result.body.startswith(b'<div'))
+
+ def test_add_static_view_package_relative(self):
+ from pyramid.interfaces import IStaticURLInfo
+
+ info = DummyStaticURLInfo()
+ config = self._makeOne(autocommit=True)
+ config.registry.registerUtility(info, IStaticURLInfo)
+ config.add_static_view('static', 'tests.test_config:files')
+ self.assertEqual(
+ info.added, [(config, 'static', 'tests.test_config:files', {})]
+ )
+
+ def test_add_static_view_package_here_relative(self):
+ from pyramid.interfaces import IStaticURLInfo
+
+ info = DummyStaticURLInfo()
+ config = self._makeOne(autocommit=True)
+ config.registry.registerUtility(info, IStaticURLInfo)
+ config.add_static_view('static', 'files')
+ self.assertEqual(
+ info.added, [(config, 'static', 'tests.test_config:files', {})]
+ )
+
+ def test_add_static_view_absolute(self):
+ import os
+ from pyramid.interfaces import IStaticURLInfo
+
+ info = DummyStaticURLInfo()
+ config = self._makeOne(autocommit=True)
+ config.registry.registerUtility(info, IStaticURLInfo)
+ here = os.path.dirname(__file__)
+ static_path = os.path.join(here, 'files')
+ config.add_static_view('static', static_path)
+ self.assertEqual(info.added, [(config, 'static', static_path, {})])
+
+ def test_add_forbidden_view(self):
+ from pyramid.renderers import null_renderer
+ from zope.interface import implementedBy
+ from pyramid.interfaces import IRequest
+ from pyramid.httpexceptions import HTTPForbidden
+
+ config = self._makeOne(autocommit=True)
+ view = lambda *arg: 'OK'
+ config.add_forbidden_view(view, renderer=null_renderer)
+ request = self._makeRequest(config)
+ view = self._getViewCallable(
+ config,
+ exc_iface=implementedBy(HTTPForbidden),
+ request_iface=IRequest,
+ )
+ result = view(None, request)
+ self.assertEqual(result, 'OK')
+
+ def test_add_forbidden_view_no_view_argument(self):
+ from zope.interface import implementedBy
+ from pyramid.interfaces import IRequest
+ from pyramid.httpexceptions import HTTPForbidden
+
+ config = self._makeOne(autocommit=True)
+ config.setup_registry()
+ config.add_forbidden_view()
+ request = self._makeRequest(config)
+ view = self._getViewCallable(
+ config,
+ exc_iface=implementedBy(HTTPForbidden),
+ request_iface=IRequest,
+ )
+ context = HTTPForbidden()
+ result = view(context, request)
+ self.assertEqual(result, context)
+
+ def test_add_forbidden_view_allows_other_predicates(self):
+ from pyramid.renderers import null_renderer
+
+ config = self._makeOne(autocommit=True)
+ # doesnt blow up
+ config.add_view_predicate('dummy', DummyPredicate)
+ config.add_forbidden_view(renderer=null_renderer, dummy='abc')
+
+ def test_add_forbidden_view_disallows_name(self):
+ config = self._makeOne(autocommit=True)
+ self.assertRaises(
+ ConfigurationError, config.add_forbidden_view, name='foo'
+ )
+
+ def test_add_forbidden_view_disallows_permission(self):
+ config = self._makeOne(autocommit=True)
+ self.assertRaises(
+ ConfigurationError, config.add_forbidden_view, permission='foo'
+ )
+
+ def test_add_forbidden_view_disallows_require_csrf(self):
+ config = self._makeOne(autocommit=True)
+ self.assertRaises(
+ ConfigurationError, config.add_forbidden_view, require_csrf=True
+ )
+
+ def test_add_forbidden_view_disallows_context(self):
+ config = self._makeOne(autocommit=True)
+ self.assertRaises(
+ ConfigurationError, config.add_forbidden_view, context='foo'
+ )
+
+ def test_add_forbidden_view_disallows_for_(self):
+ config = self._makeOne(autocommit=True)
+ self.assertRaises(
+ ConfigurationError, config.add_forbidden_view, for_='foo'
+ )
+
+ def test_add_forbidden_view_with_view_defaults(self):
+ from pyramid.interfaces import IRequest
+ from pyramid.renderers import null_renderer
+ from pyramid.exceptions import PredicateMismatch
+ from pyramid.httpexceptions import HTTPForbidden
+ from zope.interface import directlyProvides
+ from zope.interface import implementedBy
+
+ class view(object):
+ __view_defaults__ = {'containment': 'tests.test_config.IDummy'}
+
+ def __init__(self, request):
+ pass
+
+ def __call__(self):
+ return 'OK'
+
+ config = self._makeOne(autocommit=True)
+ config.add_forbidden_view(view=view, renderer=null_renderer)
+ wrapper = self._getViewCallable(
+ config,
+ exc_iface=implementedBy(HTTPForbidden),
+ request_iface=IRequest,
+ )
+ context = DummyContext()
+ directlyProvides(context, IDummy)
+ request = self._makeRequest(config)
+ self.assertEqual(wrapper(context, request), 'OK')
+ context = DummyContext()
+ request = self._makeRequest(config)
+ self.assertRaises(PredicateMismatch, wrapper, context, request)
+
+ def test_add_notfound_view(self):
+ from pyramid.renderers import null_renderer
+ from zope.interface import implementedBy
+ from pyramid.interfaces import IRequest
+ from pyramid.httpexceptions import HTTPNotFound
+
+ config = self._makeOne(autocommit=True)
+ view = lambda *arg: arg
+ config.add_notfound_view(view, renderer=null_renderer)
+ request = self._makeRequest(config)
+ view = self._getViewCallable(
+ config,
+ exc_iface=implementedBy(HTTPNotFound),
+ request_iface=IRequest,
+ )
+ result = view(None, request)
+ self.assertEqual(result, (None, request))
+
+ def test_add_notfound_view_no_view_argument(self):
+ from zope.interface import implementedBy
+ from pyramid.interfaces import IRequest
+ from pyramid.httpexceptions import HTTPNotFound
+
+ config = self._makeOne(autocommit=True)
+ config.setup_registry()
+ config.add_notfound_view()
+ request = self._makeRequest(config)
+ view = self._getViewCallable(
+ config,
+ exc_iface=implementedBy(HTTPNotFound),
+ request_iface=IRequest,
+ )
+ context = HTTPNotFound()
+ result = view(context, request)
+ self.assertEqual(result, context)
+
+ def test_add_notfound_view_allows_other_predicates(self):
+ from pyramid.renderers import null_renderer
+
+ config = self._makeOne(autocommit=True)
+ # doesnt blow up
+ config.add_view_predicate('dummy', DummyPredicate)
+ config.add_notfound_view(renderer=null_renderer, dummy='abc')
+
+ def test_add_notfound_view_disallows_name(self):
+ config = self._makeOne(autocommit=True)
+ self.assertRaises(
+ ConfigurationError, config.add_notfound_view, name='foo'
+ )
+
+ def test_add_notfound_view_disallows_permission(self):
+ config = self._makeOne(autocommit=True)
+ self.assertRaises(
+ ConfigurationError, config.add_notfound_view, permission='foo'
+ )
+
+ def test_add_notfound_view_disallows_require_csrf(self):
+ config = self._makeOne(autocommit=True)
+ self.assertRaises(
+ ConfigurationError, config.add_notfound_view, require_csrf=True
+ )
+
+ def test_add_notfound_view_disallows_context(self):
+ config = self._makeOne(autocommit=True)
+ self.assertRaises(
+ ConfigurationError, config.add_notfound_view, context='foo'
+ )
+
+ def test_add_notfound_view_disallows_for_(self):
+ config = self._makeOne(autocommit=True)
+ self.assertRaises(
+ ConfigurationError, config.add_notfound_view, for_='foo'
+ )
+
+ def test_add_notfound_view_append_slash(self):
+ from pyramid.response import Response
+ from pyramid.renderers import null_renderer
+ from zope.interface import implementedBy
+ from pyramid.interfaces import IRequest
+ from pyramid.httpexceptions import HTTPTemporaryRedirect, HTTPNotFound
+
+ config = self._makeOne(autocommit=True)
+ config.add_route('foo', '/foo/')
+
+ def view(request): # pragma: no cover
+ return Response('OK')
+
+ config.add_notfound_view(
+ view, renderer=null_renderer, append_slash=True
+ )
+ request = self._makeRequest(config)
+ request.environ['PATH_INFO'] = '/foo'
+ request.query_string = 'a=1&b=2'
+ request.path = '/scriptname/foo'
+ view = self._getViewCallable(
+ config,
+ exc_iface=implementedBy(HTTPNotFound),
+ request_iface=IRequest,
+ )
+ result = view(None, request)
+ self.assertTrue(isinstance(result, HTTPTemporaryRedirect))
+ self.assertEqual(result.location, '/scriptname/foo/?a=1&b=2')
+
+ def test_add_notfound_view_append_slash_custom_response(self):
+ from pyramid.response import Response
+ from pyramid.renderers import null_renderer
+ from zope.interface import implementedBy
+ from pyramid.interfaces import IRequest
+ from pyramid.httpexceptions import HTTPMovedPermanently, HTTPNotFound
+
+ config = self._makeOne(autocommit=True)
+ config.add_route('foo', '/foo/')
+
+ def view(request): # pragma: no cover
+ return Response('OK')
+
+ config.add_notfound_view(
+ view, renderer=null_renderer, append_slash=HTTPMovedPermanently
+ )
+ request = self._makeRequest(config)
+ request.environ['PATH_INFO'] = '/foo'
+ request.query_string = 'a=1&b=2'
+ request.path = '/scriptname/foo'
+ view = self._getViewCallable(
+ config,
+ exc_iface=implementedBy(HTTPNotFound),
+ request_iface=IRequest,
+ )
+ result = view(None, request)
+ self.assertTrue(isinstance(result, HTTPMovedPermanently))
+ self.assertEqual(result.location, '/scriptname/foo/?a=1&b=2')
+
+ def test_add_notfound_view_with_view_defaults(self):
+ from pyramid.interfaces import IRequest
+ from pyramid.renderers import null_renderer
+ from pyramid.exceptions import PredicateMismatch
+ from pyramid.httpexceptions import HTTPNotFound
+ from zope.interface import directlyProvides
+ from zope.interface import implementedBy
+
+ class view(object):
+ __view_defaults__ = {'containment': 'tests.test_config.IDummy'}
+
+ def __init__(self, request):
+ pass
+
+ def __call__(self):
+ return 'OK'
+
+ config = self._makeOne(autocommit=True)
+ config.add_notfound_view(view=view, renderer=null_renderer)
+ wrapper = self._getViewCallable(
+ config,
+ exc_iface=implementedBy(HTTPNotFound),
+ request_iface=IRequest,
+ )
+ context = DummyContext()
+ directlyProvides(context, IDummy)
+ request = self._makeRequest(config)
+ self.assertEqual(wrapper(context, request), 'OK')
+ context = DummyContext()
+ request = self._makeRequest(config)
+ self.assertRaises(PredicateMismatch, wrapper, context, request)
+
+ # Since Python 3 has to be all cool and fancy and different...
+ def _assertBody(self, response, value):
+ from pyramid.compat import text_type
+
+ if isinstance(value, text_type): # pragma: no cover
+ self.assertEqual(response.text, value)
+ else: # pragma: no cover
+ self.assertEqual(response.body, value)
+
+ def test_add_notfound_view_with_renderer(self):
+ from zope.interface import implementedBy
+ from pyramid.interfaces import IRequest
+ from pyramid.httpexceptions import HTTPNotFound
+
+ config = self._makeOne(autocommit=True)
+ view = lambda *arg: {}
+ config.introspection = False
+ config.add_notfound_view(view, renderer='json')
+ request = self._makeRequest(config)
+ view = self._getViewCallable(
+ config,
+ exc_iface=implementedBy(HTTPNotFound),
+ request_iface=IRequest,
+ )
+ result = view(None, request)
+ self._assertBody(result, '{}')
+
+ def test_add_forbidden_view_with_renderer(self):
+ from zope.interface import implementedBy
+ from pyramid.interfaces import IRequest
+ from pyramid.httpexceptions import HTTPForbidden
+
+ config = self._makeOne(autocommit=True)
+ view = lambda *arg: {}
+ config.introspection = False
+ config.add_forbidden_view(view, renderer='json')
+ request = self._makeRequest(config)
+ view = self._getViewCallable(
+ config,
+ exc_iface=implementedBy(HTTPForbidden),
+ request_iface=IRequest,
+ )
+ result = view(None, request)
+ self._assertBody(result, '{}')
+
+ def test_set_view_mapper(self):
+ from pyramid.interfaces import IViewMapperFactory
+
+ config = self._makeOne(autocommit=True)
+ mapper = object()
+ config.set_view_mapper(mapper)
+ result = config.registry.getUtility(IViewMapperFactory)
+ self.assertEqual(result, mapper)
+
+ def test_set_view_mapper_dottedname(self):
+ from pyramid.interfaces import IViewMapperFactory
+
+ config = self._makeOne(autocommit=True)
+ config.set_view_mapper('tests.test_config')
+ result = config.registry.getUtility(IViewMapperFactory)
+ from tests import test_config
+
+ self.assertEqual(result, test_config)
+
+ def test_add_normal_and_exception_view_intr_derived_callable(self):
+ from pyramid.renderers import null_renderer
+ from pyramid.exceptions import BadCSRFToken
+
+ config = self._makeOne(autocommit=True)
+ introspector = DummyIntrospector()
+ config.introspector = introspector
+ view = lambda r: 'OK'
+ config.set_default_csrf_options(require_csrf=True)
+ config.add_view(view, context=Exception, renderer=null_renderer)
+ view_intr = introspector.introspectables[-1]
+ self.assertTrue(view_intr.type_name, 'view')
+ self.assertEqual(view_intr['callable'], view)
+ derived_view = view_intr['derived_callable']
+
+ request = self._makeRequest(config)
+ request.method = 'POST'
+ request.scheme = 'http'
+ request.POST = {}
+ request.headers = {}
+ request.session = DummySession({'csrf_token': 'foo'})
+ self.assertRaises(BadCSRFToken, lambda: derived_view(None, request))
+ request.exception = Exception()
+ self.assertEqual(derived_view(None, request), 'OK')
+
+ def test_add_view_does_not_accept_iterable_accept(self):
+ from pyramid.exceptions import ConfigurationError
+
+ config = self._makeOne(autocommit=True)
+ self.assertRaises(
+ ConfigurationError, config.add_view, accept=['image/*', 'text/*']
+ )
+
+ def test_default_accept_view_order(self):
+ from pyramid.interfaces import IAcceptOrder
+
+ config = self._makeOne(autocommit=True)
+ order = config.registry.getUtility(IAcceptOrder)
+ result = [v for _, v in order.sorted()]
+ self.assertEqual(
+ result,
+ [
+ 'text/html',
+ 'application/xhtml+xml',
+ 'application/xml',
+ 'text/xml',
+ 'text/plain',
+ 'application/json',
+ ],
+ )
+
+ def test_add_accept_view_order_override(self):
+ from pyramid.interfaces import IAcceptOrder
+
+ config = self._makeOne(autocommit=False)
+ config.add_accept_view_order(
+ 'text/html',
+ weighs_more_than='text/xml',
+ weighs_less_than='application/xml',
+ )
+ config.commit()
+ order = config.registry.getUtility(IAcceptOrder)
+ result = [v for _, v in order.sorted()]
+ self.assertEqual(
+ result,
+ [
+ 'application/xhtml+xml',
+ 'application/xml',
+ 'text/html',
+ 'text/xml',
+ 'text/plain',
+ 'application/json',
+ ],
+ )
+
+ def test_add_accept_view_order_throws_on_wildcard(self):
+ config = self._makeOne(autocommit=True)
+ self.assertRaises(ValueError, config.add_accept_view_order, '*/*')
+
+ def test_add_accept_view_order_throws_on_type_mismatch(self):
+ config = self._makeOne(autocommit=True)
+ self.assertRaises(
+ ValueError,
+ config.add_accept_view_order,
+ 'text/*',
+ weighs_more_than='text/html',
+ )
+ self.assertRaises(
+ ValueError,
+ config.add_accept_view_order,
+ 'text/html',
+ weighs_less_than='application/*',
+ )
+ self.assertRaises(
+ ConfigurationError,
+ config.add_accept_view_order,
+ 'text/html',
+ weighs_more_than='text/html;charset=utf8',
+ )
+ self.assertRaises(
+ ConfigurationError,
+ config.add_accept_view_order,
+ 'text/html;charset=utf8',
+ weighs_more_than='text/plain;charset=utf8',
+ )
+
+
+class Test_runtime_exc_view(unittest.TestCase):
+ def _makeOne(self, view1, view2):
+ from pyramid.config.views import runtime_exc_view
+
+ return runtime_exc_view(view1, view2)
+
+ def test_call(self):
+ def view1(context, request):
+ return 'OK'
+
+ def view2(context, request): # pragma: no cover
+ raise AssertionError
+
+ result_view = self._makeOne(view1, view2)
+ request = DummyRequest()
+ result = result_view(None, request)
+ self.assertEqual(result, 'OK')
+
+ def test_call_dispatches_on_exception(self):
+ def view1(context, request): # pragma: no cover
+ raise AssertionError
+
+ def view2(context, request):
+ return 'OK'
+
+ result_view = self._makeOne(view1, view2)
+ request = DummyRequest()
+ request.exception = Exception()
+ result = result_view(None, request)
+ self.assertEqual(result, 'OK')
+
+ def test_permitted(self):
+ def errfn(context, request): # pragma: no cover
+ raise AssertionError
+
+ def view1(context, request): # pragma: no cover
+ raise AssertionError
+
+ view1.__permitted__ = lambda c, r: 'OK'
+
+ def view2(context, request): # pragma: no cover
+ raise AssertionError
+
+ view2.__permitted__ = errfn
+ result_view = self._makeOne(view1, view2)
+ request = DummyRequest()
+ result = result_view.__permitted__(None, request)
+ self.assertEqual(result, 'OK')
+
+ def test_permitted_dispatches_on_exception(self):
+ def errfn(context, request): # pragma: no cover
+ raise AssertionError
+
+ def view1(context, request): # pragma: no cover
+ raise AssertionError
+
+ view1.__permitted__ = errfn
+
+ def view2(context, request): # pragma: no cover
+ raise AssertionError
+
+ view2.__permitted__ = lambda c, r: 'OK'
+ result_view = self._makeOne(view1, view2)
+ request = DummyRequest()
+ request.exception = Exception()
+ result = result_view.__permitted__(None, request)
+ self.assertEqual(result, 'OK')
+
+
+class Test_requestonly(unittest.TestCase):
+ def _callFUT(self, view, attr=None):
+ from pyramid.config.views import requestonly
+
+ return requestonly(view, attr=attr)
+
+ def test_defaults(self):
+ def aview(request, a=1, b=2): # pragma: no cover
+ pass
+
+ self.assertTrue(self._callFUT(aview))
+
+ def test_otherattr(self):
+ class AView(object):
+ def __init__(self, request, a=1, b=2): # pragma: no cover
+ pass
+
+ def bleh(self): # pragma: no cover
+ pass
+
+ self.assertTrue(self._callFUT(AView, 'bleh'))
+
+
+class Test_isexception(unittest.TestCase):
+ def _callFUT(self, ob):
+ from pyramid.config.views import isexception
+
+ return isexception(ob)
+
+ def test_is_exception_instance(self):
+ class E(Exception):
+ pass
+
+ e = E()
+ self.assertEqual(self._callFUT(e), True)
+
+ def test_is_exception_class(self):
+ class E(Exception):
+ pass
+
+ self.assertEqual(self._callFUT(E), True)
+
+ def test_is_IException(self):
+ from pyramid.interfaces import IException
+
+ self.assertEqual(self._callFUT(IException), True)
+
+ def test_is_IException_subinterface(self):
+ from pyramid.interfaces import IException
+
+ class ISubException(IException):
+ pass
+
+ self.assertEqual(self._callFUT(ISubException), True)
+
+
+class TestMultiView(unittest.TestCase):
+ def _getTargetClass(self):
+ from pyramid.config.views import MultiView
+
+ return MultiView
+
+ def _makeOne(self, name='name'):
+ return self._getTargetClass()(name)
+
+ def test_class_implements_ISecuredView(self):
+ from zope.interface.verify import verifyClass
+ from pyramid.interfaces import ISecuredView
+
+ verifyClass(ISecuredView, self._getTargetClass())
+
+ def test_instance_implements_ISecuredView(self):
+ from zope.interface.verify import verifyObject
+ from pyramid.interfaces import ISecuredView
+
+ verifyObject(ISecuredView, self._makeOne())
+
+ def test_add(self):
+ mv = self._makeOne()
+ mv.add('view', 100)
+ self.assertEqual(mv.views, [(100, 'view', None)])
+ mv.add('view2', 99)
+ self.assertEqual(mv.views, [(99, 'view2', None), (100, 'view', None)])
+ mv.add('view3', 100, accept='text/html')
+ self.assertEqual(mv.media_views['text/html'], [(100, 'view3', None)])
+ mv.add('view4', 99, 'abc', accept='text/html')
+ self.assertEqual(
+ mv.media_views['text/html'],
+ [(99, 'view4', 'abc'), (100, 'view3', None)],
+ )
+ mv.add('view5', 100, accept='text/xml')
+ self.assertEqual(mv.media_views['text/xml'], [(100, 'view5', None)])
+ self.assertEqual(set(mv.accepts), set(['text/xml', 'text/html']))
+ self.assertEqual(mv.views, [(99, 'view2', None), (100, 'view', None)])
+
+ def test_add_with_phash(self):
+ mv = self._makeOne()
+ mv.add('view', 100, phash='abc')
+ self.assertEqual(mv.views, [(100, 'view', 'abc')])
+ mv.add('view', 100, phash='abc')
+ self.assertEqual(mv.views, [(100, 'view', 'abc')])
+ mv.add('view', 100, phash='def')
+ self.assertEqual(
+ mv.views, [(100, 'view', 'abc'), (100, 'view', 'def')]
+ )
+ mv.add('view', 100, phash='abc')
+ self.assertEqual(
+ mv.views, [(100, 'view', 'abc'), (100, 'view', 'def')]
+ )
+
+ def test_add_with_phash_override_accept(self):
+ mv = self._makeOne()
+
+ def view1(): # pragma: no cover
+ pass
+
+ def view2(): # pragma: no cover
+ pass
+
+ def view3(): # pragma: no cover
+ pass
+
+ mv.add(view1, 100, accept='text/html', phash='abc')
+ mv.add(view2, 100, accept='text/html', phash='abc')
+ mv.add(view3, 99, accept='text/html', phash='def')
+ self.assertEqual(
+ mv.media_views['text/html'],
+ [(99, view3, 'def'), (100, view2, 'abc')],
+ )
+
+ def test_add_with_phash_override_accept2(self):
+ mv = self._makeOne()
+
+ def view1(): # pragma: no cover
+ pass
+
+ def view2(): # pragma: no cover
+ pass
+
+ def view3(): # pragma: no cover
+ pass
+
+ mv.add(view1, 100, accept='text/html', phash='abc')
+ mv.add(view2, 100, accept='text/html', phash='def')
+ mv.add(view3, 99, accept='text/html', phash='ghi')
+ self.assertEqual(
+ mv.media_views['text/html'],
+ [(99, view3, 'ghi'), (100, view1, 'abc'), (100, view2, 'def')],
+ )
+
+ def test_multiple_with_functions_as_views(self):
+ # this failed on py3 at one point, because functions aren't orderable
+ # and we were sorting the views via a plain sort() rather than
+ # sort(key=itemgetter(0)).
+ def view1(request): # pragma: no cover
+ pass
+
+ def view2(request): # pragma: no cover
+ pass
+
+ mv = self._makeOne()
+ mv.add(view1, 100, None)
+ self.assertEqual(mv.views, [(100, view1, None)])
+ mv.add(view2, 100, None)
+ self.assertEqual(mv.views, [(100, view1, None), (100, view2, None)])
+
+ def test_get_views_request_has_no_accept(self):
+ request = DummyRequest()
+ mv = self._makeOne()
+ mv.views = [(99, lambda *arg: None)]
+ self.assertEqual(mv.get_views(request), mv.views)
+
+ def test_get_views_no_self_accepts(self):
+ request = DummyRequest()
+ request.accept = True
+ mv = self._makeOne()
+ mv.accepts = []
+ mv.views = [(99, lambda *arg: None)]
+ self.assertEqual(mv.get_views(request), mv.views)
+
+ def test_get_views(self):
+ request = DummyRequest()
+ request.accept = DummyAccept('text/html')
+ mv = self._makeOne()
+ mv.accepts = ['text/html']
+ mv.views = [(99, lambda *arg: None)]
+ html_views = [(98, lambda *arg: None)]
+ mv.media_views['text/html'] = html_views
+ self.assertEqual(mv.get_views(request), html_views + mv.views)
+
+ def test_get_views_best_match_returns_None(self):
+ request = DummyRequest()
+ request.accept = DummyAccept(None)
+ mv = self._makeOne()
+ mv.accepts = ['text/html']
+ mv.views = [(99, lambda *arg: None)]
+ self.assertEqual(mv.get_views(request), mv.views)
+
+ def test_match_not_found(self):
+ from pyramid.httpexceptions import HTTPNotFound
+
+ mv = self._makeOne()
+ context = DummyContext()
+ request = DummyRequest()
+ self.assertRaises(HTTPNotFound, mv.match, context, request)
+
+ def test_match_predicate_fails(self):
+ from pyramid.httpexceptions import HTTPNotFound
+
+ mv = self._makeOne()
+
+ def view(context, request):
+ """ """
+
+ view.__predicated__ = lambda *arg: False
+ mv.views = [(100, view, None)]
+ context = DummyContext()
+ request = DummyRequest()
+ self.assertRaises(HTTPNotFound, mv.match, context, request)
+
+ def test_match_predicate_succeeds(self):
+ mv = self._makeOne()
+
+ def view(context, request):
+ """ """
+
+ view.__predicated__ = lambda *arg: True
+ mv.views = [(100, view, None)]
+ context = DummyContext()
+ request = DummyRequest()
+ result = mv.match(context, request)
+ self.assertEqual(result, view)
+
+ def test_permitted_no_views(self):
+ from pyramid.httpexceptions import HTTPNotFound
+
+ mv = self._makeOne()
+ context = DummyContext()
+ request = DummyRequest()
+ self.assertRaises(HTTPNotFound, mv.__permitted__, context, request)
+
+ def test_permitted_no_match_with__permitted__(self):
+ mv = self._makeOne()
+
+ def view(context, request):
+ """ """
+
+ mv.views = [(100, view, None)]
+ self.assertEqual(mv.__permitted__(None, None), True)
+
+ def test_permitted(self):
+ mv = self._makeOne()
+
+ def view(context, request):
+ """ """
+
+ def permitted(context, request):
+ return False
+
+ view.__permitted__ = permitted
+ mv.views = [(100, view, None)]
+ context = DummyContext()
+ request = DummyRequest()
+ result = mv.__permitted__(context, request)
+ self.assertEqual(result, False)
+
+ def test__call__not_found(self):
+ from pyramid.httpexceptions import HTTPNotFound
+
+ mv = self._makeOne()
+ context = DummyContext()
+ request = DummyRequest()
+ self.assertRaises(HTTPNotFound, mv, context, request)
+
+ def test___call__intermediate_not_found(self):
+ from pyramid.exceptions import PredicateMismatch
+
+ mv = self._makeOne()
+ context = DummyContext()
+ request = DummyRequest()
+ request.view_name = ''
+ expected_response = DummyResponse()
+
+ def view1(context, request):
+ raise PredicateMismatch
+
+ def view2(context, request):
+ return expected_response
+
+ mv.views = [(100, view1, None), (99, view2, None)]
+ response = mv(context, request)
+ self.assertEqual(response, expected_response)
+
+ def test___call__raise_not_found_isnt_interpreted_as_pred_mismatch(self):
+ from pyramid.httpexceptions import HTTPNotFound
+
+ mv = self._makeOne()
+ context = DummyContext()
+ request = DummyRequest()
+ request.view_name = ''
+
+ def view1(context, request):
+ raise HTTPNotFound
+
+ def view2(context, request):
+ """ """
+
+ mv.views = [(100, view1, None), (99, view2, None)]
+ self.assertRaises(HTTPNotFound, mv, context, request)
+
+ def test___call__(self):
+ mv = self._makeOne()
+ context = DummyContext()
+ request = DummyRequest()
+ request.view_name = ''
+ expected_response = DummyResponse()
+
+ def view(context, request):
+ return expected_response
+
+ mv.views = [(100, view, None)]
+ response = mv(context, request)
+ self.assertEqual(response, expected_response)
+
+ def test__call_permissive__not_found(self):
+ from pyramid.httpexceptions import HTTPNotFound
+
+ mv = self._makeOne()
+ context = DummyContext()
+ request = DummyRequest()
+ self.assertRaises(HTTPNotFound, mv, context, request)
+
+ def test___call_permissive_has_call_permissive(self):
+ mv = self._makeOne()
+ context = DummyContext()
+ request = DummyRequest()
+ request.view_name = ''
+ expected_response = DummyResponse()
+
+ def view(context, request):
+ """ """
+
+ def permissive(context, request):
+ return expected_response
+
+ view.__call_permissive__ = permissive
+ mv.views = [(100, view, None)]
+ response = mv.__call_permissive__(context, request)
+ self.assertEqual(response, expected_response)
+
+ def test___call_permissive_has_no_call_permissive(self):
+ mv = self._makeOne()
+ context = DummyContext()
+ request = DummyRequest()
+ request.view_name = ''
+ expected_response = DummyResponse()
+
+ def view(context, request):
+ return expected_response
+
+ mv.views = [(100, view, None)]
+ response = mv.__call_permissive__(context, request)
+ self.assertEqual(response, expected_response)
+
+ def test__call__with_accept_match(self):
+ mv = self._makeOne()
+ context = DummyContext()
+ request = DummyRequest()
+ request.accept = DummyAccept('text/html', 'text/xml')
+ expected_response = DummyResponse()
+
+ def view(context, request):
+ return expected_response
+
+ mv.views = [(100, None)]
+ mv.media_views['text/xml'] = [(100, view, None)]
+ mv.accepts = ['text/xml']
+ response = mv(context, request)
+ self.assertEqual(response, expected_response)
+
+ def test__call__with_accept_miss(self):
+ mv = self._makeOne()
+ context = DummyContext()
+ request = DummyRequest()
+ request.accept = DummyAccept('text/plain', 'text/html')
+ expected_response = DummyResponse()
+
+ def view(context, request):
+ return expected_response
+
+ mv.views = [(100, view, None)]
+ mv.media_views['text/xml'] = [(100, None, None)]
+ mv.accepts = ['text/xml']
+ response = mv(context, request)
+ self.assertEqual(response, expected_response)
+
+
+class TestDefaultViewMapper(unittest.TestCase):
+ def setUp(self):
+ self.config = testing.setUp()
+ self.registry = self.config.registry
+
+ def tearDown(self):
+ del self.registry
+ testing.tearDown()
+
+ def _makeOne(self, **kw):
+ from pyramid.config.views import DefaultViewMapper
+
+ kw['registry'] = self.registry
+ return DefaultViewMapper(**kw)
+
+ def _makeRequest(self):
+ request = DummyRequest()
+ request.registry = self.registry
+ return request
+
+ def test_view_as_function_context_and_request(self):
+ def view(context, request):
+ return 'OK'
+
+ mapper = self._makeOne()
+ result = mapper(view)
+ self.assertTrue(result is view)
+ request = self._makeRequest()
+ self.assertEqual(result(None, request), 'OK')
+
+ def test__view_as_function_with_attr(self):
+ def view(context, request):
+ """ """
+
+ mapper = self._makeOne(attr='__name__')
+ result = mapper(view)
+ self.assertFalse(result is view)
+ request = self._makeRequest()
+ self.assertRaises(TypeError, result, None, request)
+
+ def test_view_as_function_requestonly(self):
+ def view(request):
+ return 'OK'
+
+ mapper = self._makeOne()
+ result = mapper(view)
+ self.assertFalse(result is view)
+ request = self._makeRequest()
+ self.assertEqual(result(None, request), 'OK')
+
+ def test_view_as_function_requestonly_with_attr(self):
+ def view(request):
+ """ """
+
+ mapper = self._makeOne(attr='__name__')
+ result = mapper(view)
+ self.assertFalse(result is view)
+ request = self._makeRequest()
+ self.assertRaises(TypeError, result, None, request)
+
+ def test_view_as_newstyle_class_context_and_request(self):
+ class view(object):
+ def __init__(self, context, request):
+ pass
+
+ def __call__(self):
+ return 'OK'
+
+ mapper = self._makeOne()
+ result = mapper(view)
+ self.assertFalse(result is view)
+ request = self._makeRequest()
+ self.assertEqual(result(None, request), 'OK')
+
+ def test_view_as_newstyle_class_context_and_request_with_attr(self):
+ class view(object):
+ def __init__(self, context, request):
+ pass
+
+ def index(self):
+ return 'OK'
+
+ mapper = self._makeOne(attr='index')
+ result = mapper(view)
+ self.assertFalse(result is view)
+ request = self._makeRequest()
+ self.assertEqual(result(None, request), 'OK')
+
+ def test_view_as_newstyle_class_requestonly(self):
+ class view(object):
+ def __init__(self, request):
+ pass
+
+ def __call__(self):
+ return 'OK'
+
+ mapper = self._makeOne()
+ result = mapper(view)
+ self.assertFalse(result is view)
+ request = self._makeRequest()
+ self.assertEqual(result(None, request), 'OK')
+
+ def test_view_as_newstyle_class_requestonly_with_attr(self):
+ class view(object):
+ def __init__(self, request):
+ pass
+
+ def index(self):
+ return 'OK'
+
+ mapper = self._makeOne(attr='index')
+ result = mapper(view)
+ self.assertFalse(result is view)
+ request = self._makeRequest()
+ self.assertEqual(result(None, request), 'OK')
+
+ def test_view_as_oldstyle_class_context_and_request(self):
+ class view:
+ def __init__(self, context, request):
+ pass
+
+ def __call__(self):
+ return 'OK'
+
+ mapper = self._makeOne()
+ result = mapper(view)
+ self.assertFalse(result is view)
+ request = self._makeRequest()
+ self.assertEqual(result(None, request), 'OK')
+
+ def test_view_as_oldstyle_class_context_and_request_with_attr(self):
+ class view:
+ def __init__(self, context, request):
+ pass
+
+ def index(self):
+ return 'OK'
+
+ mapper = self._makeOne(attr='index')
+ result = mapper(view)
+ self.assertFalse(result is view)
+ request = self._makeRequest()
+ self.assertEqual(result(None, request), 'OK')
+
+ def test_view_as_oldstyle_class_requestonly(self):
+ class view:
+ def __init__(self, request):
+ pass
+
+ def __call__(self):
+ return 'OK'
+
+ mapper = self._makeOne()
+ result = mapper(view)
+ self.assertFalse(result is view)
+ request = self._makeRequest()
+ self.assertEqual(result(None, request), 'OK')
+
+ def test_view_as_oldstyle_class_requestonly_with_attr(self):
+ class view:
+ def __init__(self, request):
+ pass
+
+ def index(self):
+ return 'OK'
+
+ mapper = self._makeOne(attr='index')
+ result = mapper(view)
+ self.assertFalse(result is view)
+ request = self._makeRequest()
+ self.assertEqual(result(None, request), 'OK')
+
+ def test_view_as_instance_context_and_request(self):
+ class View:
+ def __call__(self, context, request):
+ return 'OK'
+
+ view = View()
+ mapper = self._makeOne()
+ result = mapper(view)
+ self.assertTrue(result is view)
+ request = self._makeRequest()
+ self.assertEqual(result(None, request), 'OK')
+
+ def test_view_as_instance_context_and_request_and_attr(self):
+ class View:
+ def index(self, context, request):
+ return 'OK'
+
+ view = View()
+ mapper = self._makeOne(attr='index')
+ result = mapper(view)
+ self.assertFalse(result is view)
+ request = self._makeRequest()
+ self.assertEqual(result(None, request), 'OK')
+
+ def test_view_as_instance_requestonly(self):
+ class View:
+ def __call__(self, request):
+ return 'OK'
+
+ view = View()
+ mapper = self._makeOne()
+ result = mapper(view)
+ self.assertFalse(result is view)
+ request = self._makeRequest()
+ self.assertEqual(result(None, request), 'OK')
+
+ def test_view_as_instance_requestonly_with_attr(self):
+ class View:
+ def index(self, request):
+ return 'OK'
+
+ view = View()
+ mapper = self._makeOne(attr='index')
+ result = mapper(view)
+ self.assertFalse(result is view)
+ request = self._makeRequest()
+ self.assertEqual(result(None, request), 'OK')
+
+
+class Test_preserve_view_attrs(unittest.TestCase):
+ def _callFUT(self, view, wrapped_view):
+ from pyramid.config.views import preserve_view_attrs
+
+ return preserve_view_attrs(view, wrapped_view)
+
+ def test_it_same(self):
+ def view(context, request):
+ """ """
+
+ result = self._callFUT(view, view)
+ self.assertTrue(result is view)
+
+ def test_it_view_is_None(self):
+ def view(context, request):
+ """ """
+
+ result = self._callFUT(None, view)
+ self.assertTrue(result is view)
+
+ def test_it_different_with_existing_original_view(self):
+ def view1(context, request): # pragma: no cover
+ pass
+
+ view1.__original_view__ = 'abc'
+
+ def view2(context, request): # pragma: no cover
+ pass
+
+ result = self._callFUT(view1, view2)
+ self.assertEqual(result.__original_view__, 'abc')
+ self.assertFalse(result is view1)
+
+ def test_it_different(self):
+ class DummyView1:
+ """ 1 """
+
+ __name__ = '1'
+ __module__ = '1'
+
+ def __call__(self, context, request):
+ """ """
+
+ def __call_permissive__(self, context, request):
+ """ """
+
+ def __predicated__(self, context, request):
+ """ """
+
+ def __permitted__(self, context, request):
+ """ """
+
+ class DummyView2:
+ """ 2 """
+
+ __name__ = '2'
+ __module__ = '2'
+
+ def __call__(self, context, request):
+ """ """
+
+ def __call_permissive__(self, context, request):
+ """ """
+
+ def __predicated__(self, context, request):
+ """ """
+
+ def __permitted__(self, context, request):
+ """ """
+
+ view1 = DummyView1()
+ view2 = DummyView2()
+ result = self._callFUT(view2, view1)
+ self.assertEqual(result, view1)
+ self.assertTrue(view1.__original_view__ is view2)
+ self.assertTrue(view1.__doc__ is view2.__doc__)
+ self.assertTrue(view1.__module__ is view2.__module__)
+ self.assertTrue(view1.__name__ is view2.__name__)
+ self.assertTrue(
+ getattr(view1.__call_permissive__, im_func)
+ is getattr(view2.__call_permissive__, im_func)
+ )
+ self.assertTrue(
+ getattr(view1.__permitted__, im_func)
+ is getattr(view2.__permitted__, im_func)
+ )
+ self.assertTrue(
+ getattr(view1.__predicated__, im_func)
+ is getattr(view2.__predicated__, im_func)
+ )
+
+
+class TestStaticURLInfo(unittest.TestCase):
+ def _getTargetClass(self):
+ from pyramid.config.views import StaticURLInfo
+
+ return StaticURLInfo
+
+ def _makeOne(self):
+ return self._getTargetClass()()
+
+ def _makeRequest(self):
+ request = DummyRequest()
+ request.registry = DummyRegistry()
+ return request
+
+ def test_verifyClass(self):
+ from pyramid.interfaces import IStaticURLInfo
+ from zope.interface.verify import verifyClass
+
+ verifyClass(IStaticURLInfo, self._getTargetClass())
+
+ def test_verifyObject(self):
+ from pyramid.interfaces import IStaticURLInfo
+ from zope.interface.verify import verifyObject
+
+ verifyObject(IStaticURLInfo, self._makeOne())
+
+ def test_generate_missing(self):
+ inst = self._makeOne()
+ request = self._makeRequest()
+ self.assertRaises(ValueError, inst.generate, 'path', request)
+
+ def test_generate_registration_miss(self):
+ inst = self._makeOne()
+ inst.registrations = [
+ (None, 'spec', 'route_name'),
+ ('http://example.com/foo/', 'package:path/', None),
+ ]
+ request = self._makeRequest()
+ result = inst.generate('package:path/abc', request)
+ self.assertEqual(result, 'http://example.com/foo/abc')
+
+ def test_generate_slash_in_name1(self):
+ inst = self._makeOne()
+ inst.registrations = [
+ ('http://example.com/foo/', 'package:path/', None)
+ ]
+ request = self._makeRequest()
+ result = inst.generate('package:path/abc', request)
+ self.assertEqual(result, 'http://example.com/foo/abc')
+
+ def test_generate_slash_in_name2(self):
+ inst = self._makeOne()
+ inst.registrations = [
+ ('http://example.com/foo/', 'package:path/', None)
+ ]
+ request = self._makeRequest()
+ result = inst.generate('package:path/', request)
+ self.assertEqual(result, 'http://example.com/foo/')
+
+ def test_generate_quoting(self):
+ from pyramid.interfaces import IStaticURLInfo
+
+ config = testing.setUp()
+ try:
+ config.add_static_view('images', path='mypkg:templates')
+ request = testing.DummyRequest()
+ request.registry = config.registry
+ inst = config.registry.getUtility(IStaticURLInfo)
+ result = inst.generate('mypkg:templates/foo%2Fbar', request)
+ self.assertEqual(result, 'http://example.com/images/foo%252Fbar')
+ finally:
+ testing.tearDown()
+
+ def test_generate_route_url(self):
+ inst = self._makeOne()
+ inst.registrations = [(None, 'package:path/', '__viewname/')]
+
+ def route_url(n, **kw):
+ self.assertEqual(n, '__viewname/')
+ self.assertEqual(kw, {'subpath': 'abc', 'a': 1})
+ return 'url'
+
+ request = self._makeRequest()
+ request.route_url = route_url
+ result = inst.generate('package:path/abc', request, a=1)
+ self.assertEqual(result, 'url')
+
+ def test_generate_url_unquoted_local(self):
+ inst = self._makeOne()
+ inst.registrations = [(None, 'package:path/', '__viewname/')]
+
+ def route_url(n, **kw):
+ self.assertEqual(n, '__viewname/')
+ self.assertEqual(kw, {'subpath': 'abc def', 'a': 1})
+ return 'url'
+
+ request = self._makeRequest()
+ request.route_url = route_url
+ result = inst.generate('package:path/abc def', request, a=1)
+ self.assertEqual(result, 'url')
+
+ def test_generate_url_quoted_remote(self):
+ inst = self._makeOne()
+ inst.registrations = [('http://example.com/', 'package:path/', None)]
+ request = self._makeRequest()
+ result = inst.generate('package:path/abc def', request, a=1)
+ self.assertEqual(result, 'http://example.com/abc%20def')
+
+ def test_generate_url_with_custom_query(self):
+ inst = self._makeOne()
+ registrations = [('http://example.com/', 'package:path/', None)]
+ inst.registrations = registrations
+ request = self._makeRequest()
+ result = inst.generate(
+ 'package:path/abc def', request, a=1, _query='(openlayers)'
+ )
+ self.assertEqual(result, 'http://example.com/abc%20def?(openlayers)')
+
+ def test_generate_url_with_custom_anchor(self):
+ inst = self._makeOne()
+ inst.registrations = [('http://example.com/', 'package:path/', None)]
+ request = self._makeRequest()
+ uc = text_(b'La Pe\xc3\xb1a', 'utf-8')
+ result = inst.generate(
+ 'package:path/abc def', request, a=1, _anchor=uc
+ )
+ self.assertEqual(result, 'http://example.com/abc%20def#La%20Pe%C3%B1a')
+
+ def test_generate_url_cachebust(self):
+ def cachebust(request, subpath, kw):
+ kw['foo'] = 'bar'
+ return 'foo' + '/' + subpath, kw
+
+ inst = self._makeOne()
+ inst.registrations = [(None, 'package:path/', '__viewname')]
+ inst.cache_busters = [('package:path/', cachebust, False)]
+ request = self._makeRequest()
+ called = [False]
+
+ def route_url(n, **kw):
+ called[0] = True
+ self.assertEqual(n, '__viewname')
+ self.assertEqual(
+ kw,
+ {
+ 'subpath': 'foo/abc',
+ 'foo': 'bar',
+ 'pathspec': 'package:path/abc',
+ 'rawspec': 'package:path/abc',
+ },
+ )
+
+ request.route_url = route_url
+ inst.generate('package:path/abc', request)
+ self.assertTrue(called[0])
+
+ def test_generate_url_cachebust_abspath(self):
+ here = os.path.dirname(__file__) + os.sep
+
+ def cachebust(pathspec, subpath, kw):
+ kw['foo'] = 'bar'
+ return 'foo' + '/' + subpath, kw
+
+ inst = self._makeOne()
+ inst.registrations = [(None, here, '__viewname')]
+ inst.cache_busters = [(here, cachebust, False)]
+ request = self._makeRequest()
+ called = [False]
+
+ def route_url(n, **kw):
+ called[0] = True
+ self.assertEqual(n, '__viewname')
+ self.assertEqual(
+ kw,
+ {
+ 'subpath': 'foo/abc',
+ 'foo': 'bar',
+ 'pathspec': here + 'abc',
+ 'rawspec': here + 'abc',
+ },
+ )
+
+ request.route_url = route_url
+ inst.generate(here + 'abc', request)
+ self.assertTrue(called[0])
+
+ def test_generate_url_cachebust_nomatch(self):
+ def fake_cb(*a, **kw): # pragma: no cover
+ raise AssertionError
+
+ inst = self._makeOne()
+ inst.registrations = [(None, 'package:path/', '__viewname')]
+ inst.cache_busters = [('package:path2/', fake_cb, False)]
+ request = self._makeRequest()
+ called = [False]
+
+ def route_url(n, **kw):
+ called[0] = True
+ self.assertEqual(n, '__viewname')
+ self.assertEqual(
+ kw,
+ {
+ 'subpath': 'abc',
+ 'pathspec': 'package:path/abc',
+ 'rawspec': 'package:path/abc',
+ },
+ )
+
+ request.route_url = route_url
+ inst.generate('package:path/abc', request)
+ self.assertTrue(called[0])
+
+ def test_generate_url_cachebust_with_overrides(self):
+ config = testing.setUp()
+ try:
+ request = testing.DummyRequest()
+ config.add_static_view('static', 'path')
+ config.override_asset(
+ 'tests.test_config:path/', 'tests.test_config:other_path/'
+ )
+
+ def cb(val):
+ def cb_(request, subpath, kw):
+ kw['_query'] = {'x': val}
+ return subpath, kw
+
+ return cb_
+
+ config.add_cache_buster('path', cb('foo'))
+ result = request.static_url('path/foo.png')
+ self.assertEqual(result, 'http://example.com/static/foo.png?x=foo')
+ config.add_cache_buster('other_path', cb('bar'), explicit=True)
+ result = request.static_url('path/foo.png')
+ self.assertEqual(result, 'http://example.com/static/foo.png?x=bar')
+ finally:
+ testing.tearDown()
+
+ def test_add_already_exists(self):
+ config = DummyConfig()
+ inst = self._makeOne()
+ inst.registrations = [('http://example.com/', 'package:path/', None)]
+ inst.add(config, 'http://example.com', 'anotherpackage:path')
+ expected = [('http://example.com/', 'anotherpackage:path/', None)]
+ self.assertEqual(inst.registrations, expected)
+
+ def test_add_package_root(self):
+ config = DummyConfig()
+ inst = self._makeOne()
+ inst.add(config, 'http://example.com', 'package:')
+ expected = [('http://example.com/', 'package:', None)]
+ self.assertEqual(inst.registrations, expected)
+
+ def test_add_url_withendslash(self):
+ config = DummyConfig()
+ inst = self._makeOne()
+ inst.add(config, 'http://example.com/', 'anotherpackage:path')
+ expected = [('http://example.com/', 'anotherpackage:path/', None)]
+ self.assertEqual(inst.registrations, expected)
+
+ def test_add_url_noendslash(self):
+ config = DummyConfig()
+ inst = self._makeOne()
+ inst.add(config, 'http://example.com', 'anotherpackage:path')
+ expected = [('http://example.com/', 'anotherpackage:path/', None)]
+ self.assertEqual(inst.registrations, expected)
+
+ def test_add_url_noscheme(self):
+ config = DummyConfig()
+ inst = self._makeOne()
+ inst.add(config, '//example.com', 'anotherpackage:path')
+ expected = [('//example.com/', 'anotherpackage:path/', None)]
+ self.assertEqual(inst.registrations, expected)
+
+ def test_add_viewname(self):
+ from pyramid.security import NO_PERMISSION_REQUIRED
+ from pyramid.static import static_view
+
+ config = DummyConfig()
+ inst = self._makeOne()
+ inst.add(config, 'view', 'anotherpackage:path', cache_max_age=1)
+ expected = [(None, 'anotherpackage:path/', '__view/')]
+ self.assertEqual(inst.registrations, expected)
+ self.assertEqual(config.route_args, ('__view/', 'view/*subpath'))
+ self.assertEqual(config.view_kw['permission'], NO_PERMISSION_REQUIRED)
+ self.assertEqual(config.view_kw['view'].__class__, static_view)
+
+ def test_add_viewname_with_route_prefix(self):
+ config = DummyConfig()
+ config.route_prefix = '/abc'
+ inst = self._makeOne()
+ inst.add(config, 'view', 'anotherpackage:path')
+ expected = [(None, 'anotherpackage:path/', '__/abc/view/')]
+ self.assertEqual(inst.registrations, expected)
+ self.assertEqual(config.route_args, ('__/abc/view/', 'view/*subpath'))
+
+ def test_add_viewname_with_permission(self):
+ config = DummyConfig()
+ inst = self._makeOne()
+ inst.add(
+ config,
+ 'view',
+ 'anotherpackage:path',
+ cache_max_age=1,
+ permission='abc',
+ )
+ self.assertEqual(config.view_kw['permission'], 'abc')
+
+ def test_add_viewname_with_context(self):
+ config = DummyConfig()
+ inst = self._makeOne()
+ inst.add(
+ config,
+ 'view',
+ 'anotherpackage:path',
+ cache_max_age=1,
+ context=DummyContext,
+ )
+ self.assertEqual(config.view_kw['context'], DummyContext)
+
+ def test_add_viewname_with_for_(self):
+ config = DummyConfig()
+ inst = self._makeOne()
+ inst.add(
+ config,
+ 'view',
+ 'anotherpackage:path',
+ cache_max_age=1,
+ for_=DummyContext,
+ )
+ self.assertEqual(config.view_kw['context'], DummyContext)
+
+ def test_add_viewname_with_renderer(self):
+ config = DummyConfig()
+ inst = self._makeOne()
+ inst.add(
+ config,
+ 'view',
+ 'anotherpackage:path',
+ cache_max_age=1,
+ renderer='mypackage:templates/index.pt',
+ )
+ self.assertEqual(
+ config.view_kw['renderer'], 'mypackage:templates/index.pt'
+ )
+
+ def test_add_cachebust_prevented(self):
+ config = DummyConfig()
+ config.registry.settings['pyramid.prevent_cachebust'] = True
+ inst = self._makeOne()
+ cachebust = DummyCacheBuster('foo')
+ inst.add_cache_buster(config, 'mypackage:path', cachebust)
+ self.assertEqual(inst.cache_busters, [])
+
+ def test_add_cachebuster(self):
+ config = DummyConfig()
+ inst = self._makeOne()
+ inst.add_cache_buster(
+ config, 'mypackage:path', DummyCacheBuster('foo')
+ )
+ cachebust = inst.cache_busters[-1][1]
+ subpath, kw = cachebust(None, 'some/path', {})
+ self.assertEqual(subpath, 'some/path')
+ self.assertEqual(kw['x'], 'foo')
+
+ def test_add_cachebuster_abspath(self):
+ here = os.path.dirname(__file__)
+ config = DummyConfig()
+ inst = self._makeOne()
+ cb = DummyCacheBuster('foo')
+ inst.add_cache_buster(config, here, cb)
+ self.assertEqual(inst.cache_busters, [(here + os.sep, cb, False)])
+
+ def test_add_cachebuster_overwrite(self):
+ config = DummyConfig()
+ inst = self._makeOne()
+ cb1 = DummyCacheBuster('foo')
+ cb2 = DummyCacheBuster('bar')
+ inst.add_cache_buster(config, 'mypackage:path/', cb1)
+ inst.add_cache_buster(config, 'mypackage:path', cb2)
+ self.assertEqual(inst.cache_busters, [('mypackage:path/', cb2, False)])
+
+ def test_add_cachebuster_overwrite_explicit(self):
+ config = DummyConfig()
+ inst = self._makeOne()
+ cb1 = DummyCacheBuster('foo')
+ cb2 = DummyCacheBuster('bar')
+ inst.add_cache_buster(config, 'mypackage:path/', cb1)
+ inst.add_cache_buster(config, 'mypackage:path', cb2, True)
+ self.assertEqual(
+ inst.cache_busters,
+ [('mypackage:path/', cb1, False), ('mypackage:path/', cb2, True)],
+ )
+
+ def test_add_cachebuster_for_more_specific_path(self):
+ config = DummyConfig()
+ inst = self._makeOne()
+ cb1 = DummyCacheBuster('foo')
+ cb2 = DummyCacheBuster('bar')
+ cb3 = DummyCacheBuster('baz')
+ cb4 = DummyCacheBuster('xyz')
+ cb5 = DummyCacheBuster('w')
+ inst.add_cache_buster(config, 'mypackage:path', cb1)
+ inst.add_cache_buster(config, 'mypackage:path/sub', cb2, True)
+ inst.add_cache_buster(config, 'mypackage:path/sub/other', cb3)
+ inst.add_cache_buster(config, 'mypackage:path/sub/other', cb4, True)
+ inst.add_cache_buster(config, 'mypackage:path/sub/less', cb5, True)
+ self.assertEqual(
+ inst.cache_busters,
+ [
+ ('mypackage:path/', cb1, False),
+ ('mypackage:path/sub/other/', cb3, False),
+ ('mypackage:path/sub/', cb2, True),
+ ('mypackage:path/sub/less/', cb5, True),
+ ('mypackage:path/sub/other/', cb4, True),
+ ],
+ )
+
+
+class Test_view_description(unittest.TestCase):
+ def _callFUT(self, view):
+ from pyramid.config.views import view_description
+
+ return view_description(view)
+
+ def test_with_text(self):
+ def view(): # pragma: no cover
+ pass
+
+ view.__text__ = 'some text'
+ result = self._callFUT(view)
+ self.assertEqual(result, 'some text')
+
+ def test_without_text(self):
+ def view(): # pragma: no cover
+ pass
+
+ result = self._callFUT(view)
+ self.assertEqual(result, 'function tests.test_config.test_views.view')
+
+
+class Test_viewdefaults(unittest.TestCase):
+ def _makeOne(self, wrapped):
+ from pyramid.decorator import reify
+
+ return reify(wrapped)
+
+ def test_dunder_attrs_copied(self):
+ from pyramid.config.views import viewdefaults
+
+ decorator = self._makeOne(viewdefaults)
+ self.assertEqual(decorator.__doc__, viewdefaults.__doc__)
+ self.assertEqual(decorator.__name__, viewdefaults.__name__)
+ self.assertEqual(decorator.__module__, viewdefaults.__module__)
+
+
+class DummyRegistry:
+ utility = None
+
+ def __init__(self):
+ self.settings = {}
+
+ def queryUtility(self, type_or_iface, name=None, default=None):
+ return self.utility or default
+
+
+@implementer(IResponse)
+class DummyResponse(object):
+ content_type = None
+ default_content_type = None
+ body = None
+
+
+class DummyRequest:
+ subpath = ()
+ matchdict = None
+ request_iface = IRequest
+ application_url = 'http://example.com/foo'
+
+ def __init__(self, environ=None):
+ if environ is None:
+ environ = {}
+ self.environ = environ
+ self.params = {}
+ self.cookies = {}
+ self.response = DummyResponse()
+
+
+class DummyContext:
+ pass
+
+
+class DummyAccept(object):
+ def __init__(self, *matches, **kw):
+ self.matches = list(matches)
+ self.contains = kw.pop('contains', False)
+
+ def acceptable_offers(self, offers):
+ results = []
+ for match in self.matches:
+ if match in offers:
+ results.append((match, 1.0))
+ return results
+
+
+class DummyConfig:
+ def __init__(self):
+ self.registry = DummyRegistry()
+
+ route_prefix = ''
+
+ def add_route(self, *args, **kw):
+ self.route_args = args
+ self.route_kw = kw
+
+ def add_view(self, *args, **kw):
+ self.view_args = args
+ self.view_kw = kw
+
+ def action(self, discriminator, callable, introspectables=()):
+ callable()
+
+ def introspectable(self, *arg):
+ return {}
+
+
+@implementer(IMultiView)
+class DummyMultiView:
+ def __init__(self):
+ self.views = []
+ self.name = 'name'
+
+ def add(self, view, order, phash=None, accept=None, accept_order=None):
+ self.views.append((view, phash, accept, accept_order))
+
+ def __call__(self, context, request):
+ return 'OK1'
+
+ def __permitted__(self, context, request):
+ """ """
+
+
+class DummyCacheBuster(object):
+ def __init__(self, token):
+ self.token = token
+
+ def __call__(self, request, subpath, kw):
+ kw['x'] = self.token
+ return subpath, kw
+
+
+def parse_httpdate(s):
+ import datetime
+
+ # cannot use %Z, must use literal GMT; Jython honors timezone
+ # but CPython does not
+ return datetime.datetime.strptime(s, "%a, %d %b %Y %H:%M:%S GMT")
+
+
+def assert_similar_datetime(one, two):
+ for attr in ('year', 'month', 'day', 'hour', 'minute'):
+ one_attr = getattr(one, attr)
+ two_attr = getattr(two, attr)
+ if not one_attr == two_attr: # pragma: no cover
+ raise AssertionError('%r != %r in %s' % (one_attr, two_attr, attr))
+
+
+class DummyStaticURLInfo:
+ def __init__(self):
+ self.added = []
+
+ def add(self, config, name, spec, **kw):
+ self.added.append((config, name, spec, kw))
+
+
+class DummyViewDefaultsClass(object):
+ __view_defaults__ = {'containment': 'tests.test_config.IDummy'}
+
+ def __init__(self, request):
+ pass
+
+ def __call__(self):
+ return 'OK'
+
+
+class DummyPredicate(object):
+ def __init__(self, val, config):
+ self.val = val
+
+ def text(self):
+ return 'dummy'
+
+ phash = text
+
+
+class DummyIntrospector(object):
+ def __init__(self, getval=None):
+ self.related = []
+ self.introspectables = []
+ self.getval = getval
+
+ def add(self, introspectable):
+ self.introspectables.append(introspectable)
+
+ def get(self, name, discrim):
+ return self.getval
+
+ def relate(self, a, b):
+ self.related.append((a, b))
+
+
+class DummySession(dict):
+ def get_csrf_token(self):
+ return self['csrf_token']
diff --git a/tests/test_csrf.py b/tests/test_csrf.py
new file mode 100644
index 000000000..d1b569c32
--- /dev/null
+++ b/tests/test_csrf.py
@@ -0,0 +1,436 @@
+import unittest
+
+from pyramid import testing
+from pyramid.config import Configurator
+
+
+class TestLegacySessionCSRFStoragePolicy(unittest.TestCase):
+ class MockSession(object):
+ def __init__(self, current_token='02821185e4c94269bdc38e6eeae0a2f8'):
+ self.current_token = current_token
+
+ def new_csrf_token(self):
+ self.current_token = 'e5e9e30a08b34ff9842ff7d2b958c14b'
+ return self.current_token
+
+ def get_csrf_token(self):
+ return self.current_token
+
+ def _makeOne(self):
+ from pyramid.csrf import LegacySessionCSRFStoragePolicy
+
+ return LegacySessionCSRFStoragePolicy()
+
+ def test_register_session_csrf_policy(self):
+ from pyramid.csrf import LegacySessionCSRFStoragePolicy
+ from pyramid.interfaces import ICSRFStoragePolicy
+
+ config = Configurator()
+ config.set_csrf_storage_policy(self._makeOne())
+ config.commit()
+
+ policy = config.registry.queryUtility(ICSRFStoragePolicy)
+
+ self.assertTrue(isinstance(policy, LegacySessionCSRFStoragePolicy))
+
+ def test_session_csrf_implementation_delegates_to_session(self):
+ policy = self._makeOne()
+ request = DummyRequest(session=self.MockSession())
+
+ self.assertEqual(
+ policy.get_csrf_token(request), '02821185e4c94269bdc38e6eeae0a2f8'
+ )
+ self.assertEqual(
+ policy.new_csrf_token(request), 'e5e9e30a08b34ff9842ff7d2b958c14b'
+ )
+
+ def test_check_csrf_token(self):
+ request = DummyRequest(session=self.MockSession('foo'))
+
+ policy = self._makeOne()
+ self.assertTrue(policy.check_csrf_token(request, 'foo'))
+ self.assertFalse(policy.check_csrf_token(request, 'bar'))
+
+
+class TestSessionCSRFStoragePolicy(unittest.TestCase):
+ def _makeOne(self, **kw):
+ from pyramid.csrf import SessionCSRFStoragePolicy
+
+ return SessionCSRFStoragePolicy(**kw)
+
+ def test_register_session_csrf_policy(self):
+ from pyramid.csrf import SessionCSRFStoragePolicy
+ from pyramid.interfaces import ICSRFStoragePolicy
+
+ config = Configurator()
+ config.set_csrf_storage_policy(self._makeOne())
+ config.commit()
+
+ policy = config.registry.queryUtility(ICSRFStoragePolicy)
+
+ self.assertTrue(isinstance(policy, SessionCSRFStoragePolicy))
+
+ def test_it_creates_a_new_token(self):
+ request = DummyRequest(session={})
+
+ policy = self._makeOne()
+ policy._token_factory = lambda: 'foo'
+ self.assertEqual(policy.get_csrf_token(request), 'foo')
+
+ def test_get_csrf_token_returns_the_new_token(self):
+ request = DummyRequest(session={'_csrft_': 'foo'})
+
+ policy = self._makeOne()
+ self.assertEqual(policy.get_csrf_token(request), 'foo')
+
+ token = policy.new_csrf_token(request)
+ self.assertNotEqual(token, 'foo')
+ self.assertEqual(token, policy.get_csrf_token(request))
+
+ def test_check_csrf_token(self):
+ request = DummyRequest(session={})
+
+ policy = self._makeOne()
+ self.assertFalse(policy.check_csrf_token(request, 'foo'))
+
+ request.session = {'_csrft_': 'foo'}
+ self.assertTrue(policy.check_csrf_token(request, 'foo'))
+ self.assertFalse(policy.check_csrf_token(request, 'bar'))
+
+
+class TestCookieCSRFStoragePolicy(unittest.TestCase):
+ def _makeOne(self, **kw):
+ from pyramid.csrf import CookieCSRFStoragePolicy
+
+ return CookieCSRFStoragePolicy(**kw)
+
+ def test_register_cookie_csrf_policy(self):
+ from pyramid.csrf import CookieCSRFStoragePolicy
+ from pyramid.interfaces import ICSRFStoragePolicy
+
+ config = Configurator()
+ config.set_csrf_storage_policy(self._makeOne())
+ config.commit()
+
+ policy = config.registry.queryUtility(ICSRFStoragePolicy)
+
+ self.assertTrue(isinstance(policy, CookieCSRFStoragePolicy))
+
+ def test_get_cookie_csrf_with_no_existing_cookie_sets_cookies(self):
+ response = MockResponse()
+ request = DummyRequest()
+
+ policy = self._makeOne()
+ token = policy.get_csrf_token(request)
+ request.response_callback(request, response)
+ self.assertEqual(
+ response.headerlist,
+ [
+ (
+ 'Set-Cookie',
+ 'csrf_token={}; Path=/; SameSite=Lax'.format(token),
+ )
+ ],
+ )
+
+ def test_get_cookie_csrf_nondefault_samesite(self):
+ response = MockResponse()
+ request = DummyRequest()
+
+ policy = self._makeOne(samesite=None)
+ token = policy.get_csrf_token(request)
+ request.response_callback(request, response)
+ self.assertEqual(
+ response.headerlist,
+ [('Set-Cookie', 'csrf_token={}; Path=/'.format(token))],
+ )
+
+ def test_existing_cookie_csrf_does_not_set_cookie(self):
+ request = DummyRequest()
+ request.cookies = {'csrf_token': 'e6f325fee5974f3da4315a8ccf4513d2'}
+
+ policy = self._makeOne()
+ token = policy.get_csrf_token(request)
+
+ self.assertEqual(token, 'e6f325fee5974f3da4315a8ccf4513d2')
+ self.assertIsNone(request.response_callback)
+
+ def test_new_cookie_csrf_with_existing_cookie_sets_cookies(self):
+ request = DummyRequest()
+ request.cookies = {'csrf_token': 'e6f325fee5974f3da4315a8ccf4513d2'}
+
+ policy = self._makeOne()
+ token = policy.new_csrf_token(request)
+
+ response = MockResponse()
+ request.response_callback(request, response)
+ self.assertEqual(
+ response.headerlist,
+ [
+ (
+ 'Set-Cookie',
+ 'csrf_token={}; Path=/; SameSite=Lax'.format(token),
+ )
+ ],
+ )
+
+ def test_get_csrf_token_returns_the_new_token(self):
+ request = DummyRequest()
+ request.cookies = {'csrf_token': 'foo'}
+
+ policy = self._makeOne()
+ self.assertEqual(policy.get_csrf_token(request), 'foo')
+
+ token = policy.new_csrf_token(request)
+ self.assertNotEqual(token, 'foo')
+ self.assertEqual(token, policy.get_csrf_token(request))
+
+ def test_check_csrf_token(self):
+ request = DummyRequest()
+
+ policy = self._makeOne()
+ self.assertFalse(policy.check_csrf_token(request, 'foo'))
+
+ request.cookies = {'csrf_token': 'foo'}
+ self.assertTrue(policy.check_csrf_token(request, 'foo'))
+ self.assertFalse(policy.check_csrf_token(request, 'bar'))
+
+
+class Test_get_csrf_token(unittest.TestCase):
+ def setUp(self):
+ self.config = testing.setUp()
+
+ def _callFUT(self, *args, **kwargs):
+ from pyramid.csrf import get_csrf_token
+
+ return get_csrf_token(*args, **kwargs)
+
+ def test_no_override_csrf_utility_registered(self):
+ request = testing.DummyRequest()
+ self._callFUT(request)
+
+ def test_success(self):
+ self.config.set_csrf_storage_policy(DummyCSRF())
+ request = testing.DummyRequest()
+
+ csrf_token = self._callFUT(request)
+
+ self.assertEquals(csrf_token, '02821185e4c94269bdc38e6eeae0a2f8')
+
+
+class Test_new_csrf_token(unittest.TestCase):
+ def setUp(self):
+ self.config = testing.setUp()
+
+ def _callFUT(self, *args, **kwargs):
+ from pyramid.csrf import new_csrf_token
+
+ return new_csrf_token(*args, **kwargs)
+
+ def test_no_override_csrf_utility_registered(self):
+ request = testing.DummyRequest()
+ self._callFUT(request)
+
+ def test_success(self):
+ self.config.set_csrf_storage_policy(DummyCSRF())
+ request = testing.DummyRequest()
+
+ csrf_token = self._callFUT(request)
+
+ self.assertEquals(csrf_token, 'e5e9e30a08b34ff9842ff7d2b958c14b')
+
+
+class Test_check_csrf_token(unittest.TestCase):
+ def setUp(self):
+ self.config = testing.setUp()
+
+ # set up CSRF
+ self.config.set_default_csrf_options(require_csrf=False)
+
+ def _callFUT(self, *args, **kwargs):
+ from pyramid.csrf import check_csrf_token
+
+ return check_csrf_token(*args, **kwargs)
+
+ def test_success_token(self):
+ request = testing.DummyRequest()
+ request.method = "POST"
+ request.POST = {'csrf_token': request.session.get_csrf_token()}
+ self.assertEqual(self._callFUT(request, token='csrf_token'), True)
+
+ def test_success_header(self):
+ request = testing.DummyRequest()
+ request.headers['X-CSRF-Token'] = request.session.get_csrf_token()
+ self.assertEqual(self._callFUT(request, header='X-CSRF-Token'), True)
+
+ def test_success_default_token(self):
+ request = testing.DummyRequest()
+ request.method = "POST"
+ request.POST = {'csrf_token': request.session.get_csrf_token()}
+ self.assertEqual(self._callFUT(request), True)
+
+ def test_success_default_header(self):
+ request = testing.DummyRequest()
+ request.headers['X-CSRF-Token'] = request.session.get_csrf_token()
+ self.assertEqual(self._callFUT(request), True)
+
+ def test_failure_raises(self):
+ from pyramid.exceptions import BadCSRFToken
+
+ request = testing.DummyRequest()
+ self.assertRaises(BadCSRFToken, self._callFUT, request, 'csrf_token')
+
+ def test_failure_no_raises(self):
+ request = testing.DummyRequest()
+ result = self._callFUT(request, 'csrf_token', raises=False)
+ self.assertEqual(result, False)
+
+
+class Test_check_csrf_token_without_defaults_configured(unittest.TestCase):
+ def setUp(self):
+ self.config = testing.setUp()
+
+ def _callFUT(self, *args, **kwargs):
+ from pyramid.csrf import check_csrf_token
+
+ return check_csrf_token(*args, **kwargs)
+
+ def test_success_token(self):
+ request = testing.DummyRequest()
+ request.method = "POST"
+ request.POST = {'csrf_token': request.session.get_csrf_token()}
+ self.assertEqual(self._callFUT(request, token='csrf_token'), True)
+
+ def test_failure_raises(self):
+ from pyramid.exceptions import BadCSRFToken
+
+ request = testing.DummyRequest()
+ self.assertRaises(BadCSRFToken, self._callFUT, request, 'csrf_token')
+
+ def test_failure_no_raises(self):
+ request = testing.DummyRequest()
+ result = self._callFUT(request, 'csrf_token', raises=False)
+ self.assertEqual(result, False)
+
+
+class Test_check_csrf_origin(unittest.TestCase):
+ def _callFUT(self, *args, **kwargs):
+ from pyramid.csrf import check_csrf_origin
+
+ return check_csrf_origin(*args, **kwargs)
+
+ def test_success_with_http(self):
+ request = testing.DummyRequest()
+ request.scheme = "http"
+ self.assertTrue(self._callFUT(request))
+
+ def test_success_with_https_and_referrer(self):
+ request = testing.DummyRequest()
+ request.scheme = "https"
+ request.host = "example.com"
+ request.host_port = "443"
+ request.referrer = "https://example.com/login/"
+ request.registry.settings = {}
+ self.assertTrue(self._callFUT(request))
+
+ def test_success_with_https_and_origin(self):
+ request = testing.DummyRequest()
+ request.scheme = "https"
+ request.host = "example.com"
+ request.host_port = "443"
+ request.headers = {"Origin": "https://example.com/"}
+ request.referrer = "https://not-example.com/"
+ request.registry.settings = {}
+ self.assertTrue(self._callFUT(request))
+
+ def test_success_with_additional_trusted_host(self):
+ request = testing.DummyRequest()
+ request.scheme = "https"
+ request.host = "example.com"
+ request.host_port = "443"
+ request.referrer = "https://not-example.com/login/"
+ request.registry.settings = {
+ "pyramid.csrf_trusted_origins": ["not-example.com"]
+ }
+ self.assertTrue(self._callFUT(request))
+
+ def test_success_with_nonstandard_port(self):
+ request = testing.DummyRequest()
+ request.scheme = "https"
+ request.host = "example.com:8080"
+ request.host_port = "8080"
+ request.referrer = "https://example.com:8080/login/"
+ request.registry.settings = {}
+ self.assertTrue(self._callFUT(request))
+
+ def test_fails_with_wrong_host(self):
+ from pyramid.exceptions import BadCSRFOrigin
+
+ request = testing.DummyRequest()
+ request.scheme = "https"
+ request.host = "example.com"
+ request.host_port = "443"
+ request.referrer = "https://not-example.com/login/"
+ request.registry.settings = {}
+ self.assertRaises(BadCSRFOrigin, self._callFUT, request)
+ self.assertFalse(self._callFUT(request, raises=False))
+
+ def test_fails_with_no_origin(self):
+ from pyramid.exceptions import BadCSRFOrigin
+
+ request = testing.DummyRequest()
+ request.scheme = "https"
+ request.referrer = None
+ self.assertRaises(BadCSRFOrigin, self._callFUT, request)
+ self.assertFalse(self._callFUT(request, raises=False))
+
+ def test_fails_when_http_to_https(self):
+ from pyramid.exceptions import BadCSRFOrigin
+
+ request = testing.DummyRequest()
+ request.scheme = "https"
+ request.host = "example.com"
+ request.host_port = "443"
+ request.referrer = "http://example.com/evil/"
+ request.registry.settings = {}
+ self.assertRaises(BadCSRFOrigin, self._callFUT, request)
+ self.assertFalse(self._callFUT(request, raises=False))
+
+ def test_fails_with_nonstandard_port(self):
+ from pyramid.exceptions import BadCSRFOrigin
+
+ request = testing.DummyRequest()
+ request.scheme = "https"
+ request.host = "example.com:8080"
+ request.host_port = "8080"
+ request.referrer = "https://example.com/login/"
+ request.registry.settings = {}
+ self.assertRaises(BadCSRFOrigin, self._callFUT, request)
+ self.assertFalse(self._callFUT(request, raises=False))
+
+
+class DummyRequest(object):
+ registry = None
+ session = None
+ response_callback = None
+
+ def __init__(self, registry=None, session=None):
+ self.registry = registry
+ self.session = session
+ self.cookies = {}
+
+ def add_response_callback(self, callback):
+ self.response_callback = callback
+
+
+class MockResponse(object):
+ def __init__(self):
+ self.headerlist = []
+
+
+class DummyCSRF(object):
+ def new_csrf_token(self, request):
+ return 'e5e9e30a08b34ff9842ff7d2b958c14b'
+
+ def get_csrf_token(self, request):
+ return '02821185e4c94269bdc38e6eeae0a2f8'
diff --git a/tests/test_decorator.py b/tests/test_decorator.py
new file mode 100644
index 000000000..2dcc9b4d3
--- /dev/null
+++ b/tests/test_decorator.py
@@ -0,0 +1,30 @@
+import unittest
+
+
+class TestReify(unittest.TestCase):
+ def _makeOne(self, wrapped):
+ from pyramid.decorator import reify
+
+ return reify(wrapped)
+
+ def test___get__withinst(self):
+ def wrapped(inst):
+ return 'a'
+
+ decorator = self._makeOne(wrapped)
+ inst = Dummy()
+ result = decorator.__get__(inst)
+ self.assertEqual(result, 'a')
+ self.assertEqual(inst.__dict__['wrapped'], 'a')
+
+ def test___get__noinst(self):
+ def wrapped(inst):
+ return 'a' # pragma: no cover
+
+ decorator = self._makeOne(wrapped)
+ result = decorator.__get__(None)
+ self.assertEqual(result, decorator)
+
+
+class Dummy(object):
+ pass
diff --git a/tests/test_docs.py b/tests/test_docs.py
new file mode 100644
index 000000000..46c9ed765
--- /dev/null
+++ b/tests/test_docs.py
@@ -0,0 +1,36 @@
+import unittest
+
+if 0:
+ # no released version of manuel actually works with :lineno:
+ # settings yet
+ class ManuelDocsCase(unittest.TestCase):
+ def __new__(self, test):
+ return getattr(self, test)()
+
+ @classmethod
+ def test_docs(cls):
+ import os
+ import pkg_resources
+ import manuel.testing
+ import manuel.codeblock
+ import manuel.capture
+ import manuel.ignore
+
+ m = manuel.ignore.Manuel()
+ m += manuel.codeblock.Manuel()
+ m += manuel.capture.Manuel()
+ docs = []
+
+ egg_path = pkg_resources.get_distribution('pyramid').location
+ path = os.path.join(egg_path, 'docs')
+ for root, dirs, files in os.walk(path):
+ for ignore in ('.svn', '.build', '.hg', '.git', 'CVS'):
+ if ignore in dirs:
+ dirs.remove(ignore)
+
+ for filename in files:
+ if filename.endswith('.rst'):
+ docs.append(os.path.join(root, filename))
+
+ print(path)
+ return manuel.testing.TestSuite(m, *docs)
diff --git a/tests/test_encode.py b/tests/test_encode.py
new file mode 100644
index 000000000..f70050cac
--- /dev/null
+++ b/tests/test_encode.py
@@ -0,0 +1,89 @@
+import unittest
+from pyramid.compat import text_, native_
+
+
+class UrlEncodeTests(unittest.TestCase):
+ def _callFUT(self, query, doseq=False, **kw):
+ from pyramid.encode import urlencode
+
+ return urlencode(query, doseq, **kw)
+
+ def test_ascii_only(self):
+ result = self._callFUT([('a', 1), ('b', 2)])
+ self.assertEqual(result, 'a=1&b=2')
+
+ def test_unicode_key(self):
+ la = text_(b'LaPe\xc3\xb1a', 'utf-8')
+ result = self._callFUT([(la, 1), ('b', 2)])
+ self.assertEqual(result, 'LaPe%C3%B1a=1&b=2')
+
+ def test_unicode_val_single(self):
+ la = text_(b'LaPe\xc3\xb1a', 'utf-8')
+ result = self._callFUT([('a', la), ('b', 2)])
+ self.assertEqual(result, 'a=LaPe%C3%B1a&b=2')
+
+ def test_unicode_val_multiple(self):
+ la = [text_(b'LaPe\xc3\xb1a', 'utf-8')] * 2
+ result = self._callFUT([('a', la), ('b', 2)], doseq=True)
+ self.assertEqual(result, 'a=LaPe%C3%B1a&a=LaPe%C3%B1a&b=2')
+
+ def test_int_val_multiple(self):
+ s = [1, 2]
+ result = self._callFUT([('a', s)], doseq=True)
+ self.assertEqual(result, 'a=1&a=2')
+
+ def test_with_spaces(self):
+ result = self._callFUT([('a', '123 456')], doseq=True)
+ self.assertEqual(result, 'a=123+456')
+
+ def test_dict(self):
+ result = self._callFUT({'a': 1})
+ self.assertEqual(result, 'a=1')
+
+ def test_None_value(self):
+ result = self._callFUT([('a', None)])
+ self.assertEqual(result, 'a=')
+
+ def test_None_value_with_prefix(self):
+ result = self._callFUT([('a', '1'), ('b', None)])
+ self.assertEqual(result, 'a=1&b=')
+
+ def test_None_value_with_prefix_values(self):
+ result = self._callFUT([('a', '1'), ('b', None), ('c', None)])
+ self.assertEqual(result, 'a=1&b=&c=')
+
+ def test_quote_via(self):
+ def my_quoter(value):
+ return 'xxx' + value
+
+ result = self._callFUT(
+ [('a', '1'), ('b', None), ('c', None)], quote_via=my_quoter
+ )
+ self.assertEqual(result, 'xxxa=xxx1&xxxb=&xxxc=')
+
+
+class URLQuoteTests(unittest.TestCase):
+ def _callFUT(self, val, safe=''):
+ from pyramid.encode import url_quote
+
+ return url_quote(val, safe)
+
+ def test_it_bytes(self):
+ la = b'La/Pe\xc3\xb1a'
+ result = self._callFUT(la)
+ self.assertEqual(result, 'La%2FPe%C3%B1a')
+
+ def test_it_native(self):
+ la = native_(b'La/Pe\xc3\xb1a', 'utf-8')
+ result = self._callFUT(la)
+ self.assertEqual(result, 'La%2FPe%C3%B1a')
+
+ def test_it_with_safe(self):
+ la = b'La/Pe\xc3\xb1a'
+ result = self._callFUT(la, '/')
+ self.assertEqual(result, 'La/Pe%C3%B1a')
+
+ def test_it_with_nonstr_nonbinary(self):
+ la = None
+ result = self._callFUT(la, '/')
+ self.assertEqual(result, 'None')
diff --git a/tests/test_events.py b/tests/test_events.py
new file mode 100644
index 000000000..25ed5fc0d
--- /dev/null
+++ b/tests/test_events.py
@@ -0,0 +1,411 @@
+import unittest
+from pyramid import testing
+
+
+class NewRequestEventTests(unittest.TestCase):
+ def _getTargetClass(self):
+ from pyramid.events import NewRequest
+
+ return NewRequest
+
+ def _makeOne(self, request):
+ return self._getTargetClass()(request)
+
+ def test_class_conforms_to_INewRequest(self):
+ from pyramid.interfaces import INewRequest
+ from zope.interface.verify import verifyClass
+
+ klass = self._getTargetClass()
+ verifyClass(INewRequest, klass)
+
+ def test_instance_conforms_to_INewRequest(self):
+ from pyramid.interfaces import INewRequest
+ from zope.interface.verify import verifyObject
+
+ request = DummyRequest()
+ inst = self._makeOne(request)
+ verifyObject(INewRequest, inst)
+
+ def test_ctor(self):
+ request = DummyRequest()
+ inst = self._makeOne(request)
+ self.assertEqual(inst.request, request)
+
+
+class NewResponseEventTests(unittest.TestCase):
+ def _getTargetClass(self):
+ from pyramid.events import NewResponse
+
+ return NewResponse
+
+ def _makeOne(self, request, response):
+ return self._getTargetClass()(request, response)
+
+ def test_class_conforms_to_INewResponse(self):
+ from pyramid.interfaces import INewResponse
+ from zope.interface.verify import verifyClass
+
+ klass = self._getTargetClass()
+ verifyClass(INewResponse, klass)
+
+ def test_instance_conforms_to_INewResponse(self):
+ from pyramid.interfaces import INewResponse
+ from zope.interface.verify import verifyObject
+
+ request = DummyRequest()
+ response = DummyResponse()
+ inst = self._makeOne(request, response)
+ verifyObject(INewResponse, inst)
+
+ def test_ctor(self):
+ request = DummyRequest()
+ response = DummyResponse()
+ inst = self._makeOne(request, response)
+ self.assertEqual(inst.request, request)
+ self.assertEqual(inst.response, response)
+
+
+class ApplicationCreatedEventTests(unittest.TestCase):
+ def _getTargetClass(self):
+ from pyramid.events import ApplicationCreated
+
+ return ApplicationCreated
+
+ def _makeOne(self, context=object()):
+ return self._getTargetClass()(context)
+
+ def test_class_conforms_to_IApplicationCreated(self):
+ from pyramid.interfaces import IApplicationCreated
+ from zope.interface.verify import verifyClass
+
+ verifyClass(IApplicationCreated, self._getTargetClass())
+
+ def test_object_conforms_to_IApplicationCreated(self):
+ from pyramid.interfaces import IApplicationCreated
+ from zope.interface.verify import verifyObject
+
+ verifyObject(IApplicationCreated, self._makeOne())
+
+
+class WSGIApplicationCreatedEventTests(ApplicationCreatedEventTests):
+ def _getTargetClass(self):
+ from pyramid.events import WSGIApplicationCreatedEvent
+
+ return WSGIApplicationCreatedEvent
+
+ def test_class_conforms_to_IWSGIApplicationCreatedEvent(self):
+ from pyramid.interfaces import IWSGIApplicationCreatedEvent
+ from zope.interface.verify import verifyClass
+
+ verifyClass(IWSGIApplicationCreatedEvent, self._getTargetClass())
+
+ def test_object_conforms_to_IWSGIApplicationCreatedEvent(self):
+ from pyramid.interfaces import IWSGIApplicationCreatedEvent
+ from zope.interface.verify import verifyObject
+
+ verifyObject(IWSGIApplicationCreatedEvent, self._makeOne())
+
+
+class ContextFoundEventTests(unittest.TestCase):
+ def _getTargetClass(self):
+ from pyramid.events import ContextFound
+
+ return ContextFound
+
+ def _makeOne(self, request=None):
+ if request is None:
+ request = DummyRequest()
+ return self._getTargetClass()(request)
+
+ def test_class_conforms_to_IContextFound(self):
+ from zope.interface.verify import verifyClass
+ from pyramid.interfaces import IContextFound
+
+ verifyClass(IContextFound, self._getTargetClass())
+
+ def test_instance_conforms_to_IContextFound(self):
+ from zope.interface.verify import verifyObject
+ from pyramid.interfaces import IContextFound
+
+ verifyObject(IContextFound, self._makeOne())
+
+
+class AfterTraversalEventTests(ContextFoundEventTests):
+ def _getTargetClass(self):
+ from pyramid.events import AfterTraversal
+
+ return AfterTraversal
+
+ def test_class_conforms_to_IAfterTraversal(self):
+ from zope.interface.verify import verifyClass
+ from pyramid.interfaces import IAfterTraversal
+
+ verifyClass(IAfterTraversal, self._getTargetClass())
+
+ def test_instance_conforms_to_IAfterTraversal(self):
+ from zope.interface.verify import verifyObject
+ from pyramid.interfaces import IAfterTraversal
+
+ verifyObject(IAfterTraversal, self._makeOne())
+
+
+class BeforeTraversalEventTests(unittest.TestCase):
+ def _getTargetClass(self):
+ from pyramid.events import BeforeTraversal
+
+ return BeforeTraversal
+
+ def _makeOne(self, request=None):
+ if request is None:
+ request = DummyRequest()
+ return self._getTargetClass()(request)
+
+ def test_class_conforms_to_IBeforeTraversal(self):
+ from zope.interface.verify import verifyClass
+ from pyramid.interfaces import IBeforeTraversal
+
+ verifyClass(IBeforeTraversal, self._getTargetClass())
+
+ def test_instance_conforms_to_IBeforeTraversal(self):
+ from zope.interface.verify import verifyObject
+ from pyramid.interfaces import IBeforeTraversal
+
+ verifyObject(IBeforeTraversal, self._makeOne())
+
+
+class TestSubscriber(unittest.TestCase):
+ def setUp(self):
+ self.config = testing.setUp()
+
+ def tearDown(self):
+ testing.tearDown()
+
+ def _makeOne(self, *ifaces, **predicates):
+ from pyramid.events import subscriber
+
+ return subscriber(*ifaces, **predicates)
+
+ def test_register_single(self):
+ from zope.interface import Interface
+
+ class IFoo(Interface):
+ pass
+
+ class IBar(Interface):
+ pass
+
+ dec = self._makeOne(IFoo)
+
+ def foo(): # pragma: no cover
+ pass
+
+ config = DummyConfigurator()
+ scanner = Dummy()
+ scanner.config = config
+ dec.register(scanner, None, foo)
+ self.assertEqual(config.subscribed, [(foo, IFoo)])
+
+ def test_register_multi(self):
+ from zope.interface import Interface
+
+ class IFoo(Interface):
+ pass
+
+ class IBar(Interface):
+ pass
+
+ dec = self._makeOne(IFoo, IBar)
+
+ def foo(): # pragma: no cover
+ pass
+
+ config = DummyConfigurator()
+ scanner = Dummy()
+ scanner.config = config
+ dec.register(scanner, None, foo)
+ self.assertEqual(config.subscribed, [(foo, IFoo), (foo, IBar)])
+
+ def test_register_none_means_all(self):
+ from zope.interface import Interface
+
+ dec = self._makeOne()
+
+ def foo(): # pragma: no cover
+ pass
+
+ config = DummyConfigurator()
+ scanner = Dummy()
+ scanner.config = config
+ dec.register(scanner, None, foo)
+ self.assertEqual(config.subscribed, [(foo, Interface)])
+
+ def test_register_objectevent(self):
+ from zope.interface import Interface
+
+ class IFoo(Interface):
+ pass
+
+ class IBar(Interface):
+ pass
+
+ dec = self._makeOne([IFoo, IBar])
+
+ def foo(): # pragma: no cover
+ pass
+
+ config = DummyConfigurator()
+ scanner = Dummy()
+ scanner.config = config
+ dec.register(scanner, None, foo)
+ self.assertEqual(config.subscribed, [(foo, [IFoo, IBar])])
+
+ def test___call__(self):
+ dec = self._makeOne()
+ dummy_venusian = DummyVenusian()
+ dec.venusian = dummy_venusian
+
+ def foo(): # pragma: no cover
+ pass
+
+ dec(foo)
+ self.assertEqual(
+ dummy_venusian.attached, [(foo, dec.register, 'pyramid', 1)]
+ )
+
+ def test___call___with_venusian_args(self):
+ dec = self._makeOne(_category='foo', _depth=1)
+ dummy_venusian = DummyVenusian()
+ dec.venusian = dummy_venusian
+
+ def foo(): # pragma: no cover
+ pass
+
+ dec(foo)
+ self.assertEqual(
+ dummy_venusian.attached, [(foo, dec.register, 'foo', 2)]
+ )
+
+ def test_regsister_with_predicates(self):
+ from zope.interface import Interface
+
+ dec = self._makeOne(a=1)
+
+ def foo(): # pragma: no cover
+ pass
+
+ config = DummyConfigurator()
+ scanner = Dummy()
+ scanner.config = config
+ dec.register(scanner, None, foo)
+ self.assertEqual(config.subscribed, [(foo, Interface, {'a': 1})])
+
+
+class TestBeforeRender(unittest.TestCase):
+ def _makeOne(self, system, val=None):
+ from pyramid.events import BeforeRender
+
+ return BeforeRender(system, val)
+
+ @testing.skip_on(
+ 'pypy'
+ ) # see https://github.com/Pylons/pyramid/issues/3237
+ def test_instance_conforms(self):
+ from zope.interface.verify import verifyObject
+ from pyramid.interfaces import IBeforeRender
+
+ event = self._makeOne({})
+ verifyObject(IBeforeRender, event)
+
+ def test_setitem_success(self):
+ event = self._makeOne({})
+ event['a'] = 1
+ self.assertEqual(event, {'a': 1})
+
+ def test_setdefault_fail(self):
+ event = self._makeOne({})
+ result = event.setdefault('a', 1)
+ self.assertEqual(result, 1)
+ self.assertEqual(event, {'a': 1})
+
+ def test_setdefault_success(self):
+ event = self._makeOne({})
+ event['a'] = 1
+ result = event.setdefault('a', 2)
+ self.assertEqual(result, 1)
+ self.assertEqual(event, {'a': 1})
+
+ def test_update_success(self):
+ event = self._makeOne({'a': 1})
+ event.update({'b': 2})
+ self.assertEqual(event, {'a': 1, 'b': 2})
+
+ def test__contains__True(self):
+ system = {'a': 1}
+ event = self._makeOne(system)
+ self.assertTrue('a' in event)
+
+ def test__contains__False(self):
+ system = {}
+ event = self._makeOne(system)
+ self.assertFalse('a' in event)
+
+ def test__getitem__success(self):
+ system = {'a': 1}
+ event = self._makeOne(system)
+ self.assertEqual(event['a'], 1)
+
+ def test__getitem__fail(self):
+ system = {}
+ event = self._makeOne(system)
+ self.assertRaises(KeyError, event.__getitem__, 'a')
+
+ def test_get_success(self):
+ system = {'a': 1}
+ event = self._makeOne(system)
+ self.assertEqual(event.get('a'), 1)
+
+ def test_get_fail(self):
+ system = {}
+ event = self._makeOne(system)
+ self.assertEqual(event.get('a'), None)
+
+ def test_rendering_val(self):
+ system = {}
+ val = {}
+ event = self._makeOne(system, val)
+ self.assertTrue(event.rendering_val is val)
+
+
+class DummyConfigurator(object):
+ def __init__(self):
+ self.subscribed = []
+
+ def add_subscriber(self, wrapped, ifaces, **predicates):
+ if not predicates:
+ self.subscribed.append((wrapped, ifaces))
+ else:
+ self.subscribed.append((wrapped, ifaces, predicates))
+
+
+class DummyRegistry(object):
+ pass
+
+
+class DummyVenusian(object):
+ def __init__(self):
+ self.attached = []
+
+ def attach(self, wrapped, fn, category=None, depth=None):
+ self.attached.append((wrapped, fn, category, depth))
+
+
+class Dummy:
+ pass
+
+
+class DummyRequest:
+ pass
+
+
+class DummyResponse:
+ pass
diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py
new file mode 100644
index 000000000..399940c05
--- /dev/null
+++ b/tests/test_exceptions.py
@@ -0,0 +1,113 @@
+import unittest
+
+
+class TestBWCompat(unittest.TestCase):
+ def test_bwcompat_notfound(self):
+ from pyramid.exceptions import NotFound as one
+ from pyramid.httpexceptions import HTTPNotFound as two
+
+ self.assertTrue(one is two)
+
+ def test_bwcompat_forbidden(self):
+ from pyramid.exceptions import Forbidden as one
+ from pyramid.httpexceptions import HTTPForbidden as two
+
+ self.assertTrue(one is two)
+
+
+class TestBadCSRFToken(unittest.TestCase):
+ def test_response_equivalence(self):
+ from pyramid.exceptions import BadCSRFToken
+ from pyramid.httpexceptions import HTTPBadRequest
+
+ self.assertTrue(isinstance(BadCSRFToken(), HTTPBadRequest))
+
+
+class TestNotFound(unittest.TestCase):
+ def _makeOne(self, message):
+ from pyramid.exceptions import NotFound
+
+ return NotFound(message)
+
+ def test_it(self):
+ from pyramid.interfaces import IExceptionResponse
+
+ e = self._makeOne('notfound')
+ self.assertTrue(IExceptionResponse.providedBy(e))
+ self.assertEqual(e.status, '404 Not Found')
+ self.assertEqual(e.message, 'notfound')
+
+ def test_response_equivalence(self):
+ from pyramid.exceptions import NotFound
+ from pyramid.httpexceptions import HTTPNotFound
+
+ self.assertTrue(NotFound is HTTPNotFound)
+
+
+class TestForbidden(unittest.TestCase):
+ def _makeOne(self, message):
+ from pyramid.exceptions import Forbidden
+
+ return Forbidden(message)
+
+ def test_it(self):
+ from pyramid.interfaces import IExceptionResponse
+
+ e = self._makeOne('forbidden')
+ self.assertTrue(IExceptionResponse.providedBy(e))
+ self.assertEqual(e.status, '403 Forbidden')
+ self.assertEqual(e.message, 'forbidden')
+
+ def test_response_equivalence(self):
+ from pyramid.exceptions import Forbidden
+ from pyramid.httpexceptions import HTTPForbidden
+
+ self.assertTrue(Forbidden is HTTPForbidden)
+
+
+class TestConfigurationConflictError(unittest.TestCase):
+ def _makeOne(self, conflicts):
+ from pyramid.exceptions import ConfigurationConflictError
+
+ return ConfigurationConflictError(conflicts)
+
+ def test_str(self):
+ conflicts = {'a': ('1', '2', '3'), 'b': ('4', '5', '6')}
+ exc = self._makeOne(conflicts)
+ self.assertEqual(
+ str(exc),
+ """\
+Conflicting configuration actions
+ For: a
+ 1
+ 2
+ 3
+ For: b
+ 4
+ 5
+ 6""",
+ )
+
+
+class TestConfigurationExecutionError(unittest.TestCase):
+ def _makeOne(self, etype, evalue, info):
+ from pyramid.exceptions import ConfigurationExecutionError
+
+ return ConfigurationExecutionError(etype, evalue, info)
+
+ def test_str(self):
+ exc = self._makeOne('etype', 'evalue', 'info')
+ self.assertEqual(str(exc), 'etype: evalue\n in:\n info')
+
+
+class TestCyclicDependencyError(unittest.TestCase):
+ def _makeOne(self, cycles):
+ from pyramid.exceptions import CyclicDependencyError
+
+ return CyclicDependencyError(cycles)
+
+ def test___str__(self):
+ exc = self._makeOne({'a': ['c', 'd'], 'c': ['a']})
+ result = str(exc)
+ self.assertTrue("'a' sorts before ['c', 'd']" in result)
+ self.assertTrue("'c' sorts before ['a']" in result)
diff --git a/tests/test_httpexceptions.py b/tests/test_httpexceptions.py
new file mode 100644
index 000000000..4c13e096d
--- /dev/null
+++ b/tests/test_httpexceptions.py
@@ -0,0 +1,529 @@
+import unittest
+
+from pyramid.compat import bytes_, string_types, text_
+
+
+class Test_exception_response(unittest.TestCase):
+ def _callFUT(self, *arg, **kw):
+ from pyramid.httpexceptions import exception_response
+
+ return exception_response(*arg, **kw)
+
+ def test_status_400(self):
+ from pyramid.httpexceptions import HTTPBadRequest
+
+ self.assertTrue(isinstance(self._callFUT(400), HTTPBadRequest))
+
+ def test_status_404(self):
+ from pyramid.httpexceptions import HTTPNotFound
+
+ self.assertTrue(isinstance(self._callFUT(404), HTTPNotFound))
+
+ def test_status_500(self):
+ from pyramid.httpexceptions import HTTPInternalServerError
+
+ self.assertTrue(
+ isinstance(self._callFUT(500), HTTPInternalServerError)
+ )
+
+ def test_status_201(self):
+ from pyramid.httpexceptions import HTTPCreated
+
+ self.assertTrue(isinstance(self._callFUT(201), HTTPCreated))
+
+ def test_extra_kw(self):
+ resp = self._callFUT(404, headers=[('abc', 'def')])
+ self.assertEqual(resp.headers['abc'], 'def')
+
+
+class Test_default_exceptionresponse_view(unittest.TestCase):
+ def _callFUT(self, context, request):
+ from pyramid.httpexceptions import default_exceptionresponse_view
+
+ return default_exceptionresponse_view(context, request)
+
+ def test_call_with_exception(self):
+ context = Exception()
+ result = self._callFUT(context, None)
+ self.assertEqual(result, context)
+
+ def test_call_with_nonexception(self):
+ request = DummyRequest()
+ context = Exception()
+ request.exception = context
+ result = self._callFUT(None, request)
+ self.assertEqual(result, context)
+
+
+class Test__no_escape(unittest.TestCase):
+ def _callFUT(self, val):
+ from pyramid.httpexceptions import _no_escape
+
+ return _no_escape(val)
+
+ def test_null(self):
+ self.assertEqual(self._callFUT(None), '')
+
+ def test_not_basestring(self):
+ self.assertEqual(self._callFUT(42), '42')
+
+ def test_unicode(self):
+ class DummyUnicodeObject(object):
+ def __unicode__(self):
+ return text_('42')
+
+ duo = DummyUnicodeObject()
+ self.assertEqual(self._callFUT(duo), text_('42'))
+
+
+class TestHTTPException(unittest.TestCase):
+ def _getTargetClass(self):
+ from pyramid.httpexceptions import HTTPException
+
+ return HTTPException
+
+ def _getTargetSubclass(
+ self,
+ code='200',
+ title='OK',
+ explanation='explanation',
+ empty_body=False,
+ ):
+ cls = self._getTargetClass()
+
+ class Subclass(cls):
+ pass
+
+ Subclass.empty_body = empty_body
+ Subclass.code = code
+ Subclass.title = title
+ Subclass.explanation = explanation
+ return Subclass
+
+ def _makeOne(self, *arg, **kw):
+ cls = self._getTargetClass()
+ return cls(*arg, **kw)
+
+ def test_implements_IResponse(self):
+ from pyramid.interfaces import IResponse
+
+ cls = self._getTargetClass()
+ self.assertTrue(IResponse.implementedBy(cls))
+
+ def test_provides_IResponse(self):
+ from pyramid.interfaces import IResponse
+
+ inst = self._getTargetClass()()
+ self.assertTrue(IResponse.providedBy(inst))
+
+ def test_implements_IExceptionResponse(self):
+ from pyramid.interfaces import IExceptionResponse
+
+ cls = self._getTargetClass()
+ self.assertTrue(IExceptionResponse.implementedBy(cls))
+
+ def test_provides_IExceptionResponse(self):
+ from pyramid.interfaces import IExceptionResponse
+
+ inst = self._getTargetClass()()
+ self.assertTrue(IExceptionResponse.providedBy(inst))
+
+ def test_ctor_sets_detail(self):
+ exc = self._makeOne('message')
+ self.assertEqual(exc.detail, 'message')
+
+ def test_ctor_sets_comment(self):
+ exc = self._makeOne(comment='comment')
+ self.assertEqual(exc.comment, 'comment')
+
+ def test_ctor_calls_Exception_ctor(self):
+ exc = self._makeOne('message')
+ self.assertEqual(exc.message, 'message')
+
+ def test_ctor_calls_Response_ctor(self):
+ exc = self._makeOne('message')
+ self.assertEqual(exc.status, '520 Unknown Error')
+
+ def test_ctor_extends_headers(self):
+ exc = self._makeOne(headers=[('X-Foo', 'foo')])
+ self.assertEqual(exc.headers.get('X-Foo'), 'foo')
+
+ def test_ctor_sets_body_template_obj(self):
+ exc = self._makeOne(body_template='${foo}')
+ self.assertEqual(
+ exc.body_template_obj.substitute({'foo': 'foo'}), 'foo'
+ )
+
+ def test_ctor_with_empty_body(self):
+ cls = self._getTargetSubclass(empty_body=True)
+ exc = cls()
+ self.assertEqual(exc.content_type, None)
+ self.assertEqual(exc.content_length, None)
+
+ def test_ctor_with_body_doesnt_set_default_app_iter(self):
+ exc = self._makeOne(body=b'123')
+ self.assertEqual(exc.app_iter, [b'123'])
+
+ def test_ctor_with_unicode_body_doesnt_set_default_app_iter(self):
+ exc = self._makeOne(unicode_body=text_('123'))
+ self.assertEqual(exc.app_iter, [b'123'])
+
+ def test_ctor_with_app_iter_doesnt_set_default_app_iter(self):
+ exc = self._makeOne(app_iter=[b'123'])
+ self.assertEqual(exc.app_iter, [b'123'])
+
+ def test_ctor_with_body_sets_default_app_iter_html(self):
+ cls = self._getTargetSubclass()
+ exc = cls('detail')
+ environ = _makeEnviron()
+ environ['HTTP_ACCEPT'] = 'text/html'
+ start_response = DummyStartResponse()
+ body = list(exc(environ, start_response))[0]
+ self.assertTrue(body.startswith(b'<html'))
+ self.assertTrue(b'200 OK' in body)
+ self.assertTrue(b'explanation' in body)
+ self.assertTrue(b'detail' in body)
+
+ def test_ctor_with_body_sets_default_app_iter_text(self):
+ cls = self._getTargetSubclass()
+ exc = cls('detail')
+ environ = _makeEnviron()
+ start_response = DummyStartResponse()
+ body = list(exc(environ, start_response))[0]
+ self.assertEqual(body, b'200 OK\n\nexplanation\n\n\ndetail\n\n')
+
+ def test__str__detail(self):
+ exc = self._makeOne()
+ exc.detail = 'abc'
+ self.assertEqual(str(exc), 'abc')
+
+ def test__str__explanation(self):
+ exc = self._makeOne()
+ exc.explanation = 'def'
+ self.assertEqual(str(exc), 'def')
+
+ def test_wsgi_response(self):
+ exc = self._makeOne()
+ self.assertTrue(exc is exc.wsgi_response)
+
+ def test_exception(self):
+ exc = self._makeOne()
+ self.assertTrue(exc is exc.exception)
+
+ def test__calls_start_response(self):
+ cls = self._getTargetSubclass()
+ exc = cls()
+ environ = _makeEnviron()
+ start_response = DummyStartResponse()
+ exc(environ, start_response)
+ self.assertTrue(start_response.headerlist)
+ self.assertEqual(start_response.status, '200 OK')
+
+ def test_call_returns_same_body_called_twice(self):
+ # optimization
+ cls = self._getTargetSubclass()
+ exc = cls()
+ environ = _makeEnviron()
+ environ['HTTP_ACCEPT'] = '*/*'
+ start_response = DummyStartResponse()
+ app_iter = exc(environ, start_response)
+ self.assertEqual(app_iter[0], exc.body)
+
+ def test__default_app_iter_no_comment_plain(self):
+ cls = self._getTargetSubclass()
+ exc = cls()
+ environ = _makeEnviron()
+ start_response = DummyStartResponse()
+ body = list(exc(environ, start_response))[0]
+ for header in start_response.headerlist:
+ if header[0] == 'Content-Type':
+ self.assertEqual(header[1], 'text/plain; charset=UTF-8')
+ self.assertEqual(body, b'200 OK\n\nexplanation\n\n\n\n\n')
+
+ def test__default_app_iter_with_comment_plain(self):
+ cls = self._getTargetSubclass()
+ exc = cls(comment='comment')
+ environ = _makeEnviron()
+ start_response = DummyStartResponse()
+ body = list(exc(environ, start_response))[0]
+ for header in start_response.headerlist:
+ if header[0] == 'Content-Type':
+ self.assertEqual(header[1], 'text/plain; charset=UTF-8')
+ self.assertEqual(body, b'200 OK\n\nexplanation\n\n\n\ncomment\n')
+
+ def test__default_app_iter_no_comment_html(self):
+ cls = self._getTargetSubclass()
+ exc = cls()
+ environ = _makeEnviron()
+ start_response = DummyStartResponse()
+ body = list(exc(environ, start_response))[0]
+ for header in start_response.headerlist:
+ if header[0] == 'Content-Type':
+ self.assertEqual(header[1], 'text/plain; charset=UTF-8')
+ self.assertFalse(b'<!-- ' in body)
+
+ def test__content_type(self):
+ cls = self._getTargetSubclass()
+ exc = cls()
+ environ = _makeEnviron()
+ start_response = DummyStartResponse()
+ exc(environ, start_response)
+ for header in start_response.headerlist:
+ if header[0] == 'Content-Type':
+ self.assertEqual(header[1], 'text/plain; charset=UTF-8')
+
+ def test__content_type_default_is_html(self):
+ cls = self._getTargetSubclass()
+ exc = cls()
+ environ = _makeEnviron()
+ environ['HTTP_ACCEPT'] = '*/*'
+ start_response = DummyStartResponse()
+ exc(environ, start_response)
+ for header in start_response.headerlist:
+ if header[0] == 'Content-Type':
+ self.assertEqual(header[1], 'text/html; charset=UTF-8')
+
+ def test__content_type_text_html(self):
+ cls = self._getTargetSubclass()
+ exc = cls()
+ environ = _makeEnviron()
+ environ['HTTP_ACCEPT'] = 'text/html'
+ start_response = DummyStartResponse()
+ exc(environ, start_response)
+ for header in start_response.headerlist:
+ if header[0] == 'Content-Type':
+ self.assertEqual(header[1], 'text/html; charset=UTF-8')
+
+ def test__content_type_application_json(self):
+ cls = self._getTargetSubclass()
+ exc = cls()
+ environ = _makeEnviron()
+ environ['HTTP_ACCEPT'] = 'application/json'
+ start_response = DummyStartResponse()
+ exc(environ, start_response)
+ for header in start_response.headerlist:
+ if header[0] == 'Content-Type':
+ self.assertEqual(header[1], 'application/json')
+
+ def test__content_type_invalid(self):
+ cls = self._getTargetSubclass()
+ exc = cls()
+ environ = _makeEnviron()
+ environ['HTTP_ACCEPT'] = 'invalid'
+ start_response = DummyStartResponse()
+ exc(environ, start_response)
+ for header in start_response.headerlist:
+ if header[0] == 'Content-Type':
+ self.assertEqual(header[1], 'text/html; charset=UTF-8')
+
+ def test__default_app_iter_with_comment_ampersand(self):
+ cls = self._getTargetSubclass()
+ exc = cls(comment='comment & comment')
+ environ = _makeEnviron()
+ environ['HTTP_ACCEPT'] = 'text/html'
+ start_response = DummyStartResponse()
+ body = list(exc(environ, start_response))[0]
+ for header in start_response.headerlist:
+ if header[0] == 'Content-Type':
+ self.assertEqual(header[1], 'text/html; charset=UTF-8')
+ self.assertTrue(b'<!-- comment &amp; comment -->' in body)
+
+ def test__default_app_iter_with_comment_html(self):
+ cls = self._getTargetSubclass()
+ exc = cls(comment='comment & comment')
+ environ = _makeEnviron()
+ environ['HTTP_ACCEPT'] = 'text/html'
+ start_response = DummyStartResponse()
+ body = list(exc(environ, start_response))[0]
+ self.assertTrue(b'<!-- comment &amp; comment -->' in body)
+
+ def test__default_app_iter_with_comment_json(self):
+ cls = self._getTargetSubclass()
+ exc = cls(comment='comment & comment')
+ environ = _makeEnviron()
+ environ['HTTP_ACCEPT'] = 'application/json'
+ start_response = DummyStartResponse()
+ body = list(exc(environ, start_response))[0]
+ import json
+
+ retval = json.loads(body.decode('UTF-8'))
+ self.assertEqual(retval['code'], '200 OK')
+ self.assertEqual(retval['title'], 'OK')
+
+ def test__default_app_iter_with_custom_json(self):
+ def json_formatter(status, body, title, environ):
+ return {
+ 'message': body,
+ 'code': status,
+ 'title': title,
+ 'custom': environ['CUSTOM_VARIABLE'],
+ }
+
+ cls = self._getTargetSubclass()
+ exc = cls(comment='comment', json_formatter=json_formatter)
+ environ = _makeEnviron()
+ environ['HTTP_ACCEPT'] = 'application/json'
+ environ['CUSTOM_VARIABLE'] = 'custom!'
+ start_response = DummyStartResponse()
+ body = list(exc(environ, start_response))[0]
+ import json
+
+ retval = json.loads(body.decode('UTF-8'))
+ self.assertEqual(retval['code'], '200 OK')
+ self.assertEqual(retval['title'], 'OK')
+ self.assertEqual(retval['custom'], 'custom!')
+
+ def test_custom_body_template(self):
+ cls = self._getTargetSubclass()
+ exc = cls(body_template='${REQUEST_METHOD}')
+ environ = _makeEnviron()
+ start_response = DummyStartResponse()
+ body = list(exc(environ, start_response))[0]
+ self.assertEqual(body, b'200 OK\n\nGET')
+
+ def test_custom_body_template_with_custom_variable_doesnt_choke(self):
+ cls = self._getTargetSubclass()
+ exc = cls(body_template='${REQUEST_METHOD}')
+ environ = _makeEnviron()
+
+ class Choke(object):
+ def __str__(self): # pragma no cover
+ raise ValueError
+
+ environ['gardentheory.user'] = Choke()
+ start_response = DummyStartResponse()
+ body = list(exc(environ, start_response))[0]
+ self.assertEqual(body, b'200 OK\n\nGET')
+
+ def test_body_template_unicode(self):
+ cls = self._getTargetSubclass()
+ la = text_(b'/La Pe\xc3\xb1a', 'utf-8')
+ environ = _makeEnviron(unicodeval=la)
+ exc = cls(body_template='${unicodeval}')
+ start_response = DummyStartResponse()
+ body = list(exc(environ, start_response))[0]
+ self.assertEqual(body, b'200 OK\n\n/La Pe\xc3\xb1a')
+
+ def test_allow_detail_non_str(self):
+ exc = self._makeOne(detail={'error': 'This is a test'})
+ self.assertIsInstance(exc.__str__(), string_types)
+
+
+class TestRenderAllExceptionsWithoutArguments(unittest.TestCase):
+ def _doit(self, content_type):
+ from pyramid.httpexceptions import status_map
+
+ L = []
+ self.assertTrue(status_map)
+ for v in status_map.values():
+ environ = _makeEnviron()
+ start_response = DummyStartResponse()
+ exc = v()
+ exc.content_type = content_type
+ result = list(exc(environ, start_response))[0]
+ if exc.empty_body:
+ self.assertEqual(result, b'')
+ else:
+ self.assertTrue(bytes_(exc.status) in result)
+ L.append(result)
+ self.assertEqual(len(L), len(status_map))
+
+ def test_it_plain(self):
+ self._doit('text/plain')
+
+ def test_it_html(self):
+ self._doit('text/html')
+
+
+class Test_HTTPMove(unittest.TestCase):
+ def _makeOne(self, *arg, **kw):
+ from pyramid.httpexceptions import _HTTPMove
+
+ return _HTTPMove(*arg, **kw)
+
+ def test_it_location_none_valueerrors(self):
+ # Constructing a HTTPMove instance with location=None should
+ # throw a ValueError from __init__ so that a more-confusing
+ # exception won't be thrown later from .prepare(environ)
+ self.assertRaises(ValueError, self._makeOne, location=None)
+
+ def test_it_location_not_passed(self):
+ exc = self._makeOne()
+ self.assertEqual(exc.location, '')
+
+ def test_it_location_passed(self):
+ exc = self._makeOne(location='foo')
+ self.assertEqual(exc.location, 'foo')
+
+ def test_it_location_firstarg(self):
+ exc = self._makeOne('foo')
+ self.assertEqual(exc.location, 'foo')
+
+ def test_it_call_with_default_body_tmpl(self):
+ exc = self._makeOne(location='foo')
+ environ = _makeEnviron()
+ start_response = DummyStartResponse()
+ app_iter = exc(environ, start_response)
+ self.assertEqual(
+ app_iter[0],
+ (
+ b'520 Unknown Error\n\nThe resource has been moved to foo; '
+ b'you should be redirected automatically.\n\n'
+ ),
+ )
+
+
+class TestHTTPForbidden(unittest.TestCase):
+ def _makeOne(self, *arg, **kw):
+ from pyramid.httpexceptions import HTTPForbidden
+
+ return HTTPForbidden(*arg, **kw)
+
+ def test_it_result_not_passed(self):
+ exc = self._makeOne()
+ self.assertEqual(exc.result, None)
+
+ def test_it_result_passed(self):
+ exc = self._makeOne(result='foo')
+ self.assertEqual(exc.result, 'foo')
+
+
+class TestHTTPMethodNotAllowed(unittest.TestCase):
+ def _makeOne(self, *arg, **kw):
+ from pyramid.httpexceptions import HTTPMethodNotAllowed
+
+ return HTTPMethodNotAllowed(*arg, **kw)
+
+ def test_it_with_default_body_tmpl(self):
+ exc = self._makeOne()
+ environ = _makeEnviron()
+ start_response = DummyStartResponse()
+ app_iter = exc(environ, start_response)
+ self.assertEqual(
+ app_iter[0],
+ (
+ b'405 Method Not Allowed\n\nThe method GET is not '
+ b'allowed for this resource. \n\n\n'
+ ),
+ )
+
+
+class DummyRequest(object):
+ exception = None
+
+
+class DummyStartResponse(object):
+ def __call__(self, status, headerlist):
+ self.status = status
+ self.headerlist = headerlist
+
+
+def _makeEnviron(**kw):
+ environ = {
+ 'REQUEST_METHOD': 'GET',
+ 'wsgi.url_scheme': 'http',
+ 'SERVER_NAME': 'localhost',
+ 'SERVER_PORT': '80',
+ }
+ environ.update(kw)
+ return environ
diff --git a/tests/test_i18n.py b/tests/test_i18n.py
new file mode 100644
index 000000000..78891200d
--- /dev/null
+++ b/tests/test_i18n.py
@@ -0,0 +1,553 @@
+# -*- coding: utf-8 -*-
+import os
+import unittest
+from pyramid import testing
+
+here = os.path.dirname(__file__)
+localedir = os.path.join(here, 'pkgs', 'localeapp', 'locale')
+
+
+class TestTranslationString(unittest.TestCase):
+ def _makeOne(self, *arg, **kw):
+ from pyramid.i18n import TranslationString
+
+ return TranslationString(*arg, **kw)
+
+ def test_it(self):
+ # this is part of the API, we don't actually need to test much more
+ # than that it's importable
+ ts = self._makeOne('a')
+ self.assertEqual(ts, 'a')
+
+
+class TestTranslationStringFactory(unittest.TestCase):
+ def _makeOne(self, *arg, **kw):
+ from pyramid.i18n import TranslationStringFactory
+
+ return TranslationStringFactory(*arg, **kw)
+
+ def test_it(self):
+ # this is part of the API, we don't actually need to test much more
+ # than that it's importable
+ factory = self._makeOne('a')
+ self.assertEqual(factory('').domain, 'a')
+
+
+class TestLocalizer(unittest.TestCase):
+ def _makeOne(self, *arg, **kw):
+ from pyramid.i18n import Localizer
+
+ return Localizer(*arg, **kw)
+
+ def test_ctor(self):
+ localizer = self._makeOne('en_US', None)
+ self.assertEqual(localizer.locale_name, 'en_US')
+ self.assertEqual(localizer.translations, None)
+
+ def test_translate(self):
+ translations = DummyTranslations()
+ localizer = self._makeOne(None, translations)
+ self.assertEqual(
+ localizer.translate('123', domain='1', mapping={}), '123'
+ )
+ self.assertTrue(localizer.translator)
+
+ def test_pluralize(self):
+ translations = DummyTranslations()
+ localizer = self._makeOne(None, translations)
+ result = localizer.pluralize(
+ 'singular', 'plural', 1, domain='1', mapping={}
+ )
+ self.assertEqual(result, 'singular')
+ self.assertTrue(localizer.pluralizer)
+
+ def test_pluralize_pluralizer_already_added(self):
+ translations = DummyTranslations()
+ localizer = self._makeOne(None, translations)
+
+ def pluralizer(*arg, **kw):
+ return arg, kw
+
+ localizer.pluralizer = pluralizer
+ result = localizer.pluralize(
+ 'singular', 'plural', 1, domain='1', mapping={}
+ )
+ self.assertEqual(
+ result, (('singular', 'plural', 1), {'domain': '1', 'mapping': {}})
+ )
+ self.assertTrue(localizer.pluralizer is pluralizer)
+
+ def test_pluralize_default_translations(self):
+ # test that even without message ids loaded that
+ # "localizer.pluralize" "works" instead of raising an inscrutable
+ # "translations object has no attr 'plural' error; see
+ # see https://github.com/Pylons/pyramid/issues/235
+ from pyramid.i18n import Translations
+
+ translations = Translations()
+ translations._catalog = {}
+ localizer = self._makeOne(None, translations)
+ result = localizer.pluralize(
+ 'singular', 'plural', 2, domain='1', mapping={}
+ )
+ self.assertEqual(result, 'plural')
+
+
+class Test_negotiate_locale_name(unittest.TestCase):
+ def setUp(self):
+ testing.setUp()
+
+ def tearDown(self):
+ testing.tearDown()
+
+ def _callFUT(self, request):
+ from pyramid.i18n import negotiate_locale_name
+
+ return negotiate_locale_name(request)
+
+ def _registerImpl(self, impl):
+ from pyramid.threadlocal import get_current_registry
+
+ registry = get_current_registry()
+ from pyramid.interfaces import ILocaleNegotiator
+
+ registry.registerUtility(impl, ILocaleNegotiator)
+
+ def test_no_registry_on_request(self):
+ self._registerImpl(dummy_negotiator)
+ request = DummyRequest()
+ result = self._callFUT(request)
+ self.assertEqual(result, 'bogus')
+
+ def test_with_registry_on_request(self):
+ from pyramid.threadlocal import get_current_registry
+
+ registry = get_current_registry()
+ self._registerImpl(dummy_negotiator)
+ request = DummyRequest()
+ request.registry = registry
+ result = self._callFUT(request)
+ self.assertEqual(result, 'bogus')
+
+ def test_default_from_settings(self):
+ from pyramid.threadlocal import get_current_registry
+
+ registry = get_current_registry()
+ settings = {'default_locale_name': 'settings'}
+ registry.settings = settings
+ request = DummyRequest()
+ request.registry = registry
+ result = self._callFUT(request)
+ self.assertEqual(result, 'settings')
+
+ def test_use_default_locale_negotiator(self):
+ from pyramid.threadlocal import get_current_registry
+
+ registry = get_current_registry()
+ request = DummyRequest()
+ request.registry = registry
+ request._LOCALE_ = 'locale'
+ result = self._callFUT(request)
+ self.assertEqual(result, 'locale')
+
+ def test_default_default(self):
+ request = DummyRequest()
+ result = self._callFUT(request)
+ self.assertEqual(result, 'en')
+
+
+class Test_get_locale_name(unittest.TestCase):
+ def setUp(self):
+ testing.setUp()
+
+ def tearDown(self):
+ testing.tearDown()
+
+ def _callFUT(self, request):
+ from pyramid.i18n import get_locale_name
+
+ return get_locale_name(request)
+
+ def test_name_on_request(self):
+ request = DummyRequest()
+ request.locale_name = 'ie'
+ result = self._callFUT(request)
+ self.assertEqual(result, 'ie')
+
+
+class Test_make_localizer(unittest.TestCase):
+ def setUp(self):
+ testing.setUp()
+
+ def tearDown(self):
+ testing.tearDown()
+
+ def _callFUT(self, locale, tdirs):
+ from pyramid.i18n import make_localizer
+
+ return make_localizer(locale, tdirs)
+
+ def test_locale_from_mo(self):
+ from pyramid.i18n import Localizer
+
+ localedirs = [localedir]
+ locale_name = 'de'
+ result = self._callFUT(locale_name, localedirs)
+ self.assertEqual(result.__class__, Localizer)
+ self.assertEqual(
+ result.translate('Approve', 'deformsite'), 'Genehmigen'
+ )
+ self.assertEqual(result.translate('Approve'), 'Approve')
+ self.assertTrue(hasattr(result, 'pluralize'))
+
+ def test_locale_from_mo_bad_mo(self):
+ from pyramid.i18n import Localizer
+
+ localedirs = [localedir]
+ locale_name = 'be'
+ result = self._callFUT(locale_name, localedirs)
+ self.assertEqual(result.__class__, Localizer)
+ self.assertEqual(result.translate('Approve', 'deformsite'), 'Approve')
+
+ def test_locale_from_mo_mo_isdir(self):
+ from pyramid.i18n import Localizer
+
+ localedirs = [localedir]
+ locale_name = 'gb'
+ result = self._callFUT(locale_name, localedirs)
+ self.assertEqual(result.__class__, Localizer)
+ self.assertEqual(result.translate('Approve', 'deformsite'), 'Approve')
+
+ def test_territory_fallback(self):
+ from pyramid.i18n import Localizer
+
+ localedirs = [localedir]
+ locale_name = 'de_DE'
+ result = self._callFUT(locale_name, localedirs)
+ self.assertEqual(result.__class__, Localizer)
+ self.assertEqual(
+ result.translate('Submit', 'deformsite'), 'different'
+ ) # prefer translations from de_DE locale
+ self.assertEqual(
+ result.translate('Approve', 'deformsite'), 'Genehmigen'
+ ) # missing from de_DE locale, but in de
+
+
+class Test_get_localizer(unittest.TestCase):
+ def setUp(self):
+ testing.setUp()
+
+ def tearDown(self):
+ testing.tearDown()
+
+ def _callFUT(self, request):
+ from pyramid.i18n import get_localizer
+
+ return get_localizer(request)
+
+ def test_it(self):
+ request = DummyRequest()
+ request.localizer = 'localizer'
+ self.assertEqual(self._callFUT(request), 'localizer')
+
+
+class Test_default_locale_negotiator(unittest.TestCase):
+ def setUp(self):
+ testing.setUp()
+
+ def tearDown(self):
+ testing.tearDown()
+
+ def _callFUT(self, request):
+ from pyramid.i18n import default_locale_negotiator
+
+ return default_locale_negotiator(request)
+
+ def test_from_none(self):
+ request = DummyRequest()
+ result = self._callFUT(request)
+ self.assertEqual(result, None)
+
+ def test_from_request_attr(self):
+ request = DummyRequest()
+ request._LOCALE_ = 'foo'
+ result = self._callFUT(request)
+ self.assertEqual(result, 'foo')
+
+ def test_from_params(self):
+ request = DummyRequest()
+ request.params['_LOCALE_'] = 'foo'
+ result = self._callFUT(request)
+ self.assertEqual(result, 'foo')
+
+ def test_from_cookies(self):
+ request = DummyRequest()
+ request.cookies['_LOCALE_'] = 'foo'
+ result = self._callFUT(request)
+ self.assertEqual(result, 'foo')
+
+
+class TestTranslations(unittest.TestCase):
+ def _getTargetClass(self):
+ from pyramid.i18n import Translations
+
+ return Translations
+
+ def _makeOne(self):
+ messages1 = [('foo', 'Voh'), (('foo1', 1), 'Voh1')]
+ messages2 = [('foo', 'VohD'), (('foo1', 1), 'VohD1')]
+
+ klass = self._getTargetClass()
+
+ translations1 = klass(None, domain='messages')
+ translations1._catalog = dict(messages1)
+ translations1.plural = lambda *arg: 1
+ translations2 = klass(None, domain='messages1')
+ translations2._catalog = dict(messages2)
+ translations2.plural = lambda *arg: 1
+ translations = translations1.add(translations2, merge=False)
+ return translations
+
+ def test_load_locales_None(self):
+ import gettext
+
+ klass = self._getTargetClass()
+ result = klass.load(localedir, None, domain=None)
+ self.assertEqual(result.__class__, gettext.NullTranslations)
+
+ def test_load_domain_None(self):
+ import gettext
+
+ locales = ['de', 'en']
+ klass = self._getTargetClass()
+ result = klass.load(localedir, locales, domain=None)
+ self.assertEqual(result.__class__, gettext.NullTranslations)
+
+ def test_load_found_locale_and_domain(self):
+ locales = ['de', 'en']
+ klass = self._getTargetClass()
+ result = klass.load(localedir, locales, domain='deformsite')
+ self.assertEqual(result.__class__, klass)
+
+ def test_load_found_locale_and_domain_locale_is_string(self):
+ locales = 'de'
+ klass = self._getTargetClass()
+ result = klass.load(localedir, locales, domain='deformsite')
+ self.assertEqual(result.__class__, klass)
+
+ def test___repr__(self):
+ inst = self._makeOne()
+ result = repr(inst)
+ self.assertEqual(result, '<Translations: "None">')
+
+ def test_merge_not_gnutranslations(self):
+ inst = self._makeOne()
+ self.assertEqual(inst.merge(None), inst)
+
+ def test_merge_gnutranslations(self):
+ inst = self._makeOne()
+ inst2 = self._makeOne()
+ inst2._catalog['a'] = 'b'
+ inst.merge(inst2)
+ self.assertEqual(inst._catalog['a'], 'b')
+
+ def test_merge_gnutranslations_not_translations(self):
+ import gettext
+
+ t = gettext.GNUTranslations()
+ t._catalog = {'a': 'b'}
+ inst = self._makeOne()
+ inst.merge(t)
+ self.assertEqual(inst._catalog['a'], 'b')
+
+ def test_add_different_domain_merge_true_notexisting(self):
+ inst = self._makeOne()
+ inst2 = self._makeOne()
+ inst2.domain = 'domain2'
+ inst.add(inst2)
+ self.assertEqual(inst._domains['domain2'], inst2)
+
+ def test_add_different_domain_merge_true_existing(self):
+ inst = self._makeOne()
+ inst2 = self._makeOne()
+ inst3 = self._makeOne()
+ inst2.domain = 'domain2'
+ inst2._catalog['a'] = 'b'
+ inst3.domain = 'domain2'
+ inst._domains['domain2'] = inst3
+ inst.add(inst2)
+ self.assertEqual(inst._domains['domain2'], inst3)
+ self.assertEqual(inst3._catalog['a'], 'b')
+
+ def test_add_same_domain_merge_true(self):
+ inst = self._makeOne()
+ inst2 = self._makeOne()
+ inst2._catalog['a'] = 'b'
+ inst.add(inst2)
+ self.assertEqual(inst._catalog['a'], 'b')
+
+ def test_add_default_domain_replaces_plural_first_time(self):
+ # Create three empty message catalogs in the default domain
+ inst = self._getTargetClass()(None, domain='messages')
+ inst2 = self._getTargetClass()(None, domain='messages')
+ inst3 = self._getTargetClass()(None, domain='messages')
+ inst._catalog = {}
+ inst2._catalog = {}
+ inst3._catalog = {}
+
+ # The default plural scheme is the germanic one
+ self.assertEqual(inst.plural(0), 1)
+ self.assertEqual(inst.plural(1), 0)
+ self.assertEqual(inst.plural(2), 1)
+
+ # inst2 represents a message file that declares french plurals
+ inst2.plural = lambda n: n > 1
+ inst.add(inst2)
+ # that plural rule should now apply to inst
+ self.assertEqual(inst.plural(0), 0)
+ self.assertEqual(inst.plural(1), 0)
+ self.assertEqual(inst.plural(2), 1)
+
+ # We load a second message file with different plural rules
+ inst3.plural = lambda n: n > 0
+ inst.add(inst3)
+ # It doesn't override the previously loaded rule
+ self.assertEqual(inst.plural(0), 0)
+ self.assertEqual(inst.plural(1), 0)
+ self.assertEqual(inst.plural(2), 1)
+
+ def test_dgettext(self):
+ t = self._makeOne()
+ self.assertEqual(t.dgettext('messages', 'foo'), 'Voh')
+ self.assertEqual(t.dgettext('messages1', 'foo'), 'VohD')
+
+ def test_ldgettext(self):
+ t = self._makeOne()
+ self.assertEqual(t.ldgettext('messages', 'foo'), b'Voh')
+ self.assertEqual(t.ldgettext('messages1', 'foo'), b'VohD')
+
+ def test_dugettext(self):
+ t = self._makeOne()
+ self.assertEqual(t.dugettext('messages', 'foo'), 'Voh')
+ self.assertEqual(t.dugettext('messages1', 'foo'), 'VohD')
+
+ def test_dngettext(self):
+ t = self._makeOne()
+ self.assertEqual(t.dngettext('messages', 'foo1', 'foos1', 1), 'Voh1')
+ self.assertEqual(t.dngettext('messages1', 'foo1', 'foos1', 1), 'VohD1')
+
+ def test_ldngettext(self):
+ t = self._makeOne()
+ self.assertEqual(t.ldngettext('messages', 'foo1', 'foos1', 1), b'Voh1')
+ self.assertEqual(
+ t.ldngettext('messages1', 'foo1', 'foos1', 1), b'VohD1'
+ )
+
+ def test_dungettext(self):
+ t = self._makeOne()
+ self.assertEqual(t.dungettext('messages', 'foo1', 'foos1', 1), 'Voh1')
+ self.assertEqual(
+ t.dungettext('messages1', 'foo1', 'foos1', 1), 'VohD1'
+ )
+
+ def test_default_germanic_pluralization(self):
+ t = self._getTargetClass()()
+ t._catalog = {}
+ result = t.dungettext('messages', 'foo1', 'foos1', 2)
+ self.assertEqual(result, 'foos1')
+
+
+class TestLocalizerRequestMixin(unittest.TestCase):
+ def setUp(self):
+ self.config = testing.setUp()
+
+ def tearDown(self):
+ testing.tearDown()
+
+ def _makeOne(self):
+ from pyramid.i18n import LocalizerRequestMixin
+
+ request = LocalizerRequestMixin()
+ request.registry = self.config.registry
+ request.cookies = {}
+ request.params = {}
+ return request
+
+ def test_default_localizer(self):
+ # `localizer` returns a default localizer for `en`
+ from pyramid.i18n import Localizer
+
+ request = self._makeOne()
+ self.assertEqual(request.localizer.__class__, Localizer)
+ self.assertEqual(request.locale_name, 'en')
+
+ def test_custom_localizer_for_default_locale(self):
+ from pyramid.interfaces import ILocalizer
+
+ dummy = object()
+ self.config.registry.registerUtility(dummy, ILocalizer, name='en')
+ request = self._makeOne()
+ self.assertEqual(request.localizer, dummy)
+
+ def test_custom_localizer_for_custom_locale(self):
+ from pyramid.interfaces import ILocalizer
+
+ dummy = object()
+ self.config.registry.registerUtility(dummy, ILocalizer, name='ie')
+ request = self._makeOne()
+ request._LOCALE_ = 'ie'
+ self.assertEqual(request.localizer, dummy)
+
+ def test_localizer_from_mo(self):
+ from pyramid.interfaces import ITranslationDirectories
+ from pyramid.i18n import Localizer
+
+ localedirs = [localedir]
+ self.config.registry.registerUtility(
+ localedirs, ITranslationDirectories
+ )
+ request = self._makeOne()
+ request._LOCALE_ = 'de'
+ result = request.localizer
+ self.assertEqual(result.__class__, Localizer)
+ self.assertEqual(
+ result.translate('Approve', 'deformsite'), 'Genehmigen'
+ )
+ self.assertEqual(result.translate('Approve'), 'Approve')
+ self.assertTrue(hasattr(result, 'pluralize'))
+
+ def test_localizer_from_mo_bad_mo(self):
+ from pyramid.interfaces import ITranslationDirectories
+ from pyramid.i18n import Localizer
+
+ localedirs = [localedir]
+ self.config.registry.registerUtility(
+ localedirs, ITranslationDirectories
+ )
+ request = self._makeOne()
+ request._LOCALE_ = 'be'
+ result = request.localizer
+ self.assertEqual(result.__class__, Localizer)
+ self.assertEqual(result.translate('Approve', 'deformsite'), 'Approve')
+
+
+class DummyRequest(object):
+ def __init__(self):
+ self.params = {}
+ self.cookies = {}
+
+
+def dummy_negotiator(request):
+ return 'bogus'
+
+
+class DummyTranslations(object):
+ def ugettext(self, text):
+ return text
+
+ gettext = ugettext
+
+ def ungettext(self, singular, plural, n):
+ return singular
+
+ ngettext = ungettext
diff --git a/tests/test_integration.py b/tests/test_integration.py
new file mode 100644
index 000000000..d57a7cf6e
--- /dev/null
+++ b/tests/test_integration.py
@@ -0,0 +1,933 @@
+# -*- coding: utf-8 -*-
+import datetime
+import gc
+import locale
+import os
+import unittest
+from webtest import TestApp
+from zope.interface import Interface
+
+from pyramid.wsgi import wsgiapp
+from pyramid.view import view_config
+from pyramid.static import static_view
+from pyramid.testing import skip_on
+from pyramid.compat import text_, url_quote
+
+from .pkgs.exceptionviewapp.models import AnException, NotAnException
+
+# 5 years from now (more or less)
+fiveyrsfuture = datetime.datetime.utcnow() + datetime.timedelta(5 * 365)
+
+defaultlocale = locale.getdefaultlocale()[1]
+
+
+class INothing(Interface):
+ pass
+
+
+@view_config(for_=INothing)
+@wsgiapp
+def wsgiapptest(environ, start_response):
+ """ """
+ return '123'
+
+
+class WGSIAppPlusViewConfigTests(unittest.TestCase):
+ def test_it(self):
+ from venusian import ATTACH_ATTR
+ import types
+
+ self.assertTrue(getattr(wsgiapptest, ATTACH_ATTR))
+ self.assertIsInstance(wsgiapptest, types.FunctionType)
+ context = DummyContext()
+ request = DummyRequest()
+ result = wsgiapptest(context, request)
+ self.assertEqual(result, '123')
+
+ def test_scanned(self):
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IView
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.config import Configurator
+ from . import test_integration
+
+ config = Configurator()
+ config.scan(test_integration)
+ config.commit()
+ reg = config.registry
+ view = reg.adapters.lookup(
+ (IViewClassifier, IRequest, INothing), IView, name=''
+ )
+ self.assertEqual(view.__original_view__, wsgiapptest)
+
+
+class IntegrationBase(object):
+ root_factory = None
+ package = None
+
+ def setUp(self):
+ from pyramid.config import Configurator
+
+ config = Configurator(
+ root_factory=self.root_factory, package=self.package
+ )
+ config.include(self.package)
+ app = config.make_wsgi_app()
+ self.testapp = TestApp(app)
+ self.config = config
+
+ def tearDown(self):
+ self.config.end()
+
+
+here = os.path.dirname(__file__)
+
+
+class StaticAppBase(IntegrationBase):
+ def test_basic(self):
+ res = self.testapp.get('/minimal.txt', status=200)
+ _assertBody(res.body, os.path.join(here, 'fixtures/minimal.txt'))
+
+ def test_hidden(self):
+ res = self.testapp.get('/static/.hiddenfile', status=200)
+ _assertBody(
+ res.body, os.path.join(here, 'fixtures/static/.hiddenfile')
+ )
+
+ if defaultlocale is not None: # pragma: no cover
+ # These tests are expected to fail on LANG=C systems due to decode
+ # errors and on non-Linux systems due to git highchar handling
+ # vagaries
+ def test_highchars_in_pathelement(self):
+ path = os.path.join(
+ here, text_('fixtures/static/héhé/index.html', 'utf-8')
+ )
+ pathdir = os.path.dirname(path)
+ body = b'<html>hehe</html>\n'
+ try:
+ os.makedirs(pathdir)
+ with open(path, 'wb') as fp:
+ fp.write(body)
+ url = url_quote('/static/héhé/index.html')
+ res = self.testapp.get(url, status=200)
+ self.assertEqual(res.body, body)
+ finally:
+ os.unlink(path)
+ os.rmdir(pathdir)
+
+ def test_highchars_in_filename(self):
+ path = os.path.join(
+ here, text_('fixtures/static/héhé.html', 'utf-8')
+ )
+ body = b'<html>hehe file</html>\n'
+ with open(path, 'wb') as fp:
+ fp.write(body)
+ try:
+ url = url_quote('/static/héhé.html')
+ res = self.testapp.get(url, status=200)
+ self.assertEqual(res.body, body)
+ finally:
+ os.unlink(path)
+
+ def test_not_modified(self):
+ self.testapp.extra_environ = {
+ 'HTTP_IF_MODIFIED_SINCE': httpdate(fiveyrsfuture)
+ }
+ res = self.testapp.get('/minimal.txt', status=304)
+ self.assertEqual(res.body, b'')
+
+ def test_file_in_subdir(self):
+ fn = os.path.join(here, 'fixtures/static/index.html')
+ res = self.testapp.get('/static/index.html', status=200)
+ _assertBody(res.body, fn)
+
+ def test_directory_noslash_redir(self):
+ res = self.testapp.get('/static', status=301)
+ self.assertEqual(res.headers['Location'], 'http://localhost/static/')
+
+ def test_directory_noslash_redir_preserves_qs(self):
+ res = self.testapp.get('/static?a=1&b=2', status=301)
+ self.assertEqual(
+ res.headers['Location'], 'http://localhost/static/?a=1&b=2'
+ )
+
+ def test_directory_noslash_redir_with_scriptname(self):
+ self.testapp.extra_environ = {'SCRIPT_NAME': '/script_name'}
+ res = self.testapp.get('/static', status=301)
+ self.assertEqual(
+ res.headers['Location'], 'http://localhost/script_name/static/'
+ )
+
+ def test_directory_withslash(self):
+ fn = os.path.join(here, 'fixtures/static/index.html')
+ res = self.testapp.get('/static/', status=200)
+ _assertBody(res.body, fn)
+
+ def test_range_inclusive(self):
+ self.testapp.extra_environ = {'HTTP_RANGE': 'bytes=1-2'}
+ res = self.testapp.get('/static/index.html', status=206)
+ self.assertEqual(res.body, b'ht')
+
+ def test_range_tilend(self):
+ self.testapp.extra_environ = {'HTTP_RANGE': 'bytes=-5'}
+ res = self.testapp.get('/static/index.html', status=206)
+ self.assertEqual(res.body, b'html>')
+
+ def test_range_notbytes(self):
+ self.testapp.extra_environ = {'HTTP_RANGE': 'kHz=-5'}
+ res = self.testapp.get('/static/index.html', status=200)
+ _assertBody(res.body, os.path.join(here, 'fixtures/static/index.html'))
+
+ def test_range_multiple(self):
+ res = self.testapp.get(
+ '/static/index.html',
+ [('HTTP_RANGE', 'bytes=10-11,11-12')],
+ status=200,
+ )
+ _assertBody(res.body, os.path.join(here, 'fixtures/static/index.html'))
+
+ def test_range_oob(self):
+ self.testapp.extra_environ = {'HTTP_RANGE': 'bytes=1000-1002'}
+ self.testapp.get('/static/index.html', status=416)
+
+ def test_notfound(self):
+ self.testapp.get('/static/wontbefound.html', status=404)
+
+ def test_oob_dotdotslash(self):
+ self.testapp.get('/static/../../test_integration.py', status=404)
+
+ def test_oob_dotdotslash_encoded(self):
+ self.testapp.get('/static/%2E%2E%2F/test_integration.py', status=404)
+
+ def test_oob_slash(self):
+ self.testapp.get('/%2F/test_integration.py', status=404)
+
+
+class TestEventOnlySubscribers(IntegrationBase, unittest.TestCase):
+ package = 'tests.pkgs.eventonly'
+
+ def test_sendfoo(self):
+ res = self.testapp.get('/sendfoo', status=200)
+ self.assertEqual(sorted(res.body.split()), [b'foo', b'fooyup'])
+
+ def test_sendfoobar(self):
+ res = self.testapp.get('/sendfoobar', status=200)
+ self.assertEqual(
+ sorted(res.body.split()),
+ [b'foobar', b'foobar2', b'foobaryup', b'foobaryup2'],
+ )
+
+
+class TestStaticAppUsingAbsPath(StaticAppBase, unittest.TestCase):
+ package = 'tests.pkgs.static_abspath'
+
+
+class TestStaticAppUsingAssetSpec(StaticAppBase, unittest.TestCase):
+ package = 'tests.pkgs.static_assetspec'
+
+
+class TestStaticAppNoSubpath(unittest.TestCase):
+ staticapp = static_view(os.path.join(here, 'fixtures'), use_subpath=False)
+
+ def _makeRequest(self, extra):
+ from pyramid.request import Request
+ from io import BytesIO
+
+ kw = {
+ 'PATH_INFO': '',
+ 'SCRIPT_NAME': '',
+ 'SERVER_NAME': 'localhost',
+ 'SERVER_PORT': '80',
+ 'REQUEST_METHOD': 'GET',
+ 'wsgi.version': (1, 0),
+ 'wsgi.url_scheme': 'http',
+ 'wsgi.input': BytesIO(),
+ }
+ kw.update(extra)
+ request = Request(kw)
+ return request
+
+ def test_basic(self):
+ request = self._makeRequest({'PATH_INFO': '/minimal.txt'})
+ context = DummyContext()
+ result = self.staticapp(context, request)
+ self.assertEqual(result.status, '200 OK')
+ _assertBody(result.body, os.path.join(here, 'fixtures/minimal.txt'))
+
+
+class TestStaticAppWithRoutePrefix(IntegrationBase, unittest.TestCase):
+ package = 'tests.pkgs.static_routeprefix'
+
+ def test_includelevel1(self):
+ res = self.testapp.get('/static/minimal.txt', status=200)
+ _assertBody(res.body, os.path.join(here, 'fixtures/minimal.txt'))
+
+ def test_includelevel2(self):
+ res = self.testapp.get('/prefix/static/index.html', status=200)
+ _assertBody(res.body, os.path.join(here, 'fixtures/static/index.html'))
+
+
+class TestFixtureApp(IntegrationBase, unittest.TestCase):
+ package = 'tests.pkgs.fixtureapp'
+
+ def test_another(self):
+ res = self.testapp.get('/another.html', status=200)
+ self.assertEqual(res.body, b'fixture')
+
+ def test_root(self):
+ res = self.testapp.get('/', status=200)
+ self.assertEqual(res.body, b'fixture')
+
+ def test_dummyskin(self):
+ self.testapp.get('/dummyskin.html', status=404)
+
+ def test_error(self):
+ res = self.testapp.get('/error.html', status=200)
+ self.assertEqual(res.body, b'supressed')
+
+ def test_protected(self):
+ self.testapp.get('/protected.html', status=403)
+
+
+class TestStaticPermApp(IntegrationBase, unittest.TestCase):
+ package = 'tests.pkgs.staticpermapp'
+ root_factory = 'tests.pkgs.staticpermapp:RootFactory'
+
+ def test_allowed(self):
+ result = self.testapp.get('/allowed/index.html', status=200)
+ _assertBody(
+ result.body, os.path.join(here, 'fixtures/static/index.html')
+ )
+
+ def test_denied_via_acl_global_root_factory(self):
+ self.testapp.extra_environ = {'REMOTE_USER': 'bob'}
+ self.testapp.get('/protected/index.html', status=403)
+
+ def test_allowed_via_acl_global_root_factory(self):
+ self.testapp.extra_environ = {'REMOTE_USER': 'fred'}
+ result = self.testapp.get('/protected/index.html', status=200)
+ _assertBody(
+ result.body, os.path.join(here, 'fixtures/static/index.html')
+ )
+
+ def test_denied_via_acl_local_root_factory(self):
+ self.testapp.extra_environ = {'REMOTE_USER': 'fred'}
+ self.testapp.get('/factory_protected/index.html', status=403)
+
+ def test_allowed_via_acl_local_root_factory(self):
+ self.testapp.extra_environ = {'REMOTE_USER': 'bob'}
+ result = self.testapp.get('/factory_protected/index.html', status=200)
+ _assertBody(
+ result.body, os.path.join(here, 'fixtures/static/index.html')
+ )
+
+
+class TestCCBug(IntegrationBase, unittest.TestCase):
+ # "unordered" as reported in IRC by author of
+ # http://labs.creativecommons.org/2010/01/13/cc-engine-and-web-non-frameworks/
+ package = 'tests.pkgs.ccbugapp'
+
+ def test_rdf(self):
+ res = self.testapp.get('/licenses/1/v1/rdf', status=200)
+ self.assertEqual(res.body, b'rdf')
+
+ def test_juri(self):
+ res = self.testapp.get('/licenses/1/v1/juri', status=200)
+ self.assertEqual(res.body, b'juri')
+
+
+class TestHybridApp(IntegrationBase, unittest.TestCase):
+ # make sure views registered for a route "win" over views registered
+ # without one, even though the context of the non-route view may
+ # be more specific than the route view.
+ package = 'tests.pkgs.hybridapp'
+
+ def test_root(self):
+ res = self.testapp.get('/', status=200)
+ self.assertEqual(res.body, b'global')
+
+ def test_abc(self):
+ res = self.testapp.get('/abc', status=200)
+ self.assertEqual(res.body, b'route')
+
+ def test_def(self):
+ res = self.testapp.get('/def', status=200)
+ self.assertEqual(res.body, b'route2')
+
+ def test_ghi(self):
+ res = self.testapp.get('/ghi', status=200)
+ self.assertEqual(res.body, b'global')
+
+ def test_jkl(self):
+ self.testapp.get('/jkl', status=404)
+
+ def test_mno(self):
+ self.testapp.get('/mno', status=404)
+
+ def test_pqr_global2(self):
+ res = self.testapp.get('/pqr/global2', status=200)
+ self.assertEqual(res.body, b'global2')
+
+ def test_error(self):
+ res = self.testapp.get('/error', status=200)
+ self.assertEqual(res.body, b'supressed')
+
+ def test_error2(self):
+ res = self.testapp.get('/error2', status=200)
+ self.assertEqual(res.body, b'supressed2')
+
+ def test_error_sub(self):
+ res = self.testapp.get('/error_sub', status=200)
+ self.assertEqual(res.body, b'supressed2')
+
+
+class TestRestBugApp(IntegrationBase, unittest.TestCase):
+ # test bug reported by delijati 2010/2/3 (http://pastebin.com/d4cc15515)
+ package = 'tests.pkgs.restbugapp'
+
+ def test_it(self):
+ res = self.testapp.get('/pet', status=200)
+ self.assertEqual(res.body, b'gotten')
+
+
+class TestForbiddenAppHasResult(IntegrationBase, unittest.TestCase):
+ # test that forbidden exception has ACLDenied result attached
+ package = 'tests.pkgs.forbiddenapp'
+
+ def test_it(self):
+ res = self.testapp.get('/x', status=403)
+ message, result = [x.strip() for x in res.body.split(b'\n')]
+ self.assertTrue(message.endswith(b'failed permission check'))
+ self.assertTrue(
+ result.startswith(
+ b"ACLDenied permission 'private' via ACE "
+ b"'<default deny>' in ACL "
+ b"'<No ACL found on any object in resource "
+ b"lineage>' on context"
+ )
+ )
+ self.assertTrue(result.endswith(b"for principals ['system.Everyone']"))
+
+
+class TestViewDecoratorApp(IntegrationBase, unittest.TestCase):
+ package = 'tests.pkgs.viewdecoratorapp'
+
+ def test_first(self):
+ res = self.testapp.get('/first', status=200)
+ self.assertTrue(b'OK' in res.body)
+
+ def test_second(self):
+ res = self.testapp.get('/second', status=200)
+ self.assertTrue(b'OK2' in res.body)
+
+
+class TestNotFoundView(IntegrationBase, unittest.TestCase):
+ package = 'tests.pkgs.notfoundview'
+
+ def test_it(self):
+ res = self.testapp.get('/wontbefound', status=200)
+ self.assertTrue(b'generic_notfound' in res.body)
+ res = self.testapp.get('/bar', status=307)
+ self.assertEqual(res.location, 'http://localhost/bar/')
+ res = self.testapp.get('/bar/', status=200)
+ self.assertTrue(b'OK bar' in res.body)
+ res = self.testapp.get('/foo', status=307)
+ self.assertEqual(res.location, 'http://localhost/foo/')
+ res = self.testapp.get('/foo/', status=200)
+ self.assertTrue(b'OK foo2' in res.body)
+ res = self.testapp.get('/baz', status=200)
+ self.assertTrue(b'baz_notfound' in res.body)
+
+
+class TestForbiddenView(IntegrationBase, unittest.TestCase):
+ package = 'tests.pkgs.forbiddenview'
+
+ def test_it(self):
+ res = self.testapp.get('/foo', status=200)
+ self.assertTrue(b'foo_forbidden' in res.body)
+ res = self.testapp.get('/bar', status=200)
+ self.assertTrue(b'generic_forbidden' in res.body)
+
+
+class TestViewPermissionBug(IntegrationBase, unittest.TestCase):
+ # view_execution_permitted bug as reported by Shane at
+ # http://lists.repoze.org/pipermail/repoze-dev/2010-October/003603.html
+ package = 'tests.pkgs.permbugapp'
+
+ def test_test(self):
+ res = self.testapp.get('/test', status=200)
+ self.assertTrue(b'ACLDenied' in res.body)
+
+ def test_x(self):
+ self.testapp.get('/x', status=403)
+
+
+class TestDefaultViewPermissionBug(IntegrationBase, unittest.TestCase):
+ # default_view_permission bug as reported by Wiggy at
+ # http://lists.repoze.org/pipermail/repoze-dev/2010-October/003602.html
+ package = 'tests.pkgs.defpermbugapp'
+
+ def test_x(self):
+ res = self.testapp.get('/x', status=403)
+ self.assertTrue(b'failed permission check' in res.body)
+
+ def test_y(self):
+ res = self.testapp.get('/y', status=403)
+ self.assertTrue(b'failed permission check' in res.body)
+
+ def test_z(self):
+ res = self.testapp.get('/z', status=200)
+ self.assertTrue(b'public' in res.body)
+
+
+excroot = {'anexception': AnException(), 'notanexception': NotAnException()}
+
+
+class TestExceptionViewsApp(IntegrationBase, unittest.TestCase):
+ package = 'tests.pkgs.exceptionviewapp'
+ root_factory = lambda *arg: excroot
+
+ def test_root(self):
+ res = self.testapp.get('/', status=200)
+ self.assertTrue(b'maybe' in res.body)
+
+ def test_notanexception(self):
+ res = self.testapp.get('/notanexception', status=200)
+ self.assertTrue(b'no' in res.body)
+
+ def test_anexception(self):
+ res = self.testapp.get('/anexception', status=200)
+ self.assertTrue(b'yes' in res.body)
+
+ def test_route_raise_exception(self):
+ res = self.testapp.get('/route_raise_exception', status=200)
+ self.assertTrue(b'yes' in res.body)
+
+ def test_route_raise_exception2(self):
+ res = self.testapp.get('/route_raise_exception2', status=200)
+ self.assertTrue(b'yes' in res.body)
+
+ def test_route_raise_exception3(self):
+ res = self.testapp.get('/route_raise_exception3', status=200)
+ self.assertTrue(b'whoa' in res.body)
+
+ def test_route_raise_exception4(self):
+ res = self.testapp.get('/route_raise_exception4', status=200)
+ self.assertTrue(b'whoa' in res.body)
+
+ def test_raise_httpexception(self):
+ res = self.testapp.get('/route_raise_httpexception', status=200)
+ self.assertTrue(b'caught' in res.body)
+
+
+class TestConflictApp(unittest.TestCase):
+ package = 'tests.pkgs.conflictapp'
+
+ def _makeConfig(self):
+ from pyramid.config import Configurator
+
+ config = Configurator()
+ return config
+
+ def test_autoresolved_view(self):
+ config = self._makeConfig()
+ config.include(self.package)
+ app = config.make_wsgi_app()
+ self.testapp = TestApp(app)
+ res = self.testapp.get('/')
+ self.assertTrue(b'a view' in res.body)
+ res = self.testapp.get('/route')
+ self.assertTrue(b'route view' in res.body)
+
+ def test_overridden_autoresolved_view(self):
+ from pyramid.response import Response
+
+ config = self._makeConfig()
+ config.include(self.package)
+
+ def thisview(request):
+ return Response('this view')
+
+ config.add_view(thisview)
+ app = config.make_wsgi_app()
+ self.testapp = TestApp(app)
+ res = self.testapp.get('/')
+ self.assertTrue(b'this view' in res.body)
+
+ def test_overridden_route_view(self):
+ from pyramid.response import Response
+
+ config = self._makeConfig()
+ config.include(self.package)
+
+ def thisview(request):
+ return Response('this view')
+
+ config.add_view(thisview, route_name='aroute')
+ app = config.make_wsgi_app()
+ self.testapp = TestApp(app)
+ res = self.testapp.get('/route')
+ self.assertTrue(b'this view' in res.body)
+
+ def test_nonoverridden_authorization_policy(self):
+ config = self._makeConfig()
+ config.include(self.package)
+ app = config.make_wsgi_app()
+ self.testapp = TestApp(app)
+ res = self.testapp.get('/protected', status=403)
+ self.assertTrue(b'403 Forbidden' in res.body)
+
+ def test_overridden_authorization_policy(self):
+ config = self._makeConfig()
+ config.include(self.package)
+ from pyramid.testing import DummySecurityPolicy
+
+ config.set_authorization_policy(DummySecurityPolicy('fred'))
+ config.set_authentication_policy(DummySecurityPolicy(permissive=True))
+ app = config.make_wsgi_app()
+ self.testapp = TestApp(app)
+ res = self.testapp.get('/protected', status=200)
+ self.assertTrue('protected view' in res)
+
+
+class ImperativeIncludeConfigurationTest(unittest.TestCase):
+ def setUp(self):
+ from pyramid.config import Configurator
+
+ config = Configurator()
+ from .pkgs.includeapp1.root import configure
+
+ configure(config)
+ app = config.make_wsgi_app()
+ self.testapp = TestApp(app)
+ self.config = config
+
+ def tearDown(self):
+ self.config.end()
+
+ def test_root(self):
+ res = self.testapp.get('/', status=200)
+ self.assertTrue(b'root' in res.body)
+
+ def test_two(self):
+ res = self.testapp.get('/two', status=200)
+ self.assertTrue(b'two' in res.body)
+
+ def test_three(self):
+ res = self.testapp.get('/three', status=200)
+ self.assertTrue(b'three' in res.body)
+
+
+class SelfScanAppTest(unittest.TestCase):
+ def setUp(self):
+ from .test_config.pkgs.selfscan import main
+
+ config = main()
+ app = config.make_wsgi_app()
+ self.testapp = TestApp(app)
+ self.config = config
+
+ def tearDown(self):
+ self.config.end()
+
+ def test_root(self):
+ res = self.testapp.get('/', status=200)
+ self.assertTrue(b'root' in res.body)
+
+ def test_two(self):
+ res = self.testapp.get('/two', status=200)
+ self.assertTrue(b'two' in res.body)
+
+
+class WSGIApp2AppTest(unittest.TestCase):
+ def setUp(self):
+ from .pkgs.wsgiapp2app import main
+
+ config = main()
+ app = config.make_wsgi_app()
+ self.testapp = TestApp(app)
+ self.config = config
+
+ def tearDown(self):
+ self.config.end()
+
+ def test_hello(self):
+ res = self.testapp.get('/hello', status=200)
+ self.assertTrue(b'Hello' in res.body)
+
+
+class SubrequestAppTest(unittest.TestCase):
+ def setUp(self):
+ from .pkgs.subrequestapp import main
+
+ config = main()
+ app = config.make_wsgi_app()
+ self.testapp = TestApp(app)
+ self.config = config
+
+ def tearDown(self):
+ self.config.end()
+
+ def test_one(self):
+ res = self.testapp.get('/view_one', status=200)
+ self.assertTrue(b'This came from view_two, foo=bar' in res.body)
+
+ def test_three(self):
+ res = self.testapp.get('/view_three', status=500)
+ self.assertTrue(b'Bad stuff happened' in res.body)
+
+ def test_five(self):
+ res = self.testapp.get('/view_five', status=200)
+ self.assertTrue(b'Value error raised' in res.body)
+
+
+class RendererScanAppTest(IntegrationBase, unittest.TestCase):
+ package = 'tests.pkgs.rendererscanapp'
+
+ def test_root(self):
+ res = self.testapp.get('/one', status=200)
+ self.assertTrue(b'One!' in res.body)
+
+ def test_two(self):
+ res = self.testapp.get('/two', status=200)
+ self.assertTrue(b'Two!' in res.body)
+
+ def test_rescan(self):
+ self.config.scan('tests.pkgs.rendererscanapp')
+ app = self.config.make_wsgi_app()
+ testapp = TestApp(app)
+ res = testapp.get('/one', status=200)
+ self.assertTrue(b'One!' in res.body)
+ res = testapp.get('/two', status=200)
+ self.assertTrue(b'Two!' in res.body)
+
+
+class UnicodeInURLTest(unittest.TestCase):
+ def _makeConfig(self):
+ from pyramid.config import Configurator
+
+ config = Configurator()
+ return config
+
+ def _makeTestApp(self, config):
+ app = config.make_wsgi_app()
+ return TestApp(app)
+
+ def test_unicode_in_url_404(self):
+ request_path = '/avalia%C3%A7%C3%A3o_participante'
+ request_path_unicode = b'/avalia\xc3\xa7\xc3\xa3o_participante'.decode(
+ 'utf-8'
+ )
+
+ config = self._makeConfig()
+ testapp = self._makeTestApp(config)
+
+ res = testapp.get(request_path, status=404)
+
+ # Pyramid default 404 handler outputs:
+ # u'404 Not Found\n\nThe resource could not be found.\n\n\n'
+ # u'/avalia\xe7\xe3o_participante\n\n'
+ self.assertTrue(request_path_unicode in res.text)
+
+ def test_unicode_in_url_200(self):
+ request_path = '/avalia%C3%A7%C3%A3o_participante'
+ request_path_unicode = b'/avalia\xc3\xa7\xc3\xa3o_participante'.decode(
+ 'utf-8'
+ )
+
+ def myview(request):
+ return 'XXX'
+
+ config = self._makeConfig()
+ config.add_route('myroute', request_path_unicode)
+ config.add_view(myview, route_name='myroute', renderer='json')
+ testapp = self._makeTestApp(config)
+
+ res = testapp.get(request_path, status=200)
+
+ self.assertEqual(res.text, '"XXX"')
+
+
+class AcceptContentTypeTest(unittest.TestCase):
+ def _makeConfig(self):
+ def hello_view(request):
+ return {'message': 'Hello!'}
+
+ from pyramid.config import Configurator
+
+ config = Configurator()
+ config.add_route('hello', '/hello')
+ config.add_view(
+ hello_view,
+ route_name='hello',
+ accept='text/plain',
+ renderer='string',
+ )
+ config.add_view(
+ hello_view,
+ route_name='hello',
+ accept='application/json',
+ renderer='json',
+ )
+
+ def hello_fallback_view(request):
+ request.response.content_type = 'text/x-fallback'
+ return 'hello fallback'
+
+ config.add_view(
+ hello_fallback_view, route_name='hello', renderer='string'
+ )
+ return config
+
+ def _makeTestApp(self, config):
+ app = config.make_wsgi_app()
+ return TestApp(app)
+
+ def tearDown(self):
+ import pyramid.config
+
+ pyramid.config.global_registries.empty()
+
+ def test_client_side_ordering(self):
+ config = self._makeConfig()
+ app = self._makeTestApp(config)
+ res = app.get(
+ '/hello',
+ headers={'Accept': 'application/json; q=1.0, text/plain; q=0.9'},
+ status=200,
+ )
+ self.assertEqual(res.content_type, 'application/json')
+ res = app.get(
+ '/hello',
+ headers={'Accept': 'text/plain; q=0.9, application/json; q=1.0'},
+ status=200,
+ )
+ self.assertEqual(res.content_type, 'application/json')
+ res = app.get(
+ '/hello', headers={'Accept': 'application/*'}, status=200
+ )
+ self.assertEqual(res.content_type, 'application/json')
+ res = app.get('/hello', headers={'Accept': 'text/*'}, status=200)
+ self.assertEqual(res.content_type, 'text/plain')
+ res = app.get(
+ '/hello', headers={'Accept': 'something/else'}, status=200
+ )
+ self.assertEqual(res.content_type, 'text/x-fallback')
+
+ def test_default_server_side_ordering(self):
+ config = self._makeConfig()
+ app = self._makeTestApp(config)
+ res = app.get(
+ '/hello',
+ headers={'Accept': 'application/json, text/plain'},
+ status=200,
+ )
+ self.assertEqual(res.content_type, 'text/plain')
+ res = app.get(
+ '/hello',
+ headers={'Accept': 'text/plain, application/json'},
+ status=200,
+ )
+ self.assertEqual(res.content_type, 'text/plain')
+ res = app.get('/hello', headers={'Accept': '*/*'}, status=200)
+ self.assertEqual(res.content_type, 'text/plain')
+ res = app.get('/hello', status=200)
+ self.assertEqual(res.content_type, 'text/plain')
+ res = app.get('/hello', headers={'Accept': 'invalid'}, status=200)
+ self.assertEqual(res.content_type, 'text/plain')
+ res = app.get(
+ '/hello', headers={'Accept': 'something/else'}, status=200
+ )
+ self.assertEqual(res.content_type, 'text/x-fallback')
+
+ def test_custom_server_side_ordering(self):
+ config = self._makeConfig()
+ config.add_accept_view_order(
+ 'application/json', weighs_more_than='text/plain'
+ )
+ app = self._makeTestApp(config)
+ res = app.get(
+ '/hello',
+ headers={'Accept': 'application/json, text/plain'},
+ status=200,
+ )
+ self.assertEqual(res.content_type, 'application/json')
+ res = app.get(
+ '/hello',
+ headers={'Accept': 'text/plain, application/json'},
+ status=200,
+ )
+ self.assertEqual(res.content_type, 'application/json')
+ res = app.get('/hello', headers={'Accept': '*/*'}, status=200)
+ self.assertEqual(res.content_type, 'application/json')
+ res = app.get('/hello', status=200)
+ self.assertEqual(res.content_type, 'application/json')
+ res = app.get('/hello', headers={'Accept': 'invalid'}, status=200)
+ self.assertEqual(res.content_type, 'application/json')
+ res = app.get(
+ '/hello', headers={'Accept': 'something/else'}, status=200
+ )
+ self.assertEqual(res.content_type, 'text/x-fallback')
+
+
+class DummyContext(object):
+ pass
+
+
+class DummyRequest:
+ subpath = ('__init__.py',)
+ traversed = None
+ environ = {'REQUEST_METHOD': 'GET', 'wsgi.version': (1, 0)}
+
+ def get_response(self, application):
+ return application(None, None)
+
+
+def httpdate(ts):
+ return ts.strftime("%a, %d %b %Y %H:%M:%S GMT")
+
+
+def read_(filename):
+ with open(filename, 'rb') as fp:
+ val = fp.read()
+ return val
+
+
+def _assertBody(body, filename):
+ if defaultlocale is None: # pragma: no cover
+ # If system locale does not have an encoding then default to utf-8
+ filename = filename.encode('utf-8')
+ # strip both \n and \r for windows
+ body = body.replace(b'\r', b'')
+ body = body.replace(b'\n', b'')
+ data = read_(filename)
+ data = data.replace(b'\r', b'')
+ data = data.replace(b'\n', b'')
+ assert body == data
+
+
+class MemoryLeaksTest(unittest.TestCase):
+ def tearDown(self):
+ import pyramid.config
+
+ pyramid.config.global_registries.empty()
+
+ def get_gc_count(self):
+ last_collected = 0
+ while True:
+ collected = gc.collect()
+ if collected == last_collected:
+ break
+ last_collected = collected
+ return len(gc.get_objects())
+
+ @skip_on('pypy')
+ def test_memory_leaks(self):
+ from pyramid.config import Configurator
+
+ Configurator().make_wsgi_app() # Initialize all global objects
+
+ initial_count = self.get_gc_count()
+ Configurator().make_wsgi_app()
+ current_count = self.get_gc_count()
+ self.assertEqual(current_count, initial_count)
diff --git a/tests/test_location.py b/tests/test_location.py
new file mode 100644
index 000000000..163bb85aa
--- /dev/null
+++ b/tests/test_location.py
@@ -0,0 +1,51 @@
+import unittest
+from zope.interface import implementer
+from pyramid.interfaces import ILocation
+
+
+class TestInside(unittest.TestCase):
+ def _callFUT(self, one, two):
+ from pyramid.location import inside
+
+ return inside(one, two)
+
+ def test_inside(self):
+ o1 = Location()
+ o2 = Location()
+ o2.__parent__ = o1
+ o3 = Location()
+ o3.__parent__ = o2
+ o4 = Location()
+ o4.__parent__ = o3
+
+ self.assertEqual(self._callFUT(o1, o1), True)
+ self.assertEqual(self._callFUT(o2, o1), True)
+ self.assertEqual(self._callFUT(o3, o1), True)
+ self.assertEqual(self._callFUT(o4, o1), True)
+ self.assertEqual(self._callFUT(o1, o4), False)
+ self.assertEqual(self._callFUT(o1, None), False)
+
+
+class TestLineage(unittest.TestCase):
+ def _callFUT(self, context):
+ from pyramid.location import lineage
+
+ return lineage(context)
+
+ def test_lineage(self):
+ o1 = Location()
+ o2 = Location()
+ o2.__parent__ = o1
+ o3 = Location()
+ o3.__parent__ = o2
+ o4 = Location()
+ o4.__parent__ = o3
+ result = list(self._callFUT(o3))
+ self.assertEqual(result, [o3, o2, o1])
+ result = list(self._callFUT(o1))
+ self.assertEqual(result, [o1])
+
+
+@implementer(ILocation)
+class Location(object):
+ __name__ = __parent__ = None
diff --git a/tests/test_paster.py b/tests/test_paster.py
new file mode 100644
index 000000000..dd53195c7
--- /dev/null
+++ b/tests/test_paster.py
@@ -0,0 +1,193 @@
+import os
+import unittest
+from .test_scripts.dummy import DummyLoader
+
+here = os.path.dirname(__file__)
+
+
+class Test_get_app(unittest.TestCase):
+ def _callFUT(self, config_file, section_name, options=None, _loader=None):
+ import pyramid.paster
+
+ old_loader = pyramid.paster.get_config_loader
+ try:
+ if _loader is not None:
+ pyramid.paster.get_config_loader = _loader
+ return pyramid.paster.get_app(
+ config_file, section_name, options=options
+ )
+ finally:
+ pyramid.paster.get_config_loader = old_loader
+
+ def test_it(self):
+ app = DummyApp()
+ loader = DummyLoader(app=app)
+ result = self._callFUT(
+ '/foo/bar/myapp.ini', 'myapp', options={'a': 'b'}, _loader=loader
+ )
+ self.assertEqual(loader.uri.path, '/foo/bar/myapp.ini')
+ self.assertEqual(len(loader.calls), 1)
+ self.assertEqual(loader.calls[0]['op'], 'app')
+ self.assertEqual(loader.calls[0]['name'], 'myapp')
+ self.assertEqual(loader.calls[0]['defaults'], {'a': 'b'})
+ self.assertEqual(result, app)
+
+ def test_it_with_dummyapp_requiring_options(self):
+ options = {'bar': 'baz'}
+ app = self._callFUT(
+ os.path.join(here, 'fixtures', 'dummy.ini'),
+ 'myapp',
+ options=options,
+ )
+ self.assertEqual(app.settings['foo'], 'baz')
+
+
+class Test_get_appsettings(unittest.TestCase):
+ def _callFUT(self, config_file, section_name, options=None, _loader=None):
+ import pyramid.paster
+
+ old_loader = pyramid.paster.get_config_loader
+ try:
+ if _loader is not None:
+ pyramid.paster.get_config_loader = _loader
+ return pyramid.paster.get_appsettings(
+ config_file, section_name, options=options
+ )
+ finally:
+ pyramid.paster.get_config_loader = old_loader
+
+ def test_it(self):
+ values = {'a': 1}
+ loader = DummyLoader(app_settings=values)
+ result = self._callFUT(
+ '/foo/bar/myapp.ini', 'myapp', options={'a': 'b'}, _loader=loader
+ )
+ self.assertEqual(loader.uri.path, '/foo/bar/myapp.ini')
+ self.assertEqual(len(loader.calls), 1)
+ self.assertEqual(loader.calls[0]['op'], 'app_settings')
+ self.assertEqual(loader.calls[0]['name'], 'myapp')
+ self.assertEqual(loader.calls[0]['defaults'], {'a': 'b'})
+ self.assertEqual(result, values)
+
+ def test_it_with_dummyapp_requiring_options(self):
+ options = {'bar': 'baz'}
+ result = self._callFUT(
+ os.path.join(here, 'fixtures', 'dummy.ini'),
+ 'myapp',
+ options=options,
+ )
+ self.assertEqual(result['foo'], 'baz')
+
+
+class Test_setup_logging(unittest.TestCase):
+ def _callFUT(self, config_file, global_conf=None, _loader=None):
+ import pyramid.paster
+
+ old_loader = pyramid.paster.get_config_loader
+ try:
+ if _loader is not None:
+ pyramid.paster.get_config_loader = _loader
+ return pyramid.paster.setup_logging(config_file, global_conf)
+ finally:
+ pyramid.paster.get_config_loader = old_loader
+
+ def test_it_no_global_conf(self):
+ loader = DummyLoader()
+ self._callFUT('/abc.ini', _loader=loader)
+ self.assertEqual(loader.uri.path, '/abc.ini')
+ self.assertEqual(len(loader.calls), 1)
+ self.assertEqual(loader.calls[0]['op'], 'logging')
+ self.assertEqual(loader.calls[0]['defaults'], None)
+
+ def test_it_global_conf_empty(self):
+ loader = DummyLoader()
+ self._callFUT('/abc.ini', global_conf={}, _loader=loader)
+ self.assertEqual(loader.uri.path, '/abc.ini')
+ self.assertEqual(len(loader.calls), 1)
+ self.assertEqual(loader.calls[0]['op'], 'logging')
+ self.assertEqual(loader.calls[0]['defaults'], {})
+
+ def test_it_global_conf_not_empty(self):
+ loader = DummyLoader()
+ self._callFUT('/abc.ini', global_conf={'key': 'val'}, _loader=loader)
+ self.assertEqual(loader.uri.path, '/abc.ini')
+ self.assertEqual(len(loader.calls), 1)
+ self.assertEqual(loader.calls[0]['op'], 'logging')
+ self.assertEqual(loader.calls[0]['defaults'], {'key': 'val'})
+
+
+class Test_bootstrap(unittest.TestCase):
+ def _callFUT(self, config_uri, request=None):
+ from pyramid.paster import bootstrap
+
+ return bootstrap(config_uri, request)
+
+ def setUp(self):
+ import pyramid.paster
+
+ self.original_get_app = pyramid.paster.get_app
+ self.original_prepare = pyramid.paster.prepare
+ self.app = app = DummyApp()
+ self.root = root = Dummy()
+
+ class DummyGetApp(object):
+ def __call__(self, *a, **kw):
+ self.a = a
+ self.kw = kw
+ return app
+
+ self.get_app = pyramid.paster.get_app = DummyGetApp()
+
+ class DummyPrepare(object):
+ def __call__(self, *a, **kw):
+ self.a = a
+ self.kw = kw
+ return {'root': root, 'closer': lambda: None}
+
+ self.getroot = pyramid.paster.prepare = DummyPrepare()
+
+ def tearDown(self):
+ import pyramid.paster
+
+ pyramid.paster.get_app = self.original_get_app
+ pyramid.paster.prepare = self.original_prepare
+
+ def test_it_request_with_registry(self):
+ request = DummyRequest({})
+ request.registry = dummy_registry
+ result = self._callFUT('/foo/bar/myapp.ini', request)
+ self.assertEqual(result['app'], self.app)
+ self.assertEqual(result['root'], self.root)
+ self.assertTrue('closer' in result)
+
+
+class Dummy:
+ pass
+
+
+class DummyRegistry(object):
+ settings = {}
+
+
+dummy_registry = DummyRegistry()
+
+
+class DummyApp:
+ def __init__(self):
+ self.registry = dummy_registry
+
+
+def make_dummyapp(global_conf, **settings):
+ app = DummyApp()
+ app.settings = settings
+ app.global_conf = global_conf
+ return app
+
+
+class DummyRequest:
+ application_url = 'http://example.com:5432'
+ script_name = ''
+
+ def __init__(self, environ):
+ self.environ = environ
+ self.matchdict = {}
diff --git a/tests/test_path.py b/tests/test_path.py
new file mode 100644
index 000000000..626bb1139
--- /dev/null
+++ b/tests/test_path.py
@@ -0,0 +1,665 @@
+import unittest
+import os
+from pyramid.compat import PY2
+
+here = os.path.abspath(os.path.dirname(__file__))
+
+
+class TestCallerPath(unittest.TestCase):
+ def tearDown(self):
+ from . import test_path
+
+ if hasattr(test_path, '__abspath__'):
+ del test_path.__abspath__
+
+ def _callFUT(self, path, level=2):
+ from pyramid.path import caller_path
+
+ return caller_path(path, level)
+
+ def test_isabs(self):
+ result = self._callFUT('/a/b/c')
+ self.assertEqual(result, '/a/b/c')
+
+ def test_pkgrelative(self):
+ import os
+
+ result = self._callFUT('a/b/c')
+ self.assertEqual(result, os.path.join(here, 'a/b/c'))
+
+ def test_memoization_has_abspath(self):
+ import os
+ from . import test_path
+
+ test_path.__abspath__ = '/foo/bar'
+ result = self._callFUT('a/b/c')
+ self.assertEqual(result, os.path.join('/foo/bar', 'a/b/c'))
+
+ def test_memoization_success(self):
+ import os
+ from . import test_path
+
+ result = self._callFUT('a/b/c')
+ self.assertEqual(result, os.path.join(here, 'a/b/c'))
+ self.assertEqual(test_path.__abspath__, here)
+
+
+class TestCallerModule(unittest.TestCase):
+ def _callFUT(self, *arg, **kw):
+ from pyramid.path import caller_module
+
+ return caller_module(*arg, **kw)
+
+ def test_it_level_1(self):
+ from . import test_path
+
+ result = self._callFUT(1)
+ self.assertEqual(result, test_path)
+
+ def test_it_level_2(self):
+ from . import test_path
+
+ result = self._callFUT(2)
+ self.assertEqual(result, test_path)
+
+ def test_it_level_3(self):
+ from . import test_path
+
+ result = self._callFUT(3)
+ self.assertNotEqual(result, test_path)
+
+ def test_it_no___name__(self):
+ class DummyFrame(object):
+ f_globals = {}
+
+ class DummySys(object):
+ def _getframe(self, level):
+ return DummyFrame()
+
+ modules = {'__main__': 'main'}
+
+ dummy_sys = DummySys()
+ result = self._callFUT(3, sys=dummy_sys)
+ self.assertEqual(result, 'main')
+
+
+class TestCallerPackage(unittest.TestCase):
+ def _callFUT(self, *arg, **kw):
+ from pyramid.path import caller_package
+
+ return caller_package(*arg, **kw)
+
+ def test_it_level_1(self):
+ import tests
+
+ result = self._callFUT(1)
+ self.assertEqual(result, tests)
+
+ def test_it_level_2(self):
+ import tests
+
+ result = self._callFUT(2)
+ self.assertEqual(result, tests)
+
+ def test_it_level_3(self):
+ import unittest
+
+ result = self._callFUT(3)
+ self.assertEqual(result, unittest)
+
+ def test_it_package(self):
+ import tests
+
+ def dummy_caller_module(*arg):
+ return tests
+
+ result = self._callFUT(1, caller_module=dummy_caller_module)
+ self.assertEqual(result, tests)
+
+
+class TestPackagePath(unittest.TestCase):
+ def _callFUT(self, package):
+ from pyramid.path import package_path
+
+ return package_path(package)
+
+ def test_it_package(self):
+ import tests
+
+ package = DummyPackageOrModule(tests)
+ result = self._callFUT(package)
+ self.assertEqual(result, package.package_path)
+
+ def test_it_module(self):
+ from . import test_path
+
+ module = DummyPackageOrModule(test_path)
+ result = self._callFUT(module)
+ self.assertEqual(result, module.package_path)
+
+ def test_memoization_success(self):
+ from . import test_path
+
+ module = DummyPackageOrModule(test_path)
+ self._callFUT(module)
+ self.assertEqual(module.__abspath__, module.package_path)
+
+ def test_memoization_fail(self):
+ from . import test_path
+
+ module = DummyPackageOrModule(test_path, raise_exc=TypeError)
+ result = self._callFUT(module)
+ self.assertFalse(hasattr(module, '__abspath__'))
+ self.assertEqual(result, module.package_path)
+
+
+class TestPackageOf(unittest.TestCase):
+ def _callFUT(self, package):
+ from pyramid.path import package_of
+
+ return package_of(package)
+
+ def test_it_package(self):
+ import tests
+
+ package = DummyPackageOrModule(tests)
+ result = self._callFUT(package)
+ self.assertEqual(result, tests)
+
+ def test_it_module(self):
+ import tests.test_path
+ import tests
+
+ package = DummyPackageOrModule(tests.test_path)
+ result = self._callFUT(package)
+ self.assertEqual(result, tests)
+
+
+class TestPackageName(unittest.TestCase):
+ def _callFUT(self, package):
+ from pyramid.path import package_name
+
+ return package_name(package)
+
+ def test_it_package(self):
+ import tests
+
+ package = DummyPackageOrModule(tests)
+ result = self._callFUT(package)
+ self.assertEqual(result, 'tests')
+
+ def test_it_namespace_package(self):
+ import tests
+
+ package = DummyNamespacePackage(tests)
+ result = self._callFUT(package)
+ self.assertEqual(result, 'tests')
+
+ def test_it_module(self):
+ from . import test_path
+
+ module = DummyPackageOrModule(test_path)
+ result = self._callFUT(module)
+ self.assertEqual(result, 'tests')
+
+ def test_it_None(self):
+ result = self._callFUT(None)
+ self.assertEqual(result, '__main__')
+
+ def test_it_main(self):
+ import __main__
+
+ result = self._callFUT(__main__)
+ self.assertEqual(result, '__main__')
+
+
+class TestResolver(unittest.TestCase):
+ def _getTargetClass(self):
+ from pyramid.path import Resolver
+
+ return Resolver
+
+ def _makeOne(self, package):
+ return self._getTargetClass()(package)
+
+ def test_get_package_caller_package(self):
+ import tests
+ from pyramid.path import CALLER_PACKAGE
+
+ self.assertEqual(self._makeOne(CALLER_PACKAGE).get_package(), tests)
+
+ def test_get_package_name_caller_package(self):
+ from pyramid.path import CALLER_PACKAGE
+
+ self.assertEqual(
+ self._makeOne(CALLER_PACKAGE).get_package_name(), 'tests'
+ )
+
+ def test_get_package_string(self):
+ import tests
+
+ self.assertEqual(self._makeOne('tests').get_package(), tests)
+
+ def test_get_package_name_string(self):
+ self.assertEqual(self._makeOne('tests').get_package_name(), 'tests')
+
+
+class TestAssetResolver(unittest.TestCase):
+ def _getTargetClass(self):
+ from pyramid.path import AssetResolver
+
+ return AssetResolver
+
+ def _makeOne(self, package='tests'):
+ return self._getTargetClass()(package)
+
+ def test_ctor_as_package(self):
+ import sys
+
+ tests = sys.modules['tests']
+ inst = self._makeOne(tests)
+ self.assertEqual(inst.package, tests)
+
+ def test_ctor_as_str(self):
+ import sys
+
+ tests = sys.modules['tests']
+ inst = self._makeOne('tests')
+ self.assertEqual(inst.package, tests)
+
+ def test_resolve_abspath(self):
+ from pyramid.path import FSAssetDescriptor
+
+ inst = self._makeOne(None)
+ r = inst.resolve(os.path.join(here, 'test_asset.py'))
+ self.assertEqual(r.__class__, FSAssetDescriptor)
+ self.assertTrue(r.exists())
+
+ def test_resolve_absspec(self):
+ from pyramid.path import PkgResourcesAssetDescriptor
+
+ inst = self._makeOne(None)
+ r = inst.resolve('tests:test_asset.py')
+ self.assertEqual(r.__class__, PkgResourcesAssetDescriptor)
+ self.assertTrue(r.exists())
+
+ def test_resolve_relspec_with_pkg(self):
+ from pyramid.path import PkgResourcesAssetDescriptor
+
+ inst = self._makeOne('tests')
+ r = inst.resolve('test_asset.py')
+ self.assertEqual(r.__class__, PkgResourcesAssetDescriptor)
+ self.assertTrue(r.exists())
+
+ def test_resolve_relspec_no_package(self):
+ inst = self._makeOne(None)
+ self.assertRaises(ValueError, inst.resolve, 'test_asset.py')
+
+ def test_resolve_relspec_caller_package(self):
+ from pyramid.path import PkgResourcesAssetDescriptor
+ from pyramid.path import CALLER_PACKAGE
+
+ inst = self._makeOne(CALLER_PACKAGE)
+ r = inst.resolve('test_asset.py')
+ self.assertEqual(r.__class__, PkgResourcesAssetDescriptor)
+ self.assertTrue(r.exists())
+
+
+class TestPkgResourcesAssetDescriptor(unittest.TestCase):
+ def _getTargetClass(self):
+ from pyramid.path import PkgResourcesAssetDescriptor
+
+ return PkgResourcesAssetDescriptor
+
+ def _makeOne(self, pkg='tests', path='test_asset.py'):
+ return self._getTargetClass()(pkg, path)
+
+ def test_class_conforms_to_IAssetDescriptor(self):
+ from pyramid.interfaces import IAssetDescriptor
+ from zope.interface.verify import verifyClass
+
+ verifyClass(IAssetDescriptor, self._getTargetClass())
+
+ def test_instance_conforms_to_IAssetDescriptor(self):
+ from pyramid.interfaces import IAssetDescriptor
+ from zope.interface.verify import verifyObject
+
+ verifyObject(IAssetDescriptor, self._makeOne())
+
+ def test_absspec(self):
+ inst = self._makeOne()
+ self.assertEqual(inst.absspec(), 'tests:test_asset.py')
+
+ def test_abspath(self):
+ inst = self._makeOne()
+ self.assertEqual(inst.abspath(), os.path.join(here, 'test_asset.py'))
+
+ def test_stream(self):
+ inst = self._makeOne()
+ inst.pkg_resources = DummyPkgResource()
+ inst.pkg_resources.resource_stream = lambda x, y: '%s:%s' % (x, y)
+ s = inst.stream()
+ self.assertEqual(s, '%s:%s' % ('tests', 'test_asset.py'))
+
+ def test_isdir(self):
+ inst = self._makeOne()
+ inst.pkg_resources = DummyPkgResource()
+ inst.pkg_resources.resource_isdir = lambda x, y: '%s:%s' % (x, y)
+ self.assertEqual(inst.isdir(), '%s:%s' % ('tests', 'test_asset.py'))
+
+ def test_listdir(self):
+ inst = self._makeOne()
+ inst.pkg_resources = DummyPkgResource()
+ inst.pkg_resources.resource_listdir = lambda x, y: '%s:%s' % (x, y)
+ self.assertEqual(inst.listdir(), '%s:%s' % ('tests', 'test_asset.py'))
+
+ def test_exists(self):
+ inst = self._makeOne()
+ inst.pkg_resources = DummyPkgResource()
+ inst.pkg_resources.resource_exists = lambda x, y: '%s:%s' % (x, y)
+ self.assertEqual(inst.exists(), '%s:%s' % ('tests', 'test_asset.py'))
+
+
+class TestFSAssetDescriptor(unittest.TestCase):
+ def _getTargetClass(self):
+ from pyramid.path import FSAssetDescriptor
+
+ return FSAssetDescriptor
+
+ def _makeOne(self, path=os.path.join(here, 'test_asset.py')):
+ return self._getTargetClass()(path)
+
+ def test_class_conforms_to_IAssetDescriptor(self):
+ from pyramid.interfaces import IAssetDescriptor
+ from zope.interface.verify import verifyClass
+
+ verifyClass(IAssetDescriptor, self._getTargetClass())
+
+ def test_instance_conforms_to_IAssetDescriptor(self):
+ from pyramid.interfaces import IAssetDescriptor
+ from zope.interface.verify import verifyObject
+
+ verifyObject(IAssetDescriptor, self._makeOne())
+
+ def test_absspec(self):
+ inst = self._makeOne()
+ self.assertRaises(NotImplementedError, inst.absspec)
+
+ def test_abspath(self):
+ inst = self._makeOne()
+ self.assertEqual(inst.abspath(), os.path.join(here, 'test_asset.py'))
+
+ def test_stream(self):
+ inst = self._makeOne()
+ s = inst.stream()
+ val = s.read()
+ s.close()
+ self.assertTrue(b'asset' in val)
+
+ def test_isdir_False(self):
+ inst = self._makeOne()
+ self.assertFalse(inst.isdir())
+
+ def test_isdir_True(self):
+ inst = self._makeOne(here)
+ self.assertTrue(inst.isdir())
+
+ def test_listdir(self):
+ inst = self._makeOne(here)
+ self.assertTrue(inst.listdir())
+
+ def test_exists(self):
+ inst = self._makeOne()
+ self.assertTrue(inst.exists())
+
+
+class TestDottedNameResolver(unittest.TestCase):
+ def _makeOne(self, package=None):
+ from pyramid.path import DottedNameResolver
+
+ return DottedNameResolver(package)
+
+ def config_exc(self, func, *arg, **kw):
+ try:
+ func(*arg, **kw)
+ except ValueError as e:
+ return e
+ else:
+ raise AssertionError('Invalid not raised') # pragma: no cover
+
+ def test_zope_dottedname_style_resolve_builtin(self):
+ typ = self._makeOne()
+ if PY2:
+ result = typ._zope_dottedname_style('__builtin__.str', None)
+ else:
+ result = typ._zope_dottedname_style('builtins.str', None)
+ self.assertEqual(result, str)
+
+ def test_zope_dottedname_style_resolve_absolute(self):
+ typ = self._makeOne()
+ result = typ._zope_dottedname_style(
+ 'tests.test_path.TestDottedNameResolver', None
+ )
+ self.assertEqual(result, self.__class__)
+
+ def test_zope_dottedname_style_irrresolveable_absolute(self):
+ typ = self._makeOne()
+ self.assertRaises(
+ ImportError,
+ typ._zope_dottedname_style,
+ 'pyramid.test_path.nonexisting_name',
+ None,
+ )
+
+ def test__zope_dottedname_style_resolve_relative(self):
+ import tests
+
+ typ = self._makeOne()
+ result = typ._zope_dottedname_style(
+ '.test_path.TestDottedNameResolver', tests
+ )
+ self.assertEqual(result, self.__class__)
+
+ def test__zope_dottedname_style_resolve_relative_leading_dots(self):
+ import tests.test_path
+
+ typ = self._makeOne()
+ result = typ._zope_dottedname_style(
+ '..tests.test_path.TestDottedNameResolver', tests
+ )
+ self.assertEqual(result, self.__class__)
+
+ def test__zope_dottedname_style_resolve_relative_is_dot(self):
+ import tests
+
+ typ = self._makeOne()
+ result = typ._zope_dottedname_style('.', tests)
+ self.assertEqual(result, tests)
+
+ def test__zope_dottedname_style_irresolveable_relative_is_dot(self):
+ typ = self._makeOne()
+ e = self.config_exc(typ._zope_dottedname_style, '.', None)
+ self.assertEqual(
+ e.args[0], "relative name '.' irresolveable without package"
+ )
+
+ def test_zope_dottedname_style_resolve_relative_nocurrentpackage(self):
+ typ = self._makeOne()
+ e = self.config_exc(typ._zope_dottedname_style, '.whatever', None)
+ self.assertEqual(
+ e.args[0],
+ "relative name '.whatever' irresolveable without package",
+ )
+
+ def test_zope_dottedname_style_irrresolveable_relative(self):
+ import tests
+
+ typ = self._makeOne()
+ self.assertRaises(
+ ImportError, typ._zope_dottedname_style, '.notexisting', tests
+ )
+
+ def test__zope_dottedname_style_resolveable_relative(self):
+ import tests
+
+ typ = self._makeOne()
+ result = typ._zope_dottedname_style('.', tests)
+ self.assertEqual(result, tests)
+
+ def test__zope_dottedname_style_irresolveable_absolute(self):
+ typ = self._makeOne()
+ self.assertRaises(
+ ImportError, typ._zope_dottedname_style, 'pyramid.fudge.bar', None
+ )
+
+ def test__zope_dottedname_style_resolveable_absolute(self):
+ typ = self._makeOne()
+ result = typ._zope_dottedname_style(
+ 'tests.test_path.TestDottedNameResolver', None
+ )
+ self.assertEqual(result, self.__class__)
+
+ def test__pkg_resources_style_resolve_absolute(self):
+ typ = self._makeOne()
+ result = typ._pkg_resources_style(
+ 'tests.test_path:TestDottedNameResolver', None
+ )
+ self.assertEqual(result, self.__class__)
+
+ def test__pkg_resources_style_irrresolveable_absolute(self):
+ typ = self._makeOne()
+ self.assertRaises(
+ ImportError, typ._pkg_resources_style, 'tests:nonexisting', None
+ )
+
+ def test__pkg_resources_style_resolve_relative(self):
+ import tests
+
+ typ = self._makeOne()
+ result = typ._pkg_resources_style(
+ '.test_path:TestDottedNameResolver', tests
+ )
+ self.assertEqual(result, self.__class__)
+
+ def test__pkg_resources_style_resolve_relative_is_dot(self):
+ import tests
+
+ typ = self._makeOne()
+ result = typ._pkg_resources_style('.', tests)
+ self.assertEqual(result, tests)
+
+ def test__pkg_resources_style_resolve_relative_nocurrentpackage(self):
+ typ = self._makeOne()
+ self.assertRaises(
+ ValueError, typ._pkg_resources_style, '.whatever', None
+ )
+
+ def test__pkg_resources_style_irrresolveable_relative(self):
+ import pyramid
+
+ typ = self._makeOne()
+ self.assertRaises(
+ ImportError, typ._pkg_resources_style, ':notexisting', pyramid
+ )
+
+ def test_resolve_not_a_string(self):
+ typ = self._makeOne()
+ e = self.config_exc(typ.resolve, None)
+ self.assertEqual(e.args[0], 'None is not a string')
+
+ def test_resolve_using_pkgresources_style(self):
+ typ = self._makeOne()
+ result = typ.resolve('tests.test_path:TestDottedNameResolver')
+ self.assertEqual(result, self.__class__)
+
+ def test_resolve_using_zope_dottedname_style(self):
+ typ = self._makeOne()
+ result = typ.resolve('tests.test_path:TestDottedNameResolver')
+ self.assertEqual(result, self.__class__)
+
+ def test_resolve_missing_raises(self):
+ typ = self._makeOne()
+ self.assertRaises(ImportError, typ.resolve, 'cant.be.found')
+
+ def test_resolve_caller_package(self):
+ from pyramid.path import CALLER_PACKAGE
+
+ typ = self._makeOne(CALLER_PACKAGE)
+ self.assertEqual(
+ typ.resolve('.test_path.TestDottedNameResolver'), self.__class__
+ )
+
+ def test_maybe_resolve_caller_package(self):
+ from pyramid.path import CALLER_PACKAGE
+
+ typ = self._makeOne(CALLER_PACKAGE)
+ self.assertEqual(
+ typ.maybe_resolve('.test_path.TestDottedNameResolver'),
+ self.__class__,
+ )
+
+ def test_ctor_string_module_resolveable(self):
+ import tests
+
+ typ = self._makeOne('tests.test_path')
+ self.assertEqual(typ.package, tests)
+
+ def test_ctor_string_package_resolveable(self):
+ import tests
+
+ typ = self._makeOne('tests')
+ self.assertEqual(typ.package, tests)
+
+ def test_ctor_string_irresolveable(self):
+ self.assertRaises(ValueError, self._makeOne, 'cant.be.found')
+
+ def test_ctor_module(self):
+ import tests
+ from . import test_path
+
+ typ = self._makeOne(test_path)
+ self.assertEqual(typ.package, tests)
+
+ def test_ctor_package(self):
+ import tests
+
+ typ = self._makeOne(tests)
+ self.assertEqual(typ.package, tests)
+
+ def test_ctor_None(self):
+ typ = self._makeOne(None)
+ self.assertEqual(typ.package, None)
+
+
+class DummyPkgResource(object):
+ pass
+
+
+class DummyPackageOrModule:
+ def __init__(self, real_package_or_module, raise_exc=None):
+ self.__dict__['raise_exc'] = raise_exc
+ self.__dict__['__name__'] = real_package_or_module.__name__
+ import os
+
+ self.__dict__['package_path'] = os.path.dirname(
+ os.path.abspath(real_package_or_module.__file__)
+ )
+ self.__dict__['__file__'] = real_package_or_module.__file__
+
+ def __setattr__(self, key, val):
+ if self.raise_exc is not None:
+ raise self.raise_exc
+ self.__dict__[key] = val
+
+
+class DummyNamespacePackage:
+ """Has no __file__ attribute.
+ """
+
+ def __init__(self, real_package_or_module):
+ self.__name__ = real_package_or_module.__name__
+ import os
+
+ self.package_path = os.path.dirname(
+ os.path.abspath(real_package_or_module.__file__)
+ )
diff --git a/tests/test_predicates.py b/tests/test_predicates.py
new file mode 100644
index 000000000..c072b4229
--- /dev/null
+++ b/tests/test_predicates.py
@@ -0,0 +1,594 @@
+import unittest
+
+from pyramid import testing
+
+from pyramid.compat import text_
+
+
+class TestXHRPredicate(unittest.TestCase):
+ def _makeOne(self, val):
+ from pyramid.predicates import XHRPredicate
+
+ return XHRPredicate(val, None)
+
+ def test___call___true(self):
+ inst = self._makeOne(True)
+ request = Dummy()
+ request.is_xhr = True
+ result = inst(None, request)
+ self.assertTrue(result)
+
+ def test___call___false(self):
+ inst = self._makeOne(True)
+ request = Dummy()
+ request.is_xhr = False
+ result = inst(None, request)
+ self.assertFalse(result)
+
+ def test_text(self):
+ inst = self._makeOne(True)
+ self.assertEqual(inst.text(), 'xhr = True')
+
+ def test_phash(self):
+ inst = self._makeOne(True)
+ self.assertEqual(inst.phash(), 'xhr = True')
+
+
+class TestRequestMethodPredicate(unittest.TestCase):
+ def _makeOne(self, val):
+ from pyramid.predicates import RequestMethodPredicate
+
+ return RequestMethodPredicate(val, None)
+
+ def test_ctor_get_but_no_head(self):
+ inst = self._makeOne('GET')
+ self.assertEqual(inst.val, ('GET', 'HEAD'))
+
+ def test___call___true_single(self):
+ inst = self._makeOne('GET')
+ request = Dummy()
+ request.method = 'GET'
+ result = inst(None, request)
+ self.assertTrue(result)
+
+ def test___call___true_multi(self):
+ inst = self._makeOne(('GET', 'HEAD'))
+ request = Dummy()
+ request.method = 'GET'
+ result = inst(None, request)
+ self.assertTrue(result)
+
+ def test___call___false(self):
+ inst = self._makeOne(('GET', 'HEAD'))
+ request = Dummy()
+ request.method = 'POST'
+ result = inst(None, request)
+ self.assertFalse(result)
+
+ def test_text(self):
+ inst = self._makeOne(('HEAD', 'GET'))
+ self.assertEqual(inst.text(), 'request_method = GET,HEAD')
+
+ def test_phash(self):
+ inst = self._makeOne(('HEAD', 'GET'))
+ self.assertEqual(inst.phash(), 'request_method = GET,HEAD')
+
+
+class TestPathInfoPredicate(unittest.TestCase):
+ def _makeOne(self, val):
+ from pyramid.predicates import PathInfoPredicate
+
+ return PathInfoPredicate(val, None)
+
+ def test_ctor_compilefail(self):
+ from pyramid.exceptions import ConfigurationError
+
+ self.assertRaises(ConfigurationError, self._makeOne, '\\')
+
+ def test___call___true(self):
+ inst = self._makeOne(r'/\d{2}')
+ request = Dummy()
+ request.upath_info = text_('/12')
+ result = inst(None, request)
+ self.assertTrue(result)
+
+ def test___call___false(self):
+ inst = self._makeOne(r'/\d{2}')
+ request = Dummy()
+ request.upath_info = text_('/n12')
+ result = inst(None, request)
+ self.assertFalse(result)
+
+ def test_text(self):
+ inst = self._makeOne('/')
+ self.assertEqual(inst.text(), 'path_info = /')
+
+ def test_phash(self):
+ inst = self._makeOne('/')
+ self.assertEqual(inst.phash(), 'path_info = /')
+
+
+class TestRequestParamPredicate(unittest.TestCase):
+ def _makeOne(self, val):
+ from pyramid.predicates import RequestParamPredicate
+
+ return RequestParamPredicate(val, None)
+
+ def test___call___true_exists(self):
+ inst = self._makeOne('abc')
+ request = Dummy()
+ request.params = {'abc': 1}
+ result = inst(None, request)
+ self.assertTrue(result)
+
+ def test___call___true_withval(self):
+ inst = self._makeOne('abc=1')
+ request = Dummy()
+ request.params = {'abc': '1'}
+ result = inst(None, request)
+ self.assertTrue(result)
+
+ def test___call___true_multi(self):
+ inst = self._makeOne(('abc', '=def =2= '))
+ request = Dummy()
+ request.params = {'abc': '1', '=def': '2='}
+ result = inst(None, request)
+ self.assertTrue(result)
+
+ def test___call___false_multi(self):
+ inst = self._makeOne(('abc=3', 'def =2 '))
+ request = Dummy()
+ request.params = {'abc': '3', 'def': '1'}
+ result = inst(None, request)
+ self.assertFalse(result)
+
+ def test___call___false(self):
+ inst = self._makeOne('abc')
+ request = Dummy()
+ request.params = {}
+ result = inst(None, request)
+ self.assertFalse(result)
+
+ def test_text_exists(self):
+ inst = self._makeOne('abc')
+ self.assertEqual(inst.text(), 'request_param abc')
+
+ def test_text_exists_equal_sign(self):
+ inst = self._makeOne('=abc')
+ self.assertEqual(inst.text(), 'request_param =abc')
+
+ def test_text_withval(self):
+ inst = self._makeOne('abc= 1')
+ self.assertEqual(inst.text(), 'request_param abc=1')
+
+ def test_text_multi(self):
+ inst = self._makeOne(('abc= 1', 'def'))
+ self.assertEqual(inst.text(), 'request_param abc=1,def')
+
+ def test_text_multi_equal_sign(self):
+ inst = self._makeOne(('abc= 1', '=def= 2'))
+ self.assertEqual(inst.text(), 'request_param =def=2,abc=1')
+
+ def test_phash_exists(self):
+ inst = self._makeOne('abc')
+ self.assertEqual(inst.phash(), 'request_param abc')
+
+ def test_phash_exists_equal_sign(self):
+ inst = self._makeOne('=abc')
+ self.assertEqual(inst.phash(), 'request_param =abc')
+
+ def test_phash_withval(self):
+ inst = self._makeOne('abc= 1')
+ self.assertEqual(inst.phash(), "request_param abc=1")
+
+
+class TestMatchParamPredicate(unittest.TestCase):
+ def _makeOne(self, val):
+ from pyramid.predicates import MatchParamPredicate
+
+ return MatchParamPredicate(val, None)
+
+ def test___call___true_single(self):
+ inst = self._makeOne('abc=1')
+ request = Dummy()
+ request.matchdict = {'abc': '1'}
+ result = inst(None, request)
+ self.assertTrue(result)
+
+ def test___call___true_multi(self):
+ inst = self._makeOne(('abc=1', 'def=2'))
+ request = Dummy()
+ request.matchdict = {'abc': '1', 'def': '2'}
+ result = inst(None, request)
+ self.assertTrue(result)
+
+ def test___call___false(self):
+ inst = self._makeOne('abc=1')
+ request = Dummy()
+ request.matchdict = {}
+ result = inst(None, request)
+ self.assertFalse(result)
+
+ def test___call___matchdict_is_None(self):
+ inst = self._makeOne('abc=1')
+ request = Dummy()
+ request.matchdict = None
+ result = inst(None, request)
+ self.assertFalse(result)
+
+ def test_text(self):
+ inst = self._makeOne(('def= 1', 'abc =2'))
+ self.assertEqual(inst.text(), 'match_param abc=2,def=1')
+
+ def test_phash(self):
+ inst = self._makeOne(('def= 1', 'abc =2'))
+ self.assertEqual(inst.phash(), 'match_param abc=2,def=1')
+
+
+class TestCustomPredicate(unittest.TestCase):
+ def _makeOne(self, val):
+ from pyramid.predicates import CustomPredicate
+
+ return CustomPredicate(val, None)
+
+ def test___call___true(self):
+ def func(context, request):
+ self.assertEqual(context, None)
+ self.assertEqual(request, None)
+ return True
+
+ inst = self._makeOne(func)
+ result = inst(None, None)
+ self.assertTrue(result)
+
+ def test___call___false(self):
+ def func(context, request):
+ self.assertEqual(context, None)
+ self.assertEqual(request, None)
+ return False
+
+ inst = self._makeOne(func)
+ result = inst(None, None)
+ self.assertFalse(result)
+
+ def test_text_func_has___text__(self):
+ pred = predicate()
+ pred.__text__ = 'text'
+ inst = self._makeOne(pred)
+ self.assertEqual(inst.text(), 'text')
+
+ def test_text_func_repr(self):
+ pred = predicate()
+ inst = self._makeOne(pred)
+ self.assertEqual(inst.text(), 'custom predicate: object predicate')
+
+ def test_phash(self):
+ pred = predicate()
+ inst = self._makeOne(pred)
+ self.assertEqual(inst.phash(), 'custom:1')
+
+
+class TestTraversePredicate(unittest.TestCase):
+ def _makeOne(self, val):
+ from pyramid.predicates import TraversePredicate
+
+ return TraversePredicate(val, None)
+
+ def test___call__traverse_has_remainder_already(self):
+ inst = self._makeOne('/1/:a/:b')
+ info = {'traverse': 'abc'}
+ request = Dummy()
+ result = inst(info, request)
+ self.assertEqual(result, True)
+ self.assertEqual(info, {'traverse': 'abc'})
+
+ def test___call__traverse_matches(self):
+ inst = self._makeOne('/1/:a/:b')
+ info = {'match': {'a': 'a', 'b': 'b'}}
+ request = Dummy()
+ result = inst(info, request)
+ self.assertEqual(result, True)
+ self.assertEqual(
+ info, {'match': {'a': 'a', 'b': 'b', 'traverse': ('1', 'a', 'b')}}
+ )
+
+ def test___call__traverse_matches_with_highorder_chars(self):
+ inst = self._makeOne(text_(b'/La Pe\xc3\xb1a/{x}', 'utf-8'))
+ info = {'match': {'x': text_(b'Qu\xc3\xa9bec', 'utf-8')}}
+ request = Dummy()
+ result = inst(info, request)
+ self.assertEqual(result, True)
+ self.assertEqual(
+ info['match']['traverse'],
+ (
+ text_(b'La Pe\xc3\xb1a', 'utf-8'),
+ text_(b'Qu\xc3\xa9bec', 'utf-8'),
+ ),
+ )
+
+ def test_text(self):
+ inst = self._makeOne('/abc')
+ self.assertEqual(inst.text(), 'traverse matchdict pseudo-predicate')
+
+ def test_phash(self):
+ inst = self._makeOne('/abc')
+ self.assertEqual(inst.phash(), '')
+
+
+class Test_CheckCSRFTokenPredicate(unittest.TestCase):
+ def _makeOne(self, val, config):
+ from pyramid.predicates import CheckCSRFTokenPredicate
+
+ return CheckCSRFTokenPredicate(val, config)
+
+ def test_text(self):
+ inst = self._makeOne(True, None)
+ self.assertEqual(inst.text(), 'check_csrf = True')
+
+ def test_phash(self):
+ inst = self._makeOne(True, None)
+ self.assertEqual(inst.phash(), 'check_csrf = True')
+
+ def test_it_call_val_True(self):
+ inst = self._makeOne(True, None)
+ request = Dummy()
+
+ def check_csrf_token(req, val, raises=True):
+ self.assertEqual(req, request)
+ self.assertEqual(val, 'csrf_token')
+ self.assertEqual(raises, False)
+ return True
+
+ inst.check_csrf_token = check_csrf_token
+ result = inst(None, request)
+ self.assertEqual(result, True)
+
+ def test_it_call_val_str(self):
+ inst = self._makeOne('abc', None)
+ request = Dummy()
+
+ def check_csrf_token(req, val, raises=True):
+ self.assertEqual(req, request)
+ self.assertEqual(val, 'abc')
+ self.assertEqual(raises, False)
+ return True
+
+ inst.check_csrf_token = check_csrf_token
+ result = inst(None, request)
+ self.assertEqual(result, True)
+
+ def test_it_call_val_False(self):
+ inst = self._makeOne(False, None)
+ request = Dummy()
+ result = inst(None, request)
+ self.assertEqual(result, True)
+
+
+class TestHeaderPredicate(unittest.TestCase):
+ def _makeOne(self, val):
+ from pyramid.predicates import HeaderPredicate
+
+ return HeaderPredicate(val, None)
+
+ def test___call___true_exists(self):
+ inst = self._makeOne('abc')
+ request = Dummy()
+ request.headers = {'abc': 1}
+ result = inst(None, request)
+ self.assertTrue(result)
+
+ def test___call___true_withval(self):
+ inst = self._makeOne('abc:1')
+ request = Dummy()
+ request.headers = {'abc': '1'}
+ result = inst(None, request)
+ self.assertTrue(result)
+
+ def test___call___true_withregex(self):
+ inst = self._makeOne(r'abc:\d+')
+ request = Dummy()
+ request.headers = {'abc': '1'}
+ result = inst(None, request)
+ self.assertTrue(result)
+
+ def test___call___false_withregex(self):
+ inst = self._makeOne(r'abc:\d+')
+ request = Dummy()
+ request.headers = {'abc': 'a'}
+ result = inst(None, request)
+ self.assertFalse(result)
+
+ def test___call___false(self):
+ inst = self._makeOne('abc')
+ request = Dummy()
+ request.headers = {}
+ result = inst(None, request)
+ self.assertFalse(result)
+
+ def test_text_exists(self):
+ inst = self._makeOne('abc')
+ self.assertEqual(inst.text(), 'header abc')
+
+ def test_text_withval(self):
+ inst = self._makeOne('abc:1')
+ self.assertEqual(inst.text(), 'header abc=1')
+
+ def test_text_withregex(self):
+ inst = self._makeOne(r'abc:\d+')
+ self.assertEqual(inst.text(), r'header abc=\d+')
+
+ def test_phash_exists(self):
+ inst = self._makeOne('abc')
+ self.assertEqual(inst.phash(), 'header abc')
+
+ def test_phash_withval(self):
+ inst = self._makeOne('abc:1')
+ self.assertEqual(inst.phash(), "header abc=1")
+
+ def test_phash_withregex(self):
+ inst = self._makeOne(r'abc:\d+')
+ self.assertEqual(inst.phash(), r'header abc=\d+')
+
+
+class Test_PhysicalPathPredicate(unittest.TestCase):
+ def _makeOne(self, val, config):
+ from pyramid.predicates import PhysicalPathPredicate
+
+ return PhysicalPathPredicate(val, config)
+
+ def test_text(self):
+ inst = self._makeOne('/', None)
+ self.assertEqual(inst.text(), "physical_path = ('',)")
+
+ def test_phash(self):
+ inst = self._makeOne('/', None)
+ self.assertEqual(inst.phash(), "physical_path = ('',)")
+
+ def test_it_call_val_tuple_True(self):
+ inst = self._makeOne(('', 'abc'), None)
+ root = Dummy()
+ root.__name__ = ''
+ root.__parent__ = None
+ context = Dummy()
+ context.__name__ = 'abc'
+ context.__parent__ = root
+ self.assertTrue(inst(context, None))
+
+ def test_it_call_val_list_True(self):
+ inst = self._makeOne(['', 'abc'], None)
+ root = Dummy()
+ root.__name__ = ''
+ root.__parent__ = None
+ context = Dummy()
+ context.__name__ = 'abc'
+ context.__parent__ = root
+ self.assertTrue(inst(context, None))
+
+ def test_it_call_val_str_True(self):
+ inst = self._makeOne('/abc', None)
+ root = Dummy()
+ root.__name__ = ''
+ root.__parent__ = None
+ context = Dummy()
+ context.__name__ = 'abc'
+ context.__parent__ = root
+ self.assertTrue(inst(context, None))
+
+ def test_it_call_False(self):
+ inst = self._makeOne('/', None)
+ root = Dummy()
+ root.__name__ = ''
+ root.__parent__ = None
+ context = Dummy()
+ context.__name__ = 'abc'
+ context.__parent__ = root
+ self.assertFalse(inst(context, None))
+
+ def test_it_call_context_has_no_name(self):
+ inst = self._makeOne('/', None)
+ context = Dummy()
+ self.assertFalse(inst(context, None))
+
+
+class Test_EffectivePrincipalsPredicate(unittest.TestCase):
+ def setUp(self):
+ self.config = testing.setUp()
+
+ def tearDown(self):
+ testing.tearDown()
+
+ def _makeOne(self, val, config):
+ from pyramid.predicates import EffectivePrincipalsPredicate
+
+ return EffectivePrincipalsPredicate(val, config)
+
+ def test_text(self):
+ inst = self._makeOne(('verna', 'fred'), None)
+ self.assertEqual(
+ inst.text(), "effective_principals = ['fred', 'verna']"
+ )
+
+ def test_text_noniter(self):
+ inst = self._makeOne('verna', None)
+ self.assertEqual(inst.text(), "effective_principals = ['verna']")
+
+ def test_phash(self):
+ inst = self._makeOne(('verna', 'fred'), None)
+ self.assertEqual(
+ inst.phash(), "effective_principals = ['fred', 'verna']"
+ )
+
+ def test_it_call_no_authentication_policy(self):
+ request = testing.DummyRequest()
+ inst = self._makeOne(('verna', 'fred'), None)
+ context = Dummy()
+ self.assertFalse(inst(context, request))
+
+ def test_it_call_authentication_policy_provides_superset(self):
+ request = testing.DummyRequest()
+ self.config.testing_securitypolicy('fred', groupids=('verna', 'bambi'))
+ inst = self._makeOne(('verna', 'fred'), None)
+ context = Dummy()
+ self.assertTrue(inst(context, request))
+
+ def test_it_call_authentication_policy_provides_superset_implicit(self):
+ from pyramid.security import Authenticated
+
+ request = testing.DummyRequest()
+ self.config.testing_securitypolicy('fred', groupids=('verna', 'bambi'))
+ inst = self._makeOne(Authenticated, None)
+ context = Dummy()
+ self.assertTrue(inst(context, request))
+
+ def test_it_call_authentication_policy_doesnt_provide_superset(self):
+ request = testing.DummyRequest()
+ self.config.testing_securitypolicy('fred')
+ inst = self._makeOne(('verna', 'fred'), None)
+ context = Dummy()
+ self.assertFalse(inst(context, request))
+
+
+class TestNotted(unittest.TestCase):
+ def _makeOne(self, predicate):
+ from pyramid.predicates import Notted
+
+ return Notted(predicate)
+
+ def test_it_with_phash_val(self):
+ pred = DummyPredicate('val')
+ inst = self._makeOne(pred)
+ self.assertEqual(inst.text(), '!val')
+ self.assertEqual(inst.phash(), '!val')
+ self.assertEqual(inst(None, None), False)
+
+ def test_it_without_phash_val(self):
+ pred = DummyPredicate('')
+ inst = self._makeOne(pred)
+ self.assertEqual(inst.text(), '')
+ self.assertEqual(inst.phash(), '')
+ self.assertEqual(inst(None, None), True)
+
+
+class predicate(object):
+ def __repr__(self):
+ return 'predicate'
+
+ def __hash__(self):
+ return 1
+
+
+class Dummy(object):
+ pass
+
+
+class DummyPredicate(object):
+ def __init__(self, result):
+ self.result = result
+
+ def text(self):
+ return self.result
+
+ phash = text
+
+ def __call__(self, context, request):
+ return True
diff --git a/tests/test_registry.py b/tests/test_registry.py
new file mode 100644
index 000000000..aee4f0e15
--- /dev/null
+++ b/tests/test_registry.py
@@ -0,0 +1,452 @@
+import unittest
+from zope.interface import Interface
+from zope.interface import implementer
+
+
+class TestRegistry(unittest.TestCase):
+ def _getTargetClass(self):
+ from pyramid.registry import Registry
+
+ return Registry
+
+ def _makeOne(self, *args, **kw):
+ return self._getTargetClass()(*args, **kw)
+
+ def test___nonzero__(self):
+ registry = self._makeOne()
+ self.assertEqual(registry.__nonzero__(), True)
+
+ def test__lock(self):
+ registry = self._makeOne()
+ self.assertTrue(registry._lock)
+
+ def test_clear_view_cache_lookup(self):
+ registry = self._makeOne()
+ registry._view_lookup_cache[1] = 2
+ registry._clear_view_lookup_cache()
+ self.assertEqual(registry._view_lookup_cache, {})
+
+ def test_package_name(self):
+ package_name = 'testing'
+ registry = self._makeOne(package_name)
+ self.assertEqual(registry.package_name, package_name)
+
+ def test_default_package_name(self):
+ registry = self._makeOne()
+ self.assertEqual(registry.package_name, 'tests')
+
+ def test_registerHandler_and_notify(self):
+ registry = self._makeOne()
+ self.assertEqual(registry.has_listeners, False)
+ L = []
+
+ def f(event):
+ L.append(event)
+
+ registry.registerHandler(f, [IDummyEvent])
+ self.assertEqual(registry.has_listeners, True)
+ event = DummyEvent()
+ registry.notify(event)
+ self.assertEqual(L, [event])
+
+ def test_registerSubscriptionAdapter(self):
+ registry = self._makeOne()
+ self.assertEqual(registry.has_listeners, False)
+ from zope.interface import Interface
+
+ registry.registerSubscriptionAdapter(
+ DummyEvent, [IDummyEvent], Interface
+ )
+ self.assertEqual(registry.has_listeners, True)
+
+ def test__get_settings(self):
+ registry = self._makeOne()
+ registry._settings = 'foo'
+ self.assertEqual(registry.settings, 'foo')
+
+ def test__set_settings(self):
+ registry = self._makeOne()
+ registry.settings = 'foo'
+ self.assertEqual(registry._settings, 'foo')
+
+ def test_init_forwards_args(self):
+ from zope.interface import Interface
+ from zope.interface.registry import Components
+
+ dummy = object()
+ c = Components()
+ c.registerUtility(dummy, Interface)
+ registry = self._makeOne('foo', (c,))
+ self.assertEqual(registry.__name__, 'foo')
+ self.assertEqual(registry.getUtility(Interface), dummy)
+
+ def test_init_forwards_kw(self):
+ from zope.interface import Interface
+ from zope.interface.registry import Components
+
+ dummy = object()
+ c = Components()
+ c.registerUtility(dummy, Interface)
+ registry = self._makeOne(bases=(c,))
+ self.assertEqual(registry.getUtility(Interface), dummy)
+
+
+class TestIntrospector(unittest.TestCase):
+ def _getTargetClass(slf):
+ from pyramid.registry import Introspector
+
+ return Introspector
+
+ def _makeOne(self):
+ return self._getTargetClass()()
+
+ def test_conformance(self):
+ from zope.interface.verify import verifyClass
+ from zope.interface.verify import verifyObject
+ from pyramid.interfaces import IIntrospector
+
+ verifyClass(IIntrospector, self._getTargetClass())
+ verifyObject(IIntrospector, self._makeOne())
+
+ def test_add(self):
+ inst = self._makeOne()
+ intr = DummyIntrospectable()
+ inst.add(intr)
+ self.assertEqual(intr.order, 0)
+ category = {'discriminator': intr, 'discriminator_hash': intr}
+ self.assertEqual(inst._categories, {'category': category})
+
+ def test_get_success(self):
+ inst = self._makeOne()
+ intr = DummyIntrospectable()
+ inst.add(intr)
+ self.assertEqual(inst.get('category', 'discriminator'), intr)
+
+ def test_get_success_byhash(self):
+ inst = self._makeOne()
+ intr = DummyIntrospectable()
+ inst.add(intr)
+ self.assertEqual(inst.get('category', 'discriminator_hash'), intr)
+
+ def test_get_fail(self):
+ inst = self._makeOne()
+ intr = DummyIntrospectable()
+ inst.add(intr)
+ self.assertEqual(inst.get('category', 'wontexist', 'foo'), 'foo')
+
+ def test_get_category(self):
+ inst = self._makeOne()
+ intr = DummyIntrospectable()
+ intr2 = DummyIntrospectable()
+ intr2.discriminator = 'discriminator2'
+ intr2.discriminator_hash = 'discriminator2_hash'
+ inst.add(intr2)
+ inst.add(intr)
+ expected = [
+ {'introspectable': intr2, 'related': []},
+ {'introspectable': intr, 'related': []},
+ ]
+ self.assertEqual(inst.get_category('category'), expected)
+
+ def test_get_category_returns_default_on_miss(self):
+ inst = self._makeOne()
+ self.assertEqual(inst.get_category('category', '123'), '123')
+
+ def test_get_category_with_sortkey(self):
+ import operator
+
+ inst = self._makeOne()
+ intr = DummyIntrospectable()
+ intr.foo = 2
+ intr2 = DummyIntrospectable()
+ intr2.discriminator = 'discriminator2'
+ intr2.discriminator_hash = 'discriminator2_hash'
+ intr2.foo = 1
+ inst.add(intr)
+ inst.add(intr2)
+ expected = [
+ {'introspectable': intr2, 'related': []},
+ {'introspectable': intr, 'related': []},
+ ]
+ self.assertEqual(
+ inst.get_category('category', sort_key=operator.attrgetter('foo')),
+ expected,
+ )
+
+ def test_categorized(self):
+ import operator
+
+ inst = self._makeOne()
+ intr = DummyIntrospectable()
+ intr.foo = 2
+ intr2 = DummyIntrospectable()
+ intr2.discriminator = 'discriminator2'
+ intr2.discriminator_hash = 'discriminator2_hash'
+ intr2.foo = 1
+ inst.add(intr)
+ inst.add(intr2)
+ expected = [
+ (
+ 'category',
+ [
+ {'introspectable': intr2, 'related': []},
+ {'introspectable': intr, 'related': []},
+ ],
+ )
+ ]
+ self.assertEqual(
+ inst.categorized(sort_key=operator.attrgetter('foo')), expected
+ )
+
+ def test_categories(self):
+ inst = self._makeOne()
+ inst._categories['a'] = 1
+ inst._categories['b'] = 2
+ self.assertEqual(list(inst.categories()), ['a', 'b'])
+
+ def test_remove(self):
+ inst = self._makeOne()
+ intr = DummyIntrospectable()
+ intr2 = DummyIntrospectable()
+ intr2.category_name = 'category2'
+ intr2.discriminator = 'discriminator2'
+ intr2.discriminator_hash = 'discriminator2_hash'
+ inst.add(intr)
+ inst.add(intr2)
+ inst.relate(
+ ('category', 'discriminator'), ('category2', 'discriminator2')
+ )
+ inst.remove('category', 'discriminator')
+ self.assertEqual(
+ inst._categories,
+ {
+ 'category': {},
+ 'category2': {
+ 'discriminator2': intr2,
+ 'discriminator2_hash': intr2,
+ },
+ },
+ )
+ self.assertEqual(inst._refs.get(intr), None)
+ self.assertEqual(inst._refs[intr2], [])
+
+ def test_remove_fail(self):
+ inst = self._makeOne()
+ self.assertEqual(inst.remove('a', 'b'), None)
+
+ def test_relate(self):
+ inst = self._makeOne()
+ intr = DummyIntrospectable()
+ intr2 = DummyIntrospectable()
+ intr2.category_name = 'category2'
+ intr2.discriminator = 'discriminator2'
+ intr2.discriminator_hash = 'discriminator2_hash'
+ inst.add(intr)
+ inst.add(intr2)
+ inst.relate(
+ ('category', 'discriminator'), ('category2', 'discriminator2')
+ )
+ self.assertEqual(
+ inst._categories,
+ {
+ 'category': {
+ 'discriminator': intr,
+ 'discriminator_hash': intr,
+ },
+ 'category2': {
+ 'discriminator2': intr2,
+ 'discriminator2_hash': intr2,
+ },
+ },
+ )
+ self.assertEqual(inst._refs[intr], [intr2])
+ self.assertEqual(inst._refs[intr2], [intr])
+
+ def test_relate_fail(self):
+ inst = self._makeOne()
+ intr = DummyIntrospectable()
+ inst.add(intr)
+ self.assertRaises(
+ KeyError,
+ inst.relate,
+ ('category', 'discriminator'),
+ ('category2', 'discriminator2'),
+ )
+
+ def test_unrelate(self):
+ inst = self._makeOne()
+ intr = DummyIntrospectable()
+ intr2 = DummyIntrospectable()
+ intr2.category_name = 'category2'
+ intr2.discriminator = 'discriminator2'
+ intr2.discriminator_hash = 'discriminator2_hash'
+ inst.add(intr)
+ inst.add(intr2)
+ inst.relate(
+ ('category', 'discriminator'), ('category2', 'discriminator2')
+ )
+ inst.unrelate(
+ ('category', 'discriminator'), ('category2', 'discriminator2')
+ )
+ self.assertEqual(
+ inst._categories,
+ {
+ 'category': {
+ 'discriminator': intr,
+ 'discriminator_hash': intr,
+ },
+ 'category2': {
+ 'discriminator2': intr2,
+ 'discriminator2_hash': intr2,
+ },
+ },
+ )
+ self.assertEqual(inst._refs[intr], [])
+ self.assertEqual(inst._refs[intr2], [])
+
+ def test_related(self):
+ inst = self._makeOne()
+ intr = DummyIntrospectable()
+ intr2 = DummyIntrospectable()
+ intr2.category_name = 'category2'
+ intr2.discriminator = 'discriminator2'
+ intr2.discriminator_hash = 'discriminator2_hash'
+ inst.add(intr)
+ inst.add(intr2)
+ inst.relate(
+ ('category', 'discriminator'), ('category2', 'discriminator2')
+ )
+ self.assertEqual(inst.related(intr), [intr2])
+
+ def test_related_fail(self):
+ inst = self._makeOne()
+ intr = DummyIntrospectable()
+ intr2 = DummyIntrospectable()
+ intr2.category_name = 'category2'
+ intr2.discriminator = 'discriminator2'
+ intr2.discriminator_hash = 'discriminator2_hash'
+ inst.add(intr)
+ inst.add(intr2)
+ inst.relate(
+ ('category', 'discriminator'), ('category2', 'discriminator2')
+ )
+ del inst._categories['category']
+ self.assertRaises(KeyError, inst.related, intr)
+
+
+class TestIntrospectable(unittest.TestCase):
+ def _getTargetClass(slf):
+ from pyramid.registry import Introspectable
+
+ return Introspectable
+
+ def _makeOne(self, *arg, **kw):
+ return self._getTargetClass()(*arg, **kw)
+
+ def _makeOnePopulated(self):
+ return self._makeOne('category', 'discrim', 'title', 'type')
+
+ def test_conformance(self):
+ from zope.interface.verify import verifyClass
+ from zope.interface.verify import verifyObject
+ from pyramid.interfaces import IIntrospectable
+
+ verifyClass(IIntrospectable, self._getTargetClass())
+ verifyObject(IIntrospectable, self._makeOnePopulated())
+
+ def test_relate(self):
+ inst = self._makeOnePopulated()
+ inst.relate('a', 'b')
+ self.assertEqual(inst._relations, [(True, 'a', 'b')])
+
+ def test_unrelate(self):
+ inst = self._makeOnePopulated()
+ inst.unrelate('a', 'b')
+ self.assertEqual(inst._relations, [(False, 'a', 'b')])
+
+ def test_discriminator_hash(self):
+ inst = self._makeOnePopulated()
+ self.assertEqual(inst.discriminator_hash, hash(inst.discriminator))
+
+ def test___hash__(self):
+ inst = self._makeOnePopulated()
+ self.assertEqual(
+ hash(inst), hash((inst.category_name,) + (inst.discriminator,))
+ )
+
+ def test___repr__(self):
+ inst = self._makeOnePopulated()
+ self.assertEqual(
+ repr(inst),
+ "<Introspectable category 'category', discriminator 'discrim'>",
+ )
+
+ def test___nonzero__(self):
+ inst = self._makeOnePopulated()
+ self.assertEqual(inst.__nonzero__(), True)
+
+ def test___bool__(self):
+ inst = self._makeOnePopulated()
+ self.assertEqual(inst.__bool__(), True)
+
+ def test_register(self):
+ introspector = DummyIntrospector()
+ action_info = object()
+ inst = self._makeOnePopulated()
+ inst._relations.append((True, 'category1', 'discrim1'))
+ inst._relations.append((False, 'category2', 'discrim2'))
+ inst.register(introspector, action_info)
+ self.assertEqual(inst.action_info, action_info)
+ self.assertEqual(introspector.intrs, [inst])
+ self.assertEqual(
+ introspector.relations,
+ [(('category', 'discrim'), ('category1', 'discrim1'))],
+ )
+ self.assertEqual(
+ introspector.unrelations,
+ [(('category', 'discrim'), ('category2', 'discrim2'))],
+ )
+
+
+class DummyIntrospector(object):
+ def __init__(self):
+ self.intrs = []
+ self.relations = []
+ self.unrelations = []
+
+ def add(self, intr):
+ self.intrs.append(intr)
+
+ def relate(self, *pairs):
+ self.relations.append(pairs)
+
+ def unrelate(self, *pairs):
+ self.unrelations.append(pairs)
+
+
+class DummyModule:
+ __path__ = "foo"
+ __name__ = "dummy"
+ __file__ = ''
+
+
+class DummyIntrospectable(object):
+ category_name = 'category'
+ discriminator = 'discriminator'
+ title = 'title'
+ type_name = 'type'
+ order = None
+ action_info = None
+ discriminator_hash = 'discriminator_hash'
+
+ def __hash__(self):
+ return hash((self.category_name,) + (self.discriminator,))
+
+
+class IDummyEvent(Interface):
+ pass
+
+
+@implementer(IDummyEvent)
+class DummyEvent(object):
+ pass
diff --git a/tests/test_renderers.py b/tests/test_renderers.py
new file mode 100644
index 000000000..0eacfa996
--- /dev/null
+++ b/tests/test_renderers.py
@@ -0,0 +1,780 @@
+import unittest
+
+from pyramid.testing import cleanUp
+from pyramid import testing
+from pyramid.compat import text_
+
+
+class TestJSON(unittest.TestCase):
+ def setUp(self):
+ self.config = testing.setUp()
+
+ def tearDown(self):
+ testing.tearDown()
+
+ def _makeOne(self, **kw):
+ from pyramid.renderers import JSON
+
+ return JSON(**kw)
+
+ def test_it(self):
+ renderer = self._makeOne()(None)
+ result = renderer({'a': 1}, {})
+ self.assertEqual(result, '{"a": 1}')
+
+ def test_with_request_content_type_notset(self):
+ request = testing.DummyRequest()
+ renderer = self._makeOne()(None)
+ renderer({'a': 1}, {'request': request})
+ self.assertEqual(request.response.content_type, 'application/json')
+
+ def test_with_request_content_type_set(self):
+ request = testing.DummyRequest()
+ request.response.content_type = 'text/mishmash'
+ renderer = self._makeOne()(None)
+ renderer({'a': 1}, {'request': request})
+ self.assertEqual(request.response.content_type, 'text/mishmash')
+
+ def test_with_custom_adapter(self):
+ request = testing.DummyRequest()
+ from datetime import datetime
+
+ def adapter(obj, req):
+ self.assertEqual(req, request)
+ return obj.isoformat()
+
+ now = datetime.utcnow()
+ renderer = self._makeOne()
+ renderer.add_adapter(datetime, adapter)
+ result = renderer(None)({'a': now}, {'request': request})
+ self.assertEqual(result, '{"a": "%s"}' % now.isoformat())
+
+ def test_with_custom_adapter2(self):
+ request = testing.DummyRequest()
+ from datetime import datetime
+
+ def adapter(obj, req):
+ self.assertEqual(req, request)
+ return obj.isoformat()
+
+ now = datetime.utcnow()
+ renderer = self._makeOne(adapters=((datetime, adapter),))
+ result = renderer(None)({'a': now}, {'request': request})
+ self.assertEqual(result, '{"a": "%s"}' % now.isoformat())
+
+ def test_with_custom_serializer(self):
+ class Serializer(object):
+ def __call__(self, obj, **kw):
+ self.obj = obj
+ self.kw = kw
+ return 'foo'
+
+ serializer = Serializer()
+ renderer = self._makeOne(serializer=serializer, baz=5)
+ obj = {'a': 'b'}
+ result = renderer(None)(obj, {})
+ self.assertEqual(result, 'foo')
+ self.assertEqual(serializer.obj, obj)
+ self.assertEqual(serializer.kw['baz'], 5)
+ self.assertTrue('default' in serializer.kw)
+
+ def test_with_object_adapter(self):
+ request = testing.DummyRequest()
+ outerself = self
+
+ class MyObject(object):
+ def __init__(self, x):
+ self.x = x
+
+ def __json__(self, req):
+ outerself.assertEqual(req, request)
+ return {'x': self.x}
+
+ objects = [MyObject(1), MyObject(2)]
+ renderer = self._makeOne()(None)
+ result = renderer(objects, {'request': request})
+ self.assertEqual(result, '[{"x": 1}, {"x": 2}]')
+
+ def test_with_object_adapter_no___json__(self):
+ class MyObject(object):
+ def __init__(self, x):
+ self.x = x
+
+ objects = [MyObject(1), MyObject(2)]
+ renderer = self._makeOne()(None)
+ self.assertRaises(TypeError, renderer, objects, {})
+
+
+class Test_string_renderer_factory(unittest.TestCase):
+ def _callFUT(self, name):
+ from pyramid.renderers import string_renderer_factory
+
+ return string_renderer_factory(name)
+
+ def test_it_unicode(self):
+ renderer = self._callFUT(None)
+ value = text_('La Pe\xc3\xb1a', 'utf-8')
+ result = renderer(value, {})
+ self.assertEqual(result, value)
+
+ def test_it_str(self):
+ renderer = self._callFUT(None)
+ value = 'La Pe\xc3\xb1a'
+ result = renderer(value, {})
+ self.assertEqual(result, value)
+
+ def test_it_other(self):
+ renderer = self._callFUT(None)
+ value = None
+ result = renderer(value, {})
+ self.assertEqual(result, 'None')
+
+ def test_with_request_content_type_notset(self):
+ request = testing.DummyRequest()
+ renderer = self._callFUT(None)
+ renderer('', {'request': request})
+ self.assertEqual(request.response.content_type, 'text/plain')
+
+ def test_with_request_content_type_set(self):
+ request = testing.DummyRequest()
+ request.response.content_type = 'text/mishmash'
+ renderer = self._callFUT(None)
+ renderer('', {'request': request})
+ self.assertEqual(request.response.content_type, 'text/mishmash')
+
+
+class TestRendererHelper(unittest.TestCase):
+ def setUp(self):
+ self.config = cleanUp()
+
+ def tearDown(self):
+ cleanUp()
+
+ def _makeOne(self, *arg, **kw):
+ from pyramid.renderers import RendererHelper
+
+ return RendererHelper(*arg, **kw)
+
+ def test_instance_conforms(self):
+ from zope.interface.verify import verifyObject
+ from pyramid.interfaces import IRendererInfo
+
+ helper = self._makeOne()
+ verifyObject(IRendererInfo, helper)
+
+ def test_settings_registry_settings_is_None(self):
+ class Dummy(object):
+ settings = None
+
+ helper = self._makeOne(registry=Dummy)
+ self.assertEqual(helper.settings, {})
+
+ def test_settings_registry_name_is_None(self):
+ class Dummy(object):
+ settings = None
+
+ helper = self._makeOne(registry=Dummy)
+ self.assertEqual(helper.name, None)
+ self.assertEqual(helper.type, '')
+
+ def test_settings_registry_settings_is_not_None(self):
+ class Dummy(object):
+ settings = {'a': 1}
+
+ helper = self._makeOne(registry=Dummy)
+ self.assertEqual(helper.settings, {'a': 1})
+
+ def _registerRendererFactory(self):
+ from pyramid.interfaces import IRendererFactory
+
+ def renderer(*arg):
+ def respond(*arg):
+ return arg
+
+ renderer.respond = respond
+ return respond
+
+ self.config.registry.registerUtility(
+ renderer, IRendererFactory, name='.foo'
+ )
+ return renderer
+
+ def _registerResponseFactory(self):
+ from pyramid.interfaces import IResponseFactory
+
+ class ResponseFactory(object):
+ pass
+
+ self.config.registry.registerUtility(
+ lambda r: ResponseFactory(), IResponseFactory
+ )
+
+ def test_render_to_response(self):
+ self._registerRendererFactory()
+ self._registerResponseFactory()
+ request = Dummy()
+ helper = self._makeOne('loo.foo')
+ response = helper.render_to_response('values', {}, request=request)
+ self.assertEqual(response.app_iter[0], 'values')
+ self.assertEqual(response.app_iter[1], {})
+
+ def test_get_renderer(self):
+ factory = self._registerRendererFactory()
+ helper = self._makeOne('loo.foo')
+ self.assertEqual(helper.get_renderer(), factory.respond)
+
+ def test_render_view(self):
+ import pyramid.csrf
+
+ self._registerRendererFactory()
+ self._registerResponseFactory()
+ request = Dummy()
+ helper = self._makeOne('loo.foo')
+ view = 'view'
+ context = 'context'
+ request = testing.DummyRequest()
+ response = 'response'
+ response = helper.render_view(request, response, view, context)
+ get_csrf = response.app_iter[1].pop('get_csrf_token')
+ self.assertEqual(get_csrf.args, (request,))
+ self.assertEqual(get_csrf.func, pyramid.csrf.get_csrf_token)
+ self.assertEqual(response.app_iter[0], 'response')
+ self.assertEqual(
+ response.app_iter[1],
+ {
+ 'renderer_info': helper,
+ 'renderer_name': 'loo.foo',
+ 'request': request,
+ 'context': 'context',
+ 'view': 'view',
+ 'req': request,
+ },
+ )
+
+ def test_render_explicit_registry(self):
+ factory = self._registerRendererFactory()
+
+ class DummyRegistry(object):
+ def __init__(self):
+ self.responses = [factory, lambda *arg: {}, None]
+
+ def queryUtility(self, iface, name=None):
+ self.queried = True
+ return self.responses.pop(0)
+
+ def notify(self, event):
+ self.event = event
+
+ reg = DummyRegistry()
+ helper = self._makeOne('loo.foo', registry=reg)
+ result = helper.render('value', {})
+ self.assertEqual(result[0], 'value')
+ self.assertEqual(result[1], {})
+ self.assertTrue(reg.queried)
+ self.assertEqual(reg.event, {})
+ self.assertEqual(reg.event.__class__.__name__, 'BeforeRender')
+
+ def test_render_system_values_is_None(self):
+ import pyramid.csrf
+
+ self._registerRendererFactory()
+ request = Dummy()
+ context = Dummy()
+ request.context = context
+ helper = self._makeOne('loo.foo')
+ result = helper.render('values', None, request=request)
+ get_csrf = result[1].pop('get_csrf_token')
+ self.assertEqual(get_csrf.args, (request,))
+ self.assertEqual(get_csrf.func, pyramid.csrf.get_csrf_token)
+ system = {
+ 'request': request,
+ 'context': context,
+ 'renderer_name': 'loo.foo',
+ 'view': None,
+ 'renderer_info': helper,
+ 'req': request,
+ }
+ self.assertEqual(result[0], 'values')
+ self.assertEqual(result[1], system)
+
+ def test__make_response_request_is_None(self):
+ request = None
+ helper = self._makeOne('loo.foo')
+ response = helper._make_response('abc', request)
+ self.assertEqual(response.body, b'abc')
+
+ def test__make_response_request_is_None_response_factory_exists(self):
+ self._registerResponseFactory()
+ request = None
+ helper = self._makeOne('loo.foo')
+ response = helper._make_response(b'abc', request)
+ self.assertEqual(response.__class__.__name__, 'ResponseFactory')
+ self.assertEqual(response.body, b'abc')
+
+ def test__make_response_result_is_unicode(self):
+ from pyramid.response import Response
+
+ request = testing.DummyRequest()
+ request.response = Response()
+ helper = self._makeOne('loo.foo')
+ la = text_('/La Pe\xc3\xb1a', 'utf-8')
+ response = helper._make_response(la, request)
+ self.assertEqual(response.body, la.encode('utf-8'))
+
+ def test__make_response_result_is_str(self):
+ from pyramid.response import Response
+
+ request = testing.DummyRequest()
+ request.response = Response()
+ helper = self._makeOne('loo.foo')
+ la = text_('/La Pe\xc3\xb1a', 'utf-8')
+ response = helper._make_response(la.encode('utf-8'), request)
+ self.assertEqual(response.body, la.encode('utf-8'))
+
+ def test__make_response_result_is_iterable(self):
+ from pyramid.response import Response
+
+ request = testing.DummyRequest()
+ request.response = Response()
+ helper = self._makeOne('loo.foo')
+ la = text_('/La Pe\xc3\xb1a', 'utf-8')
+ response = helper._make_response([la.encode('utf-8')], request)
+ self.assertEqual(response.body, la.encode('utf-8'))
+
+ def test__make_response_result_is_other(self):
+ self._registerResponseFactory()
+ request = None
+ helper = self._makeOne('loo.foo')
+ result = object()
+ response = helper._make_response(result, request)
+ self.assertEqual(response.body, result)
+
+ def test__make_response_result_is_None_no_body(self):
+ from pyramid.response import Response
+
+ request = testing.DummyRequest()
+ request.response = Response()
+ helper = self._makeOne('loo.foo')
+ response = helper._make_response(None, request)
+ self.assertEqual(response.body, b'')
+
+ def test__make_response_result_is_None_existing_body_not_molested(self):
+ from pyramid.response import Response
+
+ request = testing.DummyRequest()
+ response = Response()
+ response.body = b'abc'
+ request.response = response
+ helper = self._makeOne('loo.foo')
+ response = helper._make_response(None, request)
+ self.assertEqual(response.body, b'abc')
+
+ def test_with_alternate_response_factory(self):
+ from pyramid.interfaces import IResponseFactory
+
+ class ResponseFactory(object):
+ def __init__(self):
+ pass
+
+ self.config.registry.registerUtility(
+ lambda r: ResponseFactory(), IResponseFactory
+ )
+ request = testing.DummyRequest()
+ helper = self._makeOne('loo.foo')
+ response = helper._make_response(b'abc', request)
+ self.assertEqual(response.__class__, ResponseFactory)
+ self.assertEqual(response.body, b'abc')
+
+ def test__make_response_with_real_request(self):
+ # functional
+ from pyramid.request import Request
+
+ request = Request({})
+ request.registry = self.config.registry
+ request.response.status = '406 You Lose'
+ helper = self._makeOne('loo.foo')
+ response = helper._make_response('abc', request)
+ self.assertEqual(response.status, '406 You Lose')
+ self.assertEqual(response.body, b'abc')
+
+ def test_clone_noargs(self):
+ helper = self._makeOne('name', 'package', 'registry')
+ cloned_helper = helper.clone()
+ self.assertEqual(cloned_helper.name, 'name')
+ self.assertEqual(cloned_helper.package, 'package')
+ self.assertEqual(cloned_helper.registry, 'registry')
+ self.assertFalse(helper is cloned_helper)
+
+ def test_clone_allargs(self):
+ helper = self._makeOne('name', 'package', 'registry')
+ cloned_helper = helper.clone(
+ name='name2', package='package2', registry='registry2'
+ )
+ self.assertEqual(cloned_helper.name, 'name2')
+ self.assertEqual(cloned_helper.package, 'package2')
+ self.assertEqual(cloned_helper.registry, 'registry2')
+ self.assertFalse(helper is cloned_helper)
+
+ def test_renderer_absolute_file(self):
+ registry = self.config.registry
+ settings = {}
+ registry.settings = settings
+ from pyramid.interfaces import IRendererFactory
+ import os
+
+ here = os.path.dirname(os.path.abspath(__file__))
+ fixture = os.path.join(here, 'fixtures/minimal.pt')
+
+ def factory(info, **kw):
+ return info
+
+ self.config.registry.registerUtility(
+ factory, IRendererFactory, name='.pt'
+ )
+ result = self._makeOne(fixture).renderer
+ self.assertEqual(result.registry, registry)
+ self.assertEqual(result.type, '.pt')
+ self.assertEqual(result.package, None)
+ self.assertEqual(result.name, fixture)
+ self.assertEqual(result.settings, settings)
+
+ def test_renderer_with_package(self):
+ import pyramid
+
+ registry = self.config.registry
+ settings = {}
+ registry.settings = settings
+ from pyramid.interfaces import IRendererFactory
+ import os
+
+ here = os.path.dirname(os.path.abspath(__file__))
+ fixture = os.path.join(here, 'fixtures/minimal.pt')
+
+ def factory(info, **kw):
+ return info
+
+ self.config.registry.registerUtility(
+ factory, IRendererFactory, name='.pt'
+ )
+ result = self._makeOne(fixture, pyramid).renderer
+ self.assertEqual(result.registry, registry)
+ self.assertEqual(result.type, '.pt')
+ self.assertEqual(result.package, pyramid)
+ self.assertEqual(result.name, fixture)
+ self.assertEqual(result.settings, settings)
+
+ def test_renderer_missing(self):
+ inst = self._makeOne('foo')
+ self.assertRaises(ValueError, getattr, inst, 'renderer')
+
+
+class TestNullRendererHelper(unittest.TestCase):
+ def setUp(self):
+ self.config = cleanUp()
+
+ def tearDown(self):
+ cleanUp()
+
+ def _makeOne(self, *arg, **kw):
+ from pyramid.renderers import NullRendererHelper
+
+ return NullRendererHelper(*arg, **kw)
+
+ def test_instance_conforms(self):
+ from zope.interface.verify import verifyObject
+ from pyramid.interfaces import IRendererInfo
+
+ helper = self._makeOne()
+ verifyObject(IRendererInfo, helper)
+
+ def test_render_view(self):
+ helper = self._makeOne()
+ self.assertEqual(helper.render_view(None, True, None, None), True)
+
+ def test_render(self):
+ helper = self._makeOne()
+ self.assertEqual(helper.render(True, None, None), True)
+
+ def test_render_to_response(self):
+ helper = self._makeOne()
+ self.assertEqual(helper.render_to_response(True, None, None), True)
+
+ def test_clone(self):
+ helper = self._makeOne()
+ self.assertTrue(helper.clone() is helper)
+
+
+class Test_render(unittest.TestCase):
+ def setUp(self):
+ self.config = testing.setUp()
+
+ def tearDown(self):
+ testing.tearDown()
+
+ def _callFUT(self, renderer_name, value, request=None, package=None):
+ from pyramid.renderers import render
+
+ return render(renderer_name, value, request=request, package=package)
+
+ def _registerRenderer(self):
+ renderer = self.config.testing_add_renderer('tests:abc/def.pt')
+ renderer.string_response = 'abc'
+ return renderer
+
+ def test_it_no_request(self):
+ renderer = self._registerRenderer()
+ result = self._callFUT('abc/def.pt', dict(a=1))
+ self.assertEqual(result, 'abc')
+ renderer.assert_(a=1)
+ renderer.assert_(request=None)
+
+ def test_it_with_request(self):
+ renderer = self._registerRenderer()
+ request = testing.DummyRequest()
+ result = self._callFUT('abc/def.pt', dict(a=1), request=request)
+ self.assertEqual(result, 'abc')
+ renderer.assert_(a=1)
+ renderer.assert_(request=request)
+
+ def test_it_with_package(self):
+ import tests
+
+ renderer = self._registerRenderer()
+ request = testing.DummyRequest()
+ result = self._callFUT(
+ 'abc/def.pt', dict(a=1), request=request, package=tests
+ )
+ self.assertEqual(result, 'abc')
+ renderer.assert_(a=1)
+ renderer.assert_(request=request)
+
+ def test_response_preserved(self):
+ request = testing.DummyRequest()
+ response = object() # should error if mutated
+ request.response = response
+ # use a json renderer, which will mutate the response
+ result = self._callFUT('json', dict(a=1), request=request)
+ self.assertEqual(result, '{"a": 1}')
+ self.assertEqual(request.response, response)
+
+ def test_no_response_to_preserve(self):
+ from pyramid.decorator import reify
+
+ class DummyRequestWithClassResponse(object):
+ _response = DummyResponse()
+ _response.content_type = None
+ _response.default_content_type = None
+
+ @reify
+ def response(self):
+ return self._response
+
+ request = DummyRequestWithClassResponse()
+ # use a json renderer, which will mutate the response
+ result = self._callFUT('json', dict(a=1), request=request)
+ self.assertEqual(result, '{"a": 1}')
+ self.assertFalse('response' in request.__dict__)
+
+
+class Test_render_to_response(unittest.TestCase):
+ def setUp(self):
+ self.config = testing.setUp()
+
+ def tearDown(self):
+ testing.tearDown()
+
+ def _callFUT(
+ self, renderer_name, value, request=None, package=None, response=None
+ ):
+ from pyramid.renderers import render_to_response
+
+ return render_to_response(
+ renderer_name,
+ value,
+ request=request,
+ package=package,
+ response=response,
+ )
+
+ def test_it_no_request(self):
+ renderer = self.config.testing_add_renderer('tests:abc/def.pt')
+ renderer.string_response = 'abc'
+ response = self._callFUT('abc/def.pt', dict(a=1))
+ self.assertEqual(response.body, b'abc')
+ renderer.assert_(a=1)
+ renderer.assert_(request=None)
+
+ def test_it_with_request(self):
+ renderer = self.config.testing_add_renderer('tests:abc/def.pt')
+ renderer.string_response = 'abc'
+ request = testing.DummyRequest()
+ response = self._callFUT('abc/def.pt', dict(a=1), request=request)
+ self.assertEqual(response.body, b'abc')
+ renderer.assert_(a=1)
+ renderer.assert_(request=request)
+
+ def test_it_with_package(self):
+ import tests
+
+ renderer = self.config.testing_add_renderer('tests:abc/def.pt')
+ renderer.string_response = 'abc'
+ request = testing.DummyRequest()
+ response = self._callFUT(
+ 'abc/def.pt', dict(a=1), request=request, package=tests
+ )
+ self.assertEqual(response.body, b'abc')
+ renderer.assert_(a=1)
+ renderer.assert_(request=request)
+
+ def test_response_preserved(self):
+ request = testing.DummyRequest()
+ response = object() # should error if mutated
+ request.response = response
+ # use a json renderer, which will mutate the response
+ result = self._callFUT('json', dict(a=1), request=request)
+ self.assertEqual(result.body, b'{"a": 1}')
+ self.assertNotEqual(request.response, result)
+ self.assertEqual(request.response, response)
+
+ def test_no_response_to_preserve(self):
+ from pyramid.decorator import reify
+
+ class DummyRequestWithClassResponse(object):
+ _response = DummyResponse()
+ _response.content_type = None
+ _response.default_content_type = None
+
+ @reify
+ def response(self):
+ return self._response
+
+ request = DummyRequestWithClassResponse()
+ # use a json renderer, which will mutate the response
+ result = self._callFUT('json', dict(a=1), request=request)
+ self.assertEqual(result.body, b'{"a": 1}')
+ self.assertFalse('response' in request.__dict__)
+
+ def test_custom_response_object(self):
+ class DummyRequestWithClassResponse(object):
+ pass
+
+ request = DummyRequestWithClassResponse()
+ response = DummyResponse()
+ # use a json renderer, which will mutate the response
+ result = self._callFUT(
+ 'json', dict(a=1), request=request, response=response
+ )
+ self.assertTrue(result is response)
+ self.assertEqual(result.body, b'{"a": 1}')
+ self.assertFalse('response' in request.__dict__)
+
+
+class Test_get_renderer(unittest.TestCase):
+ def setUp(self):
+ self.config = testing.setUp()
+
+ def tearDown(self):
+ testing.tearDown()
+
+ def _callFUT(self, renderer_name, **kw):
+ from pyramid.renderers import get_renderer
+
+ return get_renderer(renderer_name, **kw)
+
+ def test_it_no_package(self):
+ renderer = self.config.testing_add_renderer('tests:abc/def.pt')
+ result = self._callFUT('abc/def.pt')
+ self.assertEqual(result, renderer)
+
+ def test_it_with_package(self):
+ import tests
+
+ renderer = self.config.testing_add_renderer('tests:abc/def.pt')
+ result = self._callFUT('abc/def.pt', package=tests)
+ self.assertEqual(result, renderer)
+
+ def test_it_with_registry(self):
+ renderer = self.config.testing_add_renderer('tests:abc/def.pt')
+ result = self._callFUT('abc/def.pt', registry=self.config.registry)
+ self.assertEqual(result, renderer)
+
+ def test_it_with_isolated_registry(self):
+ from pyramid.config import Configurator
+
+ isolated_config = Configurator()
+ renderer = isolated_config.testing_add_renderer('tests:abc/def.pt')
+ result = self._callFUT('abc/def.pt', registry=isolated_config.registry)
+ self.assertEqual(result, renderer)
+
+
+class TestJSONP(unittest.TestCase):
+ def _makeOne(self, param_name='callback'):
+ from pyramid.renderers import JSONP
+
+ return JSONP(param_name)
+
+ def test_render_to_jsonp(self):
+ renderer_factory = self._makeOne()
+ renderer = renderer_factory(None)
+ request = testing.DummyRequest()
+ request.GET['callback'] = 'callback'
+ result = renderer({'a': '1'}, {'request': request})
+ self.assertEqual(result, '/**/callback({"a": "1"});')
+ self.assertEqual(
+ request.response.content_type, 'application/javascript'
+ )
+
+ def test_render_to_jsonp_with_dot(self):
+ renderer_factory = self._makeOne()
+ renderer = renderer_factory(None)
+ request = testing.DummyRequest()
+ request.GET['callback'] = 'angular.callbacks._0'
+ result = renderer({'a': '1'}, {'request': request})
+ self.assertEqual(result, '/**/angular.callbacks._0({"a": "1"});')
+ self.assertEqual(
+ request.response.content_type, 'application/javascript'
+ )
+
+ def test_render_to_json(self):
+ renderer_factory = self._makeOne()
+ renderer = renderer_factory(None)
+ request = testing.DummyRequest()
+ result = renderer({'a': '1'}, {'request': request})
+ self.assertEqual(result, '{"a": "1"}')
+ self.assertEqual(request.response.content_type, 'application/json')
+
+ def test_render_without_request(self):
+ renderer_factory = self._makeOne()
+ renderer = renderer_factory(None)
+ result = renderer({'a': '1'}, {})
+ self.assertEqual(result, '{"a": "1"}')
+
+ def test_render_to_jsonp_invalid_callback(self):
+ from pyramid.httpexceptions import HTTPBadRequest
+
+ renderer_factory = self._makeOne()
+ renderer = renderer_factory(None)
+ request = testing.DummyRequest()
+ request.GET['callback'] = '78mycallback'
+ self.assertRaises(
+ HTTPBadRequest, renderer, {'a': '1'}, {'request': request}
+ )
+
+
+class Dummy:
+ pass
+
+
+class DummyResponse:
+ status = '200 OK'
+ default_content_type = 'text/html'
+ content_type = default_content_type
+ headerlist = ()
+ app_iter = ()
+ body = b''
+
+ # compat for renderer that will set unicode on py3
+ def _set_text(self, val): # pragma: no cover
+ self.body = val.encode('utf8')
+
+ text = property(fset=_set_text)
diff --git a/tests/test_request.py b/tests/test_request.py
new file mode 100644
index 000000000..dcac501aa
--- /dev/null
+++ b/tests/test_request.py
@@ -0,0 +1,657 @@
+import unittest
+from pyramid import testing
+
+from pyramid.compat import PY2, text_, bytes_, native_
+from pyramid.security import AuthenticationAPIMixin, AuthorizationAPIMixin
+
+
+class TestRequest(unittest.TestCase):
+ def setUp(self):
+ self.config = testing.setUp()
+
+ def tearDown(self):
+ testing.tearDown()
+
+ def _getTargetClass(self):
+ from pyramid.request import Request
+
+ return Request
+
+ def _makeOne(self, environ=None):
+ if environ is None:
+ environ = {}
+ return self._getTargetClass()(environ)
+
+ def _registerResourceURL(self):
+ from pyramid.interfaces import IResourceURL
+ from zope.interface import Interface
+
+ class DummyResourceURL(object):
+ def __init__(self, context, request):
+ self.physical_path = '/context/'
+ self.virtual_path = '/context/'
+
+ self.config.registry.registerAdapter(
+ DummyResourceURL, (Interface, Interface), IResourceURL
+ )
+
+ def test_class_conforms_to_IRequest(self):
+ from zope.interface.verify import verifyClass
+ from pyramid.interfaces import IRequest
+
+ verifyClass(IRequest, self._getTargetClass())
+
+ def test_instance_conforms_to_IRequest(self):
+ from zope.interface.verify import verifyObject
+ from pyramid.interfaces import IRequest
+
+ verifyObject(IRequest, self._makeOne())
+
+ def test_ResponseClass_is_pyramid_Response(self):
+ from pyramid.response import Response
+
+ cls = self._getTargetClass()
+ self.assertEqual(cls.ResponseClass, Response)
+
+ def test_implements_security_apis(self):
+ apis = (AuthenticationAPIMixin, AuthorizationAPIMixin)
+ r = self._makeOne()
+ self.assertTrue(isinstance(r, apis))
+
+ def test_charset_defaults_to_utf8(self):
+ r = self._makeOne({'PATH_INFO': '/'})
+ self.assertEqual(r.charset, 'UTF-8')
+
+ def test_exception_defaults_to_None(self):
+ r = self._makeOne({'PATH_INFO': '/'})
+ self.assertEqual(r.exception, None)
+
+ def test_matchdict_defaults_to_None(self):
+ r = self._makeOne({'PATH_INFO': '/'})
+ self.assertEqual(r.matchdict, None)
+
+ def test_matched_route_defaults_to_None(self):
+ r = self._makeOne({'PATH_INFO': '/'})
+ self.assertEqual(r.matched_route, None)
+
+ def test_params_decoded_from_utf_8_by_default(self):
+ environ = {'PATH_INFO': '/', 'QUERY_STRING': 'la=La%20Pe%C3%B1a'}
+ request = self._makeOne(environ)
+ request.charset = None
+ self.assertEqual(request.GET['la'], text_(b'La Pe\xf1a'))
+
+ def test_tmpl_context(self):
+ from pyramid.request import TemplateContext
+
+ inst = self._makeOne()
+ result = inst.tmpl_context
+ self.assertEqual(result.__class__, TemplateContext)
+
+ def test_session_configured(self):
+ from pyramid.interfaces import ISessionFactory
+
+ inst = self._makeOne()
+
+ def factory(request):
+ return 'orangejuice'
+
+ self.config.registry.registerUtility(factory, ISessionFactory)
+ inst.registry = self.config.registry
+ self.assertEqual(inst.session, 'orangejuice')
+ self.assertEqual(inst.__dict__['session'], 'orangejuice')
+
+ def test_session_not_configured(self):
+ inst = self._makeOne()
+ inst.registry = self.config.registry
+ self.assertRaises(AttributeError, getattr, inst, 'session')
+
+ def test_setattr_and_getattr_dotnotation(self):
+ inst = self._makeOne()
+ inst.foo = 1
+ self.assertEqual(inst.foo, 1)
+
+ def test_setattr_and_getattr(self):
+ environ = {}
+ inst = self._makeOne(environ)
+ setattr(inst, 'bar', 1)
+ self.assertEqual(getattr(inst, 'bar'), 1)
+ self.assertEqual(environ, {}) # make sure we're not using adhoc attrs
+
+ def test_add_response_callback(self):
+ inst = self._makeOne()
+ self.assertEqual(len(inst.response_callbacks), 0)
+
+ def callback(request, response):
+ """ """
+
+ inst.add_response_callback(callback)
+ self.assertEqual(list(inst.response_callbacks), [callback])
+ inst.add_response_callback(callback)
+ self.assertEqual(list(inst.response_callbacks), [callback, callback])
+
+ def test__process_response_callbacks(self):
+ inst = self._makeOne()
+
+ def callback1(request, response):
+ request.called1 = True
+ response.called1 = True
+
+ def callback2(request, response):
+ request.called2 = True
+ response.called2 = True
+
+ inst.add_response_callback(callback1)
+ inst.add_response_callback(callback2)
+ response = DummyResponse()
+ inst._process_response_callbacks(response)
+ self.assertEqual(inst.called1, True)
+ self.assertEqual(inst.called2, True)
+ self.assertEqual(response.called1, True)
+ self.assertEqual(response.called2, True)
+ self.assertEqual(len(inst.response_callbacks), 0)
+
+ def test__process_response_callback_adding_response_callback(self):
+ """
+ When a response callback adds another callback, that new callback
+ should still be called.
+
+ See https://github.com/Pylons/pyramid/pull/1373
+ """
+ inst = self._makeOne()
+
+ def callback1(request, response):
+ request.called1 = True
+ response.called1 = True
+ request.add_response_callback(callback2)
+
+ def callback2(request, response):
+ request.called2 = True
+ response.called2 = True
+
+ inst.add_response_callback(callback1)
+ response = DummyResponse()
+ inst._process_response_callbacks(response)
+ self.assertEqual(inst.called1, True)
+ self.assertEqual(inst.called2, True)
+ self.assertEqual(response.called1, True)
+ self.assertEqual(response.called2, True)
+ self.assertEqual(len(inst.response_callbacks), 0)
+
+ def test_add_finished_callback(self):
+ inst = self._makeOne()
+ self.assertEqual(len(inst.finished_callbacks), 0)
+
+ def callback(request):
+ """ """
+
+ inst.add_finished_callback(callback)
+ self.assertEqual(list(inst.finished_callbacks), [callback])
+ inst.add_finished_callback(callback)
+ self.assertEqual(list(inst.finished_callbacks), [callback, callback])
+
+ def test__process_finished_callbacks(self):
+ inst = self._makeOne()
+
+ def callback1(request):
+ request.called1 = True
+
+ def callback2(request):
+ request.called2 = True
+
+ inst.add_finished_callback(callback1)
+ inst.add_finished_callback(callback2)
+ inst._process_finished_callbacks()
+ self.assertEqual(inst.called1, True)
+ self.assertEqual(inst.called2, True)
+ self.assertEqual(len(inst.finished_callbacks), 0)
+
+ def test_resource_url(self):
+ self._registerResourceURL()
+ environ = {
+ 'PATH_INFO': '/',
+ 'SERVER_NAME': 'example.com',
+ 'SERVER_PORT': '80',
+ 'wsgi.url_scheme': 'http',
+ }
+ inst = self._makeOne(environ)
+ root = DummyContext()
+ result = inst.resource_url(root)
+ self.assertEqual(result, 'http://example.com/context/')
+
+ def test_route_url(self):
+ environ = {
+ 'PATH_INFO': '/',
+ 'SERVER_NAME': 'example.com',
+ 'SERVER_PORT': '5432',
+ 'QUERY_STRING': 'la=La%20Pe%C3%B1a',
+ 'wsgi.url_scheme': 'http',
+ }
+ from pyramid.interfaces import IRoutesMapper
+
+ inst = self._makeOne(environ)
+ mapper = DummyRoutesMapper(route=DummyRoute('/1/2/3'))
+ self.config.registry.registerUtility(mapper, IRoutesMapper)
+ result = inst.route_url(
+ 'flub',
+ 'extra1',
+ 'extra2',
+ a=1,
+ b=2,
+ c=3,
+ _query={'a': 1},
+ _anchor=text_("foo"),
+ )
+ self.assertEqual(
+ result, 'http://example.com:5432/1/2/3/extra1/extra2?a=1#foo'
+ )
+
+ def test_route_path(self):
+ environ = {
+ 'PATH_INFO': '/',
+ 'SERVER_NAME': 'example.com',
+ 'SERVER_PORT': '5432',
+ 'QUERY_STRING': 'la=La%20Pe%C3%B1a',
+ 'wsgi.url_scheme': 'http',
+ }
+ from pyramid.interfaces import IRoutesMapper
+
+ inst = self._makeOne(environ)
+ mapper = DummyRoutesMapper(route=DummyRoute('/1/2/3'))
+ self.config.registry.registerUtility(mapper, IRoutesMapper)
+ result = inst.route_path(
+ 'flub',
+ 'extra1',
+ 'extra2',
+ a=1,
+ b=2,
+ c=3,
+ _query={'a': 1},
+ _anchor=text_("foo"),
+ )
+ self.assertEqual(result, '/1/2/3/extra1/extra2?a=1#foo')
+
+ def test_static_url(self):
+ from pyramid.interfaces import IStaticURLInfo
+
+ environ = {
+ 'PATH_INFO': '/',
+ 'SERVER_NAME': 'example.com',
+ 'SERVER_PORT': '5432',
+ 'QUERY_STRING': '',
+ 'wsgi.url_scheme': 'http',
+ }
+ request = self._makeOne(environ)
+ info = DummyStaticURLInfo('abc')
+ self.config.registry.registerUtility(info, IStaticURLInfo)
+ result = request.static_url('pyramid.tests:static/foo.css')
+ self.assertEqual(result, 'abc')
+ self.assertEqual(
+ info.args, ('pyramid.tests:static/foo.css', request, {})
+ )
+
+ def test_is_response_false(self):
+ request = self._makeOne()
+ request.registry = self.config.registry
+ self.assertEqual(request.is_response('abc'), False)
+
+ def test_is_response_true_ob_is_pyramid_response(self):
+ from pyramid.response import Response
+
+ r = Response('hello')
+ request = self._makeOne()
+ request.registry = self.config.registry
+ self.assertEqual(request.is_response(r), True)
+
+ def test_is_response_false_adapter_is_not_self(self):
+ from pyramid.interfaces import IResponse
+
+ request = self._makeOne()
+ request.registry = self.config.registry
+
+ def adapter(ob):
+ return object()
+
+ class Foo(object):
+ pass
+
+ foo = Foo()
+ request.registry.registerAdapter(adapter, (Foo,), IResponse)
+ self.assertEqual(request.is_response(foo), False)
+
+ def test_is_response_adapter_true(self):
+ from pyramid.interfaces import IResponse
+
+ request = self._makeOne()
+ request.registry = self.config.registry
+
+ class Foo(object):
+ pass
+
+ foo = Foo()
+
+ def adapter(ob):
+ return ob
+
+ request.registry.registerAdapter(adapter, (Foo,), IResponse)
+ self.assertEqual(request.is_response(foo), True)
+
+ def test_json_body_invalid_json(self):
+ request = self._makeOne({'REQUEST_METHOD': 'POST'})
+ request.body = b'{'
+ self.assertRaises(ValueError, getattr, request, 'json_body')
+
+ def test_json_body_valid_json(self):
+ request = self._makeOne({'REQUEST_METHOD': 'POST'})
+ request.body = b'{"a":1}'
+ self.assertEqual(request.json_body, {'a': 1})
+
+ def test_json_body_alternate_charset(self):
+ import json
+
+ request = self._makeOne({'REQUEST_METHOD': 'POST'})
+ inp = text_(
+ b'/\xe6\xb5\x81\xe8\xa1\x8c\xe8\xb6\x8b\xe5\x8a\xbf', 'utf-8'
+ )
+ if PY2:
+ body = json.dumps({'a': inp}).decode('utf-8').encode('utf-16')
+ else:
+ body = bytes(json.dumps({'a': inp}), 'utf-16')
+ request.body = body
+ request.content_type = 'application/json; charset=utf-16'
+ self.assertEqual(request.json_body, {'a': inp})
+
+ def test_json_body_GET_request(self):
+ request = self._makeOne({'REQUEST_METHOD': 'GET'})
+ self.assertRaises(ValueError, getattr, request, 'json_body')
+
+ def test_set_property(self):
+ request = self._makeOne()
+ opts = [2, 1]
+
+ def connect(obj):
+ return opts.pop()
+
+ request.set_property(connect, name='db')
+ self.assertEqual(1, request.db)
+ self.assertEqual(2, request.db)
+
+ def test_set_property_reify(self):
+ request = self._makeOne()
+ opts = [2, 1]
+
+ def connect(obj):
+ return opts.pop()
+
+ request.set_property(connect, name='db', reify=True)
+ self.assertEqual(1, request.db)
+ self.assertEqual(1, request.db)
+
+
+class Test_route_request_iface(unittest.TestCase):
+ def _callFUT(self, name):
+ from pyramid.request import route_request_iface
+
+ return route_request_iface(name)
+
+ def test_it(self):
+ iface = self._callFUT('routename')
+ self.assertEqual(iface.__name__, 'routename_IRequest')
+ self.assertTrue(hasattr(iface, 'combined'))
+ self.assertEqual(
+ iface.combined.__name__, 'routename_combined_IRequest'
+ )
+
+ def test_it_routename_with_spaces(self):
+ # see https://github.com/Pylons/pyramid/issues/232
+ iface = self._callFUT('routename with spaces')
+ self.assertEqual(iface.__name__, 'routename with spaces_IRequest')
+ self.assertTrue(hasattr(iface, 'combined'))
+ self.assertEqual(
+ iface.combined.__name__, 'routename with spaces_combined_IRequest'
+ )
+
+
+class Test_add_global_response_headers(unittest.TestCase):
+ def _callFUT(self, request, headerlist):
+ from pyramid.request import add_global_response_headers
+
+ return add_global_response_headers(request, headerlist)
+
+ def test_it(self):
+ request = DummyRequest()
+ response = DummyResponse()
+ self._callFUT(request, [('c', 1)])
+ self.assertEqual(len(request.response_callbacks), 1)
+ request.response_callbacks[0](None, response)
+ self.assertEqual(response.headerlist, [('c', 1)])
+
+
+class Test_call_app_with_subpath_as_path_info(unittest.TestCase):
+ def _callFUT(self, request, app):
+ from pyramid.request import call_app_with_subpath_as_path_info
+
+ return call_app_with_subpath_as_path_info(request, app)
+
+ def test_it_all_request_and_environment_data_missing(self):
+ request = DummyRequest({})
+ response = self._callFUT(request, 'app')
+ self.assertTrue(request.copied)
+ self.assertEqual(response, 'app')
+ self.assertEqual(request.environ['SCRIPT_NAME'], '')
+ self.assertEqual(request.environ['PATH_INFO'], '/')
+
+ def test_it_with_subpath_and_path_info(self):
+ request = DummyRequest({'PATH_INFO': '/hello'})
+ request.subpath = ('hello',)
+ response = self._callFUT(request, 'app')
+ self.assertTrue(request.copied)
+ self.assertEqual(response, 'app')
+ self.assertEqual(request.environ['SCRIPT_NAME'], '')
+ self.assertEqual(request.environ['PATH_INFO'], '/hello')
+
+ def test_it_with_subpath_and_path_info_path_info_endswith_slash(self):
+ request = DummyRequest({'PATH_INFO': '/hello/'})
+ request.subpath = ('hello',)
+ response = self._callFUT(request, 'app')
+ self.assertTrue(request.copied)
+ self.assertEqual(response, 'app')
+ self.assertEqual(request.environ['SCRIPT_NAME'], '')
+ self.assertEqual(request.environ['PATH_INFO'], '/hello/')
+
+ def test_it_with_subpath_and_path_info_extra_script_name(self):
+ request = DummyRequest(
+ {'PATH_INFO': '/hello', 'SCRIPT_NAME': '/script'}
+ )
+ request.subpath = ('hello',)
+ response = self._callFUT(request, 'app')
+ self.assertTrue(request.copied)
+ self.assertEqual(response, 'app')
+ self.assertEqual(request.environ['SCRIPT_NAME'], '/script')
+ self.assertEqual(request.environ['PATH_INFO'], '/hello')
+
+ def test_it_with_extra_slashes_in_path_info(self):
+ request = DummyRequest(
+ {'PATH_INFO': '//hello/', 'SCRIPT_NAME': '/script'}
+ )
+ request.subpath = ('hello',)
+ response = self._callFUT(request, 'app')
+ self.assertTrue(request.copied)
+ self.assertEqual(response, 'app')
+ self.assertEqual(request.environ['SCRIPT_NAME'], '/script')
+ self.assertEqual(request.environ['PATH_INFO'], '/hello/')
+
+ def test_subpath_path_info_and_script_name_have_utf8(self):
+ encoded = native_(text_(b'La Pe\xc3\xb1a'))
+ decoded = text_(bytes_(encoded), 'utf-8')
+ request = DummyRequest(
+ {'PATH_INFO': '/' + encoded, 'SCRIPT_NAME': '/' + encoded}
+ )
+ request.subpath = (decoded,)
+ response = self._callFUT(request, 'app')
+ self.assertTrue(request.copied)
+ self.assertEqual(response, 'app')
+ self.assertEqual(request.environ['SCRIPT_NAME'], '/' + encoded)
+ self.assertEqual(request.environ['PATH_INFO'], '/' + encoded)
+
+
+class Test_apply_request_extensions(unittest.TestCase):
+ def setUp(self):
+ self.config = testing.setUp()
+
+ def tearDown(self):
+ testing.tearDown()
+
+ def _callFUT(self, request, extensions=None):
+ from pyramid.request import apply_request_extensions
+
+ return apply_request_extensions(request, extensions=extensions)
+
+ def test_it_with_registry(self):
+ from pyramid.interfaces import IRequestExtensions
+
+ extensions = Dummy()
+ extensions.methods = {'foo': lambda x, y: y}
+ extensions.descriptors = {'bar': property(lambda x: 'bar')}
+ self.config.registry.registerUtility(extensions, IRequestExtensions)
+ request = DummyRequest()
+ request.registry = self.config.registry
+ self._callFUT(request)
+ self.assertEqual(request.bar, 'bar')
+ self.assertEqual(request.foo('abc'), 'abc')
+
+ def test_it_override_extensions(self):
+ from pyramid.interfaces import IRequestExtensions
+
+ ignore = Dummy()
+ ignore.methods = {'x': lambda x, y, z: 'asdf'}
+ ignore.descriptors = {'bar': property(lambda x: 'asdf')}
+ self.config.registry.registerUtility(ignore, IRequestExtensions)
+ request = DummyRequest()
+ request.registry = self.config.registry
+
+ extensions = Dummy()
+ extensions.methods = {'foo': lambda x, y: y}
+ extensions.descriptors = {'bar': property(lambda x: 'bar')}
+ self._callFUT(request, extensions=extensions)
+ self.assertRaises(AttributeError, lambda: request.x)
+ self.assertEqual(request.bar, 'bar')
+ self.assertEqual(request.foo('abc'), 'abc')
+
+
+class Dummy(object):
+ pass
+
+
+class Test_subclassing_Request(unittest.TestCase):
+ def test_subclass(self):
+ from pyramid.interfaces import IRequest
+ from pyramid.request import Request
+
+ class RequestSub(Request):
+ pass
+
+ self.assertTrue(hasattr(Request, '__provides__'))
+ self.assertTrue(hasattr(Request, '__implemented__'))
+ self.assertTrue(hasattr(Request, '__providedBy__'))
+ self.assertFalse(hasattr(RequestSub, '__provides__'))
+ self.assertTrue(hasattr(RequestSub, '__providedBy__'))
+ self.assertTrue(hasattr(RequestSub, '__implemented__'))
+
+ self.assertTrue(IRequest.implementedBy(RequestSub))
+ # The call to implementedBy will add __provides__ to the class
+ self.assertTrue(hasattr(RequestSub, '__provides__'))
+
+ def test_subclass_with_implementer(self):
+ from pyramid.interfaces import IRequest
+ from pyramid.request import Request
+ from pyramid.util import InstancePropertyHelper
+ from zope.interface import implementer
+
+ @implementer(IRequest)
+ class RequestSub(Request):
+ pass
+
+ self.assertTrue(hasattr(Request, '__provides__'))
+ self.assertTrue(hasattr(Request, '__implemented__'))
+ self.assertTrue(hasattr(Request, '__providedBy__'))
+ self.assertTrue(hasattr(RequestSub, '__provides__'))
+ self.assertTrue(hasattr(RequestSub, '__providedBy__'))
+ self.assertTrue(hasattr(RequestSub, '__implemented__'))
+
+ req = RequestSub({})
+ helper = InstancePropertyHelper()
+ helper.apply_properties(req, {'b': 'b'})
+
+ self.assertTrue(IRequest.providedBy(req))
+ self.assertTrue(IRequest.implementedBy(RequestSub))
+
+ def test_subclass_mutate_before_providedBy(self):
+ from pyramid.interfaces import IRequest
+ from pyramid.request import Request
+ from pyramid.util import InstancePropertyHelper
+
+ class RequestSub(Request):
+ pass
+
+ req = RequestSub({})
+ helper = InstancePropertyHelper()
+ helper.apply_properties(req, {'b': 'b'})
+
+ self.assertTrue(IRequest.providedBy(req))
+ self.assertTrue(IRequest.implementedBy(RequestSub))
+
+
+class DummyRequest(object):
+ def __init__(self, environ=None):
+ if environ is None:
+ environ = {}
+ self.environ = environ
+
+ def add_response_callback(self, callback):
+ self.response_callbacks = [callback]
+
+ def get_response(self, app):
+ return app
+
+ def copy(self):
+ self.copied = True
+ return self
+
+
+class DummyResponse:
+ def __init__(self):
+ self.headerlist = []
+
+
+class DummyContext:
+ pass
+
+
+class DummyRoutesMapper:
+ raise_exc = None
+
+ def __init__(self, route=None, raise_exc=False):
+ self.route = route
+
+ def get_route(self, route_name):
+ return self.route
+
+
+class DummyRoute:
+ pregenerator = None
+
+ def __init__(self, result='/1/2/3'):
+ self.result = result
+
+ def generate(self, kw):
+ self.kw = kw
+ return self.result
+
+
+class DummyStaticURLInfo:
+ def __init__(self, result):
+ self.result = result
+
+ def generate(self, path, request, **kw):
+ self.args = path, request, kw
+ return self.result
diff --git a/tests/test_response.py b/tests/test_response.py
new file mode 100644
index 000000000..5231e47f0
--- /dev/null
+++ b/tests/test_response.py
@@ -0,0 +1,262 @@
+import io
+import mimetypes
+import os
+import unittest
+from pyramid import testing
+
+
+class TestResponse(unittest.TestCase):
+ def _getTargetClass(self):
+ from pyramid.response import Response
+
+ return Response
+
+ def test_implements_IResponse(self):
+ from pyramid.interfaces import IResponse
+
+ cls = self._getTargetClass()
+ self.assertTrue(IResponse.implementedBy(cls))
+
+ def test_provides_IResponse(self):
+ from pyramid.interfaces import IResponse
+
+ inst = self._getTargetClass()()
+ self.assertTrue(IResponse.providedBy(inst))
+
+
+class TestFileResponse(unittest.TestCase):
+ def _makeOne(self, file, **kw):
+ from pyramid.response import FileResponse
+
+ return FileResponse(file, **kw)
+
+ def _getPath(self, suffix='txt'):
+ here = os.path.dirname(__file__)
+ return os.path.join(here, 'fixtures', 'minimal.%s' % (suffix,))
+
+ def test_with_image_content_type(self):
+ path = self._getPath('jpg')
+ r = self._makeOne(path, content_type='image/jpeg')
+ self.assertEqual(r.content_type, 'image/jpeg')
+ self.assertEqual(r.headers['content-type'], 'image/jpeg')
+ path = self._getPath()
+ r.app_iter.close()
+
+ def test_with_xml_content_type(self):
+ path = self._getPath('xml')
+ r = self._makeOne(path, content_type='application/xml')
+ self.assertEqual(r.content_type, 'application/xml')
+ self.assertEqual(
+ r.headers['content-type'], 'application/xml; charset=UTF-8'
+ )
+ r.app_iter.close()
+
+ def test_with_pdf_content_type(self):
+ path = self._getPath('xml')
+ r = self._makeOne(path, content_type='application/pdf')
+ self.assertEqual(r.content_type, 'application/pdf')
+ self.assertEqual(r.headers['content-type'], 'application/pdf')
+ r.app_iter.close()
+
+ def test_without_content_type(self):
+ for suffix in ('txt', 'xml', 'pdf'):
+ path = self._getPath(suffix)
+ r = self._makeOne(path)
+ self.assertEqual(
+ r.headers['content-type'].split(';')[0],
+ mimetypes.guess_type(path, strict=False)[0],
+ )
+ r.app_iter.close()
+
+ def test_python_277_bug_15207(self):
+ # python 2.7.7 on windows has a bug where its mimetypes.guess_type
+ # function returns Unicode for the content_type, unlike any previous
+ # version of Python. See https://github.com/Pylons/pyramid/issues/1360
+ # for more information.
+ from pyramid.compat import text_
+ import mimetypes as old_mimetypes
+ from pyramid import response
+
+ class FakeMimetypesModule(object):
+ def guess_type(self, *arg, **kw):
+ return text_('foo/bar'), None
+
+ fake_mimetypes = FakeMimetypesModule()
+ try:
+ response.mimetypes = fake_mimetypes
+ path = self._getPath('xml')
+ r = self._makeOne(path)
+ self.assertEqual(r.content_type, 'foo/bar')
+ self.assertEqual(type(r.content_type), str)
+ finally:
+ response.mimetypes = old_mimetypes
+
+
+class TestFileIter(unittest.TestCase):
+ def _makeOne(self, file, block_size):
+ from pyramid.response import FileIter
+
+ return FileIter(file, block_size)
+
+ def test___iter__(self):
+ f = io.BytesIO(b'abc')
+ inst = self._makeOne(f, 1)
+ self.assertEqual(inst.__iter__(), inst)
+
+ def test_iteration(self):
+ data = b'abcdef'
+ f = io.BytesIO(b'abcdef')
+ inst = self._makeOne(f, 1)
+ r = b''
+ for x in inst:
+ self.assertEqual(len(x), 1)
+ r += x
+ self.assertEqual(r, data)
+
+ def test_close(self):
+ f = io.BytesIO(b'abc')
+ inst = self._makeOne(f, 1)
+ inst.close()
+ self.assertTrue(f.closed)
+
+
+class Test_patch_mimetypes(unittest.TestCase):
+ def _callFUT(self, module):
+ from pyramid.response import init_mimetypes
+
+ return init_mimetypes(module)
+
+ def test_has_init(self):
+ class DummyMimetypes(object):
+ def init(self):
+ self.initted = True
+
+ module = DummyMimetypes()
+ result = self._callFUT(module)
+ self.assertEqual(result, True)
+ self.assertEqual(module.initted, True)
+
+ def test_missing_init(self):
+ class DummyMimetypes(object):
+ pass
+
+ module = DummyMimetypes()
+ result = self._callFUT(module)
+ self.assertEqual(result, False)
+
+
+class TestResponseAdapter(unittest.TestCase):
+ def setUp(self):
+ registry = Dummy()
+ self.config = testing.setUp(registry=registry)
+
+ def tearDown(self):
+ self.config.end()
+
+ def _makeOne(self, *types_or_ifaces, **kw):
+ from pyramid.response import response_adapter
+
+ return response_adapter(*types_or_ifaces, **kw)
+
+ def test_register_single(self):
+ from zope.interface import Interface
+
+ class IFoo(Interface):
+ pass
+
+ dec = self._makeOne(IFoo)
+
+ def foo(): # pragma: no cover
+ pass
+
+ config = DummyConfigurator()
+ scanner = Dummy()
+ scanner.config = config
+ dec.register(scanner, None, foo)
+ self.assertEqual(config.adapters, [(foo, IFoo)])
+
+ def test_register_multi(self):
+ from zope.interface import Interface
+
+ class IFoo(Interface):
+ pass
+
+ class IBar(Interface):
+ pass
+
+ dec = self._makeOne(IFoo, IBar)
+
+ def foo(): # pragma: no cover
+ pass
+
+ config = DummyConfigurator()
+ scanner = Dummy()
+ scanner.config = config
+ dec.register(scanner, None, foo)
+ self.assertEqual(config.adapters, [(foo, IFoo), (foo, IBar)])
+
+ def test___call__(self):
+ from zope.interface import Interface
+
+ class IFoo(Interface):
+ pass
+
+ dec = self._makeOne(IFoo)
+ dummy_venusian = DummyVenusian()
+ dec.venusian = dummy_venusian
+
+ def foo(): # pragma: no cover
+ pass
+
+ dec(foo)
+ self.assertEqual(
+ dummy_venusian.attached, [(foo, dec.register, 'pyramid', 1)]
+ )
+
+ def test___call___with_venusian_args(self):
+ from zope.interface import Interface
+
+ class IFoo(Interface):
+ pass
+
+ dec = self._makeOne(IFoo, _category='foo', _depth=1)
+ dummy_venusian = DummyVenusian()
+ dec.venusian = dummy_venusian
+
+ def foo(): # pragma: no cover
+ pass
+
+ dec(foo)
+ self.assertEqual(
+ dummy_venusian.attached, [(foo, dec.register, 'foo', 2)]
+ )
+
+
+class TestGetResponseFactory(unittest.TestCase):
+ def test_get_factory(self):
+ from pyramid.registry import Registry
+ from pyramid.response import Response, _get_response_factory
+
+ registry = Registry()
+ response = _get_response_factory(registry)(None)
+ self.assertTrue(isinstance(response, Response))
+
+
+class Dummy(object):
+ pass
+
+
+class DummyConfigurator(object):
+ def __init__(self):
+ self.adapters = []
+
+ def add_response_adapter(self, wrapped, type_or_iface):
+ self.adapters.append((wrapped, type_or_iface))
+
+
+class DummyVenusian(object):
+ def __init__(self):
+ self.attached = []
+
+ def attach(self, wrapped, fn, category=None, depth=None):
+ self.attached.append((wrapped, fn, category, depth))
diff --git a/tests/test_router.py b/tests/test_router.py
new file mode 100644
index 000000000..3e66757f6
--- /dev/null
+++ b/tests/test_router.py
@@ -0,0 +1,1724 @@
+import unittest
+from zope.interface import implementer
+
+from pyramid import testing
+from pyramid.interfaces import IResponse
+
+
+class TestRouter(unittest.TestCase):
+ def setUp(self):
+ self.config = testing.setUp()
+ self.registry = self.config.registry
+
+ def tearDown(self):
+ testing.tearDown()
+
+ def _registerRouteRequest(self, name):
+ from pyramid.interfaces import IRouteRequest
+ from pyramid.request import route_request_iface
+
+ iface = route_request_iface(name)
+ self.registry.registerUtility(iface, IRouteRequest, name=name)
+ return iface
+
+ def _connectRoute(self, name, path, factory=None):
+ from pyramid.interfaces import IRoutesMapper
+ from pyramid.urldispatch import RoutesMapper
+
+ mapper = self.registry.queryUtility(IRoutesMapper)
+ if mapper is None:
+ mapper = RoutesMapper()
+ self.registry.registerUtility(mapper, IRoutesMapper)
+ return mapper.connect(name, path, factory)
+
+ def _registerLogger(self):
+ from pyramid.interfaces import IDebugLogger
+
+ logger = DummyLogger()
+ self.registry.registerUtility(logger, IDebugLogger)
+ return logger
+
+ def _registerSettings(self, **kw):
+ settings = {
+ 'debug_authorization': False,
+ 'debug_notfound': False,
+ 'debug_routematch': False,
+ }
+ settings.update(kw)
+ self.registry.settings = settings
+
+ def _registerTraverserFactory(
+ self,
+ context,
+ view_name='',
+ subpath=None,
+ traversed=None,
+ virtual_root=None,
+ virtual_root_path=None,
+ raise_error=None,
+ **kw
+ ):
+ from pyramid.interfaces import ITraverser
+
+ if virtual_root is None:
+ virtual_root = context
+ if subpath is None:
+ subpath = []
+ if traversed is None:
+ traversed = []
+ if virtual_root_path is None:
+ virtual_root_path = []
+
+ class DummyTraverserFactory:
+ def __init__(self, root):
+ self.root = root
+
+ def __call__(self, request):
+ if raise_error:
+ raise raise_error
+ values = {
+ 'root': self.root,
+ 'context': context,
+ 'view_name': view_name,
+ 'subpath': subpath,
+ 'traversed': traversed,
+ 'virtual_root': virtual_root,
+ 'virtual_root_path': virtual_root_path,
+ }
+ kw.update(values)
+ return kw
+
+ self.registry.registerAdapter(
+ DummyTraverserFactory, (None,), ITraverser, name=''
+ )
+
+ def _registerView(self, app, name, classifier, req_iface, ctx_iface):
+ from pyramid.interfaces import IView
+
+ self.registry.registerAdapter(
+ app, (classifier, req_iface, ctx_iface), IView, name
+ )
+
+ def _registerEventListener(self, iface):
+ L = []
+
+ def listener(event):
+ L.append(event)
+
+ self.registry.registerHandler(listener, (iface,))
+ return L
+
+ def _registerRootFactory(self, val):
+ rootfactory = DummyRootFactory(val)
+ from pyramid.interfaces import IRootFactory
+
+ self.registry.registerUtility(rootfactory, IRootFactory)
+ return rootfactory
+
+ def _getTargetClass(self):
+ from pyramid.router import Router
+
+ return Router
+
+ def _makeOne(self):
+ klass = self._getTargetClass()
+ return klass(self.registry)
+
+ def _makeEnviron(self, **extras):
+ environ = {
+ 'wsgi.url_scheme': 'http',
+ 'SERVER_NAME': 'localhost',
+ 'SERVER_PORT': '8080',
+ 'REQUEST_METHOD': 'GET',
+ 'PATH_INFO': '/',
+ }
+ environ.update(extras)
+ return environ
+
+ def test_ctor_registry_has_no_settings(self):
+ self.registry.settings = None
+ router = self._makeOne()
+ self.assertEqual(router.debug_notfound, False)
+ self.assertEqual(router.debug_routematch, False)
+ self.assertFalse('debug_notfound' in router.__dict__)
+ self.assertFalse('debug_routematch' in router.__dict__)
+
+ def test_root_policy(self):
+ context = DummyContext()
+ self._registerTraverserFactory(context)
+ rootfactory = self._registerRootFactory('abc')
+ router = self._makeOne()
+ self.assertEqual(router.root_policy, rootfactory)
+
+ def test_request_factory(self):
+ from pyramid.interfaces import IRequestFactory
+
+ class DummyRequestFactory(object):
+ pass
+
+ self.registry.registerUtility(DummyRequestFactory, IRequestFactory)
+ router = self._makeOne()
+ self.assertEqual(router.request_factory, DummyRequestFactory)
+
+ def test_tween_factories(self):
+ from pyramid.interfaces import ITweens
+ from pyramid.config.tweens import Tweens
+ from pyramid.response import Response
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IResponse
+
+ tweens = Tweens()
+ self.registry.registerUtility(tweens, ITweens)
+ L = []
+
+ def tween_factory1(handler, registry):
+ L.append((handler, registry))
+
+ def wrapper(request):
+ request.environ['handled'].append('one')
+ return handler(request)
+
+ wrapper.name = 'one'
+ wrapper.child = handler
+ return wrapper
+
+ def tween_factory2(handler, registry):
+ L.append((handler, registry))
+
+ def wrapper(request):
+ request.environ['handled'] = ['two']
+ return handler(request)
+
+ wrapper.name = 'two'
+ wrapper.child = handler
+ return wrapper
+
+ tweens.add_implicit('one', tween_factory1)
+ tweens.add_implicit('two', tween_factory2)
+ router = self._makeOne()
+ self.assertEqual(router.handle_request.name, 'two')
+ self.assertEqual(router.handle_request.child.name, 'one')
+ self.assertEqual(
+ router.handle_request.child.child.__name__, 'handle_request'
+ )
+ context = DummyContext()
+ self._registerTraverserFactory(context)
+ environ = self._makeEnviron()
+ view = DummyView('abc')
+ self._registerView(
+ self.config.derive_view(view), '', IViewClassifier, None, None
+ )
+ start_response = DummyStartResponse()
+
+ def make_response(s):
+ return Response(s)
+
+ router.registry.registerAdapter(make_response, (str,), IResponse)
+ app_iter = router(environ, start_response)
+ self.assertEqual(app_iter, [b'abc'])
+ self.assertEqual(start_response.status, '200 OK')
+ self.assertEqual(environ['handled'], ['two', 'one'])
+
+ def test_call_traverser_default(self):
+ from pyramid.httpexceptions import HTTPNotFound
+
+ environ = self._makeEnviron()
+ logger = self._registerLogger()
+ router = self._makeOne()
+ start_response = DummyStartResponse()
+ why = exc_raised(HTTPNotFound, router, environ, start_response)
+ self.assertTrue('/' in why.args[0], why)
+ self.assertFalse('debug_notfound' in why.args[0])
+ self.assertEqual(len(logger.messages), 0)
+
+ def test_traverser_raises_notfound_class(self):
+ from pyramid.httpexceptions import HTTPNotFound
+
+ environ = self._makeEnviron()
+ context = DummyContext()
+ self._registerTraverserFactory(context, raise_error=HTTPNotFound)
+ router = self._makeOne()
+ start_response = DummyStartResponse()
+ self.assertRaises(HTTPNotFound, router, environ, start_response)
+
+ def test_traverser_raises_notfound_instance(self):
+ from pyramid.httpexceptions import HTTPNotFound
+
+ environ = self._makeEnviron()
+ context = DummyContext()
+ self._registerTraverserFactory(
+ context, raise_error=HTTPNotFound('foo')
+ )
+ router = self._makeOne()
+ start_response = DummyStartResponse()
+ why = exc_raised(HTTPNotFound, router, environ, start_response)
+ self.assertTrue('foo' in why.args[0], why)
+
+ def test_traverser_raises_forbidden_class(self):
+ from pyramid.httpexceptions import HTTPForbidden
+
+ environ = self._makeEnviron()
+ context = DummyContext()
+ self._registerTraverserFactory(context, raise_error=HTTPForbidden)
+ router = self._makeOne()
+ start_response = DummyStartResponse()
+ self.assertRaises(HTTPForbidden, router, environ, start_response)
+
+ def test_traverser_raises_forbidden_instance(self):
+ from pyramid.httpexceptions import HTTPForbidden
+
+ environ = self._makeEnviron()
+ context = DummyContext()
+ self._registerTraverserFactory(
+ context, raise_error=HTTPForbidden('foo')
+ )
+ router = self._makeOne()
+ start_response = DummyStartResponse()
+ why = exc_raised(HTTPForbidden, router, environ, start_response)
+ self.assertTrue('foo' in why.args[0], why)
+
+ def test_call_no_view_registered_no_isettings(self):
+ from pyramid.httpexceptions import HTTPNotFound
+
+ environ = self._makeEnviron()
+ context = DummyContext()
+ self._registerTraverserFactory(context)
+ logger = self._registerLogger()
+ router = self._makeOne()
+ start_response = DummyStartResponse()
+ why = exc_raised(HTTPNotFound, router, environ, start_response)
+ self.assertTrue('/' in why.args[0], why)
+ self.assertFalse('debug_notfound' in why.args[0])
+ self.assertEqual(len(logger.messages), 0)
+
+ def test_call_no_view_registered_debug_notfound_false(self):
+ from pyramid.httpexceptions import HTTPNotFound
+
+ environ = self._makeEnviron()
+ context = DummyContext()
+ self._registerTraverserFactory(context)
+ logger = self._registerLogger()
+ self._registerSettings(debug_notfound=False)
+ router = self._makeOne()
+ start_response = DummyStartResponse()
+ why = exc_raised(HTTPNotFound, router, environ, start_response)
+ self.assertTrue('/' in why.args[0], why)
+ self.assertFalse('debug_notfound' in why.args[0])
+ self.assertEqual(len(logger.messages), 0)
+
+ def test_call_no_view_registered_debug_notfound_true(self):
+ from pyramid.httpexceptions import HTTPNotFound
+
+ environ = self._makeEnviron()
+ context = DummyContext()
+ self._registerTraverserFactory(context)
+ self._registerSettings(debug_notfound=True)
+ logger = self._registerLogger()
+ router = self._makeOne()
+ start_response = DummyStartResponse()
+ why = exc_raised(HTTPNotFound, router, environ, start_response)
+ self.assertTrue(
+ "debug_notfound of url http://localhost:8080/; " in why.args[0]
+ )
+ self.assertTrue("view_name: '', subpath: []" in why.args[0])
+ self.assertTrue('http://localhost:8080' in why.args[0], why)
+
+ self.assertEqual(len(logger.messages), 1)
+ message = logger.messages[0]
+ self.assertTrue('of url http://localhost:8080' in message)
+ self.assertTrue("path_info: " in message)
+ self.assertTrue('DummyContext' in message)
+ self.assertTrue("view_name: ''" in message)
+ self.assertTrue("subpath: []" in message)
+
+ def test_call_view_returns_non_iresponse(self):
+ from pyramid.interfaces import IViewClassifier
+
+ context = DummyContext()
+ self._registerTraverserFactory(context)
+ environ = self._makeEnviron()
+ view = DummyView('abc')
+ self._registerView(
+ self.config.derive_view(view), '', IViewClassifier, None, None
+ )
+ router = self._makeOne()
+ start_response = DummyStartResponse()
+ self.assertRaises(ValueError, router, environ, start_response)
+
+ def test_call_view_returns_adapted_response(self):
+ from pyramid.response import Response
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IResponse
+
+ context = DummyContext()
+ self._registerTraverserFactory(context)
+ environ = self._makeEnviron()
+ view = DummyView('abc')
+ self._registerView(
+ self.config.derive_view(view), '', IViewClassifier, None, None
+ )
+ router = self._makeOne()
+ start_response = DummyStartResponse()
+
+ def make_response(s):
+ return Response(s)
+
+ router.registry.registerAdapter(make_response, (str,), IResponse)
+ app_iter = router(environ, start_response)
+ self.assertEqual(app_iter, [b'abc'])
+ self.assertEqual(start_response.status, '200 OK')
+
+ def test_call_with_request_extensions(self):
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IRequestExtensions
+ from pyramid.interfaces import IRequest
+ from pyramid.request import Request
+ from pyramid.util import InstancePropertyHelper
+
+ context = DummyContext()
+ self._registerTraverserFactory(context)
+
+ class Extensions(object):
+ def __init__(self):
+ self.methods = {}
+ self.descriptors = {}
+
+ extensions = Extensions()
+ ext_method = lambda r: 'bar'
+ name, fn = InstancePropertyHelper.make_property(ext_method, name='foo')
+ extensions.descriptors[name] = fn
+ request = Request.blank('/')
+ request.request_iface = IRequest
+ request.registry = self.registry
+
+ def request_factory(environ):
+ return request
+
+ self.registry.registerUtility(extensions, IRequestExtensions)
+ environ = self._makeEnviron()
+ response = DummyResponse()
+ response.app_iter = ['Hello world']
+ view = DummyView(response)
+ self._registerView(
+ self.config.derive_view(view), '', IViewClassifier, None, None
+ )
+ router = self._makeOne()
+ router.request_factory = request_factory
+ start_response = DummyStartResponse()
+ router(environ, start_response)
+ self.assertEqual(view.request.foo, 'bar')
+
+ def test_call_view_registered_nonspecific_default_path(self):
+ from pyramid.interfaces import IViewClassifier
+
+ context = DummyContext()
+ self._registerTraverserFactory(context)
+ response = DummyResponse()
+ response.app_iter = ['Hello world']
+ view = DummyView(response)
+ environ = self._makeEnviron()
+ self._registerView(
+ self.config.derive_view(view), '', IViewClassifier, None, None
+ )
+ self._registerRootFactory(context)
+ router = self._makeOne()
+ start_response = DummyStartResponse()
+ result = router(environ, start_response)
+ self.assertEqual(result, ['Hello world'])
+ self.assertEqual(start_response.headers, ())
+ self.assertEqual(start_response.status, '200 OK')
+ request = view.request
+ self.assertEqual(request.view_name, '')
+ self.assertEqual(request.subpath, [])
+ self.assertEqual(request.context, context)
+ self.assertEqual(request.root, context)
+
+ def test_call_view_registered_nonspecific_nondefault_path_and_subpath(
+ self
+ ):
+ from pyramid.interfaces import IViewClassifier
+
+ context = DummyContext()
+ self._registerTraverserFactory(
+ context, view_name='foo', subpath=['bar'], traversed=['context']
+ )
+ self._registerRootFactory(context)
+ response = DummyResponse()
+ response.app_iter = ['Hello world']
+ view = DummyView(response)
+ environ = self._makeEnviron()
+ self._registerView(view, 'foo', IViewClassifier, None, None)
+ router = self._makeOne()
+ start_response = DummyStartResponse()
+ result = router(environ, start_response)
+ self.assertEqual(result, ['Hello world'])
+ self.assertEqual(start_response.headers, ())
+ self.assertEqual(start_response.status, '200 OK')
+ request = view.request
+ self.assertEqual(request.view_name, 'foo')
+ self.assertEqual(request.subpath, ['bar'])
+ self.assertEqual(request.context, context)
+ self.assertEqual(request.root, context)
+
+ def test_call_view_registered_specific_success(self):
+ from zope.interface import Interface
+ from zope.interface import directlyProvides
+
+ class IContext(Interface):
+ pass
+
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IViewClassifier
+
+ context = DummyContext()
+ directlyProvides(context, IContext)
+ self._registerTraverserFactory(context)
+ self._registerRootFactory(context)
+ response = DummyResponse()
+ response.app_iter = ['Hello world']
+ view = DummyView(response)
+ environ = self._makeEnviron()
+ self._registerView(view, '', IViewClassifier, IRequest, IContext)
+ router = self._makeOne()
+ start_response = DummyStartResponse()
+ result = router(environ, start_response)
+ self.assertEqual(result, ['Hello world'])
+ self.assertEqual(start_response.headers, ())
+ self.assertEqual(start_response.status, '200 OK')
+ request = view.request
+ self.assertEqual(request.view_name, '')
+ self.assertEqual(request.subpath, [])
+ self.assertEqual(request.context, context)
+ self.assertEqual(request.root, context)
+
+ def test_call_view_registered_specific_fail(self):
+ from zope.interface import Interface
+ from zope.interface import directlyProvides
+ from pyramid.httpexceptions import HTTPNotFound
+ from pyramid.interfaces import IViewClassifier
+
+ class IContext(Interface):
+ pass
+
+ class INotContext(Interface):
+ pass
+
+ from pyramid.interfaces import IRequest
+
+ context = DummyContext()
+ directlyProvides(context, INotContext)
+ self._registerTraverserFactory(context, subpath=[''])
+ response = DummyResponse()
+ view = DummyView(response)
+ environ = self._makeEnviron()
+ self._registerView(view, '', IViewClassifier, IRequest, IContext)
+ router = self._makeOne()
+ start_response = DummyStartResponse()
+ self.assertRaises(HTTPNotFound, router, environ, start_response)
+
+ def test_call_view_raises_forbidden(self):
+ from zope.interface import Interface
+ from zope.interface import directlyProvides
+ from pyramid.httpexceptions import HTTPForbidden
+
+ class IContext(Interface):
+ pass
+
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IViewClassifier
+
+ context = DummyContext()
+ directlyProvides(context, IContext)
+ self._registerTraverserFactory(context, subpath=[''])
+ response = DummyResponse()
+ view = DummyView(
+ response, raise_exception=HTTPForbidden("unauthorized")
+ )
+ environ = self._makeEnviron()
+ self._registerView(view, '', IViewClassifier, IRequest, IContext)
+ router = self._makeOne()
+ start_response = DummyStartResponse()
+ why = exc_raised(HTTPForbidden, router, environ, start_response)
+ self.assertEqual(why.args[0], 'unauthorized')
+
+ def test_call_view_raises_notfound(self):
+ from zope.interface import Interface
+ from zope.interface import directlyProvides
+
+ class IContext(Interface):
+ pass
+
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.httpexceptions import HTTPNotFound
+
+ context = DummyContext()
+ directlyProvides(context, IContext)
+ self._registerTraverserFactory(context, subpath=[''])
+ response = DummyResponse()
+ view = DummyView(response, raise_exception=HTTPNotFound("notfound"))
+ environ = self._makeEnviron()
+ self._registerView(view, '', IViewClassifier, IRequest, IContext)
+ router = self._makeOne()
+ start_response = DummyStartResponse()
+ why = exc_raised(HTTPNotFound, router, environ, start_response)
+ self.assertEqual(why.args[0], 'notfound')
+
+ def test_call_view_raises_response_cleared(self):
+ from zope.interface import Interface
+ from zope.interface import directlyProvides
+ from pyramid.interfaces import IExceptionViewClassifier
+
+ class IContext(Interface):
+ pass
+
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IViewClassifier
+
+ context = DummyContext()
+ directlyProvides(context, IContext)
+ self._registerTraverserFactory(context, subpath=[''])
+
+ def view(context, request):
+ request.response.a = 1
+ raise KeyError
+
+ def exc_view(context, request):
+ self.assertFalse(hasattr(request.response, 'a'))
+ request.response.body = b'OK'
+ return request.response
+
+ environ = self._makeEnviron()
+ self._registerView(view, '', IViewClassifier, IRequest, IContext)
+ self._registerView(
+ exc_view, '', IExceptionViewClassifier, IRequest, KeyError
+ )
+ router = self._makeOne()
+ start_response = DummyStartResponse()
+ itera = router(environ, start_response)
+ self.assertEqual(itera, [b'OK'])
+
+ def test_call_request_has_response_callbacks(self):
+ from zope.interface import Interface
+ from zope.interface import directlyProvides
+
+ class IContext(Interface):
+ pass
+
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IViewClassifier
+
+ context = DummyContext()
+ directlyProvides(context, IContext)
+ self._registerTraverserFactory(context, subpath=[''])
+ response = DummyResponse('200 OK')
+
+ def view(context, request):
+ def callback(request, response):
+ response.called_back = True
+
+ request.add_response_callback(callback)
+ return response
+
+ environ = self._makeEnviron()
+ self._registerView(view, '', IViewClassifier, IRequest, IContext)
+ router = self._makeOne()
+ start_response = DummyStartResponse()
+ router(environ, start_response)
+ self.assertEqual(response.called_back, True)
+
+ def test_call_request_has_finished_callbacks_when_view_succeeds(self):
+ from zope.interface import Interface
+ from zope.interface import directlyProvides
+
+ class IContext(Interface):
+ pass
+
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IViewClassifier
+
+ context = DummyContext()
+ directlyProvides(context, IContext)
+ self._registerTraverserFactory(context, subpath=[''])
+ response = DummyResponse('200 OK')
+
+ def view(context, request):
+ def callback(request):
+ request.environ['called_back'] = True
+
+ request.add_finished_callback(callback)
+ return response
+
+ environ = self._makeEnviron()
+ self._registerView(view, '', IViewClassifier, IRequest, IContext)
+ router = self._makeOne()
+ start_response = DummyStartResponse()
+ router(environ, start_response)
+ self.assertEqual(environ['called_back'], True)
+
+ def test_call_request_has_finished_callbacks_when_view_raises(self):
+ from zope.interface import Interface
+ from zope.interface import directlyProvides
+
+ class IContext(Interface):
+ pass
+
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IViewClassifier
+
+ context = DummyContext()
+ directlyProvides(context, IContext)
+ self._registerTraverserFactory(context, subpath=[''])
+
+ def view(context, request):
+ def callback(request):
+ request.environ['called_back'] = True
+
+ request.add_finished_callback(callback)
+ raise NotImplementedError
+
+ environ = self._makeEnviron()
+ self._registerView(view, '', IViewClassifier, IRequest, IContext)
+ router = self._makeOne()
+ start_response = DummyStartResponse()
+ exc_raised(NotImplementedError, router, environ, start_response)
+ self.assertEqual(environ['called_back'], True)
+
+ def test_call_request_factory_raises(self):
+ # making sure finally doesnt barf when a request cannot be created
+ environ = self._makeEnviron()
+ router = self._makeOne()
+
+ def dummy_request_factory(environ):
+ raise NotImplementedError
+
+ router.request_factory = dummy_request_factory
+ start_response = DummyStartResponse()
+ exc_raised(NotImplementedError, router, environ, start_response)
+
+ def test_call_eventsends(self):
+ from pyramid.interfaces import INewRequest
+ from pyramid.interfaces import INewResponse
+ from pyramid.interfaces import IBeforeTraversal
+ from pyramid.interfaces import IContextFound
+ from pyramid.interfaces import IViewClassifier
+
+ context = DummyContext()
+ self._registerTraverserFactory(context)
+ response = DummyResponse()
+ response.app_iter = ['Hello world']
+ view = DummyView(response)
+ environ = self._makeEnviron()
+ self._registerView(view, '', IViewClassifier, None, None)
+ request_events = self._registerEventListener(INewRequest)
+ beforetraversal_events = self._registerEventListener(IBeforeTraversal)
+ context_found_events = self._registerEventListener(IContextFound)
+ response_events = self._registerEventListener(INewResponse)
+ router = self._makeOne()
+ start_response = DummyStartResponse()
+ result = router(environ, start_response)
+ self.assertEqual(len(request_events), 1)
+ self.assertEqual(request_events[0].request.environ, environ)
+ self.assertEqual(len(beforetraversal_events), 1)
+ self.assertEqual(beforetraversal_events[0].request.environ, environ)
+ self.assertEqual(len(context_found_events), 1)
+ self.assertEqual(context_found_events[0].request.environ, environ)
+ self.assertEqual(context_found_events[0].request.context, context)
+ self.assertEqual(len(response_events), 1)
+ self.assertEqual(response_events[0].response, response)
+ self.assertEqual(response_events[0].request.context, context)
+ self.assertEqual(result, response.app_iter)
+
+ def test_call_newrequest_evllist_exc_can_be_caught_by_exceptionview(self):
+ from pyramid.interfaces import INewRequest
+ from pyramid.interfaces import IExceptionViewClassifier
+ from pyramid.interfaces import IRequest
+
+ context = DummyContext()
+ self._registerTraverserFactory(context)
+ environ = self._makeEnviron()
+
+ def listener(event):
+ raise KeyError
+
+ self.registry.registerHandler(listener, (INewRequest,))
+ exception_response = DummyResponse()
+ exception_response.app_iter = ["Hello, world"]
+ exception_view = DummyView(exception_response)
+ environ = self._makeEnviron()
+ self._registerView(
+ exception_view, '', IExceptionViewClassifier, IRequest, KeyError
+ )
+ router = self._makeOne()
+ start_response = DummyStartResponse()
+ result = router(environ, start_response)
+ self.assertEqual(result, exception_response.app_iter)
+
+ def test_call_route_matches_and_has_factory(self):
+ from pyramid.interfaces import IViewClassifier
+
+ logger = self._registerLogger()
+ self._registerSettings(debug_routematch=True)
+ self._registerRouteRequest('foo')
+ root = object()
+
+ def factory(request):
+ return root
+
+ route = self._connectRoute('foo', 'archives/:action/:article', factory)
+ route.predicates = [DummyPredicate()]
+ context = DummyContext()
+ self._registerTraverserFactory(context)
+ response = DummyResponse()
+ response.app_iter = ['Hello world']
+ view = DummyView(response)
+ environ = self._makeEnviron(PATH_INFO='/archives/action1/article1')
+ self._registerView(view, '', IViewClassifier, None, None)
+ self._registerRootFactory(context)
+ router = self._makeOne()
+ start_response = DummyStartResponse()
+ result = router(environ, start_response)
+ self.assertEqual(result, ['Hello world'])
+ self.assertEqual(start_response.headers, ())
+ self.assertEqual(start_response.status, '200 OK')
+ request = view.request
+ self.assertEqual(request.view_name, '')
+ self.assertEqual(request.subpath, [])
+ self.assertEqual(request.context, context)
+ self.assertEqual(request.root, root)
+ matchdict = {'action': 'action1', 'article': 'article1'}
+ self.assertEqual(request.matchdict, matchdict)
+ self.assertEqual(request.matched_route.name, 'foo')
+ self.assertEqual(len(logger.messages), 1)
+ self.assertTrue(
+ logger.messages[0].startswith(
+ "route matched for url http://localhost:8080"
+ "/archives/action1/article1; "
+ "route_name: 'foo', "
+ "path_info: "
+ )
+ )
+ self.assertTrue("predicates: 'predicate'" in logger.messages[0])
+
+ def test_call_route_match_miss_debug_routematch(self):
+ from pyramid.httpexceptions import HTTPNotFound
+
+ logger = self._registerLogger()
+ self._registerSettings(debug_routematch=True)
+ self._registerRouteRequest('foo')
+ self._connectRoute('foo', 'archives/:action/:article')
+ context = DummyContext()
+ self._registerTraverserFactory(context)
+ environ = self._makeEnviron(PATH_INFO='/wontmatch')
+ self._registerRootFactory(context)
+ router = self._makeOne()
+ start_response = DummyStartResponse()
+ self.assertRaises(HTTPNotFound, router, environ, start_response)
+
+ self.assertEqual(len(logger.messages), 1)
+ self.assertEqual(
+ logger.messages[0],
+ 'no route matched for url http://localhost:8080/wontmatch',
+ )
+
+ def test_call_route_matches_doesnt_overwrite_subscriber_iface(self):
+ from pyramid.interfaces import INewRequest
+ from pyramid.interfaces import IViewClassifier
+ from zope.interface import alsoProvides
+ from zope.interface import Interface
+
+ self._registerRouteRequest('foo')
+
+ class IFoo(Interface):
+ pass
+
+ def listener(event):
+ alsoProvides(event.request, IFoo)
+
+ self.registry.registerHandler(listener, (INewRequest,))
+ root = object()
+
+ def factory(request):
+ return root
+
+ self._connectRoute('foo', 'archives/:action/:article', factory)
+ context = DummyContext()
+ self._registerTraverserFactory(context)
+ response = DummyResponse()
+ response.app_iter = ['Hello world']
+ view = DummyView(response)
+ environ = self._makeEnviron(PATH_INFO='/archives/action1/article1')
+ self._registerView(view, '', IViewClassifier, None, None)
+ self._registerRootFactory(context)
+ router = self._makeOne()
+ start_response = DummyStartResponse()
+ result = router(environ, start_response)
+ self.assertEqual(result, ['Hello world'])
+ self.assertEqual(start_response.headers, ())
+ self.assertEqual(start_response.status, '200 OK')
+ request = view.request
+ self.assertEqual(request.view_name, '')
+ self.assertEqual(request.subpath, [])
+ self.assertEqual(request.context, context)
+ self.assertEqual(request.root, root)
+ matchdict = {'action': 'action1', 'article': 'article1'}
+ self.assertEqual(request.matchdict, matchdict)
+ self.assertEqual(request.matched_route.name, 'foo')
+ self.assertTrue(IFoo.providedBy(request))
+
+ def test_root_factory_raises_notfound(self):
+ from pyramid.interfaces import IRootFactory
+ from pyramid.httpexceptions import HTTPNotFound
+ from zope.interface import Interface
+ from zope.interface import directlyProvides
+
+ def rootfactory(request):
+ raise HTTPNotFound('from root factory')
+
+ self.registry.registerUtility(rootfactory, IRootFactory)
+
+ class IContext(Interface):
+ pass
+
+ context = DummyContext()
+ directlyProvides(context, IContext)
+ environ = self._makeEnviron()
+ router = self._makeOne()
+ start_response = DummyStartResponse()
+ why = exc_raised(HTTPNotFound, router, environ, start_response)
+ self.assertTrue('from root factory' in why.args[0])
+
+ def test_root_factory_raises_forbidden(self):
+ from pyramid.interfaces import IRootFactory
+ from pyramid.httpexceptions import HTTPForbidden
+ from zope.interface import Interface
+ from zope.interface import directlyProvides
+
+ def rootfactory(request):
+ raise HTTPForbidden('from root factory')
+
+ self.registry.registerUtility(rootfactory, IRootFactory)
+
+ class IContext(Interface):
+ pass
+
+ context = DummyContext()
+ directlyProvides(context, IContext)
+ environ = self._makeEnviron()
+ router = self._makeOne()
+ start_response = DummyStartResponse()
+ why = exc_raised(HTTPForbidden, router, environ, start_response)
+ self.assertTrue('from root factory' in why.args[0])
+
+ def test_root_factory_exception_propagating(self):
+ from pyramid.interfaces import IRootFactory
+ from zope.interface import Interface
+ from zope.interface import directlyProvides
+
+ def rootfactory(request):
+ raise RuntimeError()
+
+ self.registry.registerUtility(rootfactory, IRootFactory)
+
+ class IContext(Interface):
+ pass
+
+ context = DummyContext()
+ directlyProvides(context, IContext)
+ environ = self._makeEnviron()
+ router = self._makeOne()
+ start_response = DummyStartResponse()
+ self.assertRaises(RuntimeError, router, environ, start_response)
+
+ def test_traverser_exception_propagating(self):
+ environ = self._makeEnviron()
+ context = DummyContext()
+ self._registerTraverserFactory(context, raise_error=RuntimeError())
+ router = self._makeOne()
+ start_response = DummyStartResponse()
+ self.assertRaises(RuntimeError, router, environ, start_response)
+
+ def test_call_view_exception_propagating(self):
+ from zope.interface import Interface
+ from zope.interface import directlyProvides
+
+ class IContext(Interface):
+ pass
+
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IRequestFactory
+ from pyramid.interfaces import IExceptionViewClassifier
+
+ def rfactory(environ):
+ return request
+
+ self.registry.registerUtility(rfactory, IRequestFactory)
+ from pyramid.request import Request
+
+ request = Request.blank('/')
+ context = DummyContext()
+ directlyProvides(context, IContext)
+ self._registerTraverserFactory(context, subpath=[''])
+ response = DummyResponse()
+ response.app_iter = ['OK']
+ error = RuntimeError()
+ view = DummyView(response, raise_exception=error)
+ environ = self._makeEnviron()
+
+ def exception_view(context, request):
+ self.assertEqual(request.exc_info[0], RuntimeError)
+ return response
+
+ self._registerView(view, '', IViewClassifier, IRequest, IContext)
+ self._registerView(
+ exception_view,
+ '',
+ IExceptionViewClassifier,
+ IRequest,
+ RuntimeError,
+ )
+ router = self._makeOne()
+ start_response = DummyStartResponse()
+ result = router(environ, start_response)
+ self.assertEqual(result, ['OK'])
+ # exc_info and exception should still be around on the request after
+ # the excview tween has run (see
+ # https://github.com/Pylons/pyramid/issues/1223)
+ self.assertEqual(request.exception, error)
+ self.assertEqual(request.exc_info[:2], (RuntimeError, error))
+
+ def test_call_view_raises_exception_view(self):
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IExceptionViewClassifier
+ from pyramid.interfaces import IRequest
+
+ response = DummyResponse()
+ exception_response = DummyResponse()
+ exception_response.app_iter = ["Hello, world"]
+ view = DummyView(response, raise_exception=RuntimeError)
+
+ def exception_view(context, request):
+ self.assertEqual(request.exception.__class__, RuntimeError)
+ return exception_response
+
+ environ = self._makeEnviron()
+ self._registerView(view, '', IViewClassifier, IRequest, None)
+ self._registerView(
+ exception_view,
+ '',
+ IExceptionViewClassifier,
+ IRequest,
+ RuntimeError,
+ )
+ router = self._makeOne()
+ start_response = DummyStartResponse()
+ result = router(environ, start_response)
+ self.assertEqual(result, ["Hello, world"])
+
+ def test_call_view_raises_super_exception_sub_exception_view(self):
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IExceptionViewClassifier
+ from pyramid.interfaces import IRequest
+
+ class SuperException(Exception):
+ pass
+
+ class SubException(SuperException):
+ pass
+
+ response = DummyResponse()
+ exception_response = DummyResponse()
+ exception_response.app_iter = ["Hello, world"]
+ view = DummyView(response, raise_exception=SuperException)
+ exception_view = DummyView(exception_response)
+ environ = self._makeEnviron()
+ self._registerView(view, '', IViewClassifier, IRequest, None)
+ self._registerView(
+ exception_view,
+ '',
+ IExceptionViewClassifier,
+ IRequest,
+ SubException,
+ )
+ router = self._makeOne()
+ start_response = DummyStartResponse()
+ self.assertRaises(SuperException, router, environ, start_response)
+
+ def test_call_view_raises_sub_exception_super_exception_view(self):
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IExceptionViewClassifier
+ from pyramid.interfaces import IRequest
+
+ class SuperException(Exception):
+ pass
+
+ class SubException(SuperException):
+ pass
+
+ response = DummyResponse()
+ exception_response = DummyResponse()
+ exception_response.app_iter = ["Hello, world"]
+ view = DummyView(response, raise_exception=SubException)
+ exception_view = DummyView(exception_response)
+ environ = self._makeEnviron()
+ self._registerView(view, '', IViewClassifier, IRequest, None)
+ self._registerView(
+ exception_view,
+ '',
+ IExceptionViewClassifier,
+ IRequest,
+ SuperException,
+ )
+ router = self._makeOne()
+ start_response = DummyStartResponse()
+ result = router(environ, start_response)
+ self.assertEqual(result, ["Hello, world"])
+
+ def test_call_view_raises_exception_another_exception_view(self):
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IExceptionViewClassifier
+ from pyramid.interfaces import IRequest
+
+ class MyException(Exception):
+ pass
+
+ class AnotherException(Exception):
+ pass
+
+ response = DummyResponse()
+ exception_response = DummyResponse()
+ exception_response.app_iter = ["Hello, world"]
+ view = DummyView(response, raise_exception=MyException)
+ exception_view = DummyView(exception_response)
+ environ = self._makeEnviron()
+ self._registerView(view, '', IViewClassifier, IRequest, None)
+ self._registerView(
+ exception_view,
+ '',
+ IExceptionViewClassifier,
+ IRequest,
+ AnotherException,
+ )
+ router = self._makeOne()
+ start_response = DummyStartResponse()
+ self.assertRaises(MyException, router, environ, start_response)
+
+ def test_root_factory_raises_exception_view(self):
+ from pyramid.interfaces import IRootFactory
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IExceptionViewClassifier
+
+ def rootfactory(request):
+ raise RuntimeError()
+
+ self.registry.registerUtility(rootfactory, IRootFactory)
+ exception_response = DummyResponse()
+ exception_response.app_iter = ["Hello, world"]
+ exception_view = DummyView(exception_response)
+ self._registerView(
+ exception_view,
+ '',
+ IExceptionViewClassifier,
+ IRequest,
+ RuntimeError,
+ )
+ environ = self._makeEnviron()
+ router = self._makeOne()
+ start_response = DummyStartResponse()
+ app_iter = router(environ, start_response)
+ self.assertEqual(app_iter, ["Hello, world"])
+
+ def test_traverser_raises_exception_view(self):
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IExceptionViewClassifier
+
+ environ = self._makeEnviron()
+ context = DummyContext()
+ self._registerTraverserFactory(context, raise_error=RuntimeError())
+ exception_response = DummyResponse()
+ exception_response.app_iter = ["Hello, world"]
+ exception_view = DummyView(exception_response)
+ self._registerView(
+ exception_view,
+ '',
+ IExceptionViewClassifier,
+ IRequest,
+ RuntimeError,
+ )
+ router = self._makeOne()
+ start_response = DummyStartResponse()
+ result = router(environ, start_response)
+ self.assertEqual(result, ["Hello, world"])
+
+ def test_exception_view_returns_non_iresponse(self):
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IExceptionViewClassifier
+
+ environ = self._makeEnviron()
+ response = DummyResponse()
+ view = DummyView(response, raise_exception=RuntimeError)
+
+ self._registerView(
+ self.config.derive_view(view), '', IViewClassifier, IRequest, None
+ )
+ exception_view = DummyView(None)
+ self._registerView(
+ self.config.derive_view(exception_view),
+ '',
+ IExceptionViewClassifier,
+ IRequest,
+ RuntimeError,
+ )
+ router = self._makeOne()
+ start_response = DummyStartResponse()
+ self.assertRaises(ValueError, router, environ, start_response)
+
+ def test_call_route_raises_route_exception_view(self):
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IExceptionViewClassifier
+
+ req_iface = self._registerRouteRequest('foo')
+ self._connectRoute('foo', 'archives/:action/:article', None)
+ view = DummyView(DummyResponse(), raise_exception=RuntimeError)
+ self._registerView(view, '', IViewClassifier, req_iface, None)
+ response = DummyResponse()
+ response.app_iter = ["Hello, world"]
+ exception_view = DummyView(response)
+ self._registerView(
+ exception_view,
+ '',
+ IExceptionViewClassifier,
+ req_iface,
+ RuntimeError,
+ )
+ environ = self._makeEnviron(PATH_INFO='/archives/action1/article1')
+ start_response = DummyStartResponse()
+ router = self._makeOne()
+ result = router(environ, start_response)
+ self.assertEqual(result, ["Hello, world"])
+
+ def test_call_view_raises_exception_route_view(self):
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IExceptionViewClassifier
+ from pyramid.interfaces import IRequest
+
+ req_iface = self._registerRouteRequest('foo')
+ self._connectRoute('foo', 'archives/:action/:article', None)
+ view = DummyView(DummyResponse(), raise_exception=RuntimeError)
+ self._registerView(view, '', IViewClassifier, IRequest, None)
+ response = DummyResponse()
+ response.app_iter = ["Hello, world"]
+ exception_view = DummyView(response)
+ self._registerView(
+ exception_view,
+ '',
+ IExceptionViewClassifier,
+ req_iface,
+ RuntimeError,
+ )
+ environ = self._makeEnviron()
+ start_response = DummyStartResponse()
+ router = self._makeOne()
+ self.assertRaises(RuntimeError, router, environ, start_response)
+
+ def test_call_route_raises_exception_view(self):
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IExceptionViewClassifier
+ from pyramid.interfaces import IRequest
+
+ req_iface = self._registerRouteRequest('foo')
+ self._connectRoute('foo', 'archives/:action/:article', None)
+ view = DummyView(DummyResponse(), raise_exception=RuntimeError)
+ self._registerView(view, '', IViewClassifier, req_iface, None)
+ response = DummyResponse()
+ response.app_iter = ["Hello, world"]
+ exception_view = DummyView(response)
+ self._registerView(
+ exception_view,
+ '',
+ IExceptionViewClassifier,
+ IRequest,
+ RuntimeError,
+ )
+ environ = self._makeEnviron(PATH_INFO='/archives/action1/article1')
+ start_response = DummyStartResponse()
+ router = self._makeOne()
+ result = router(environ, start_response)
+ self.assertEqual(result, ["Hello, world"])
+
+ def test_call_route_raises_super_exception_sub_exception_view(self):
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IExceptionViewClassifier
+ from pyramid.interfaces import IRequest
+
+ class SuperException(Exception):
+ pass
+
+ class SubException(SuperException):
+ pass
+
+ req_iface = self._registerRouteRequest('foo')
+ self._connectRoute('foo', 'archives/:action/:article', None)
+ view = DummyView(DummyResponse(), raise_exception=SuperException)
+ self._registerView(view, '', IViewClassifier, req_iface, None)
+ response = DummyResponse()
+ response.app_iter = ["Hello, world"]
+ exception_view = DummyView(response)
+ self._registerView(
+ exception_view,
+ '',
+ IExceptionViewClassifier,
+ IRequest,
+ SubException,
+ )
+ environ = self._makeEnviron(PATH_INFO='/archives/action1/article1')
+ start_response = DummyStartResponse()
+ router = self._makeOne()
+ self.assertRaises(SuperException, router, environ, start_response)
+
+ def test_call_route_raises_sub_exception_super_exception_view(self):
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IExceptionViewClassifier
+ from pyramid.interfaces import IRequest
+
+ class SuperException(Exception):
+ pass
+
+ class SubException(SuperException):
+ pass
+
+ req_iface = self._registerRouteRequest('foo')
+ self._connectRoute('foo', 'archives/:action/:article', None)
+ view = DummyView(DummyResponse(), raise_exception=SubException)
+ self._registerView(view, '', IViewClassifier, req_iface, None)
+ response = DummyResponse()
+ response.app_iter = ["Hello, world"]
+ exception_view = DummyView(response)
+ self._registerView(
+ exception_view,
+ '',
+ IExceptionViewClassifier,
+ IRequest,
+ SuperException,
+ )
+ environ = self._makeEnviron(PATH_INFO='/archives/action1/article1')
+ start_response = DummyStartResponse()
+ router = self._makeOne()
+ result = router(environ, start_response)
+ self.assertEqual(result, ["Hello, world"])
+
+ def test_call_route_raises_exception_another_exception_view(self):
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IExceptionViewClassifier
+ from pyramid.interfaces import IRequest
+
+ class MyException(Exception):
+ pass
+
+ class AnotherException(Exception):
+ pass
+
+ req_iface = self._registerRouteRequest('foo')
+ self._connectRoute('foo', 'archives/:action/:article', None)
+ view = DummyView(DummyResponse(), raise_exception=MyException)
+ self._registerView(view, '', IViewClassifier, req_iface, None)
+ response = DummyResponse()
+ response.app_iter = ["Hello, world"]
+ exception_view = DummyView(response)
+ self._registerView(
+ exception_view,
+ '',
+ IExceptionViewClassifier,
+ IRequest,
+ AnotherException,
+ )
+ environ = self._makeEnviron(PATH_INFO='/archives/action1/article1')
+ start_response = DummyStartResponse()
+ router = self._makeOne()
+ self.assertRaises(MyException, router, environ, start_response)
+
+ def test_call_route_raises_exception_view_specializing(self):
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IExceptionViewClassifier
+ from pyramid.interfaces import IRequest
+
+ req_iface = self._registerRouteRequest('foo')
+ self._connectRoute('foo', 'archives/:action/:article', None)
+ view = DummyView(DummyResponse(), raise_exception=RuntimeError)
+ self._registerView(view, '', IViewClassifier, req_iface, None)
+ response = DummyResponse()
+ response.app_iter = ["Hello, world"]
+ exception_view = DummyView(response)
+ self._registerView(
+ exception_view,
+ '',
+ IExceptionViewClassifier,
+ IRequest,
+ RuntimeError,
+ )
+ response_spec = DummyResponse()
+ response_spec.app_iter = ["Hello, special world"]
+ exception_view_spec = DummyView(response_spec)
+ self._registerView(
+ exception_view_spec,
+ '',
+ IExceptionViewClassifier,
+ req_iface,
+ RuntimeError,
+ )
+ environ = self._makeEnviron(PATH_INFO='/archives/action1/article1')
+ start_response = DummyStartResponse()
+ router = self._makeOne()
+ result = router(environ, start_response)
+ self.assertEqual(result, ["Hello, special world"])
+
+ def test_call_route_raises_exception_view_another_route(self):
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IExceptionViewClassifier
+
+ req_iface = self._registerRouteRequest('foo')
+ another_req_iface = self._registerRouteRequest('bar')
+ self._connectRoute('foo', 'archives/:action/:article', None)
+ view = DummyView(DummyResponse(), raise_exception=RuntimeError)
+ self._registerView(view, '', IViewClassifier, req_iface, None)
+ response = DummyResponse()
+ response.app_iter = ["Hello, world"]
+ exception_view = DummyView(response)
+ self._registerView(
+ exception_view,
+ '',
+ IExceptionViewClassifier,
+ another_req_iface,
+ RuntimeError,
+ )
+ environ = self._makeEnviron(PATH_INFO='/archives/action1/article1')
+ start_response = DummyStartResponse()
+ router = self._makeOne()
+ self.assertRaises(RuntimeError, router, environ, start_response)
+
+ def test_call_view_raises_exception_view_route(self):
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IExceptionViewClassifier
+
+ req_iface = self._registerRouteRequest('foo')
+ response = DummyResponse()
+ exception_response = DummyResponse()
+ exception_response.app_iter = ["Hello, world"]
+ view = DummyView(response, raise_exception=RuntimeError)
+ exception_view = DummyView(exception_response)
+ environ = self._makeEnviron()
+ self._registerView(view, '', IViewClassifier, IRequest, None)
+ self._registerView(
+ exception_view,
+ '',
+ IExceptionViewClassifier,
+ req_iface,
+ RuntimeError,
+ )
+ router = self._makeOne()
+ start_response = DummyStartResponse()
+ self.assertRaises(RuntimeError, router, environ, start_response)
+
+ def test_call_view_raises_predicate_mismatch(self):
+ from pyramid.exceptions import PredicateMismatch
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IRequest
+
+ view = DummyView(DummyResponse(), raise_exception=PredicateMismatch)
+ self._registerView(view, '', IViewClassifier, IRequest, None)
+ environ = self._makeEnviron()
+ router = self._makeOne()
+ start_response = DummyStartResponse()
+ self.assertRaises(PredicateMismatch, router, environ, start_response)
+
+ def test_call_view_predicate_mismatch_doesnt_hide_views(self):
+ from pyramid.exceptions import PredicateMismatch
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IRequest, IResponse
+ from pyramid.response import Response
+
+ class BaseContext:
+ pass
+
+ class DummyContext(BaseContext):
+ pass
+
+ context = DummyContext()
+ self._registerTraverserFactory(context)
+ view = DummyView(DummyResponse(), raise_exception=PredicateMismatch)
+ self._registerView(view, '', IViewClassifier, IRequest, DummyContext)
+ good_view = DummyView('abc')
+ self._registerView(
+ self.config.derive_view(good_view),
+ '',
+ IViewClassifier,
+ IRequest,
+ BaseContext,
+ )
+ router = self._makeOne()
+
+ def make_response(s):
+ return Response(s)
+
+ router.registry.registerAdapter(make_response, (str,), IResponse)
+ environ = self._makeEnviron()
+ start_response = DummyStartResponse()
+ app_iter = router(environ, start_response)
+ self.assertEqual(app_iter, [b'abc'])
+
+ def test_call_view_multiple_predicate_mismatches_dont_hide_views(self):
+ from pyramid.exceptions import PredicateMismatch
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IRequest, IResponse
+ from pyramid.response import Response
+ from zope.interface import Interface, implementer
+
+ class IBaseContext(Interface):
+ pass
+
+ class IContext(IBaseContext):
+ pass
+
+ @implementer(IContext)
+ class DummyContext:
+ pass
+
+ context = DummyContext()
+ self._registerTraverserFactory(context)
+ view1 = DummyView(DummyResponse(), raise_exception=PredicateMismatch)
+ self._registerView(view1, '', IViewClassifier, IRequest, DummyContext)
+ view2 = DummyView(DummyResponse(), raise_exception=PredicateMismatch)
+ self._registerView(view2, '', IViewClassifier, IRequest, IContext)
+ good_view = DummyView('abc')
+ self._registerView(
+ self.config.derive_view(good_view),
+ '',
+ IViewClassifier,
+ IRequest,
+ IBaseContext,
+ )
+ router = self._makeOne()
+
+ def make_response(s):
+ return Response(s)
+
+ router.registry.registerAdapter(make_response, (str,), IResponse)
+ environ = self._makeEnviron()
+ start_response = DummyStartResponse()
+ app_iter = router(environ, start_response)
+ self.assertEqual(app_iter, [b'abc'])
+
+ def test_call_view_predicate_mismatch_doesnt_find_unrelated_views(self):
+ from pyramid.exceptions import PredicateMismatch
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IRequest
+ from zope.interface import Interface, implementer
+
+ class IContext(Interface):
+ pass
+
+ class IOtherContext(Interface):
+ pass
+
+ @implementer(IContext)
+ class DummyContext:
+ pass
+
+ context = DummyContext()
+ self._registerTraverserFactory(context)
+ view = DummyView(DummyResponse(), raise_exception=PredicateMismatch)
+ self._registerView(view, '', IViewClassifier, IRequest, DummyContext)
+ please_dont_call_me_view = DummyView('abc')
+ self._registerView(
+ self.config.derive_view(please_dont_call_me_view),
+ '',
+ IViewClassifier,
+ IRequest,
+ IOtherContext,
+ )
+ router = self._makeOne()
+ environ = self._makeEnviron()
+ router = self._makeOne()
+ start_response = DummyStartResponse()
+ self.assertRaises(PredicateMismatch, router, environ, start_response)
+
+ def test_custom_execution_policy(self):
+ from pyramid.interfaces import IExecutionPolicy
+ from pyramid.request import Request
+ from pyramid.response import Response
+
+ registry = self.config.registry
+
+ def dummy_policy(environ, router):
+ return Response(status=200, body=b'foo')
+
+ registry.registerUtility(dummy_policy, IExecutionPolicy)
+ router = self._makeOne()
+ resp = Request.blank('/').get_response(router)
+ self.assertEqual(resp.status_code, 200)
+ self.assertEqual(resp.body, b'foo')
+
+ def test_execution_policy_handles_exception(self):
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IExceptionViewClassifier
+ from pyramid.interfaces import IRequest
+
+ class Exception1(Exception):
+ pass
+
+ class Exception2(Exception):
+ pass
+
+ req_iface = self._registerRouteRequest('foo')
+ self._connectRoute('foo', 'archives/:action/:article', None)
+ view = DummyView(DummyResponse(), raise_exception=Exception1)
+ self._registerView(view, '', IViewClassifier, req_iface, None)
+ exception_view1 = DummyView(
+ DummyResponse(), raise_exception=Exception2
+ )
+ self._registerView(
+ exception_view1, '', IExceptionViewClassifier, IRequest, Exception1
+ )
+ response = DummyResponse()
+ response.app_iter = ["Hello, world"]
+ exception_view2 = DummyView(response)
+ self._registerView(
+ exception_view2, '', IExceptionViewClassifier, IRequest, Exception2
+ )
+ environ = self._makeEnviron(PATH_INFO='/archives/action1/article1')
+ start_response = DummyStartResponse()
+ router = self._makeOne()
+ result = router(environ, start_response)
+ self.assertEqual(result, ["Hello, world"])
+
+ def test_request_context_with_statement(self):
+ from pyramid.threadlocal import get_current_request
+ from pyramid.interfaces import IExecutionPolicy
+ from pyramid.request import Request
+ from pyramid.response import Response
+
+ registry = self.config.registry
+ result = []
+
+ def dummy_policy(environ, router):
+ with router.request_context(environ):
+ result.append(get_current_request())
+ result.append(get_current_request())
+ return Response(status=200, body=b'foo')
+
+ registry.registerUtility(dummy_policy, IExecutionPolicy)
+ router = self._makeOne()
+ resp = Request.blank('/test_path').get_response(router)
+ self.assertEqual(resp.status_code, 200)
+ self.assertEqual(resp.body, b'foo')
+ self.assertEqual(result[0].path_info, '/test_path')
+ self.assertEqual(result[1], None)
+
+ def test_request_context_manually(self):
+ from pyramid.threadlocal import get_current_request
+ from pyramid.interfaces import IExecutionPolicy
+ from pyramid.request import Request
+ from pyramid.response import Response
+
+ registry = self.config.registry
+ result = []
+
+ def dummy_policy(environ, router):
+ ctx = router.request_context(environ)
+ ctx.begin()
+ result.append(get_current_request())
+ ctx.end()
+ result.append(get_current_request())
+ return Response(status=200, body=b'foo')
+
+ registry.registerUtility(dummy_policy, IExecutionPolicy)
+ router = self._makeOne()
+ resp = Request.blank('/test_path').get_response(router)
+ self.assertEqual(resp.status_code, 200)
+ self.assertEqual(resp.body, b'foo')
+ self.assertEqual(result[0].path_info, '/test_path')
+ self.assertEqual(result[1], None)
+
+
+class DummyPredicate(object):
+ def __call__(self, info, request):
+ return True
+
+ def text(self):
+ return 'predicate'
+
+
+class DummyContext:
+ pass
+
+
+class DummyView:
+ def __init__(self, response, raise_exception=None):
+ self.response = response
+ self.raise_exception = raise_exception
+
+ def __call__(self, context, request):
+ self.context = context
+ self.request = request
+ if self.raise_exception is not None:
+ raise self.raise_exception
+ return self.response
+
+
+class DummyRootFactory:
+ def __init__(self, root):
+ self.root = root
+
+ def __call__(self, environ):
+ return self.root
+
+
+class DummyStartResponse:
+ status = ()
+ headers = ()
+
+ def __call__(self, status, headers):
+ self.status = status
+ self.headers = headers
+
+
+@implementer(IResponse)
+class DummyResponse(object):
+ headerlist = ()
+ app_iter = ()
+ environ = None
+
+ def __init__(self, status='200 OK'):
+ self.status = status
+
+ def __call__(self, environ, start_response):
+ self.environ = environ
+ start_response(self.status, self.headerlist)
+ return self.app_iter
+
+
+class DummyAuthenticationPolicy:
+ pass
+
+
+class DummyLogger:
+ def __init__(self):
+ self.messages = []
+
+ def info(self, msg):
+ self.messages.append(msg)
+
+ warn = info
+ debug = info
+
+
+def exc_raised(exc, func, *arg, **kw):
+ try:
+ func(*arg, **kw)
+ except exc as e:
+ return e
+ else:
+ raise AssertionError('%s not raised' % exc) # pragma: no cover
diff --git a/tests/test_scripting.py b/tests/test_scripting.py
new file mode 100644
index 000000000..8f74f35f8
--- /dev/null
+++ b/tests/test_scripting.py
@@ -0,0 +1,242 @@
+import unittest
+
+
+class Test_get_root(unittest.TestCase):
+ def _callFUT(self, app, request=None):
+ from pyramid.scripting import get_root
+
+ return get_root(app, request)
+
+ def _makeRegistry(self):
+ return DummyRegistry([DummyFactory])
+
+ def setUp(self):
+ from pyramid.threadlocal import manager
+
+ self.manager = manager
+ self.default = manager.get()
+
+ def test_it_norequest(self):
+ registry = self._makeRegistry()
+ app = DummyApp(registry=registry)
+ root, closer = self._callFUT(app)
+ self.assertEqual(dummy_root, root)
+ pushed = self.manager.get()
+ self.assertEqual(pushed['registry'], registry)
+ self.assertEqual(pushed['request'].registry, registry)
+ self.assertEqual(pushed['request'].environ['path'], '/')
+ closer()
+ self.assertEqual(self.default, self.manager.get())
+
+ def test_it_withrequest(self):
+ registry = self._makeRegistry()
+ app = DummyApp(registry=registry)
+ request = DummyRequest({})
+ root, closer = self._callFUT(app, request)
+ self.assertEqual(dummy_root, root)
+ pushed = self.manager.get()
+ self.assertEqual(pushed['registry'], registry)
+ self.assertEqual(pushed['request'], request)
+ self.assertEqual(pushed['request'].registry, registry)
+ closer()
+ self.assertEqual(self.default, self.manager.get())
+
+
+class Test_prepare(unittest.TestCase):
+ def _callFUT(self, request=None, registry=None):
+ from pyramid.scripting import prepare
+
+ return prepare(request, registry)
+
+ def _makeRegistry(self, L=None):
+ if L is None:
+ L = [None, DummyFactory]
+ return DummyRegistry(L)
+
+ def setUp(self):
+ from pyramid.threadlocal import manager
+
+ self.manager = manager
+ self.default = manager.get()
+
+ def test_it_no_valid_apps(self):
+ from pyramid.exceptions import ConfigurationError
+
+ self.assertRaises(ConfigurationError, self._callFUT)
+
+ def test_it_norequest(self):
+ registry = self._makeRegistry([DummyFactory, None, DummyFactory])
+ info = self._callFUT(registry=registry)
+ root, closer, request = info['root'], info['closer'], info['request']
+ pushed = self.manager.get()
+ self.assertEqual(pushed['registry'], registry)
+ self.assertEqual(pushed['request'].registry, registry)
+ self.assertEqual(root.a, (pushed['request'],))
+ closer()
+ self.assertEqual(self.default, self.manager.get())
+ self.assertEqual(request.context, root)
+
+ def test_it_withrequest_hasregistry(self):
+ request = DummyRequest({})
+ registry = request.registry = self._makeRegistry()
+ info = self._callFUT(request=request)
+ root, closer, request = info['root'], info['closer'], info['request']
+ pushed = self.manager.get()
+ self.assertEqual(pushed['request'], request)
+ self.assertEqual(pushed['registry'], registry)
+ self.assertEqual(pushed['request'].registry, registry)
+ self.assertEqual(root.a, (request,))
+ closer()
+ self.assertEqual(self.default, self.manager.get())
+ self.assertEqual(request.context, root)
+ self.assertEqual(request.registry, registry)
+
+ def test_it_withrequest_noregistry(self):
+ request = DummyRequest({})
+ registry = self._makeRegistry()
+ info = self._callFUT(request=request, registry=registry)
+ root, closer, request = info['root'], info['closer'], info['request']
+ closer()
+ self.assertEqual(request.context, root)
+ # should be set by prepare
+ self.assertEqual(request.registry, registry)
+
+ def test_it_with_request_and_registry(self):
+ request = DummyRequest({})
+ registry = request.registry = self._makeRegistry()
+ info = self._callFUT(request=request, registry=registry)
+ root, closer, root = info['root'], info['closer'], info['root']
+ pushed = self.manager.get()
+ self.assertEqual(pushed['request'], request)
+ self.assertEqual(pushed['registry'], registry)
+ self.assertEqual(pushed['request'].registry, registry)
+ self.assertEqual(root.a, (request,))
+ closer()
+ self.assertEqual(self.default, self.manager.get())
+ self.assertEqual(request.context, root)
+
+ def test_it_with_request_context_already_set(self):
+ request = DummyRequest({})
+ context = Dummy()
+ request.context = context
+ registry = request.registry = self._makeRegistry()
+ info = self._callFUT(request=request, registry=registry)
+ closer = info['closer']
+ closer()
+ self.assertEqual(request.context, context)
+
+ def test_it_with_extensions(self):
+ from pyramid.util import InstancePropertyHelper
+
+ exts = DummyExtensions()
+ ext_method = lambda r: 'bar'
+ name, fn = InstancePropertyHelper.make_property(ext_method, 'foo')
+ exts.descriptors[name] = fn
+ request = DummyRequest({})
+ registry = request.registry = self._makeRegistry([exts, DummyFactory])
+ info = self._callFUT(request=request, registry=registry)
+ self.assertEqual(request.foo, 'bar')
+ closer = info['closer']
+ closer()
+
+ def test_it_is_a_context_manager(self):
+ request = DummyRequest({})
+ registry = request.registry = self._makeRegistry()
+ closer_called = [False]
+ with self._callFUT(request=request) as info:
+ root, request = info['root'], info['request']
+ pushed = self.manager.get()
+ self.assertEqual(pushed['request'], request)
+ self.assertEqual(pushed['registry'], registry)
+ self.assertEqual(pushed['request'].registry, registry)
+ self.assertEqual(root.a, (request,))
+ orig_closer = info['closer']
+
+ def closer():
+ orig_closer()
+ closer_called[0] = True
+
+ info['closer'] = closer
+ self.assertTrue(closer_called[0])
+ self.assertEqual(self.default, self.manager.get())
+ self.assertEqual(request.context, root)
+ self.assertEqual(request.registry, registry)
+
+
+class Test__make_request(unittest.TestCase):
+ def _callFUT(self, path='/', registry=None):
+ from pyramid.scripting import _make_request
+
+ return _make_request(path, registry)
+
+ def _makeRegistry(self):
+ return DummyRegistry([DummyFactory])
+
+ def test_it_with_registry(self):
+ registry = self._makeRegistry()
+ request = self._callFUT('/', registry)
+ self.assertEqual(request.environ['path'], '/')
+ self.assertEqual(request.registry, registry)
+
+ def test_it_with_no_registry(self):
+ from pyramid.config import global_registries
+
+ registry = self._makeRegistry()
+ global_registries.add(registry)
+ try:
+ request = self._callFUT('/hello')
+ self.assertEqual(request.environ['path'], '/hello')
+ self.assertEqual(request.registry, registry)
+ finally:
+ global_registries.empty()
+
+
+class Dummy:
+ pass
+
+
+dummy_root = Dummy()
+
+
+class DummyFactory(object):
+ @classmethod
+ def blank(cls, path):
+ req = DummyRequest({'path': path})
+ return req
+
+ def __init__(self, *a, **kw):
+ self.a = a
+ self.kw = kw
+
+
+class DummyRegistry(object):
+ def __init__(self, utilities):
+ self.utilities = utilities
+
+ def queryUtility(self, iface, default=None): # pragma: no cover
+ if self.utilities:
+ return self.utilities.pop(0)
+ return default
+
+
+class DummyApp:
+ def __init__(self, registry=None):
+ if registry:
+ self.registry = registry
+
+ def root_factory(self, environ):
+ return dummy_root
+
+
+class DummyRequest(object):
+ matchdict = None
+ matched_route = None
+
+ def __init__(self, environ):
+ self.environ = environ
+
+
+class DummyExtensions:
+ def __init__(self):
+ self.descriptors = {}
+ self.methods = {}
diff --git a/tests/test_scripts/__init__.py b/tests/test_scripts/__init__.py
new file mode 100644
index 000000000..5bb534f79
--- /dev/null
+++ b/tests/test_scripts/__init__.py
@@ -0,0 +1 @@
+# package
diff --git a/tests/test_scripts/dummy.py b/tests/test_scripts/dummy.py
new file mode 100644
index 000000000..8e340f645
--- /dev/null
+++ b/tests/test_scripts/dummy.py
@@ -0,0 +1,220 @@
+from zope.interface import implementer
+from pyramid.interfaces import IMultiView
+
+
+class DummyTweens(object):
+ def __init__(self, implicit, explicit):
+ self._implicit = implicit
+ self.explicit = explicit
+ self.name_to_alias = {}
+
+ def implicit(self):
+ return self._implicit
+
+
+class Dummy:
+ pass
+
+
+dummy_root = Dummy()
+
+
+class DummyRegistry(object):
+ settings = {}
+
+ def queryUtility(self, iface, default=None, name=''):
+ return default
+
+
+dummy_registry = DummyRegistry()
+
+
+class DummyShell(object):
+ env = {}
+ help = ''
+ called = False
+ dummy_attr = 1
+
+ def __call__(self, env, help):
+ self.env = env
+ self.help = help
+ self.called = True
+ self.env['request'].dummy_attr = self.dummy_attr
+
+
+class DummyInteractor:
+ def __call__(self, banner, local):
+ self.banner = banner
+ self.local = local
+
+
+class DummyApp:
+ def __init__(self):
+ self.registry = dummy_registry
+
+
+class DummyMapper(object):
+ def __init__(self, *routes):
+ self.routes = routes
+
+ def get_routes(self, include_static=False):
+ return self.routes
+
+
+class DummyRoute(object):
+ def __init__(
+ self, name, pattern, factory=None, matchdict=None, predicate=None
+ ):
+ self.name = name
+ self.path = pattern
+ self.pattern = pattern
+ self.factory = factory
+ self.matchdict = matchdict
+ self.predicates = []
+ if predicate is not None:
+ self.predicates = [predicate]
+
+ def match(self, route):
+ return self.matchdict
+
+
+class DummyRequest:
+ application_url = 'http://example.com:5432'
+ script_name = ''
+
+ def __init__(self, environ):
+ self.environ = environ
+ self.matchdict = {}
+
+
+class DummyView(object):
+ def __init__(self, **attrs):
+ self.__request_attrs__ = attrs
+
+ def view(context, request): # pragma: no cover
+ pass
+
+
+@implementer(IMultiView)
+class DummyMultiView(object):
+ def __init__(self, *views, **attrs):
+ self.views = [(None, view, None) for view in views]
+ self.__request_attrs__ = attrs
+
+
+class DummyCloser(object):
+ def __call__(self):
+ self.called = True
+
+
+class DummyBootstrap(object):
+ def __init__(
+ self,
+ app=None,
+ registry=None,
+ request=None,
+ root=None,
+ root_factory=None,
+ closer=None,
+ ):
+ self.app = app or DummyApp()
+ if registry is None:
+ registry = DummyRegistry()
+ self.registry = registry
+ if request is None:
+ request = DummyRequest({})
+ self.request = request
+ if root is None:
+ root = Dummy()
+ self.root = root
+ if root_factory is None:
+ root_factory = Dummy()
+ self.root_factory = root_factory
+ if closer is None:
+ closer = DummyCloser()
+ self.closer = closer
+
+ def __call__(self, *a, **kw):
+ self.a = a
+ self.kw = kw
+ registry = kw.get('registry', self.registry)
+ request = kw.get('request', self.request)
+ request.registry = registry
+ return {
+ 'app': self.app,
+ 'registry': registry,
+ 'request': request,
+ 'root': self.root,
+ 'root_factory': self.root_factory,
+ 'closer': self.closer,
+ }
+
+
+class DummyEntryPoint(object):
+ def __init__(self, name, module):
+ self.name = name
+ self.module = module
+
+ def load(self):
+ return self.module
+
+
+class DummyPkgResources(object):
+ def __init__(self, entry_point_values):
+ self.entry_points = []
+
+ for name, module in entry_point_values.items():
+ self.entry_points.append(DummyEntryPoint(name, module))
+
+ def iter_entry_points(self, name):
+ return self.entry_points
+
+
+class dummy_setup_logging(object):
+ def __call__(self, config_uri, global_conf):
+ self.config_uri = config_uri
+ self.defaults = global_conf
+
+
+class DummyLoader(object):
+ def __init__(
+ self, settings=None, app_settings=None, app=None, server=None
+ ):
+ if not settings:
+ settings = {}
+ if not app_settings:
+ app_settings = {}
+ self.settings = settings
+ self.app_settings = app_settings
+ self.app = app
+ self.server = server
+ self.calls = []
+
+ def __call__(self, uri):
+ import plaster
+
+ self.uri = plaster.parse_uri(uri)
+ return self
+
+ def add_call(self, op, name, defaults):
+ self.calls.append({'op': op, 'name': name, 'defaults': defaults})
+
+ def get_settings(self, name=None, defaults=None):
+ self.add_call('settings', name, defaults)
+ return self.settings.get(name, {})
+
+ def get_wsgi_app(self, name=None, defaults=None):
+ self.add_call('app', name, defaults)
+ return self.app
+
+ def get_wsgi_app_settings(self, name=None, defaults=None):
+ self.add_call('app_settings', name, defaults)
+ return self.app_settings
+
+ def get_wsgi_server(self, name=None, defaults=None):
+ self.add_call('server', name, defaults)
+ return self.server
+
+ def setup_logging(self, defaults):
+ self.add_call('logging', None, defaults)
+ self.defaults = defaults
diff --git a/tests/test_scripts/pystartup.txt b/tests/test_scripts/pystartup.txt
new file mode 100644
index 000000000..c62c4ca74
--- /dev/null
+++ b/tests/test_scripts/pystartup.txt
@@ -0,0 +1,3 @@
+# this file has a .txt extension to avoid coverage reports
+# since it is not imported but rather the contents are read and exec'd
+foo = 1
diff --git a/tests/test_scripts/test_common.py b/tests/test_scripts/test_common.py
new file mode 100644
index 000000000..e286d3c3e
--- /dev/null
+++ b/tests/test_scripts/test_common.py
@@ -0,0 +1,16 @@
+import unittest
+
+
+class TestParseVars(unittest.TestCase):
+ def test_parse_vars_good(self):
+ from pyramid.scripts.common import parse_vars
+
+ vars = ['a=1', 'b=2']
+ result = parse_vars(vars)
+ self.assertEqual(result, {'a': '1', 'b': '2'})
+
+ def test_parse_vars_bad(self):
+ from pyramid.scripts.common import parse_vars
+
+ vars = ['a']
+ self.assertRaises(ValueError, parse_vars, vars)
diff --git a/tests/test_scripts/test_pdistreport.py b/tests/test_scripts/test_pdistreport.py
new file mode 100644
index 000000000..031a6ff2b
--- /dev/null
+++ b/tests/test_scripts/test_pdistreport.py
@@ -0,0 +1,84 @@
+import unittest
+
+
+class TestPDistReportCommand(unittest.TestCase):
+ def _callFUT(self, **kw):
+ argv = []
+ from pyramid.scripts.pdistreport import main
+
+ return main(argv, **kw)
+
+ def test_no_dists(self):
+ def platform():
+ return 'myplatform'
+
+ pkg_resources = DummyPkgResources()
+ L = []
+
+ def out(*args):
+ L.extend(args)
+
+ result = self._callFUT(
+ pkg_resources=pkg_resources, platform=platform, out=out
+ )
+ self.assertEqual(result, None)
+ self.assertEqual(
+ L,
+ ['Pyramid version:', '1', 'Platform:', 'myplatform', 'Packages:'],
+ )
+
+ def test_with_dists(self):
+ def platform():
+ return 'myplatform'
+
+ working_set = (DummyDistribution('abc'), DummyDistribution('def'))
+ pkg_resources = DummyPkgResources(working_set)
+ L = []
+
+ def out(*args):
+ L.extend(args)
+
+ result = self._callFUT(
+ pkg_resources=pkg_resources, platform=platform, out=out
+ )
+ self.assertEqual(result, None)
+ self.assertEqual(
+ L,
+ [
+ 'Pyramid version:',
+ '1',
+ 'Platform:',
+ 'myplatform',
+ 'Packages:',
+ ' ',
+ 'abc',
+ '1',
+ ' ',
+ '/projects/abc',
+ ' ',
+ 'def',
+ '1',
+ ' ',
+ '/projects/def',
+ ],
+ )
+
+
+class DummyPkgResources(object):
+ def __init__(self, working_set=()):
+ self.working_set = working_set
+
+ def get_distribution(self, name):
+ return Version('1')
+
+
+class Version(object):
+ def __init__(self, version):
+ self.version = version
+
+
+class DummyDistribution(object):
+ def __init__(self, name):
+ self.project_name = name
+ self.version = '1'
+ self.location = '/projects/%s' % name
diff --git a/tests/test_scripts/test_prequest.py b/tests/test_scripts/test_prequest.py
new file mode 100644
index 000000000..1521172bc
--- /dev/null
+++ b/tests/test_scripts/test_prequest.py
@@ -0,0 +1,258 @@
+import unittest
+from . import dummy
+
+
+class TestPRequestCommand(unittest.TestCase):
+ def _getTargetClass(self):
+ from pyramid.scripts.prequest import PRequestCommand
+
+ return PRequestCommand
+
+ def _makeOne(self, argv, headers=None):
+ cmd = self._getTargetClass()(argv)
+
+ def helloworld(environ, start_request):
+ self._environ = environ
+ self._path_info = environ['PATH_INFO']
+ start_request('200 OK', headers or [])
+ return [b'abc']
+
+ self.loader = dummy.DummyLoader(app=helloworld)
+ self._out = []
+ cmd._get_config_loader = self.loader
+ cmd.out = self.out
+ return cmd
+
+ def out(self, msg):
+ self._out.append(msg)
+
+ def test_command_not_enough_args(self):
+ command = self._makeOne([])
+ command.run()
+ self.assertEqual(
+ self._out, ['You must provide at least two arguments']
+ )
+
+ def test_command_two_args(self):
+ command = self._makeOne(
+ ['', 'development.ini', '/'],
+ [('Content-Type', 'text/html; charset=UTF-8')],
+ )
+ command.run()
+ self.assertEqual(self._path_info, '/')
+ self.assertEqual(self.loader.uri.path, 'development.ini')
+ self.assertEqual(self.loader.calls[0]['op'], 'logging')
+ self.assertEqual(self.loader.calls[1]['op'], 'app')
+ self.assertEqual(self.loader.calls[1]['name'], None)
+ self.assertEqual(self._out, ['abc'])
+
+ def test_command_path_doesnt_start_with_slash(self):
+ command = self._makeOne(
+ ['', 'development.ini', 'abc'],
+ [('Content-Type', 'text/html; charset=UTF-8')],
+ )
+ command.run()
+ self.assertEqual(self._path_info, '/abc')
+ self.assertEqual(self.loader.uri.path, 'development.ini')
+ self.assertEqual(self._out, ['abc'])
+
+ def test_command_has_bad_config_header(self):
+ command = self._makeOne(['', '--header=name', 'development.ini', '/'])
+ command.run()
+ self.assertEqual(
+ self._out[0],
+ (
+ "Bad --header=name option, value must be in the form "
+ "'name:value'"
+ ),
+ )
+
+ def test_command_has_good_header_var(self):
+ command = self._makeOne(
+ ['', '--header=name:value', 'development.ini', '/'],
+ [('Content-Type', 'text/html; charset=UTF-8')],
+ )
+ command.run()
+ self.assertEqual(self._environ['HTTP_NAME'], 'value')
+ self.assertEqual(self._path_info, '/')
+ self.assertEqual(self._out, ['abc'])
+
+ def test_command_w_basic_auth(self):
+ command = self._makeOne(
+ [
+ '',
+ '--login=user:password',
+ '--header=name:value',
+ 'development.ini',
+ '/',
+ ],
+ [('Content-Type', 'text/html; charset=UTF-8')],
+ )
+ command.run()
+ self.assertEqual(self._environ['HTTP_NAME'], 'value')
+ self.assertEqual(
+ self._environ['HTTP_AUTHORIZATION'], 'Basic dXNlcjpwYXNzd29yZA=='
+ )
+ self.assertEqual(self._path_info, '/')
+ self.assertEqual(self._out, ['abc'])
+
+ def test_command_has_content_type_header_var(self):
+ command = self._makeOne(
+ ['', '--header=content-type:app/foo', 'development.ini', '/'],
+ [('Content-Type', 'text/html; charset=UTF-8')],
+ )
+ command.run()
+ self.assertEqual(self._environ['CONTENT_TYPE'], 'app/foo')
+ self.assertEqual(self._path_info, '/')
+ self.assertEqual(self._out, ['abc'])
+
+ def test_command_has_multiple_header_vars(self):
+ command = self._makeOne(
+ [
+ '',
+ '--header=name:value',
+ '--header=name2:value2',
+ 'development.ini',
+ '/',
+ ],
+ [('Content-Type', 'text/html; charset=UTF-8')],
+ )
+ command.run()
+ self.assertEqual(self._environ['HTTP_NAME'], 'value')
+ self.assertEqual(self._environ['HTTP_NAME2'], 'value2')
+ self.assertEqual(self._path_info, '/')
+ self.assertEqual(self._out, ['abc'])
+
+ def test_command_method_get(self):
+ command = self._makeOne(
+ ['', '--method=GET', 'development.ini', '/'],
+ [('Content-Type', 'text/html; charset=UTF-8')],
+ )
+ command.run()
+ self.assertEqual(self._environ['REQUEST_METHOD'], 'GET')
+ self.assertEqual(self._path_info, '/')
+ self.assertEqual(self._out, ['abc'])
+
+ def test_command_method_post(self):
+ from pyramid.compat import NativeIO
+
+ command = self._makeOne(
+ ['', '--method=POST', 'development.ini', '/'],
+ [('Content-Type', 'text/html; charset=UTF-8')],
+ )
+ stdin = NativeIO()
+ command.stdin = stdin
+ command.run()
+ self.assertEqual(self._environ['REQUEST_METHOD'], 'POST')
+ self.assertEqual(self._environ['CONTENT_LENGTH'], '-1')
+ self.assertEqual(self._environ['wsgi.input'], stdin)
+ self.assertEqual(self._path_info, '/')
+ self.assertEqual(self._out, ['abc'])
+
+ def test_command_method_put(self):
+ from pyramid.compat import NativeIO
+
+ command = self._makeOne(
+ ['', '--method=PUT', 'development.ini', '/'],
+ [('Content-Type', 'text/html; charset=UTF-8')],
+ )
+ stdin = NativeIO()
+ command.stdin = stdin
+ command.run()
+ self.assertEqual(self._environ['REQUEST_METHOD'], 'PUT')
+ self.assertEqual(self._environ['CONTENT_LENGTH'], '-1')
+ self.assertEqual(self._environ['wsgi.input'], stdin)
+ self.assertEqual(self._path_info, '/')
+ self.assertEqual(self._out, ['abc'])
+
+ def test_command_method_patch(self):
+ from pyramid.compat import NativeIO
+
+ command = self._makeOne(
+ ['', '--method=PATCH', 'development.ini', '/'],
+ [('Content-Type', 'text/html; charset=UTF-8')],
+ )
+ stdin = NativeIO()
+ command.stdin = stdin
+ command.run()
+ self.assertEqual(self._environ['REQUEST_METHOD'], 'PATCH')
+ self.assertEqual(self._environ['CONTENT_LENGTH'], '-1')
+ self.assertEqual(self._environ['wsgi.input'], stdin)
+ self.assertEqual(self._path_info, '/')
+ self.assertEqual(self._out, ['abc'])
+
+ def test_command_method_propfind(self):
+ from pyramid.compat import NativeIO
+
+ command = self._makeOne(
+ ['', '--method=PROPFIND', 'development.ini', '/'],
+ [('Content-Type', 'text/html; charset=UTF-8')],
+ )
+ stdin = NativeIO()
+ command.stdin = stdin
+ command.run()
+ self.assertEqual(self._environ['REQUEST_METHOD'], 'PROPFIND')
+ self.assertEqual(self._path_info, '/')
+ self.assertEqual(self._out, ['abc'])
+
+ def test_command_method_options(self):
+ from pyramid.compat import NativeIO
+
+ command = self._makeOne(
+ ['', '--method=OPTIONS', 'development.ini', '/'],
+ [('Content-Type', 'text/html; charset=UTF-8')],
+ )
+ stdin = NativeIO()
+ command.stdin = stdin
+ command.run()
+ self.assertEqual(self._environ['REQUEST_METHOD'], 'OPTIONS')
+ self.assertEqual(self._path_info, '/')
+ self.assertEqual(self._out, ['abc'])
+
+ def test_command_with_query_string(self):
+ command = self._makeOne(
+ ['', 'development.ini', '/abc?a=1&b=2&c'],
+ [('Content-Type', 'text/html; charset=UTF-8')],
+ )
+ command.run()
+ self.assertEqual(self._environ['QUERY_STRING'], 'a=1&b=2&c')
+ self.assertEqual(self._path_info, '/abc')
+ self.assertEqual(self._out, ['abc'])
+
+ def test_command_display_headers(self):
+ command = self._makeOne(
+ ['', '--display-headers', 'development.ini', '/'],
+ [('Content-Type', 'text/html; charset=UTF-8')],
+ )
+ command.run()
+ self.assertEqual(self._path_info, '/')
+ self.assertEqual(
+ self._out,
+ ['200 OK', 'Content-Type: text/html; charset=UTF-8', 'abc'],
+ )
+
+ def test_command_response_has_no_charset(self):
+ command = self._makeOne(
+ ['', '--method=GET', 'development.ini', '/'],
+ headers=[('Content-Type', 'image/jpeg')],
+ )
+ command.run()
+ self.assertEqual(self._path_info, '/')
+
+ self.assertEqual(self._out, [b'abc'])
+
+ def test_command_method_configures_logging(self):
+ command = self._makeOne(['', 'development.ini', '/'])
+ command.run()
+ self.assertEqual(self.loader.calls[0]['op'], 'logging')
+
+
+class Test_main(unittest.TestCase):
+ def _callFUT(self, argv):
+ from pyramid.scripts.prequest import main
+
+ return main(argv, True)
+
+ def test_it(self):
+ result = self._callFUT(['prequest'])
+ self.assertEqual(result, 2)
diff --git a/tests/test_scripts/test_proutes.py b/tests/test_scripts/test_proutes.py
new file mode 100644
index 000000000..5e3f359f6
--- /dev/null
+++ b/tests/test_scripts/test_proutes.py
@@ -0,0 +1,823 @@
+import os
+import unittest
+from . import dummy
+
+
+class DummyIntrospector(object):
+ def __init__(self):
+ self.relations = {}
+ self.introspectables = {}
+
+ def get(self, name, discrim):
+ pass
+
+
+class TestPRoutesCommand(unittest.TestCase):
+ def _getTargetClass(self):
+ from pyramid.scripts.proutes import PRoutesCommand
+
+ return PRoutesCommand
+
+ def _makeOne(self):
+ cmd = self._getTargetClass()([])
+ cmd.bootstrap = dummy.DummyBootstrap()
+ cmd.get_config_loader = dummy.DummyLoader()
+ cmd.args.config_uri = '/foo/bar/myapp.ini#myapp'
+
+ return cmd
+
+ def _makeRegistry(self):
+ from pyramid.registry import Registry
+
+ registry = Registry()
+ registry.introspector = DummyIntrospector()
+ return registry
+
+ def _makeConfig(self, *arg, **kw):
+ from pyramid.config import Configurator
+
+ config = Configurator(*arg, **kw)
+ return config
+
+ def test_good_args(self):
+ cmd = self._getTargetClass()([])
+ cmd.bootstrap = dummy.DummyBootstrap()
+ cmd.get_config_loader = dummy.DummyLoader()
+ cmd.args.config_uri = '/foo/bar/myapp.ini#myapp'
+ cmd.args.config_args = ('a=1',)
+ route = dummy.DummyRoute('a', '/a')
+ mapper = dummy.DummyMapper(route)
+ cmd._get_mapper = lambda *arg: mapper
+ registry = self._makeRegistry()
+ cmd.bootstrap = dummy.DummyBootstrap(registry=registry)
+ L = []
+ cmd.out = lambda msg: L.append(msg)
+ cmd.run()
+ self.assertTrue('<unknown>' in ''.join(L))
+
+ def test_bad_args(self):
+ cmd = self._getTargetClass()([])
+ cmd.bootstrap = dummy.DummyBootstrap()
+ cmd.get_config_loader = dummy.DummyLoader()
+ cmd.args.config_uri = '/foo/bar/myapp.ini#myapp'
+ cmd.args.config_vars = ('a',)
+ route = dummy.DummyRoute('a', '/a')
+ mapper = dummy.DummyMapper(route)
+ cmd._get_mapper = lambda *arg: mapper
+
+ self.assertRaises(ValueError, cmd.run)
+
+ def test_no_routes(self):
+ command = self._makeOne()
+ mapper = dummy.DummyMapper()
+ command._get_mapper = lambda *arg: mapper
+ L = []
+ command.out = L.append
+ result = command.run()
+ self.assertEqual(result, 0)
+ self.assertEqual(L, [])
+
+ def test_no_mapper(self):
+ command = self._makeOne()
+ command._get_mapper = lambda *arg: None
+ L = []
+ command.out = L.append
+ result = command.run()
+ self.assertEqual(result, 0)
+ self.assertEqual(L, [])
+
+ def test_single_route_no_route_registered(self):
+ command = self._makeOne()
+ route = dummy.DummyRoute('a', '/a')
+ mapper = dummy.DummyMapper(route)
+ command._get_mapper = lambda *arg: mapper
+ registry = self._makeRegistry()
+ command.bootstrap = dummy.DummyBootstrap(registry=registry)
+
+ L = []
+ command.out = L.append
+ result = command.run()
+ self.assertEqual(result, 0)
+ self.assertEqual(len(L), 3)
+ self.assertEqual(L[-1].split(), ['a', '/a', '<unknown>', '*'])
+
+ def test_route_with_no_slash_prefix(self):
+ command = self._makeOne()
+ route = dummy.DummyRoute('a', 'a')
+ mapper = dummy.DummyMapper(route)
+ command._get_mapper = lambda *arg: mapper
+ L = []
+ command.out = L.append
+ registry = self._makeRegistry()
+ command.bootstrap = dummy.DummyBootstrap(registry=registry)
+ result = command.run()
+ self.assertEqual(result, 0)
+ self.assertEqual(len(L), 3)
+ self.assertEqual(L[-1].split(), ['a', '/a', '<unknown>', '*'])
+
+ def test_single_route_no_views_registered(self):
+ from zope.interface import Interface
+ from pyramid.interfaces import IRouteRequest
+
+ registry = self._makeRegistry()
+
+ def view(): # pragma: no cover
+ pass
+
+ class IMyRoute(Interface):
+ pass
+
+ registry.registerUtility(IMyRoute, IRouteRequest, name='a')
+ command = self._makeOne()
+ route = dummy.DummyRoute('a', '/a')
+ mapper = dummy.DummyMapper(route)
+ command._get_mapper = lambda *arg: mapper
+ L = []
+ command.out = L.append
+ command.bootstrap = dummy.DummyBootstrap(registry=registry)
+ result = command.run()
+ self.assertEqual(result, 0)
+ self.assertEqual(len(L), 3)
+ self.assertEqual(L[-1].split()[:3], ['a', '/a', '<unknown>'])
+
+ def test_single_route_one_view_registered(self):
+ from zope.interface import Interface
+ from pyramid.interfaces import IRouteRequest
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IView
+
+ registry = self._makeRegistry()
+
+ def view(): # pragma: no cover
+ pass
+
+ class IMyRoute(Interface):
+ pass
+
+ registry.registerAdapter(
+ view, (IViewClassifier, IMyRoute, Interface), IView, ''
+ )
+ registry.registerUtility(IMyRoute, IRouteRequest, name='a')
+ command = self._makeOne()
+ route = dummy.DummyRoute('a', '/a')
+ mapper = dummy.DummyMapper(route)
+ command._get_mapper = lambda *arg: mapper
+ L = []
+ command.out = L.append
+ command.bootstrap = dummy.DummyBootstrap(registry=registry)
+ result = command.run()
+ self.assertEqual(result, 0)
+ self.assertEqual(len(L), 3)
+ compare_to = L[-1].split()[:3]
+ self.assertEqual(
+ compare_to, ['a', '/a', 'tests.test_scripts.test_proutes.view']
+ )
+
+ def test_one_route_with_long_name_one_view_registered(self):
+ from zope.interface import Interface
+ from pyramid.interfaces import IRouteRequest
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IView
+
+ registry = self._makeRegistry()
+
+ def view(): # pragma: no cover
+ pass
+
+ class IMyRoute(Interface):
+ pass
+
+ registry.registerAdapter(
+ view, (IViewClassifier, IMyRoute, Interface), IView, ''
+ )
+
+ registry.registerUtility(
+ IMyRoute, IRouteRequest, name='very_long_name_123'
+ )
+
+ command = self._makeOne()
+ route = dummy.DummyRoute(
+ 'very_long_name_123', '/and_very_long_pattern_as_well'
+ )
+ mapper = dummy.DummyMapper(route)
+ command._get_mapper = lambda *arg: mapper
+ L = []
+ command.out = L.append
+ command.bootstrap = dummy.DummyBootstrap(registry=registry)
+ result = command.run()
+ self.assertEqual(result, 0)
+ self.assertEqual(len(L), 3)
+ compare_to = L[-1].split()[:3]
+ self.assertEqual(
+ compare_to,
+ [
+ 'very_long_name_123',
+ '/and_very_long_pattern_as_well',
+ 'tests.test_scripts.test_proutes.view',
+ ],
+ )
+
+ def test_class_view(self):
+ from pyramid.renderers import null_renderer as nr
+
+ config = self._makeConfig(autocommit=True)
+ config.add_route('foo', '/a/b')
+ config.add_view(
+ route_name='foo',
+ view=dummy.DummyView,
+ attr='view',
+ renderer=nr,
+ request_method='POST',
+ )
+
+ command = self._makeOne()
+ L = []
+ command.out = L.append
+ command.bootstrap = dummy.DummyBootstrap(registry=config.registry)
+ result = command.run()
+ self.assertEqual(result, 0)
+ self.assertEqual(len(L), 3)
+ compare_to = L[-1].split()
+ expected = [
+ 'foo',
+ '/a/b',
+ 'tests.test_scripts.dummy.DummyView.view',
+ 'POST',
+ ]
+ self.assertEqual(compare_to, expected)
+
+ def test_single_route_one_view_registered_with_factory(self):
+ from zope.interface import Interface
+ from pyramid.interfaces import IRouteRequest
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IView
+
+ registry = self._makeRegistry()
+
+ def view(): # pragma: no cover
+ pass
+
+ class IMyRoot(Interface):
+ pass
+
+ class IMyRoute(Interface):
+ pass
+
+ registry.registerAdapter(
+ view, (IViewClassifier, IMyRoute, IMyRoot), IView, ''
+ )
+ registry.registerUtility(IMyRoute, IRouteRequest, name='a')
+ command = self._makeOne()
+
+ def factory(request): # pragma: no cover
+ pass
+
+ route = dummy.DummyRoute('a', '/a', factory=factory)
+ mapper = dummy.DummyMapper(route)
+ command._get_mapper = lambda *arg: mapper
+ L = []
+ command.out = L.append
+ command.bootstrap = dummy.DummyBootstrap(registry=registry)
+ result = command.run()
+ self.assertEqual(result, 0)
+ self.assertEqual(len(L), 3)
+ self.assertEqual(L[-1].split()[:3], ['a', '/a', '<unknown>'])
+
+ def test_single_route_multiview_registered(self):
+ from zope.interface import Interface
+ from pyramid.interfaces import IRouteRequest
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IMultiView
+
+ registry = self._makeRegistry()
+
+ def view(): # pragma: no cover
+ pass
+
+ class IMyRoute(Interface):
+ pass
+
+ multiview1 = dummy.DummyMultiView(
+ view, context='context', view_name='a1'
+ )
+
+ registry.registerAdapter(
+ multiview1, (IViewClassifier, IMyRoute, Interface), IMultiView, ''
+ )
+ registry.registerUtility(IMyRoute, IRouteRequest, name='a')
+ command = self._makeOne()
+ route = dummy.DummyRoute('a', '/a')
+ mapper = dummy.DummyMapper(route)
+ command._get_mapper = lambda *arg: mapper
+ L = []
+ command.out = L.append
+ command.bootstrap = dummy.DummyBootstrap(registry=registry)
+ result = command.run()
+ self.assertEqual(result, 0)
+ self.assertEqual(len(L), 3)
+ compare_to = L[-1].split()[:3]
+ view_module = 'tests.test_scripts.dummy'
+ view_str = '<tests.test_scripts.dummy.DummyMultiView'
+ final = '%s.%s' % (view_module, view_str)
+
+ self.assertEqual(compare_to, ['a', '/a', final])
+
+ def test__get_mapper(self):
+ from pyramid.urldispatch import RoutesMapper
+
+ command = self._makeOne()
+ registry = self._makeRegistry()
+
+ result = command._get_mapper(registry)
+ self.assertEqual(result.__class__, RoutesMapper)
+
+ def test_one_route_all_methods_view_only_post(self):
+ from pyramid.renderers import null_renderer as nr
+
+ def view1(context, request): # pragma: no cover
+ return 'view1'
+
+ config = self._makeConfig(autocommit=True)
+ config.add_route('foo', '/a/b')
+ config.add_view(
+ route_name='foo', view=view1, renderer=nr, request_method='POST'
+ )
+
+ command = self._makeOne()
+ L = []
+ command.out = L.append
+ command.bootstrap = dummy.DummyBootstrap(registry=config.registry)
+ result = command.run()
+ self.assertEqual(result, 0)
+ self.assertEqual(len(L), 3)
+ compare_to = L[-1].split()
+ expected = [
+ 'foo',
+ '/a/b',
+ 'tests.test_scripts.test_proutes.view1',
+ 'POST',
+ ]
+ self.assertEqual(compare_to, expected)
+
+ def test_one_route_only_post_view_all_methods(self):
+ from pyramid.renderers import null_renderer as nr
+
+ def view1(context, request): # pragma: no cover
+ return 'view1'
+
+ config = self._makeConfig(autocommit=True)
+ config.add_route('foo', '/a/b', request_method='POST')
+ config.add_view(route_name='foo', view=view1, renderer=nr)
+
+ command = self._makeOne()
+ L = []
+ command.out = L.append
+ command.bootstrap = dummy.DummyBootstrap(registry=config.registry)
+ result = command.run()
+ self.assertEqual(result, 0)
+ self.assertEqual(len(L), 3)
+ compare_to = L[-1].split()
+ expected = [
+ 'foo',
+ '/a/b',
+ 'tests.test_scripts.test_proutes.view1',
+ 'POST',
+ ]
+ self.assertEqual(compare_to, expected)
+
+ def test_one_route_only_post_view_post_and_get(self):
+ from pyramid.renderers import null_renderer as nr
+
+ def view1(context, request): # pragma: no cover
+ return 'view1'
+
+ config = self._makeConfig(autocommit=True)
+ config.add_route('foo', '/a/b', request_method='POST')
+ config.add_view(
+ route_name='foo',
+ view=view1,
+ renderer=nr,
+ request_method=('POST', 'GET'),
+ )
+
+ command = self._makeOne()
+ L = []
+ command.out = L.append
+ command.bootstrap = dummy.DummyBootstrap(registry=config.registry)
+ result = command.run()
+ self.assertEqual(result, 0)
+ self.assertEqual(len(L), 3)
+ compare_to = L[-1].split()
+ expected = [
+ 'foo',
+ '/a/b',
+ 'tests.test_scripts.test_proutes.view1',
+ 'POST',
+ ]
+ self.assertEqual(compare_to, expected)
+
+ def test_route_request_method_mismatch(self):
+ from pyramid.renderers import null_renderer as nr
+
+ def view1(context, request): # pragma: no cover
+ return 'view1'
+
+ config = self._makeConfig(autocommit=True)
+ config.add_route('foo', '/a/b', request_method='POST')
+ config.add_view(
+ route_name='foo', view=view1, renderer=nr, request_method='GET'
+ )
+
+ command = self._makeOne()
+ L = []
+ command.out = L.append
+ command.bootstrap = dummy.DummyBootstrap(registry=config.registry)
+ result = command.run()
+ self.assertEqual(result, 0)
+ self.assertEqual(len(L), 3)
+ compare_to = L[-1].split()
+ expected = [
+ 'foo',
+ '/a/b',
+ 'tests.test_scripts.test_proutes.view1',
+ '<route',
+ 'mismatch>',
+ ]
+ self.assertEqual(compare_to, expected)
+
+ def test_route_static_views(self):
+ config = self._makeConfig(autocommit=True)
+ config.add_static_view('static', 'static', cache_max_age=3600)
+ path2 = os.path.normpath('/var/www/static')
+ config.add_static_view(name='static2', path=path2)
+ config.add_static_view(
+ name='pyramid_scaffold',
+ path='pyramid:scaffolds/starter/+package+/static',
+ )
+
+ command = self._makeOne()
+ L = []
+ command.out = L.append
+ command.bootstrap = dummy.DummyBootstrap(registry=config.registry)
+ result = command.run()
+ self.assertEqual(result, 0)
+ self.assertEqual(len(L), 5)
+
+ expected = [
+ [
+ '__static/',
+ '/static/*subpath',
+ 'tests.test_scripts:static/',
+ '*',
+ ],
+ ['__static2/', '/static2/*subpath', path2 + os.sep, '*'],
+ [
+ '__pyramid_scaffold/',
+ '/pyramid_scaffold/*subpath',
+ 'pyramid:scaffolds/starter/+package+/static/',
+ '*',
+ ],
+ ]
+
+ for index, line in enumerate(L[2:]):
+ data = line.split()
+ self.assertEqual(data, expected[index])
+
+ def test_route_no_view(self):
+ config = self._makeConfig(autocommit=True)
+ config.add_route('foo', '/a/b', request_method='POST')
+
+ command = self._makeOne()
+ L = []
+ command.out = L.append
+ command.bootstrap = dummy.DummyBootstrap(registry=config.registry)
+ result = command.run()
+ self.assertEqual(result, 0)
+ self.assertEqual(len(L), 3)
+ compare_to = L[-1].split()
+ expected = ['foo', '/a/b', '<unknown>', 'POST']
+ self.assertEqual(compare_to, expected)
+
+ def test_route_as_wsgiapp(self):
+ from pyramid.wsgi import wsgiapp2
+
+ config1 = self._makeConfig(autocommit=True)
+
+ def view1(context, request): # pragma: no cover
+ return 'view1'
+
+ config1.add_route('foo', '/a/b', request_method='POST')
+ config1.add_view(view=view1, route_name='foo')
+
+ config2 = self._makeConfig(autocommit=True)
+ config2.add_route('foo', '/a/b', request_method='POST')
+ config2.add_view(wsgiapp2(config1.make_wsgi_app()), route_name='foo')
+
+ command = self._makeOne()
+ L = []
+ command.out = L.append
+ command.bootstrap = dummy.DummyBootstrap(registry=config2.registry)
+ result = command.run()
+ self.assertEqual(result, 0)
+ self.assertEqual(len(L), 3)
+ compare_to = L[-1].split()
+ expected = ['foo', '/a/b', '<wsgiapp>', 'POST']
+ self.assertEqual(compare_to, expected)
+
+ def test_route_is_get_view_request_method_not_post(self):
+ from pyramid.renderers import null_renderer as nr
+ from pyramid.config import not_
+
+ def view1(context, request): # pragma: no cover
+ return 'view1'
+
+ config = self._makeConfig(autocommit=True)
+ config.add_route('foo', '/a/b', request_method='GET')
+ config.add_view(
+ route_name='foo',
+ view=view1,
+ renderer=nr,
+ request_method=not_('POST'),
+ )
+
+ command = self._makeOne()
+ L = []
+ command.out = L.append
+ command.bootstrap = dummy.DummyBootstrap(registry=config.registry)
+ result = command.run()
+ self.assertEqual(result, 0)
+ self.assertEqual(len(L), 3)
+ compare_to = L[-1].split()
+ expected = [
+ 'foo',
+ '/a/b',
+ 'tests.test_scripts.test_proutes.view1',
+ 'GET',
+ ]
+ self.assertEqual(compare_to, expected)
+
+ def test_view_request_method_not_post(self):
+ from pyramid.renderers import null_renderer as nr
+ from pyramid.config import not_
+
+ def view1(context, request): # pragma: no cover
+ return 'view1'
+
+ config = self._makeConfig(autocommit=True)
+ config.add_route('foo', '/a/b')
+ config.add_view(
+ route_name='foo',
+ view=view1,
+ renderer=nr,
+ request_method=not_('POST'),
+ )
+
+ command = self._makeOne()
+ L = []
+ command.out = L.append
+ command.bootstrap = dummy.DummyBootstrap(registry=config.registry)
+ result = command.run()
+ self.assertEqual(result, 0)
+ self.assertEqual(len(L), 3)
+ compare_to = L[-1].split()
+ expected = [
+ 'foo',
+ '/a/b',
+ 'tests.test_scripts.test_proutes.view1',
+ '!POST,*',
+ ]
+ self.assertEqual(compare_to, expected)
+
+ def test_view_glob(self):
+ from pyramid.renderers import null_renderer as nr
+ from pyramid.config import not_
+
+ def view1(context, request): # pragma: no cover
+ return 'view1'
+
+ def view2(context, request): # pragma: no cover
+ return 'view2'
+
+ config = self._makeConfig(autocommit=True)
+ config.add_route('foo', '/a/b')
+ config.add_view(
+ route_name='foo',
+ view=view1,
+ renderer=nr,
+ request_method=not_('POST'),
+ )
+
+ config.add_route('bar', '/b/a')
+ config.add_view(
+ route_name='bar',
+ view=view2,
+ renderer=nr,
+ request_method=not_('POST'),
+ )
+
+ command = self._makeOne()
+ command.args.glob = '*foo*'
+
+ L = []
+ command.out = L.append
+ command.bootstrap = dummy.DummyBootstrap(registry=config.registry)
+ result = command.run()
+ self.assertEqual(result, 0)
+ self.assertEqual(len(L), 3)
+ compare_to = L[-1].split()
+ expected = [
+ 'foo',
+ '/a/b',
+ 'tests.test_scripts.test_proutes.view1',
+ '!POST,*',
+ ]
+ self.assertEqual(compare_to, expected)
+
+ def test_good_format(self):
+ from pyramid.renderers import null_renderer as nr
+ from pyramid.config import not_
+
+ def view1(context, request): # pragma: no cover
+ return 'view1'
+
+ config = self._makeConfig(autocommit=True)
+ config.add_route('foo', '/a/b')
+ config.add_view(
+ route_name='foo',
+ view=view1,
+ renderer=nr,
+ request_method=not_('POST'),
+ )
+
+ command = self._makeOne()
+ command.args.glob = '*foo*'
+ command.args.format = 'method,name'
+ L = []
+ command.out = L.append
+ command.bootstrap = dummy.DummyBootstrap(registry=config.registry)
+ result = command.run()
+ self.assertEqual(result, 0)
+ self.assertEqual(len(L), 3)
+ compare_to = L[-1].split()
+ expected = ['!POST,*', 'foo']
+
+ self.assertEqual(compare_to, expected)
+ self.assertEqual(L[0].split(), ['Method', 'Name'])
+
+ def test_bad_format(self):
+ from pyramid.renderers import null_renderer as nr
+ from pyramid.config import not_
+
+ def view1(context, request): # pragma: no cover
+ return 'view1'
+
+ config = self._makeConfig(autocommit=True)
+ config.add_route('foo', '/a/b')
+ config.add_view(
+ route_name='foo',
+ view=view1,
+ renderer=nr,
+ request_method=not_('POST'),
+ )
+
+ command = self._makeOne()
+ command.args.glob = '*foo*'
+ command.args.format = 'predicates,name,pattern'
+ L = []
+ command.out = L.append
+ command.bootstrap = dummy.DummyBootstrap(registry=config.registry)
+ expected = (
+ "You provided invalid formats ['predicates'], "
+ "Available formats are ['name', 'pattern', 'view', 'method']"
+ )
+ result = command.run()
+ self.assertEqual(result, 2)
+ self.assertEqual(L[0], expected)
+
+ def test_config_format_ini_newlines(self):
+ from pyramid.renderers import null_renderer as nr
+ from pyramid.config import not_
+
+ def view1(context, request): # pragma: no cover
+ return 'view1'
+
+ config = self._makeConfig(autocommit=True)
+ config.add_route('foo', '/a/b')
+ config.add_view(
+ route_name='foo',
+ view=view1,
+ renderer=nr,
+ request_method=not_('POST'),
+ )
+
+ command = self._makeOne()
+
+ L = []
+ command.out = L.append
+ command.bootstrap = dummy.DummyBootstrap(registry=config.registry)
+ command.get_config_loader = dummy.DummyLoader(
+ {'proutes': {'format': 'method\nname'}}
+ )
+
+ result = command.run()
+ self.assertEqual(result, 0)
+ self.assertEqual(len(L), 3)
+ compare_to = L[-1].split()
+ expected = ['!POST,*', 'foo']
+
+ self.assertEqual(compare_to, expected)
+ self.assertEqual(L[0].split(), ['Method', 'Name'])
+
+ def test_config_format_ini_spaces(self):
+ from pyramid.renderers import null_renderer as nr
+ from pyramid.config import not_
+
+ def view1(context, request): # pragma: no cover
+ return 'view1'
+
+ config = self._makeConfig(autocommit=True)
+ config.add_route('foo', '/a/b')
+ config.add_view(
+ route_name='foo',
+ view=view1,
+ renderer=nr,
+ request_method=not_('POST'),
+ )
+
+ command = self._makeOne()
+
+ L = []
+ command.out = L.append
+ command.bootstrap = dummy.DummyBootstrap(registry=config.registry)
+ command.get_config_loader = dummy.DummyLoader(
+ {'proutes': {'format': 'method name'}}
+ )
+
+ result = command.run()
+ self.assertEqual(result, 0)
+ self.assertEqual(len(L), 3)
+ compare_to = L[-1].split()
+ expected = ['!POST,*', 'foo']
+
+ self.assertEqual(compare_to, expected)
+ self.assertEqual(L[0].split(), ['Method', 'Name'])
+
+ def test_config_format_ini_commas(self):
+ from pyramid.renderers import null_renderer as nr
+ from pyramid.config import not_
+
+ def view1(context, request): # pragma: no cover
+ return 'view1'
+
+ config = self._makeConfig(autocommit=True)
+ config.add_route('foo', '/a/b')
+ config.add_view(
+ route_name='foo',
+ view=view1,
+ renderer=nr,
+ request_method=not_('POST'),
+ )
+
+ command = self._makeOne()
+
+ L = []
+ command.out = L.append
+ command.bootstrap = dummy.DummyBootstrap(registry=config.registry)
+ command.get_config_loader = dummy.DummyLoader(
+ {'proutes': {'format': 'method,name'}}
+ )
+
+ result = command.run()
+ self.assertEqual(result, 0)
+ self.assertEqual(len(L), 3)
+ compare_to = L[-1].split()
+ expected = ['!POST,*', 'foo']
+
+ self.assertEqual(compare_to, expected)
+ self.assertEqual(L[0].split(), ['Method', 'Name'])
+
+ def test_static_routes_included_in_list(self):
+ config = self._makeConfig(autocommit=True)
+ config.add_route('foo', 'http://example.com/bar.aspx', static=True)
+
+ command = self._makeOne()
+ L = []
+ command.out = L.append
+ command.bootstrap = dummy.DummyBootstrap(registry=config.registry)
+ result = command.run()
+ self.assertEqual(result, 0)
+ self.assertEqual(len(L), 3)
+ compare_to = L[-1].split()
+ expected = ['foo', 'http://example.com/bar.aspx', '<unknown>', '*']
+ self.assertEqual(compare_to, expected)
+
+
+class Test_main(unittest.TestCase):
+ def _callFUT(self, argv):
+ from pyramid.scripts.proutes import main
+
+ return main(argv, quiet=True)
+
+ def test_it(self):
+ result = self._callFUT(['proutes'])
+ self.assertEqual(result, 2)
diff --git a/tests/test_scripts/test_pserve.py b/tests/test_scripts/test_pserve.py
new file mode 100644
index 000000000..b85f4ddb7
--- /dev/null
+++ b/tests/test_scripts/test_pserve.py
@@ -0,0 +1,139 @@
+import os
+import unittest
+from . import dummy
+
+
+here = os.path.abspath(os.path.dirname(__file__))
+
+
+class TestPServeCommand(unittest.TestCase):
+ def setUp(self):
+ from pyramid.compat import NativeIO
+
+ self.out_ = NativeIO()
+
+ def out(self, msg):
+ self.out_.write(msg)
+
+ def _getTargetClass(self):
+ from pyramid.scripts.pserve import PServeCommand
+
+ return PServeCommand
+
+ def _makeOne(self, *args):
+ effargs = ['pserve']
+ effargs.extend(args)
+ cmd = self._getTargetClass()(effargs)
+ cmd.out = self.out
+ self.loader = dummy.DummyLoader()
+ cmd._get_config_loader = self.loader
+ return cmd
+
+ def test_run_no_args(self):
+ inst = self._makeOne()
+ result = inst.run()
+ self.assertEqual(result, 2)
+ self.assertEqual(self.out_.getvalue(), 'You must give a config file')
+
+ def test_parse_vars_good(self):
+ inst = self._makeOne('development.ini', 'a=1', 'b=2')
+ app = dummy.DummyApp()
+
+ def get_app(name, global_conf):
+ app.name = name
+ app.global_conf = global_conf
+ return app
+
+ self.loader.get_wsgi_app = get_app
+ self.loader.server = lambda x: x
+
+ inst.run()
+ self.assertEqual(app.global_conf, {'a': '1', 'b': '2'})
+
+ def test_parse_vars_bad(self):
+ inst = self._makeOne('development.ini', 'a')
+ self.assertRaises(ValueError, inst.run)
+
+ def test_config_file_finds_watch_files(self):
+ inst = self._makeOne('development.ini')
+ loader = self.loader('/base/path.ini')
+ loader.settings = {
+ 'pserve': {'watch_files': 'foo\n/baz\ntests.test_scripts:*.py'}
+ }
+ inst.pserve_file_config(loader, global_conf={'a': '1'})
+ self.assertEqual(loader.calls[0]['defaults'], {'a': '1'})
+ self.assertEqual(
+ inst.watch_files,
+ set(
+ [
+ os.path.abspath('/base/foo'),
+ os.path.abspath('/baz'),
+ os.path.abspath(os.path.join(here, '*.py')),
+ ]
+ ),
+ )
+
+ def test_config_file_finds_open_url(self):
+ inst = self._makeOne('development.ini')
+ loader = self.loader('/base/path.ini')
+ loader.settings = {'pserve': {'open_url': 'http://127.0.0.1:8080/'}}
+ inst.pserve_file_config(loader, global_conf={'a': '1'})
+ self.assertEqual(loader.calls[0]['defaults'], {'a': '1'})
+ self.assertEqual(inst.open_url, 'http://127.0.0.1:8080/')
+
+ def test_guess_server_url(self):
+ inst = self._makeOne('development.ini')
+ loader = self.loader('/base/path.ini')
+ loader.settings = {'server:foo': {'port': '8080'}}
+ url = inst.guess_server_url(loader, 'foo', global_conf={'a': '1'})
+ self.assertEqual(loader.calls[0]['defaults'], {'a': '1'})
+ self.assertEqual(url, 'http://127.0.0.1:8080')
+
+ def test_reload_call_hupper_with_correct_args(self):
+ from pyramid.scripts import pserve
+
+ class AttrDict(dict):
+ def __init__(self, *args, **kwargs):
+ super(AttrDict, self).__init__(*args, **kwargs)
+ self.__dict__ = self
+
+ def dummy_start_reloader(*args, **kwargs):
+ dummy_start_reloader.args = args
+ dummy_start_reloader.kwargs = kwargs
+
+ orig_hupper = pserve.hupper
+ try:
+ pserve.hupper = AttrDict(
+ is_active=lambda: False, start_reloader=dummy_start_reloader
+ )
+
+ inst = self._makeOne('--reload', 'development.ini')
+ inst.run()
+ finally:
+ pserve.hupper = orig_hupper
+
+ self.assertEquals(
+ dummy_start_reloader.args, ('pyramid.scripts.pserve.main',)
+ )
+ self.assertEquals(
+ dummy_start_reloader.kwargs,
+ {
+ 'reload_interval': 1,
+ 'verbose': 1,
+ 'worker_kwargs': {
+ 'argv': ['pserve', '--reload', 'development.ini'],
+ 'quiet': False,
+ },
+ },
+ )
+
+
+class Test_main(unittest.TestCase):
+ def _callFUT(self, argv):
+ from pyramid.scripts.pserve import main
+
+ return main(argv, quiet=True)
+
+ def test_it(self):
+ result = self._callFUT(['pserve'])
+ self.assertEqual(result, 2)
diff --git a/tests/test_scripts/test_pshell.py b/tests/test_scripts/test_pshell.py
new file mode 100644
index 000000000..6beaacda6
--- /dev/null
+++ b/tests/test_scripts/test_pshell.py
@@ -0,0 +1,431 @@
+import os
+import unittest
+from . import dummy
+
+
+class TestPShellCommand(unittest.TestCase):
+ def _getTargetClass(self):
+ from pyramid.scripts.pshell import PShellCommand
+
+ return PShellCommand
+
+ def _makeOne(
+ self,
+ patch_bootstrap=True,
+ patch_loader=True,
+ patch_args=True,
+ patch_options=True,
+ ):
+ cmd = self._getTargetClass()([])
+
+ if patch_bootstrap:
+ self.bootstrap = dummy.DummyBootstrap()
+ cmd.bootstrap = self.bootstrap
+ if patch_loader:
+ self.loader = dummy.DummyLoader()
+ cmd.get_config_loader = self.loader
+ if patch_args:
+
+ class Args(object):
+ pass
+
+ self.args = Args()
+ self.args.config_uri = '/foo/bar/myapp.ini#myapp'
+ cmd.args.config_uri = self.args.config_uri
+ if patch_options:
+
+ class Options(object):
+ pass
+
+ self.options = Options()
+ self.options.python_shell = ''
+ self.options.setup = None
+ self.options.list = None
+ cmd.options = self.options
+
+ # default to None to prevent side-effects from running tests in
+ # unknown environments
+ cmd.pystartup = None
+ return cmd
+
+ def _makeEntryPoints(self, command, shells):
+ command.pkg_resources = dummy.DummyPkgResources(shells)
+
+ def test_command_loads_default_shell(self):
+ command = self._makeOne()
+ shell = dummy.DummyShell()
+ self._makeEntryPoints(command, {})
+
+ command.default_runner = shell
+ command.run()
+ self.assertEqual(self.bootstrap.a[0], '/foo/bar/myapp.ini#myapp')
+ self.assertEqual(
+ shell.env,
+ {
+ 'app': self.bootstrap.app,
+ 'root': self.bootstrap.root,
+ 'registry': self.bootstrap.registry,
+ 'request': self.bootstrap.request,
+ 'root_factory': self.bootstrap.root_factory,
+ },
+ )
+ self.assertTrue(self.bootstrap.closer.called)
+ self.assertTrue(shell.help)
+
+ def test_command_errors_with_unknown_shell(self):
+ command = self._makeOne()
+ out_calls = []
+
+ def out(msg):
+ out_calls.append(msg)
+
+ command.out = out
+
+ shell = dummy.DummyShell()
+
+ self._makeEntryPoints(command, {})
+
+ command.default_runner = shell
+ command.args.python_shell = 'unknown_python_shell'
+ result = command.run()
+ self.assertEqual(result, 1)
+ self.assertEqual(
+ out_calls, ['could not find a shell named "unknown_python_shell"']
+ )
+ self.assertEqual(self.bootstrap.a[0], '/foo/bar/myapp.ini#myapp')
+ self.assertTrue(self.bootstrap.closer.called)
+
+ def test_command_loads_ipython(self):
+ command = self._makeOne()
+ shell = dummy.DummyShell()
+ bad_shell = dummy.DummyShell()
+ self._makeEntryPoints(
+ command, {'ipython': shell, 'bpython': bad_shell}
+ )
+
+ command.args.python_shell = 'ipython'
+
+ command.run()
+ self.assertEqual(self.bootstrap.a[0], '/foo/bar/myapp.ini#myapp')
+ self.assertEqual(
+ shell.env,
+ {
+ 'app': self.bootstrap.app,
+ 'root': self.bootstrap.root,
+ 'registry': self.bootstrap.registry,
+ 'request': self.bootstrap.request,
+ 'root_factory': self.bootstrap.root_factory,
+ },
+ )
+ self.assertTrue(self.bootstrap.closer.called)
+ self.assertTrue(shell.help)
+
+ def test_shell_entry_points(self):
+ command = self._makeOne()
+ dshell = dummy.DummyShell()
+
+ self._makeEntryPoints(command, {'ipython': dshell, 'bpython': dshell})
+
+ command.default_runner = None
+ shell = command.make_shell()
+ self.assertEqual(shell, dshell)
+
+ def test_shell_override(self):
+ command = self._makeOne()
+ ipshell = dummy.DummyShell()
+ bpshell = dummy.DummyShell()
+ dshell = dummy.DummyShell()
+
+ self._makeEntryPoints(command, {})
+
+ command.default_runner = dshell
+
+ shell = command.make_shell()
+ self.assertEqual(shell, dshell)
+
+ command.args.python_shell = 'ipython'
+ self.assertRaises(ValueError, command.make_shell)
+
+ self._makeEntryPoints(
+ command, {'ipython': ipshell, 'bpython': bpshell, 'python': dshell}
+ )
+
+ command.args.python_shell = 'ipython'
+ shell = command.make_shell()
+ self.assertEqual(shell, ipshell)
+
+ command.args.python_shell = 'bpython'
+ shell = command.make_shell()
+ self.assertEqual(shell, bpshell)
+
+ command.args.python_shell = 'python'
+ shell = command.make_shell()
+ self.assertEqual(shell, dshell)
+
+ def test_shell_ordering(self):
+ command = self._makeOne()
+ ipshell = dummy.DummyShell()
+ bpshell = dummy.DummyShell()
+ dshell = dummy.DummyShell()
+
+ self._makeEntryPoints(
+ command, {'ipython': ipshell, 'bpython': bpshell, 'python': dshell}
+ )
+
+ command.default_runner = dshell
+
+ command.preferred_shells = ['ipython', 'bpython']
+ shell = command.make_shell()
+ self.assertEqual(shell, ipshell)
+
+ command.preferred_shells = ['bpython', 'python']
+ shell = command.make_shell()
+ self.assertEqual(shell, bpshell)
+
+ command.preferred_shells = ['python', 'ipython']
+ shell = command.make_shell()
+ self.assertEqual(shell, dshell)
+
+ def test_command_loads_custom_items(self):
+ command = self._makeOne()
+ model = dummy.Dummy()
+ user = dummy.Dummy()
+ self.loader.settings = {'pshell': {'m': model, 'User': user}}
+ shell = dummy.DummyShell()
+ command.run(shell)
+ self.assertEqual(self.bootstrap.a[0], '/foo/bar/myapp.ini#myapp')
+ self.assertEqual(
+ shell.env,
+ {
+ 'app': self.bootstrap.app,
+ 'root': self.bootstrap.root,
+ 'registry': self.bootstrap.registry,
+ 'request': self.bootstrap.request,
+ 'root_factory': self.bootstrap.root_factory,
+ 'm': model,
+ 'User': user,
+ },
+ )
+ self.assertTrue(self.bootstrap.closer.called)
+ self.assertTrue(shell.help)
+
+ def test_command_setup(self):
+ command = self._makeOne()
+
+ def setup(env):
+ env['a'] = 1
+ env['root'] = 'root override'
+ env['none'] = None
+
+ self.loader.settings = {'pshell': {'setup': setup}}
+ shell = dummy.DummyShell()
+ command.run(shell)
+ self.assertEqual(self.bootstrap.a[0], '/foo/bar/myapp.ini#myapp')
+ self.assertEqual(
+ shell.env,
+ {
+ 'app': self.bootstrap.app,
+ 'root': 'root override',
+ 'registry': self.bootstrap.registry,
+ 'request': self.bootstrap.request,
+ 'root_factory': self.bootstrap.root_factory,
+ 'a': 1,
+ 'none': None,
+ },
+ )
+ self.assertTrue(self.bootstrap.closer.called)
+ self.assertTrue(shell.help)
+
+ def test_command_setup_generator(self):
+ command = self._makeOne()
+ did_resume_after_yield = {}
+
+ def setup(env):
+ env['a'] = 1
+ env['root'] = 'root override'
+ env['none'] = None
+ request = env['request']
+ yield
+ did_resume_after_yield['result'] = True
+ self.assertEqual(request.dummy_attr, 1)
+
+ self.loader.settings = {'pshell': {'setup': setup}}
+ shell = dummy.DummyShell()
+ command.run(shell)
+ self.assertEqual(self.bootstrap.a[0], '/foo/bar/myapp.ini#myapp')
+ self.assertEqual(
+ shell.env,
+ {
+ 'app': self.bootstrap.app,
+ 'root': 'root override',
+ 'registry': self.bootstrap.registry,
+ 'request': self.bootstrap.request,
+ 'root_factory': self.bootstrap.root_factory,
+ 'a': 1,
+ 'none': None,
+ },
+ )
+ self.assertTrue(did_resume_after_yield['result'])
+ self.assertTrue(self.bootstrap.closer.called)
+ self.assertTrue(shell.help)
+
+ def test_command_default_shell_option(self):
+ command = self._makeOne()
+ ipshell = dummy.DummyShell()
+ dshell = dummy.DummyShell()
+ self._makeEntryPoints(command, {'ipython': ipshell, 'python': dshell})
+ self.loader.settings = {
+ 'pshell': {'default_shell': 'bpython python\nipython'}
+ }
+ command.run()
+ self.assertEqual(self.bootstrap.a[0], '/foo/bar/myapp.ini#myapp')
+ self.assertTrue(dshell.called)
+
+ def test_command_loads_check_variable_override_order(self):
+ command = self._makeOne()
+ model = dummy.Dummy()
+
+ def setup(env):
+ env['a'] = 1
+ env['m'] = 'model override'
+ env['root'] = 'root override'
+
+ self.loader.settings = {'pshell': {'setup': setup, 'm': model}}
+ shell = dummy.DummyShell()
+ command.run(shell)
+ self.assertEqual(self.bootstrap.a[0], '/foo/bar/myapp.ini#myapp')
+ self.assertEqual(
+ shell.env,
+ {
+ 'app': self.bootstrap.app,
+ 'root': 'root override',
+ 'registry': self.bootstrap.registry,
+ 'request': self.bootstrap.request,
+ 'root_factory': self.bootstrap.root_factory,
+ 'a': 1,
+ 'm': 'model override',
+ },
+ )
+ self.assertTrue(self.bootstrap.closer.called)
+ self.assertTrue(shell.help)
+
+ def test_command_loads_setup_from_options(self):
+ command = self._makeOne()
+
+ def setup(env):
+ env['a'] = 1
+ env['root'] = 'root override'
+
+ model = dummy.Dummy()
+ self.loader.settings = {'pshell': {'setup': 'abc', 'm': model}}
+ command.args.setup = setup
+ shell = dummy.DummyShell()
+ command.run(shell)
+ self.assertEqual(self.bootstrap.a[0], '/foo/bar/myapp.ini#myapp')
+ self.assertEqual(
+ shell.env,
+ {
+ 'app': self.bootstrap.app,
+ 'root': 'root override',
+ 'registry': self.bootstrap.registry,
+ 'request': self.bootstrap.request,
+ 'root_factory': self.bootstrap.root_factory,
+ 'a': 1,
+ 'm': model,
+ },
+ )
+ self.assertTrue(self.bootstrap.closer.called)
+ self.assertTrue(shell.help)
+
+ def test_command_custom_section_override(self):
+ command = self._makeOne()
+ dummy_ = dummy.Dummy()
+ self.loader.settings = {
+ 'pshell': {
+ 'app': dummy_,
+ 'root': dummy_,
+ 'registry': dummy_,
+ 'request': dummy_,
+ }
+ }
+ shell = dummy.DummyShell()
+ command.run(shell)
+ self.assertEqual(self.bootstrap.a[0], '/foo/bar/myapp.ini#myapp')
+ self.assertEqual(
+ shell.env,
+ {
+ 'app': dummy_,
+ 'root': dummy_,
+ 'registry': dummy_,
+ 'request': dummy_,
+ 'root_factory': self.bootstrap.root_factory,
+ },
+ )
+ self.assertTrue(self.bootstrap.closer.called)
+ self.assertTrue(shell.help)
+
+ def test_command_loads_pythonstartup(self):
+ command = self._makeOne()
+ command.pystartup = os.path.abspath(
+ os.path.join(os.path.dirname(__file__), 'pystartup.txt')
+ )
+ shell = dummy.DummyShell()
+ command.run(shell)
+ self.assertEqual(self.bootstrap.a[0], '/foo/bar/myapp.ini#myapp')
+ self.assertEqual(
+ shell.env,
+ {
+ 'app': self.bootstrap.app,
+ 'root': self.bootstrap.root,
+ 'registry': self.bootstrap.registry,
+ 'request': self.bootstrap.request,
+ 'root_factory': self.bootstrap.root_factory,
+ 'foo': 1,
+ },
+ )
+ self.assertTrue(self.bootstrap.closer.called)
+ self.assertTrue(shell.help)
+
+ def test_list_shells(self):
+ command = self._makeOne()
+
+ dshell = dummy.DummyShell()
+ out_calls = []
+
+ def out(msg):
+ out_calls.append(msg)
+
+ command.out = out
+
+ self._makeEntryPoints(command, {'ipython': dshell, 'python': dshell})
+
+ command.args.list = True
+ result = command.run()
+ self.assertEqual(result, 0)
+ self.assertEqual(
+ out_calls, ['Available shells:', ' ipython', ' python']
+ )
+
+
+class Test_python_shell_runner(unittest.TestCase):
+ def _callFUT(self, env, help, interact):
+ from pyramid.scripts.pshell import python_shell_runner
+
+ return python_shell_runner(env, help, interact=interact)
+
+ def test_it(self):
+ interact = dummy.DummyInteractor()
+ self._callFUT({'foo': 'bar'}, 'a help message', interact)
+ self.assertEqual(interact.local, {'foo': 'bar'})
+ self.assertTrue('a help message' in interact.banner)
+
+
+class Test_main(unittest.TestCase):
+ def _callFUT(self, argv):
+ from pyramid.scripts.pshell import main
+
+ return main(argv, quiet=True)
+
+ def test_it(self):
+ result = self._callFUT(['pshell'])
+ self.assertEqual(result, 2)
diff --git a/tests/test_scripts/test_ptweens.py b/tests/test_scripts/test_ptweens.py
new file mode 100644
index 000000000..ee50887f6
--- /dev/null
+++ b/tests/test_scripts/test_ptweens.py
@@ -0,0 +1,69 @@
+import unittest
+from . import dummy
+
+
+class TestPTweensCommand(unittest.TestCase):
+ def _getTargetClass(self):
+ from pyramid.scripts.ptweens import PTweensCommand
+
+ return PTweensCommand
+
+ def _makeOne(self):
+ cmd = self._getTargetClass()([])
+ cmd.bootstrap = dummy.DummyBootstrap()
+ cmd.setup_logging = dummy.dummy_setup_logging()
+ cmd.args.config_uri = '/foo/bar/myapp.ini#myapp'
+ return cmd
+
+ def test_command_no_tweens(self):
+ command = self._makeOne()
+ command._get_tweens = lambda *arg: None
+ L = []
+ command.out = L.append
+ result = command.run()
+ self.assertEqual(result, 0)
+ self.assertEqual(L, [])
+
+ def test_command_implicit_tweens_only(self):
+ command = self._makeOne()
+ tweens = dummy.DummyTweens([('name', 'item')], None)
+ command._get_tweens = lambda *arg: tweens
+ L = []
+ command.out = L.append
+ result = command.run()
+ self.assertEqual(result, 0)
+ self.assertEqual(
+ L[0],
+ '"pyramid.tweens" config value NOT set (implicitly ordered tweens '
+ 'used)',
+ )
+
+ def test_command_implicit_and_explicit_tweens(self):
+ command = self._makeOne()
+ tweens = dummy.DummyTweens([('name', 'item')], [('name2', 'item2')])
+ command._get_tweens = lambda *arg: tweens
+ L = []
+ command.out = L.append
+ result = command.run()
+ self.assertEqual(result, 0)
+ self.assertEqual(
+ L[0],
+ '"pyramid.tweens" config value set (explicitly ordered tweens '
+ 'used)',
+ )
+
+ def test__get_tweens(self):
+ command = self._makeOne()
+ registry = dummy.DummyRegistry()
+ self.assertEqual(command._get_tweens(registry), None)
+
+
+class Test_main(unittest.TestCase):
+ def _callFUT(self, argv):
+ from pyramid.scripts.ptweens import main
+
+ return main(argv, quiet=True)
+
+ def test_it(self):
+ result = self._callFUT(['ptweens'])
+ self.assertEqual(result, 2)
diff --git a/tests/test_scripts/test_pviews.py b/tests/test_scripts/test_pviews.py
new file mode 100644
index 000000000..0b26a9cf3
--- /dev/null
+++ b/tests/test_scripts/test_pviews.py
@@ -0,0 +1,597 @@
+import unittest
+from . import dummy
+
+
+class TestPViewsCommand(unittest.TestCase):
+ def _getTargetClass(self):
+ from pyramid.scripts.pviews import PViewsCommand
+
+ return PViewsCommand
+
+ def _makeOne(self, registry=None):
+ cmd = self._getTargetClass()([])
+ cmd.bootstrap = dummy.DummyBootstrap(registry=registry)
+ cmd.setup_logging = dummy.dummy_setup_logging()
+ cmd.args.config_uri = '/foo/bar/myapp.ini#myapp'
+ return cmd
+
+ def _makeRequest(self, url, registry):
+ from pyramid.request import Request
+
+ request = Request.blank('/a')
+ request.registry = registry
+ return request
+
+ def _register_mapper(self, registry, routes):
+ from pyramid.interfaces import IRoutesMapper
+
+ mapper = dummy.DummyMapper(*routes)
+ registry.registerUtility(mapper, IRoutesMapper)
+
+ def test__find_view_no_match(self):
+ from pyramid.registry import Registry
+
+ registry = Registry()
+ self._register_mapper(registry, [])
+ command = self._makeOne(registry)
+ request = self._makeRequest('/a', registry)
+ result = command._find_view(request)
+ self.assertEqual(result, None)
+
+ def test__find_view_no_match_multiview_registered(self):
+ from zope.interface import implementer
+ from zope.interface import providedBy
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IMultiView
+ from pyramid.traversal import DefaultRootFactory
+ from pyramid.registry import Registry
+
+ registry = Registry()
+
+ @implementer(IMultiView)
+ class View1(object):
+ pass
+
+ request = dummy.DummyRequest({'PATH_INFO': '/a'})
+ root = DefaultRootFactory(request)
+ root_iface = providedBy(root)
+ registry.registerAdapter(
+ View1(), (IViewClassifier, IRequest, root_iface), IMultiView
+ )
+ self._register_mapper(registry, [])
+ command = self._makeOne(registry=registry)
+ request = self._makeRequest('/x', registry)
+ result = command._find_view(request)
+ self.assertEqual(result, None)
+
+ def test__find_view_traversal(self):
+ from zope.interface import providedBy
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IView
+ from pyramid.traversal import DefaultRootFactory
+ from pyramid.registry import Registry
+
+ registry = Registry()
+
+ def view1(): # pragma: no cover
+ pass
+
+ request = dummy.DummyRequest({'PATH_INFO': '/a'})
+ root = DefaultRootFactory(request)
+ root_iface = providedBy(root)
+ registry.registerAdapter(
+ view1, (IViewClassifier, IRequest, root_iface), IView, name='a'
+ )
+ self._register_mapper(registry, [])
+ command = self._makeOne(registry=registry)
+ request = self._makeRequest('/a', registry)
+ result = command._find_view(request)
+ self.assertEqual(result, view1)
+
+ def test__find_view_traversal_multiview(self):
+ from zope.interface import implementer
+ from zope.interface import providedBy
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IMultiView
+ from pyramid.traversal import DefaultRootFactory
+ from pyramid.registry import Registry
+
+ registry = Registry()
+
+ @implementer(IMultiView)
+ class View1(object):
+ pass
+
+ request = dummy.DummyRequest({'PATH_INFO': '/a'})
+ root = DefaultRootFactory(request)
+ root_iface = providedBy(root)
+ view = View1()
+ registry.registerAdapter(
+ view, (IViewClassifier, IRequest, root_iface), IMultiView, name='a'
+ )
+ self._register_mapper(registry, [])
+ command = self._makeOne(registry=registry)
+ request = self._makeRequest('/a', registry)
+ result = command._find_view(request)
+ self.assertEqual(result, view)
+
+ def test__find_view_route_no_multiview(self):
+ from zope.interface import Interface
+ from zope.interface import implementer
+ from pyramid.interfaces import IRouteRequest
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IView
+ from pyramid.registry import Registry
+
+ registry = Registry()
+
+ def view(): # pragma: no cover
+ pass
+
+ class IMyRoot(Interface):
+ pass
+
+ class IMyRoute(Interface):
+ pass
+
+ registry.registerAdapter(
+ view, (IViewClassifier, IMyRoute, IMyRoot), IView, ''
+ )
+ registry.registerUtility(IMyRoute, IRouteRequest, name='a')
+
+ @implementer(IMyRoot)
+ class Factory(object):
+ def __init__(self, request):
+ pass
+
+ routes = [
+ dummy.DummyRoute('a', '/a', factory=Factory, matchdict={}),
+ dummy.DummyRoute('b', '/b', factory=Factory),
+ ]
+ self._register_mapper(registry, routes)
+ command = self._makeOne(registry=registry)
+ request = self._makeRequest('/a', registry)
+ result = command._find_view(request)
+ self.assertEqual(result, view)
+
+ def test__find_view_route_multiview_no_view_registered(self):
+ from zope.interface import Interface
+ from zope.interface import implementer
+ from pyramid.interfaces import IRouteRequest
+ from pyramid.interfaces import IMultiView
+ from pyramid.interfaces import IRootFactory
+ from pyramid.registry import Registry
+
+ registry = Registry()
+
+ def view1(): # pragma: no cover
+ pass
+
+ def view2(): # pragma: no cover
+ pass
+
+ class IMyRoot(Interface):
+ pass
+
+ class IMyRoute1(Interface):
+ pass
+
+ class IMyRoute2(Interface):
+ pass
+
+ registry.registerUtility(IMyRoute1, IRouteRequest, name='a')
+ registry.registerUtility(IMyRoute2, IRouteRequest, name='b')
+
+ @implementer(IMyRoot)
+ class Factory(object):
+ def __init__(self, request):
+ pass
+
+ registry.registerUtility(Factory, IRootFactory)
+ routes = [
+ dummy.DummyRoute('a', '/a', matchdict={}),
+ dummy.DummyRoute('b', '/a', matchdict={}),
+ ]
+ self._register_mapper(registry, routes)
+ command = self._makeOne(registry=registry)
+ request = self._makeRequest('/a', registry)
+ result = command._find_view(request)
+ self.assertTrue(IMultiView.providedBy(result))
+
+ def test__find_view_route_multiview(self):
+ from zope.interface import Interface
+ from zope.interface import implementer
+ from pyramid.interfaces import IRouteRequest
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IView
+ from pyramid.interfaces import IMultiView
+ from pyramid.interfaces import IRootFactory
+ from pyramid.registry import Registry
+
+ registry = Registry()
+
+ def view1(): # pragma: no cover
+ pass
+
+ def view2(): # pragma: no cover
+ pass
+
+ class IMyRoot(Interface):
+ pass
+
+ class IMyRoute1(Interface):
+ pass
+
+ class IMyRoute2(Interface):
+ pass
+
+ registry.registerAdapter(
+ view1, (IViewClassifier, IMyRoute1, IMyRoot), IView, ''
+ )
+ registry.registerAdapter(
+ view2, (IViewClassifier, IMyRoute2, IMyRoot), IView, ''
+ )
+ registry.registerUtility(IMyRoute1, IRouteRequest, name='a')
+ registry.registerUtility(IMyRoute2, IRouteRequest, name='b')
+
+ @implementer(IMyRoot)
+ class Factory(object):
+ def __init__(self, request):
+ pass
+
+ registry.registerUtility(Factory, IRootFactory)
+ routes = [
+ dummy.DummyRoute('a', '/a', matchdict={}),
+ dummy.DummyRoute('b', '/a', matchdict={}),
+ ]
+ self._register_mapper(registry, routes)
+ command = self._makeOne(registry=registry)
+ request = self._makeRequest('/a', registry)
+ result = command._find_view(request)
+ self.assertTrue(IMultiView.providedBy(result))
+ self.assertEqual(len(result.views), 2)
+ self.assertTrue((None, view1, None) in result.views)
+ self.assertTrue((None, view2, None) in result.views)
+
+ def test__find_multi_routes_all_match(self):
+ command = self._makeOne()
+
+ def factory(request): # pragma: no cover
+ pass
+
+ routes = [
+ dummy.DummyRoute('a', '/a', factory=factory, matchdict={}),
+ dummy.DummyRoute('b', '/a', factory=factory, matchdict={}),
+ ]
+ mapper = dummy.DummyMapper(*routes)
+ request = dummy.DummyRequest({'PATH_INFO': '/a'})
+ result = command._find_multi_routes(mapper, request)
+ self.assertEqual(
+ result,
+ [
+ {'match': {}, 'route': routes[0]},
+ {'match': {}, 'route': routes[1]},
+ ],
+ )
+
+ def test__find_multi_routes_some_match(self):
+ command = self._makeOne()
+
+ def factory(request): # pragma: no cover
+ pass
+
+ routes = [
+ dummy.DummyRoute('a', '/a', factory=factory),
+ dummy.DummyRoute('b', '/a', factory=factory, matchdict={}),
+ ]
+ mapper = dummy.DummyMapper(*routes)
+ request = dummy.DummyRequest({'PATH_INFO': '/a'})
+ result = command._find_multi_routes(mapper, request)
+ self.assertEqual(result, [{'match': {}, 'route': routes[1]}])
+
+ def test__find_multi_routes_none_match(self):
+ command = self._makeOne()
+
+ def factory(request): # pragma: no cover
+ pass
+
+ routes = [
+ dummy.DummyRoute('a', '/a', factory=factory),
+ dummy.DummyRoute('b', '/a', factory=factory),
+ ]
+ mapper = dummy.DummyMapper(*routes)
+ request = dummy.DummyRequest({'PATH_INFO': '/a'})
+ result = command._find_multi_routes(mapper, request)
+ self.assertEqual(result, [])
+
+ def test_views_command_not_found(self):
+ from pyramid.registry import Registry
+
+ registry = Registry()
+ command = self._makeOne(registry=registry)
+ L = []
+ command.out = L.append
+ command._find_view = lambda arg1: None
+ command.args.config_uri = '/foo/bar/myapp.ini#myapp'
+ command.args.url = '/a'
+ result = command.run()
+ self.assertEqual(result, 0)
+ self.assertEqual(L[1], 'URL = /a')
+ self.assertEqual(L[3], ' Not found.')
+
+ def test_views_command_not_found_url_starts_without_slash(self):
+ from pyramid.registry import Registry
+
+ registry = Registry()
+ command = self._makeOne(registry=registry)
+ L = []
+ command.out = L.append
+ command._find_view = lambda arg1: None
+ command.args.config_uri = '/foo/bar/myapp.ini#myapp'
+ command.args.url = 'a'
+ result = command.run()
+ self.assertEqual(result, 0)
+ self.assertEqual(L[1], 'URL = /a')
+ self.assertEqual(L[3], ' Not found.')
+
+ def test_views_command_single_view_traversal(self):
+ from pyramid.registry import Registry
+
+ registry = Registry()
+ command = self._makeOne(registry=registry)
+ L = []
+ command.out = L.append
+ view = dummy.DummyView(context='context', view_name='a')
+ command._find_view = lambda arg1: view
+ command.args.config_uri = '/foo/bar/myapp.ini#myapp'
+ command.args.url = '/a'
+ result = command.run()
+ self.assertEqual(result, 0)
+ self.assertEqual(L[1], 'URL = /a')
+ self.assertEqual(L[3], ' context: context')
+ self.assertEqual(L[4], ' view name: a')
+ self.assertEqual(L[8], ' tests.test_scripts.dummy.DummyView')
+
+ def test_views_command_single_view_function_traversal(self):
+ from pyramid.registry import Registry
+
+ registry = Registry()
+ command = self._makeOne(registry=registry)
+ L = []
+ command.out = L.append
+
+ def view(): # pragma: no cover
+ pass
+
+ view.__request_attrs__ = {'context': 'context', 'view_name': 'a'}
+ command._find_view = lambda arg1: view
+ command.args.config_uri = '/foo/bar/myapp.ini#myapp'
+ command.args.url = '/a'
+ result = command.run()
+ self.assertEqual(result, 0)
+ self.assertEqual(L[1], 'URL = /a')
+ self.assertEqual(L[3], ' context: context')
+ self.assertEqual(L[4], ' view name: a')
+ self.assertEqual(L[8], ' tests.test_scripts.test_pviews.view')
+
+ def test_views_command_single_view_traversal_with_permission(self):
+ from pyramid.registry import Registry
+
+ registry = Registry()
+ command = self._makeOne(registry=registry)
+ L = []
+ command.out = L.append
+ view = dummy.DummyView(context='context', view_name='a')
+ view.__permission__ = 'test'
+ command._find_view = lambda arg1: view
+ command.args.config_uri = '/foo/bar/myapp.ini#myapp'
+ command.args.url = '/a'
+ result = command.run()
+ self.assertEqual(result, 0)
+ self.assertEqual(L[1], 'URL = /a')
+ self.assertEqual(L[3], ' context: context')
+ self.assertEqual(L[4], ' view name: a')
+ self.assertEqual(L[8], ' tests.test_scripts.dummy.DummyView')
+ self.assertEqual(L[9], ' required permission = test')
+
+ def test_views_command_single_view_traversal_with_predicates(self):
+ from pyramid.registry import Registry
+
+ registry = Registry()
+ command = self._makeOne(registry=registry)
+ L = []
+ command.out = L.append
+
+ def predicate(): # pragma: no cover
+ pass
+
+ predicate.text = lambda *arg: "predicate = x"
+ view = dummy.DummyView(context='context', view_name='a')
+ view.__predicates__ = [predicate]
+ command._find_view = lambda arg1: view
+ command.args.config_uri = '/foo/bar/myapp.ini#myapp'
+ command.args.url = '/a'
+ result = command.run()
+ self.assertEqual(result, 0)
+ self.assertEqual(L[1], 'URL = /a')
+ self.assertEqual(L[3], ' context: context')
+ self.assertEqual(L[4], ' view name: a')
+ self.assertEqual(L[8], ' tests.test_scripts.dummy.DummyView')
+ self.assertEqual(L[9], ' view predicates (predicate = x)')
+
+ def test_views_command_single_view_route(self):
+ from pyramid.registry import Registry
+
+ registry = Registry()
+ command = self._makeOne(registry=registry)
+ L = []
+ command.out = L.append
+ route = dummy.DummyRoute('a', '/a', matchdict={})
+ view = dummy.DummyView(
+ context='context', view_name='a', matched_route=route, subpath=''
+ )
+ command._find_view = lambda arg1: view
+ command.args.config_uri = '/foo/bar/myapp.ini#myapp'
+ command.args.url = '/a'
+ result = command.run()
+ self.assertEqual(result, 0)
+ self.assertEqual(L[1], 'URL = /a')
+ self.assertEqual(L[3], ' context: context')
+ self.assertEqual(L[4], ' view name: a')
+ self.assertEqual(L[6], ' Route:')
+ self.assertEqual(L[8], ' route name: a')
+ self.assertEqual(L[9], ' route pattern: /a')
+ self.assertEqual(L[10], ' route path: /a')
+ self.assertEqual(L[11], ' subpath: ')
+ self.assertEqual(L[15], ' tests.test_scripts.dummy.DummyView')
+
+ def test_views_command_multi_view_nested(self):
+ from pyramid.registry import Registry
+
+ registry = Registry()
+ command = self._makeOne(registry=registry)
+ L = []
+ command.out = L.append
+ view1 = dummy.DummyView(context='context', view_name='a1')
+ view1.__name__ = 'view1'
+ view1.__view_attr__ = 'call'
+ multiview1 = dummy.DummyMultiView(
+ view1, context='context', view_name='a1'
+ )
+ multiview2 = dummy.DummyMultiView(
+ multiview1, context='context', view_name='a'
+ )
+ command._find_view = lambda arg1: multiview2
+ command.args.config_uri = '/foo/bar/myapp.ini#myapp'
+ command.args.url = '/a'
+ result = command.run()
+ self.assertEqual(result, 0)
+ self.assertEqual(L[1], 'URL = /a')
+ self.assertEqual(L[3], ' context: context')
+ self.assertEqual(L[4], ' view name: a')
+ self.assertEqual(L[8], ' tests.test_scripts.dummy.DummyMultiView')
+ self.assertEqual(L[12], ' tests.test_scripts.dummy.view1.call')
+
+ def test_views_command_single_view_route_with_route_predicates(self):
+ from pyramid.registry import Registry
+
+ registry = Registry()
+ command = self._makeOne(registry=registry)
+ L = []
+ command.out = L.append
+
+ def predicate(): # pragma: no cover
+ pass
+
+ predicate.text = lambda *arg: "predicate = x"
+ route = dummy.DummyRoute('a', '/a', matchdict={}, predicate=predicate)
+ view = dummy.DummyView(
+ context='context', view_name='a', matched_route=route, subpath=''
+ )
+ command._find_view = lambda arg1: view
+ command.args.config_uri = '/foo/bar/myapp.ini#myapp'
+ command.args.url = '/a'
+ result = command.run()
+ self.assertEqual(result, 0)
+ self.assertEqual(L[1], 'URL = /a')
+ self.assertEqual(L[3], ' context: context')
+ self.assertEqual(L[4], ' view name: a')
+ self.assertEqual(L[6], ' Route:')
+ self.assertEqual(L[8], ' route name: a')
+ self.assertEqual(L[9], ' route pattern: /a')
+ self.assertEqual(L[10], ' route path: /a')
+ self.assertEqual(L[11], ' subpath: ')
+ self.assertEqual(L[12], ' route predicates (predicate = x)')
+ self.assertEqual(L[16], ' tests.test_scripts.dummy.DummyView')
+
+ def test_views_command_multiview(self):
+ from pyramid.registry import Registry
+
+ registry = Registry()
+ command = self._makeOne(registry=registry)
+ L = []
+ command.out = L.append
+ view = dummy.DummyView(context='context')
+ view.__name__ = 'view'
+ view.__view_attr__ = 'call'
+ multiview = dummy.DummyMultiView(
+ view, context='context', view_name='a'
+ )
+ command._find_view = lambda arg1: multiview
+ command.args.config_uri = '/foo/bar/myapp.ini#myapp'
+ command.args.url = '/a'
+ result = command.run()
+ self.assertEqual(result, 0)
+ self.assertEqual(L[1], 'URL = /a')
+ self.assertEqual(L[3], ' context: context')
+ self.assertEqual(L[4], ' view name: a')
+ self.assertEqual(L[8], ' tests.test_scripts.dummy.view.call')
+
+ def test_views_command_multiview_with_permission(self):
+ from pyramid.registry import Registry
+
+ registry = Registry()
+ command = self._makeOne(registry=registry)
+ L = []
+ command.out = L.append
+ view = dummy.DummyView(context='context')
+ view.__name__ = 'view'
+ view.__view_attr__ = 'call'
+ view.__permission__ = 'test'
+ multiview = dummy.DummyMultiView(
+ view, context='context', view_name='a'
+ )
+ command._find_view = lambda arg1: multiview
+ command.args.config_uri = '/foo/bar/myapp.ini#myapp'
+ command.args.url = '/a'
+ result = command.run()
+ self.assertEqual(result, 0)
+ self.assertEqual(L[1], 'URL = /a')
+ self.assertEqual(L[3], ' context: context')
+ self.assertEqual(L[4], ' view name: a')
+ self.assertEqual(L[8], ' tests.test_scripts.dummy.view.call')
+ self.assertEqual(L[9], ' required permission = test')
+
+ def test_views_command_multiview_with_predicates(self):
+ from pyramid.registry import Registry
+
+ registry = Registry()
+ command = self._makeOne(registry=registry)
+ L = []
+ command.out = L.append
+
+ def predicate(): # pragma: no cover
+ pass
+
+ predicate.text = lambda *arg: "predicate = x"
+ view = dummy.DummyView(context='context')
+ view.__name__ = 'view'
+ view.__view_attr__ = 'call'
+ view.__predicates__ = [predicate]
+ multiview = dummy.DummyMultiView(
+ view, context='context', view_name='a'
+ )
+ command._find_view = lambda arg1: multiview
+ command.args.config_uri = '/foo/bar/myapp.ini#myapp'
+ command.args.url = '/a'
+ result = command.run()
+ self.assertEqual(result, 0)
+ self.assertEqual(L[1], 'URL = /a')
+ self.assertEqual(L[3], ' context: context')
+ self.assertEqual(L[4], ' view name: a')
+ self.assertEqual(L[8], ' tests.test_scripts.dummy.view.call')
+ self.assertEqual(L[9], ' view predicates (predicate = x)')
+
+
+class Test_main(unittest.TestCase):
+ def _callFUT(self, argv):
+ from pyramid.scripts.pviews import main
+
+ return main(argv, quiet=True)
+
+ def test_it(self):
+ result = self._callFUT(['pviews'])
+ self.assertEqual(result, 2)
diff --git a/tests/test_security.py b/tests/test_security.py
new file mode 100644
index 000000000..8b8028f61
--- /dev/null
+++ b/tests/test_security.py
@@ -0,0 +1,541 @@
+import unittest
+
+from pyramid import testing
+
+
+class TestAllPermissionsList(unittest.TestCase):
+ def setUp(self):
+ testing.setUp()
+
+ def tearDown(self):
+ testing.tearDown()
+
+ def _getTargetClass(self):
+ from pyramid.security import AllPermissionsList
+
+ return AllPermissionsList
+
+ def _makeOne(self):
+ return self._getTargetClass()()
+
+ def test_equality_w_self(self):
+ thing = self._makeOne()
+ self.assertTrue(thing.__eq__(thing))
+
+ def test_equality_w_other_instances_of_class(self):
+ thing = self._makeOne()
+ other = self._makeOne()
+ self.assertTrue(thing.__eq__(other))
+
+ def test_equality_miss(self):
+ thing = self._makeOne()
+ other = object()
+ self.assertFalse(thing.__eq__(other))
+
+ def test_contains_w_string(self):
+ thing = self._makeOne()
+ self.assertTrue('anything' in thing)
+
+ def test_contains_w_object(self):
+ thing = self._makeOne()
+ self.assertTrue(object() in thing)
+
+ def test_iterable(self):
+ thing = self._makeOne()
+ self.assertEqual(list(thing), [])
+
+ def test_singleton(self):
+ from pyramid.security import ALL_PERMISSIONS
+
+ self.assertEqual(ALL_PERMISSIONS.__class__, self._getTargetClass())
+
+
+class TestAllowed(unittest.TestCase):
+ def _getTargetClass(self):
+ from pyramid.security import Allowed
+
+ return Allowed
+
+ def _makeOne(self, *arg, **kw):
+ klass = self._getTargetClass()
+ return klass(*arg, **kw)
+
+ def test_it(self):
+ allowed = self._makeOne('hello')
+ self.assertEqual(allowed.msg, 'hello')
+ self.assertEqual(allowed, True)
+ self.assertTrue(allowed)
+ self.assertEqual(str(allowed), 'hello')
+ self.assertTrue('<Allowed instance at ' in repr(allowed))
+ self.assertTrue("with msg 'hello'>" in repr(allowed))
+
+
+class TestDenied(unittest.TestCase):
+ def _getTargetClass(self):
+ from pyramid.security import Denied
+
+ return Denied
+
+ def _makeOne(self, *arg, **kw):
+ klass = self._getTargetClass()
+ return klass(*arg, **kw)
+
+ def test_it(self):
+ denied = self._makeOne('hello')
+ self.assertEqual(denied.msg, 'hello')
+ self.assertEqual(denied, False)
+ self.assertFalse(denied)
+ self.assertEqual(str(denied), 'hello')
+ self.assertTrue('<Denied instance at ' in repr(denied))
+ self.assertTrue("with msg 'hello'>" in repr(denied))
+
+
+class TestACLAllowed(unittest.TestCase):
+ def _getTargetClass(self):
+ from pyramid.security import ACLAllowed
+
+ return ACLAllowed
+
+ def _makeOne(self, *arg, **kw):
+ klass = self._getTargetClass()
+ return klass(*arg, **kw)
+
+ def test_it(self):
+ from pyramid.security import Allowed
+
+ msg = (
+ "ACLAllowed permission 'permission' via ACE 'ace' in ACL 'acl' "
+ "on context 'ctx' for principals 'principals'"
+ )
+ allowed = self._makeOne(
+ 'ace', 'acl', 'permission', 'principals', 'ctx'
+ )
+ self.assertIsInstance(allowed, Allowed)
+ self.assertTrue(msg in allowed.msg)
+ self.assertEqual(allowed, True)
+ self.assertTrue(allowed)
+ self.assertEqual(str(allowed), msg)
+ self.assertTrue('<ACLAllowed instance at ' in repr(allowed))
+ self.assertTrue("with msg %r>" % msg in repr(allowed))
+
+
+class TestACLDenied(unittest.TestCase):
+ def _getTargetClass(self):
+ from pyramid.security import ACLDenied
+
+ return ACLDenied
+
+ def _makeOne(self, *arg, **kw):
+ klass = self._getTargetClass()
+ return klass(*arg, **kw)
+
+ def test_it(self):
+ from pyramid.security import Denied
+
+ msg = (
+ "ACLDenied permission 'permission' via ACE 'ace' in ACL 'acl' "
+ "on context 'ctx' for principals 'principals'"
+ )
+ denied = self._makeOne('ace', 'acl', 'permission', 'principals', 'ctx')
+ self.assertIsInstance(denied, Denied)
+ self.assertTrue(msg in denied.msg)
+ self.assertEqual(denied, False)
+ self.assertFalse(denied)
+ self.assertEqual(str(denied), msg)
+ self.assertTrue('<ACLDenied instance at ' in repr(denied))
+ self.assertTrue("with msg %r>" % msg in repr(denied))
+
+
+class TestPrincipalsAllowedByPermission(unittest.TestCase):
+ def setUp(self):
+ testing.setUp()
+
+ def tearDown(self):
+ testing.tearDown()
+
+ def _callFUT(self, *arg):
+ from pyramid.security import principals_allowed_by_permission
+
+ return principals_allowed_by_permission(*arg)
+
+ def test_no_authorization_policy(self):
+ from pyramid.security import Everyone
+
+ context = DummyContext()
+ result = self._callFUT(context, 'view')
+ self.assertEqual(result, [Everyone])
+
+ def test_with_authorization_policy(self):
+ from pyramid.threadlocal import get_current_registry
+
+ registry = get_current_registry()
+ _registerAuthorizationPolicy(registry, 'yo')
+ context = DummyContext()
+ result = self._callFUT(context, 'view')
+ self.assertEqual(result, 'yo')
+
+
+class TestRemember(unittest.TestCase):
+ def setUp(self):
+ testing.setUp()
+
+ def tearDown(self):
+ testing.tearDown()
+
+ def _callFUT(self, *arg, **kwarg):
+ from pyramid.security import remember
+
+ return remember(*arg, **kwarg)
+
+ def test_no_authentication_policy(self):
+ request = _makeRequest()
+ result = self._callFUT(request, 'me')
+ self.assertEqual(result, [])
+
+ def test_with_authentication_policy(self):
+ request = _makeRequest()
+ registry = request.registry
+ _registerAuthenticationPolicy(registry, 'yo')
+ result = self._callFUT(request, 'me')
+ self.assertEqual(result, [('X-Pyramid-Test', 'me')])
+
+ def test_with_authentication_policy_no_reg_on_request(self):
+ from pyramid.threadlocal import get_current_registry
+
+ registry = get_current_registry()
+ request = _makeRequest()
+ del request.registry
+ _registerAuthenticationPolicy(registry, 'yo')
+ result = self._callFUT(request, 'me')
+ self.assertEqual(result, [('X-Pyramid-Test', 'me')])
+
+ def test_with_missing_arg(self):
+ request = _makeRequest()
+ registry = request.registry
+ _registerAuthenticationPolicy(registry, 'yo')
+ self.assertRaises(TypeError, lambda: self._callFUT(request))
+
+
+class TestForget(unittest.TestCase):
+ def setUp(self):
+ testing.setUp()
+
+ def tearDown(self):
+ testing.tearDown()
+
+ def _callFUT(self, *arg):
+ from pyramid.security import forget
+
+ return forget(*arg)
+
+ def test_no_authentication_policy(self):
+ request = _makeRequest()
+ result = self._callFUT(request)
+ self.assertEqual(result, [])
+
+ def test_with_authentication_policy(self):
+ request = _makeRequest()
+ _registerAuthenticationPolicy(request.registry, 'yo')
+ result = self._callFUT(request)
+ self.assertEqual(result, [('X-Pyramid-Test', 'logout')])
+
+ def test_with_authentication_policy_no_reg_on_request(self):
+ from pyramid.threadlocal import get_current_registry
+
+ registry = get_current_registry()
+ request = _makeRequest()
+ del request.registry
+ _registerAuthenticationPolicy(registry, 'yo')
+ result = self._callFUT(request)
+ self.assertEqual(result, [('X-Pyramid-Test', 'logout')])
+
+
+class TestViewExecutionPermitted(unittest.TestCase):
+ def setUp(self):
+ testing.setUp()
+
+ def tearDown(self):
+ testing.tearDown()
+
+ def _callFUT(self, *arg, **kw):
+ from pyramid.security import view_execution_permitted
+
+ return view_execution_permitted(*arg, **kw)
+
+ def _registerSecuredView(self, view_name, allow=True):
+ from pyramid.threadlocal import get_current_registry
+ from zope.interface import Interface
+ from pyramid.interfaces import ISecuredView
+ from pyramid.interfaces import IViewClassifier
+
+ class Checker(object):
+ def __permitted__(self, context, request):
+ self.context = context
+ self.request = request
+ return allow
+
+ checker = Checker()
+ reg = get_current_registry()
+ reg.registerAdapter(
+ checker,
+ (IViewClassifier, Interface, Interface),
+ ISecuredView,
+ view_name,
+ )
+ return checker
+
+ def test_no_permission(self):
+ from zope.interface import Interface
+ from pyramid.threadlocal import get_current_registry
+ from pyramid.interfaces import ISettings
+ from pyramid.interfaces import IView
+ from pyramid.interfaces import IViewClassifier
+
+ settings = dict(debug_authorization=True)
+ reg = get_current_registry()
+ reg.registerUtility(settings, ISettings)
+ context = DummyContext()
+ request = testing.DummyRequest({})
+
+ class DummyView(object):
+ pass
+
+ view = DummyView()
+ reg.registerAdapter(
+ view, (IViewClassifier, Interface, Interface), IView, ''
+ )
+ result = self._callFUT(context, request, '')
+ msg = result.msg
+ self.assertTrue("Allowed: view name '' in context" in msg)
+ self.assertTrue('(no permission defined)' in msg)
+ self.assertEqual(result, True)
+
+ def test_no_view_registered(self):
+ from pyramid.threadlocal import get_current_registry
+ from pyramid.interfaces import ISettings
+
+ settings = dict(debug_authorization=True)
+ reg = get_current_registry()
+ reg.registerUtility(settings, ISettings)
+ context = DummyContext()
+ request = testing.DummyRequest({})
+ self.assertRaises(TypeError, self._callFUT, context, request, '')
+
+ def test_with_permission(self):
+ from zope.interface import Interface
+ from zope.interface import directlyProvides
+ from pyramid.interfaces import IRequest
+
+ class IContext(Interface):
+ pass
+
+ context = DummyContext()
+ directlyProvides(context, IContext)
+ self._registerSecuredView('', True)
+ request = testing.DummyRequest({})
+ directlyProvides(request, IRequest)
+ result = self._callFUT(context, request, '')
+ self.assertTrue(result)
+
+
+class TestAuthenticatedUserId(unittest.TestCase):
+ def setUp(self):
+ testing.setUp()
+
+ def tearDown(self):
+ testing.tearDown()
+
+ def test_no_authentication_policy(self):
+ request = _makeRequest()
+ self.assertEqual(request.authenticated_userid, None)
+
+ def test_with_authentication_policy(self):
+ request = _makeRequest()
+ _registerAuthenticationPolicy(request.registry, 'yo')
+ self.assertEqual(request.authenticated_userid, 'yo')
+
+ def test_with_authentication_policy_no_reg_on_request(self):
+ from pyramid.threadlocal import get_current_registry
+
+ registry = get_current_registry()
+ request = _makeRequest()
+ del request.registry
+ _registerAuthenticationPolicy(registry, 'yo')
+ self.assertEqual(request.authenticated_userid, 'yo')
+
+
+class TestUnAuthenticatedUserId(unittest.TestCase):
+ def setUp(self):
+ testing.setUp()
+
+ def tearDown(self):
+ testing.tearDown()
+
+ def test_no_authentication_policy(self):
+ request = _makeRequest()
+ self.assertEqual(request.unauthenticated_userid, None)
+
+ def test_with_authentication_policy(self):
+ request = _makeRequest()
+ _registerAuthenticationPolicy(request.registry, 'yo')
+ self.assertEqual(request.unauthenticated_userid, 'yo')
+
+ def test_with_authentication_policy_no_reg_on_request(self):
+ from pyramid.threadlocal import get_current_registry
+
+ registry = get_current_registry()
+ request = _makeRequest()
+ del request.registry
+ _registerAuthenticationPolicy(registry, 'yo')
+ self.assertEqual(request.unauthenticated_userid, 'yo')
+
+
+class TestEffectivePrincipals(unittest.TestCase):
+ def setUp(self):
+ testing.setUp()
+
+ def tearDown(self):
+ testing.tearDown()
+
+ def test_no_authentication_policy(self):
+ from pyramid.security import Everyone
+
+ request = _makeRequest()
+ self.assertEqual(request.effective_principals, [Everyone])
+
+ def test_with_authentication_policy(self):
+ request = _makeRequest()
+ _registerAuthenticationPolicy(request.registry, 'yo')
+ self.assertEqual(request.effective_principals, 'yo')
+
+ def test_with_authentication_policy_no_reg_on_request(self):
+ from pyramid.threadlocal import get_current_registry
+
+ registry = get_current_registry()
+ request = _makeRequest()
+ del request.registry
+ _registerAuthenticationPolicy(registry, 'yo')
+ self.assertEqual(request.effective_principals, 'yo')
+
+
+class TestHasPermission(unittest.TestCase):
+ def setUp(self):
+ testing.setUp()
+
+ def tearDown(self):
+ testing.tearDown()
+
+ def _makeOne(self):
+ from pyramid.security import AuthorizationAPIMixin
+ from pyramid.registry import Registry
+
+ mixin = AuthorizationAPIMixin()
+ mixin.registry = Registry()
+ mixin.context = object()
+ return mixin
+
+ def test_no_authentication_policy(self):
+ request = self._makeOne()
+ result = request.has_permission('view')
+ self.assertTrue(result)
+ self.assertEqual(result.msg, 'No authentication policy in use.')
+
+ def test_with_no_authorization_policy(self):
+ request = self._makeOne()
+ _registerAuthenticationPolicy(request.registry, None)
+ self.assertRaises(
+ ValueError, request.has_permission, 'view', context=None
+ )
+
+ def test_with_authn_and_authz_policies_registered(self):
+ request = self._makeOne()
+ _registerAuthenticationPolicy(request.registry, None)
+ _registerAuthorizationPolicy(request.registry, 'yo')
+ self.assertEqual(request.has_permission('view', context=None), 'yo')
+
+ def test_with_no_reg_on_request(self):
+ from pyramid.threadlocal import get_current_registry
+
+ registry = get_current_registry()
+ request = self._makeOne()
+ del request.registry
+ _registerAuthenticationPolicy(registry, None)
+ _registerAuthorizationPolicy(registry, 'yo')
+ self.assertEqual(request.has_permission('view'), 'yo')
+
+ def test_with_no_context_passed(self):
+ request = self._makeOne()
+ self.assertTrue(request.has_permission('view'))
+
+ def test_with_no_context_passed_or_on_request(self):
+ request = self._makeOne()
+ del request.context
+ self.assertRaises(AttributeError, request.has_permission, 'view')
+
+
+_TEST_HEADER = 'X-Pyramid-Test'
+
+
+class DummyContext:
+ def __init__(self, *arg, **kw):
+ self.__dict__.update(kw)
+
+
+class DummyAuthenticationPolicy:
+ def __init__(self, result):
+ self.result = result
+
+ def effective_principals(self, request):
+ return self.result
+
+ def unauthenticated_userid(self, request):
+ return self.result
+
+ def authenticated_userid(self, request):
+ return self.result
+
+ def remember(self, request, userid, **kw):
+ headers = [(_TEST_HEADER, userid)]
+ self._header_remembered = headers[0]
+ return headers
+
+ def forget(self, request):
+ headers = [(_TEST_HEADER, 'logout')]
+ self._header_forgotten = headers[0]
+ return headers
+
+
+class DummyAuthorizationPolicy:
+ def __init__(self, result):
+ self.result = result
+
+ def permits(self, context, principals, permission):
+ return self.result
+
+ def principals_allowed_by_permission(self, context, permission):
+ return self.result
+
+
+def _registerAuthenticationPolicy(reg, result):
+ from pyramid.interfaces import IAuthenticationPolicy
+
+ policy = DummyAuthenticationPolicy(result)
+ reg.registerUtility(policy, IAuthenticationPolicy)
+ return policy
+
+
+def _registerAuthorizationPolicy(reg, result):
+ from pyramid.interfaces import IAuthorizationPolicy
+
+ policy = DummyAuthorizationPolicy(result)
+ reg.registerUtility(policy, IAuthorizationPolicy)
+ return policy
+
+
+def _makeRequest():
+ from pyramid.registry import Registry
+
+ request = testing.DummyRequest(environ={})
+ request.registry = Registry()
+ request.context = object()
+ return request
diff --git a/tests/test_session.py b/tests/test_session.py
new file mode 100644
index 000000000..5e2a1ff55
--- /dev/null
+++ b/tests/test_session.py
@@ -0,0 +1,640 @@
+import base64
+import json
+import unittest
+from pyramid import testing
+from pyramid.compat import pickle
+
+
+class SharedCookieSessionTests(object):
+ def test_ctor_no_cookie(self):
+ request = testing.DummyRequest()
+ session = self._makeOne(request)
+ self.assertEqual(dict(session), {})
+
+ def test_instance_conforms(self):
+ from zope.interface.verify import verifyObject
+ from pyramid.interfaces import ISession
+
+ request = testing.DummyRequest()
+ session = self._makeOne(request)
+ verifyObject(ISession, session)
+
+ def test_ctor_with_cookie_still_valid(self):
+ import time
+
+ request = testing.DummyRequest()
+ cookieval = self._serialize((time.time(), 0, {'state': 1}))
+ request.cookies['session'] = cookieval
+ session = self._makeOne(request)
+ self.assertEqual(dict(session), {'state': 1})
+
+ def test_ctor_with_cookie_expired(self):
+ request = testing.DummyRequest()
+ cookieval = self._serialize((0, 0, {'state': 1}))
+ request.cookies['session'] = cookieval
+ session = self._makeOne(request)
+ self.assertEqual(dict(session), {})
+
+ def test_ctor_with_bad_cookie_cannot_deserialize(self):
+ request = testing.DummyRequest()
+ request.cookies['session'] = 'abc'
+ session = self._makeOne(request)
+ self.assertEqual(dict(session), {})
+
+ def test_ctor_with_bad_cookie_not_tuple(self):
+ request = testing.DummyRequest()
+ cookieval = self._serialize('abc')
+ request.cookies['session'] = cookieval
+ session = self._makeOne(request)
+ self.assertEqual(dict(session), {})
+
+ def test_timeout(self):
+ import time
+
+ request = testing.DummyRequest()
+ cookieval = self._serialize((time.time() - 5, 0, {'state': 1}))
+ request.cookies['session'] = cookieval
+ session = self._makeOne(request, timeout=1)
+ self.assertEqual(dict(session), {})
+
+ def test_timeout_never(self):
+ import time
+
+ request = testing.DummyRequest()
+ LONG_TIME = 31536000
+ cookieval = self._serialize((time.time() + LONG_TIME, 0, {'state': 1}))
+ request.cookies['session'] = cookieval
+ session = self._makeOne(request, timeout=None)
+ self.assertEqual(dict(session), {'state': 1})
+
+ def test_timeout_str(self):
+ import time
+
+ request = testing.DummyRequest()
+ cookieval = self._serialize((time.time() - 5, 0, {'state': 1}))
+ request.cookies['session'] = cookieval
+ session = self._makeOne(request, timeout='1')
+ self.assertEqual(dict(session), {})
+
+ def test_timeout_invalid(self):
+ request = testing.DummyRequest()
+ self.assertRaises(
+ ValueError, self._makeOne, request, timeout='Invalid value'
+ )
+
+ def test_changed(self):
+ request = testing.DummyRequest()
+ session = self._makeOne(request)
+ self.assertEqual(session.changed(), None)
+ self.assertTrue(session._dirty)
+
+ def test_invalidate(self):
+ request = testing.DummyRequest()
+ session = self._makeOne(request)
+ session['a'] = 1
+ self.assertEqual(session.invalidate(), None)
+ self.assertFalse('a' in session)
+
+ def test_reissue_triggered(self):
+ import time
+
+ request = testing.DummyRequest()
+ cookieval = self._serialize((time.time() - 2, 0, {'state': 1}))
+ request.cookies['session'] = cookieval
+ session = self._makeOne(request)
+ self.assertEqual(session['state'], 1)
+ self.assertTrue(session._dirty)
+
+ def test__set_cookie_on_exception(self):
+ request = testing.DummyRequest()
+ request.exception = True
+ session = self._makeOne(request)
+ session._cookie_on_exception = False
+ response = DummyResponse()
+ self.assertEqual(session._set_cookie(response), False)
+
+ def test__set_cookie_on_exception_no_request_exception(self):
+ import webob
+
+ request = testing.DummyRequest()
+ request.exception = None
+ session = self._makeOne(request)
+ session._cookie_on_exception = False
+ response = webob.Response()
+ self.assertEqual(session._set_cookie(response), True)
+ self.assertEqual(response.headerlist[-1][0], 'Set-Cookie')
+
+ def test__set_cookie_cookieval_too_long(self):
+ request = testing.DummyRequest()
+ session = self._makeOne(request)
+ session['abc'] = 'x' * 100000
+ response = DummyResponse()
+ self.assertRaises(ValueError, session._set_cookie, response)
+
+ def test__set_cookie_real_webob_response(self):
+ import webob
+
+ request = testing.DummyRequest()
+ session = self._makeOne(request)
+ session['abc'] = 'x'
+ response = webob.Response()
+ self.assertEqual(session._set_cookie(response), True)
+ self.assertEqual(response.headerlist[-1][0], 'Set-Cookie')
+
+ def test__set_cookie_options(self):
+ from pyramid.response import Response
+
+ request = testing.DummyRequest()
+ request.exception = None
+ session = self._makeOne(
+ request,
+ cookie_name='abc',
+ path='/foo',
+ domain='localhost',
+ secure=True,
+ httponly=True,
+ )
+ session['abc'] = 'x'
+ response = Response()
+ self.assertEqual(session._set_cookie(response), True)
+ cookieval = response.headerlist[-1][1]
+ val, domain, path, secure, httponly, samesite = [
+ x.strip() for x in cookieval.split(';')
+ ]
+ self.assertTrue(val.startswith('abc='))
+ self.assertEqual(domain, 'Domain=localhost')
+ self.assertEqual(path, 'Path=/foo')
+ self.assertEqual(secure, 'secure')
+ self.assertEqual(httponly, 'HttpOnly')
+ self.assertEqual(samesite, 'SameSite=Lax')
+
+ def test_flash_default(self):
+ request = testing.DummyRequest()
+ session = self._makeOne(request)
+ session.flash('msg1')
+ session.flash('msg2')
+ self.assertEqual(session['_f_'], ['msg1', 'msg2'])
+
+ def test_flash_allow_duplicate_false(self):
+ request = testing.DummyRequest()
+ session = self._makeOne(request)
+ session.flash('msg1')
+ session.flash('msg1', allow_duplicate=False)
+ self.assertEqual(session['_f_'], ['msg1'])
+
+ def test_flash_allow_duplicate_true_and_msg_not_in_storage(self):
+ request = testing.DummyRequest()
+ session = self._makeOne(request)
+ session.flash('msg1', allow_duplicate=True)
+ self.assertEqual(session['_f_'], ['msg1'])
+
+ def test_flash_allow_duplicate_false_and_msg_not_in_storage(self):
+ request = testing.DummyRequest()
+ session = self._makeOne(request)
+ session.flash('msg1', allow_duplicate=False)
+ self.assertEqual(session['_f_'], ['msg1'])
+
+ def test_flash_mixed(self):
+ request = testing.DummyRequest()
+ session = self._makeOne(request)
+ session.flash('warn1', 'warn')
+ session.flash('warn2', 'warn')
+ session.flash('err1', 'error')
+ session.flash('err2', 'error')
+ self.assertEqual(session['_f_warn'], ['warn1', 'warn2'])
+
+ def test_pop_flash_default_queue(self):
+ request = testing.DummyRequest()
+ session = self._makeOne(request)
+ queue = ['one', 'two']
+ session['_f_'] = queue
+ result = session.pop_flash()
+ self.assertEqual(result, queue)
+ self.assertEqual(session.get('_f_'), None)
+
+ def test_pop_flash_nodefault_queue(self):
+ request = testing.DummyRequest()
+ session = self._makeOne(request)
+ queue = ['one', 'two']
+ session['_f_error'] = queue
+ result = session.pop_flash('error')
+ self.assertEqual(result, queue)
+ self.assertEqual(session.get('_f_error'), None)
+
+ def test_peek_flash_default_queue(self):
+ request = testing.DummyRequest()
+ session = self._makeOne(request)
+ queue = ['one', 'two']
+ session['_f_'] = queue
+ result = session.peek_flash()
+ self.assertEqual(result, queue)
+ self.assertEqual(session.get('_f_'), queue)
+
+ def test_peek_flash_nodefault_queue(self):
+ request = testing.DummyRequest()
+ session = self._makeOne(request)
+ queue = ['one', 'two']
+ session['_f_error'] = queue
+ result = session.peek_flash('error')
+ self.assertEqual(result, queue)
+ self.assertEqual(session.get('_f_error'), queue)
+
+ def test_new_csrf_token(self):
+ request = testing.DummyRequest()
+ session = self._makeOne(request)
+ token = session.new_csrf_token()
+ self.assertEqual(token, session['_csrft_'])
+
+ def test_get_csrf_token(self):
+ request = testing.DummyRequest()
+ session = self._makeOne(request)
+ session['_csrft_'] = 'token'
+ token = session.get_csrf_token()
+ self.assertEqual(token, 'token')
+ self.assertTrue('_csrft_' in session)
+
+ def test_get_csrf_token_new(self):
+ request = testing.DummyRequest()
+ session = self._makeOne(request)
+ token = session.get_csrf_token()
+ self.assertTrue(token)
+ self.assertTrue('_csrft_' in session)
+
+ def test_no_set_cookie_with_exception(self):
+ import webob
+
+ request = testing.DummyRequest()
+ request.exception = True
+ session = self._makeOne(request, set_on_exception=False)
+ session['a'] = 1
+ callbacks = request.response_callbacks
+ self.assertEqual(len(callbacks), 1)
+ response = webob.Response()
+ result = callbacks[0](request, response)
+ self.assertEqual(result, None)
+ self.assertFalse('Set-Cookie' in dict(response.headerlist))
+
+ def test_set_cookie_with_exception(self):
+ import webob
+
+ request = testing.DummyRequest()
+ request.exception = True
+ session = self._makeOne(request)
+ session['a'] = 1
+ callbacks = request.response_callbacks
+ self.assertEqual(len(callbacks), 1)
+ response = webob.Response()
+ result = callbacks[0](request, response)
+ self.assertEqual(result, None)
+ self.assertTrue('Set-Cookie' in dict(response.headerlist))
+
+ def test_cookie_is_set(self):
+ import webob
+
+ request = testing.DummyRequest()
+ session = self._makeOne(request)
+ session['a'] = 1
+ callbacks = request.response_callbacks
+ self.assertEqual(len(callbacks), 1)
+ response = webob.Response()
+ result = callbacks[0](request, response)
+ self.assertEqual(result, None)
+ self.assertTrue('Set-Cookie' in dict(response.headerlist))
+
+
+class TestBaseCookieSession(SharedCookieSessionTests, unittest.TestCase):
+ def _makeOne(self, request, **kw):
+ from pyramid.session import BaseCookieSessionFactory
+
+ serializer = DummySerializer()
+ return BaseCookieSessionFactory(serializer, **kw)(request)
+
+ def _serialize(self, value):
+ return base64.b64encode(json.dumps(value).encode('utf-8'))
+
+ def test_reissue_not_triggered(self):
+ import time
+
+ request = testing.DummyRequest()
+ cookieval = self._serialize((time.time(), 0, {'state': 1}))
+ request.cookies['session'] = cookieval
+ session = self._makeOne(request, reissue_time=1)
+ self.assertEqual(session['state'], 1)
+ self.assertFalse(session._dirty)
+
+ def test_reissue_never(self):
+ request = testing.DummyRequest()
+ cookieval = self._serialize((0, 0, {'state': 1}))
+ request.cookies['session'] = cookieval
+ session = self._makeOne(request, reissue_time=None, timeout=None)
+ self.assertEqual(session['state'], 1)
+ self.assertFalse(session._dirty)
+
+ def test_reissue_str_triggered(self):
+ import time
+
+ request = testing.DummyRequest()
+ cookieval = self._serialize((time.time() - 2, 0, {'state': 1}))
+ request.cookies['session'] = cookieval
+ session = self._makeOne(request, reissue_time='0')
+ self.assertEqual(session['state'], 1)
+ self.assertTrue(session._dirty)
+
+ def test_reissue_invalid(self):
+ request = testing.DummyRequest()
+ self.assertRaises(
+ ValueError, self._makeOne, request, reissue_time='invalid value'
+ )
+
+ def test_cookie_max_age_invalid(self):
+ request = testing.DummyRequest()
+ self.assertRaises(
+ ValueError, self._makeOne, request, max_age='invalid value'
+ )
+
+
+class TestSignedCookieSession(SharedCookieSessionTests, unittest.TestCase):
+ def _makeOne(self, request, **kw):
+ from pyramid.session import SignedCookieSessionFactory
+
+ kw.setdefault('secret', 'secret')
+ return SignedCookieSessionFactory(**kw)(request)
+
+ def _serialize(self, value, salt=b'pyramid.session.', hashalg='sha512'):
+ import base64
+ import hashlib
+ import hmac
+ import json
+
+ digestmod = lambda: hashlib.new(hashalg)
+ cstruct = json.dumps(value).encode('utf-8')
+ sig = hmac.new(salt + b'secret', cstruct, digestmod).digest()
+ return base64.urlsafe_b64encode(sig + cstruct).rstrip(b'=')
+
+ def test_reissue_not_triggered(self):
+ import time
+
+ request = testing.DummyRequest()
+ cookieval = self._serialize((time.time(), 0, {'state': 1}))
+ request.cookies['session'] = cookieval
+ session = self._makeOne(request, reissue_time=1)
+ self.assertEqual(session['state'], 1)
+ self.assertFalse(session._dirty)
+
+ def test_reissue_never(self):
+ request = testing.DummyRequest()
+ cookieval = self._serialize((0, 0, {'state': 1}))
+ request.cookies['session'] = cookieval
+ session = self._makeOne(request, reissue_time=None, timeout=None)
+ self.assertEqual(session['state'], 1)
+ self.assertFalse(session._dirty)
+
+ def test_reissue_str_triggered(self):
+ import time
+
+ request = testing.DummyRequest()
+ cookieval = self._serialize((time.time() - 2, 0, {'state': 1}))
+ request.cookies['session'] = cookieval
+ session = self._makeOne(request, reissue_time='0')
+ self.assertEqual(session['state'], 1)
+ self.assertTrue(session._dirty)
+
+ def test_reissue_invalid(self):
+ request = testing.DummyRequest()
+ self.assertRaises(
+ ValueError, self._makeOne, request, reissue_time='invalid value'
+ )
+
+ def test_cookie_max_age_invalid(self):
+ request = testing.DummyRequest()
+ self.assertRaises(
+ ValueError, self._makeOne, request, max_age='invalid value'
+ )
+
+ def test_custom_salt(self):
+ import time
+
+ request = testing.DummyRequest()
+ cookieval = self._serialize((time.time(), 0, {'state': 1}), salt=b'f.')
+ request.cookies['session'] = cookieval
+ session = self._makeOne(request, salt=b'f.')
+ self.assertEqual(session['state'], 1)
+
+ def test_salt_mismatch(self):
+ import time
+
+ request = testing.DummyRequest()
+ cookieval = self._serialize((time.time(), 0, {'state': 1}), salt=b'f.')
+ request.cookies['session'] = cookieval
+ session = self._makeOne(request, salt=b'g.')
+ self.assertEqual(session, {})
+
+ def test_custom_hashalg(self):
+ import time
+
+ request = testing.DummyRequest()
+ cookieval = self._serialize(
+ (time.time(), 0, {'state': 1}), hashalg='sha1'
+ )
+ request.cookies['session'] = cookieval
+ session = self._makeOne(request, hashalg='sha1')
+ self.assertEqual(session['state'], 1)
+
+ def test_hashalg_mismatch(self):
+ import time
+
+ request = testing.DummyRequest()
+ cookieval = self._serialize(
+ (time.time(), 0, {'state': 1}), hashalg='sha1'
+ )
+ request.cookies['session'] = cookieval
+ session = self._makeOne(request, hashalg='sha256')
+ self.assertEqual(session, {})
+
+ def test_secret_mismatch(self):
+ import time
+
+ request = testing.DummyRequest()
+ cookieval = self._serialize((time.time(), 0, {'state': 1}))
+ request.cookies['session'] = cookieval
+ session = self._makeOne(request, secret='evilsecret')
+ self.assertEqual(session, {})
+
+ def test_custom_serializer(self):
+ import base64
+ from hashlib import sha512
+ import hmac
+ import time
+
+ request = testing.DummyRequest()
+ serializer = DummySerializer()
+ cstruct = serializer.dumps((time.time(), 0, {'state': 1}))
+ sig = hmac.new(b'pyramid.session.secret', cstruct, sha512).digest()
+ cookieval = base64.urlsafe_b64encode(sig + cstruct).rstrip(b'=')
+ request.cookies['session'] = cookieval
+ session = self._makeOne(request, serializer=serializer)
+ self.assertEqual(session['state'], 1)
+
+ def test_invalid_data_size(self):
+ from hashlib import sha512
+ import base64
+
+ request = testing.DummyRequest()
+ num_bytes = sha512().digest_size - 1
+ cookieval = base64.b64encode(b' ' * num_bytes)
+ request.cookies['session'] = cookieval
+ session = self._makeOne(request)
+ self.assertEqual(session, {})
+
+ def test_very_long_key(self):
+ verylongkey = b'a' * 1024
+ import webob
+
+ request = testing.DummyRequest()
+ session = self._makeOne(request, secret=verylongkey)
+ session['a'] = 1
+ callbacks = request.response_callbacks
+ self.assertEqual(len(callbacks), 1)
+ response = webob.Response()
+
+ try:
+ result = callbacks[0](request, response)
+ except TypeError: # pragma: no cover
+ self.fail('HMAC failed to initialize due to key length.')
+
+ self.assertEqual(result, None)
+ self.assertTrue('Set-Cookie' in dict(response.headerlist))
+
+
+class Test_manage_accessed(unittest.TestCase):
+ def _makeOne(self, wrapped):
+ from pyramid.session import manage_accessed
+
+ return manage_accessed(wrapped)
+
+ def test_accessed_set(self):
+ request = testing.DummyRequest()
+ session = DummySessionFactory(request)
+ session.renewed = 0
+ wrapper = self._makeOne(session.__class__.get)
+ wrapper(session, 'a')
+ self.assertNotEqual(session.accessed, None)
+ self.assertTrue(session._dirty)
+
+ def test_accessed_without_renew(self):
+ import time
+
+ request = testing.DummyRequest()
+ session = DummySessionFactory(request)
+ session._reissue_time = 5
+ session.renewed = time.time()
+ wrapper = self._makeOne(session.__class__.get)
+ wrapper(session, 'a')
+ self.assertNotEqual(session.accessed, None)
+ self.assertFalse(session._dirty)
+
+ def test_already_dirty(self):
+ request = testing.DummyRequest()
+ session = DummySessionFactory(request)
+ session.renewed = 0
+ session._dirty = True
+ session['a'] = 1
+ wrapper = self._makeOne(session.__class__.get)
+ self.assertEqual(wrapper.__doc__, session.get.__doc__)
+ result = wrapper(session, 'a')
+ self.assertEqual(result, 1)
+ callbacks = request.response_callbacks
+ if callbacks is not None:
+ self.assertEqual(len(callbacks), 0)
+
+
+class Test_manage_changed(unittest.TestCase):
+ def _makeOne(self, wrapped):
+ from pyramid.session import manage_changed
+
+ return manage_changed(wrapped)
+
+ def test_it(self):
+ request = testing.DummyRequest()
+ session = DummySessionFactory(request)
+ wrapper = self._makeOne(session.__class__.__setitem__)
+ wrapper(session, 'a', 1)
+ self.assertNotEqual(session.accessed, None)
+ self.assertTrue(session._dirty)
+
+
+class TestPickleSerializer(unittest.TestCase):
+ def _makeOne(self):
+ from pyramid.session import PickleSerializer
+
+ return PickleSerializer()
+
+ def test_loads(self):
+ # generated from dumping Dummy() using protocol=2
+ cstruct = b'\x80\x02ctests.test_session\nDummy\nq\x00)\x81q\x01.'
+ serializer = self._makeOne()
+ result = serializer.loads(cstruct)
+ self.assertIsInstance(result, Dummy)
+
+ def test_loads_raises_ValueError_on_invalid_data(self):
+ cstruct = b'not pickled'
+ serializer = self._makeOne()
+ self.assertRaises(ValueError, serializer.loads, cstruct)
+
+ def test_loads_raises_ValueError_on_bad_import(self):
+ # generated from dumping an object that cannot be found anymore, eg:
+ # class Foo: pass
+ # print(pickle.dumps(Foo()))
+ cstruct = b'(i__main__\nFoo\np0\n(dp1\nb.'
+ serializer = self._makeOne()
+ self.assertRaises(ValueError, serializer.loads, cstruct)
+
+ def test_dumps(self):
+ obj = Dummy()
+ serializer = self._makeOne()
+ result = serializer.dumps(obj)
+ expected_result = pickle.dumps(obj, protocol=pickle.HIGHEST_PROTOCOL)
+ self.assertEqual(result, expected_result)
+ self.assertIsInstance(result, bytes)
+
+
+class Dummy(object):
+ pass
+
+
+class DummySerializer(object):
+ def dumps(self, value):
+ return base64.b64encode(json.dumps(value).encode('utf-8'))
+
+ def loads(self, value):
+ try:
+ return json.loads(base64.b64decode(value).decode('utf-8'))
+
+ # base64.b64decode raises a TypeError on py2 instead of a ValueError
+ # and a ValueError is required for the session to handle it properly
+ except TypeError:
+ raise ValueError
+
+
+class DummySessionFactory(dict):
+ _dirty = False
+ _cookie_name = 'session'
+ _cookie_max_age = None
+ _cookie_path = '/'
+ _cookie_domain = None
+ _cookie_secure = False
+ _cookie_httponly = False
+ _timeout = 1200
+ _reissue_time = 0
+
+ def __init__(self, request):
+ self.request = request
+ dict.__init__(self, {})
+
+ def changed(self):
+ self._dirty = True
+
+
+class DummyResponse(object):
+ def __init__(self):
+ self.headerlist = []
diff --git a/tests/test_settings.py b/tests/test_settings.py
new file mode 100644
index 000000000..e8be490ee
--- /dev/null
+++ b/tests/test_settings.py
@@ -0,0 +1,86 @@
+import unittest
+
+
+class Test_asbool(unittest.TestCase):
+ def _callFUT(self, s):
+ from pyramid.settings import asbool
+
+ return asbool(s)
+
+ def test_s_is_None(self):
+ result = self._callFUT(None)
+ self.assertEqual(result, False)
+
+ def test_s_is_True(self):
+ result = self._callFUT(True)
+ self.assertEqual(result, True)
+
+ def test_s_is_False(self):
+ result = self._callFUT(False)
+ self.assertEqual(result, False)
+
+ def test_s_is_true(self):
+ result = self._callFUT('True')
+ self.assertEqual(result, True)
+
+ def test_s_is_false(self):
+ result = self._callFUT('False')
+ self.assertEqual(result, False)
+
+ def test_s_is_yes(self):
+ result = self._callFUT('yes')
+ self.assertEqual(result, True)
+
+ def test_s_is_on(self):
+ result = self._callFUT('on')
+ self.assertEqual(result, True)
+
+ def test_s_is_1(self):
+ result = self._callFUT(1)
+ self.assertEqual(result, True)
+
+
+class Test_aslist_cronly(unittest.TestCase):
+ def _callFUT(self, val):
+ from pyramid.settings import aslist_cronly
+
+ return aslist_cronly(val)
+
+ def test_with_list(self):
+ result = self._callFUT(['abc', 'def'])
+ self.assertEqual(result, ['abc', 'def'])
+
+ def test_with_string(self):
+ result = self._callFUT('abc def')
+ self.assertEqual(result, ['abc def'])
+
+ def test_with_string_crsep(self):
+ result = self._callFUT(' abc\n def')
+ self.assertEqual(result, ['abc', 'def'])
+
+
+class Test_aslist(unittest.TestCase):
+ def _callFUT(self, val, **kw):
+ from pyramid.settings import aslist
+
+ return aslist(val, **kw)
+
+ def test_with_list(self):
+ result = self._callFUT(['abc', 'def'])
+ self.assertEqual(list(result), ['abc', 'def'])
+
+ def test_with_string(self):
+ result = self._callFUT('abc def')
+ self.assertEqual(result, ['abc', 'def'])
+
+ def test_with_string_crsep(self):
+ result = self._callFUT(' abc\n def')
+ self.assertEqual(result, ['abc', 'def'])
+
+ def test_with_string_crsep_spacesep(self):
+ result = self._callFUT(' abc\n def ghi')
+ self.assertEqual(result, ['abc', 'def', 'ghi'])
+
+ def test_with_string_crsep_spacesep_no_flatten(self):
+ result = self._callFUT(' abc\n def ghi ', flatten=False)
+ self.assertEqual(result, ['abc', 'def ghi'])
diff --git a/tests/test_static.py b/tests/test_static.py
new file mode 100644
index 000000000..a323b1d89
--- /dev/null
+++ b/tests/test_static.py
@@ -0,0 +1,521 @@
+import datetime
+import os.path
+import unittest
+
+here = os.path.dirname(__file__)
+
+# 5 years from now (more or less)
+fiveyrsfuture = datetime.datetime.utcnow() + datetime.timedelta(5 * 365)
+
+
+class Test_static_view_use_subpath_False(unittest.TestCase):
+ def _getTargetClass(self):
+ from pyramid.static import static_view
+
+ return static_view
+
+ def _makeOne(self, *arg, **kw):
+ return self._getTargetClass()(*arg, **kw)
+
+ def _makeRequest(self, kw=None):
+ from pyramid.request import Request
+
+ environ = {
+ 'wsgi.url_scheme': 'http',
+ 'wsgi.version': (1, 0),
+ 'SERVER_NAME': 'example.com',
+ 'SERVER_PORT': '6543',
+ 'PATH_INFO': '/',
+ 'SCRIPT_NAME': '',
+ 'REQUEST_METHOD': 'GET',
+ }
+ if kw is not None:
+ environ.update(kw)
+ return Request(environ=environ)
+
+ def test_ctor_defaultargs(self):
+ inst = self._makeOne('package:resource_name')
+ self.assertEqual(inst.package_name, 'package')
+ self.assertEqual(inst.docroot, 'resource_name')
+ self.assertEqual(inst.cache_max_age, 3600)
+ self.assertEqual(inst.index, 'index.html')
+
+ def test_call_adds_slash_path_info_empty(self):
+ inst = self._makeOne('tests:fixtures/static')
+ request = self._makeRequest({'PATH_INFO': ''})
+ context = DummyContext()
+ from pyramid.httpexceptions import HTTPMovedPermanently
+
+ self.assertRaises(HTTPMovedPermanently, inst, context, request)
+
+ def test_path_info_slash_means_index_html(self):
+ inst = self._makeOne('tests:fixtures/static')
+ request = self._makeRequest()
+ context = DummyContext()
+ response = inst(context, request)
+ self.assertTrue(b'<html>static</html>' in response.body)
+
+ def test_oob_singledot(self):
+ inst = self._makeOne('tests:fixtures/static')
+ request = self._makeRequest({'PATH_INFO': '/./index.html'})
+ context = DummyContext()
+ response = inst(context, request)
+ self.assertEqual(response.status, '200 OK')
+ self.assertTrue(b'<html>static</html>' in response.body)
+
+ def test_oob_emptyelement(self):
+ inst = self._makeOne('tests:fixtures/static')
+ request = self._makeRequest({'PATH_INFO': '//index.html'})
+ context = DummyContext()
+ response = inst(context, request)
+ self.assertEqual(response.status, '200 OK')
+ self.assertTrue(b'<html>static</html>' in response.body)
+
+ def test_oob_dotdotslash(self):
+ inst = self._makeOne('tests:fixtures/static')
+ request = self._makeRequest({'PATH_INFO': '/subdir/../../minimal.pt'})
+ context = DummyContext()
+ from pyramid.httpexceptions import HTTPNotFound
+
+ self.assertRaises(HTTPNotFound, inst, context, request)
+
+ def test_oob_dotdotslash_encoded(self):
+ inst = self._makeOne('tests:fixtures/static')
+ request = self._makeRequest(
+ {'PATH_INFO': '/subdir/%2E%2E%2F%2E%2E/minimal.pt'}
+ )
+ context = DummyContext()
+ from pyramid.httpexceptions import HTTPNotFound
+
+ self.assertRaises(HTTPNotFound, inst, context, request)
+
+ def test_oob_os_sep(self):
+ import os
+
+ inst = self._makeOne('tests:fixtures/static')
+ dds = '..' + os.sep
+ request = self._makeRequest(
+ {'PATH_INFO': '/subdir/%s%sminimal.pt' % (dds, dds)}
+ )
+ context = DummyContext()
+ from pyramid.httpexceptions import HTTPNotFound
+
+ self.assertRaises(HTTPNotFound, inst, context, request)
+
+ def test_resource_doesnt_exist(self):
+ inst = self._makeOne('tests:fixtures/static')
+ request = self._makeRequest({'PATH_INFO': '/notthere'})
+ context = DummyContext()
+ from pyramid.httpexceptions import HTTPNotFound
+
+ self.assertRaises(HTTPNotFound, inst, context, request)
+
+ def test_resource_isdir(self):
+ inst = self._makeOne('tests:fixtures/static')
+ request = self._makeRequest({'PATH_INFO': '/subdir/'})
+ context = DummyContext()
+ response = inst(context, request)
+ self.assertTrue(b'<html>subdir</html>' in response.body)
+
+ def test_resource_is_file(self):
+ inst = self._makeOne('tests:fixtures/static')
+ request = self._makeRequest({'PATH_INFO': '/index.html'})
+ context = DummyContext()
+ response = inst(context, request)
+ self.assertTrue(b'<html>static</html>' in response.body)
+
+ def test_resource_is_file_with_wsgi_file_wrapper(self):
+ from pyramid.response import _BLOCK_SIZE
+
+ inst = self._makeOne('tests:fixtures/static')
+ request = self._makeRequest({'PATH_INFO': '/index.html'})
+
+ class _Wrapper(object):
+ def __init__(self, file, block_size=None):
+ self.file = file
+ self.block_size = block_size
+
+ request.environ['wsgi.file_wrapper'] = _Wrapper
+ context = DummyContext()
+ response = inst(context, request)
+ app_iter = response.app_iter
+ self.assertTrue(isinstance(app_iter, _Wrapper))
+ self.assertTrue(b'<html>static</html>' in app_iter.file.read())
+ self.assertEqual(app_iter.block_size, _BLOCK_SIZE)
+ app_iter.file.close()
+
+ def test_resource_is_file_with_cache_max_age(self):
+ inst = self._makeOne('tests:fixtures/static', cache_max_age=600)
+ request = self._makeRequest({'PATH_INFO': '/index.html'})
+ context = DummyContext()
+ response = inst(context, request)
+ self.assertTrue(b'<html>static</html>' in response.body)
+ self.assertEqual(len(response.headerlist), 5)
+ header_names = [x[0] for x in response.headerlist]
+ header_names.sort()
+ self.assertEqual(
+ header_names,
+ [
+ 'Cache-Control',
+ 'Content-Length',
+ 'Content-Type',
+ 'Expires',
+ 'Last-Modified',
+ ],
+ )
+
+ def test_resource_is_file_with_no_cache_max_age(self):
+ inst = self._makeOne('tests:fixtures/static', cache_max_age=None)
+ request = self._makeRequest({'PATH_INFO': '/index.html'})
+ context = DummyContext()
+ response = inst(context, request)
+ self.assertTrue(b'<html>static</html>' in response.body)
+ self.assertEqual(len(response.headerlist), 3)
+ header_names = [x[0] for x in response.headerlist]
+ header_names.sort()
+ self.assertEqual(
+ header_names, ['Content-Length', 'Content-Type', 'Last-Modified']
+ )
+
+ def test_resource_notmodified(self):
+ inst = self._makeOne('tests:fixtures/static')
+ request = self._makeRequest({'PATH_INFO': '/index.html'})
+ request.if_modified_since = fiveyrsfuture
+ context = DummyContext()
+ response = inst(context, request)
+ start_response = DummyStartResponse()
+ app_iter = response(request.environ, start_response)
+ try:
+ self.assertEqual(start_response.status, '304 Not Modified')
+ self.assertEqual(list(app_iter), [])
+ finally:
+ app_iter.close()
+
+ def test_not_found(self):
+ inst = self._makeOne('tests:fixtures/static')
+ request = self._makeRequest({'PATH_INFO': '/notthere.html'})
+ context = DummyContext()
+ from pyramid.httpexceptions import HTTPNotFound
+
+ self.assertRaises(HTTPNotFound, inst, context, request)
+
+ def test_gz_resource_no_content_encoding(self):
+ inst = self._makeOne('tests:fixtures/static')
+ request = self._makeRequest({'PATH_INFO': '/arcs.svg.tgz'})
+ context = DummyContext()
+ response = inst(context, request)
+ self.assertEqual(response.status, '200 OK')
+ self.assertEqual(response.content_type, 'application/x-tar')
+ self.assertEqual(response.content_encoding, None)
+ response.app_iter.close()
+
+ def test_resource_no_content_encoding(self):
+ inst = self._makeOne('tests:fixtures/static')
+ request = self._makeRequest({'PATH_INFO': '/index.html'})
+ context = DummyContext()
+ response = inst(context, request)
+ self.assertEqual(response.status, '200 OK')
+ self.assertEqual(response.content_type, 'text/html')
+ self.assertEqual(response.content_encoding, None)
+ response.app_iter.close()
+
+
+class Test_static_view_use_subpath_True(unittest.TestCase):
+ def _getTargetClass(self):
+ from pyramid.static import static_view
+
+ return static_view
+
+ def _makeOne(self, *arg, **kw):
+ kw['use_subpath'] = True
+ return self._getTargetClass()(*arg, **kw)
+
+ def _makeRequest(self, kw=None):
+ from pyramid.request import Request
+
+ environ = {
+ 'wsgi.url_scheme': 'http',
+ 'wsgi.version': (1, 0),
+ 'SERVER_NAME': 'example.com',
+ 'SERVER_PORT': '6543',
+ 'PATH_INFO': '/',
+ 'SCRIPT_NAME': '',
+ 'REQUEST_METHOD': 'GET',
+ }
+ if kw is not None:
+ environ.update(kw)
+ return Request(environ=environ)
+
+ def test_ctor_defaultargs(self):
+ inst = self._makeOne('package:resource_name')
+ self.assertEqual(inst.package_name, 'package')
+ self.assertEqual(inst.docroot, 'resource_name')
+ self.assertEqual(inst.cache_max_age, 3600)
+ self.assertEqual(inst.index, 'index.html')
+
+ def test_call_adds_slash_path_info_empty(self):
+ inst = self._makeOne('tests:fixtures/static')
+ request = self._makeRequest({'PATH_INFO': ''})
+ request.subpath = ()
+ context = DummyContext()
+ from pyramid.httpexceptions import HTTPMovedPermanently
+
+ self.assertRaises(HTTPMovedPermanently, inst, context, request)
+
+ def test_path_info_slash_means_index_html(self):
+ inst = self._makeOne('tests:fixtures/static')
+ request = self._makeRequest()
+ request.subpath = ()
+ context = DummyContext()
+ response = inst(context, request)
+ self.assertTrue(b'<html>static</html>' in response.body)
+
+ def test_oob_singledot(self):
+ inst = self._makeOne('tests:fixtures/static')
+ request = self._makeRequest()
+ request.subpath = ('.', 'index.html')
+ context = DummyContext()
+ from pyramid.httpexceptions import HTTPNotFound
+
+ self.assertRaises(HTTPNotFound, inst, context, request)
+
+ def test_oob_emptyelement(self):
+ inst = self._makeOne('tests:fixtures/static')
+ request = self._makeRequest()
+ request.subpath = ('', 'index.html')
+ context = DummyContext()
+ from pyramid.httpexceptions import HTTPNotFound
+
+ self.assertRaises(HTTPNotFound, inst, context, request)
+
+ def test_oob_dotdotslash(self):
+ inst = self._makeOne('tests:fixtures/static')
+ request = self._makeRequest()
+ request.subpath = ('subdir', '..', '..', 'minimal.pt')
+ context = DummyContext()
+ from pyramid.httpexceptions import HTTPNotFound
+
+ self.assertRaises(HTTPNotFound, inst, context, request)
+
+ def test_oob_dotdotslash_encoded(self):
+ inst = self._makeOne('tests:fixtures/static')
+ request = self._makeRequest()
+ request.subpath = ('subdir', '%2E%2E', '%2E%2E', 'minimal.pt')
+ context = DummyContext()
+ from pyramid.httpexceptions import HTTPNotFound
+
+ self.assertRaises(HTTPNotFound, inst, context, request)
+
+ def test_oob_os_sep(self):
+ import os
+
+ inst = self._makeOne('tests:fixtures/static')
+ dds = '..' + os.sep
+ request = self._makeRequest()
+ request.subpath = ('subdir', dds, dds, 'minimal.pt')
+ context = DummyContext()
+ from pyramid.httpexceptions import HTTPNotFound
+
+ self.assertRaises(HTTPNotFound, inst, context, request)
+
+ def test_resource_doesnt_exist(self):
+ inst = self._makeOne('tests:fixtures/static')
+ request = self._makeRequest()
+ request.subpath = 'notthere,'
+ context = DummyContext()
+ from pyramid.httpexceptions import HTTPNotFound
+
+ self.assertRaises(HTTPNotFound, inst, context, request)
+
+ def test_resource_isdir(self):
+ inst = self._makeOne('tests:fixtures/static')
+ request = self._makeRequest()
+ request.subpath = ('subdir',)
+ context = DummyContext()
+ response = inst(context, request)
+ self.assertTrue(b'<html>subdir</html>' in response.body)
+
+ def test_resource_is_file(self):
+ inst = self._makeOne('tests:fixtures/static')
+ request = self._makeRequest()
+ request.subpath = ('index.html',)
+ context = DummyContext()
+ response = inst(context, request)
+ self.assertTrue(b'<html>static</html>' in response.body)
+
+ def test_resource_is_file_with_cache_max_age(self):
+ inst = self._makeOne('tests:fixtures/static', cache_max_age=600)
+ request = self._makeRequest()
+ request.subpath = ('index.html',)
+ context = DummyContext()
+ response = inst(context, request)
+ self.assertTrue(b'<html>static</html>' in response.body)
+ self.assertEqual(len(response.headerlist), 5)
+ header_names = [x[0] for x in response.headerlist]
+ header_names.sort()
+ self.assertEqual(
+ header_names,
+ [
+ 'Cache-Control',
+ 'Content-Length',
+ 'Content-Type',
+ 'Expires',
+ 'Last-Modified',
+ ],
+ )
+
+ def test_resource_is_file_with_no_cache_max_age(self):
+ inst = self._makeOne('tests:fixtures/static', cache_max_age=None)
+ request = self._makeRequest()
+ request.subpath = ('index.html',)
+ context = DummyContext()
+ response = inst(context, request)
+ self.assertTrue(b'<html>static</html>' in response.body)
+ self.assertEqual(len(response.headerlist), 3)
+ header_names = [x[0] for x in response.headerlist]
+ header_names.sort()
+ self.assertEqual(
+ header_names, ['Content-Length', 'Content-Type', 'Last-Modified']
+ )
+
+ def test_resource_notmodified(self):
+ inst = self._makeOne('tests:fixtures/static')
+ request = self._makeRequest()
+ request.if_modified_since = fiveyrsfuture
+ request.subpath = ('index.html',)
+ context = DummyContext()
+ response = inst(context, request)
+ start_response = DummyStartResponse()
+ app_iter = response(request.environ, start_response)
+ try:
+ self.assertEqual(start_response.status, '304 Not Modified')
+ self.assertEqual(list(app_iter), [])
+ finally:
+ app_iter.close()
+
+ def test_not_found(self):
+ inst = self._makeOne('tests:fixtures/static')
+ request = self._makeRequest()
+ request.subpath = ('notthere.html',)
+ context = DummyContext()
+ from pyramid.httpexceptions import HTTPNotFound
+
+ self.assertRaises(HTTPNotFound, inst, context, request)
+
+
+class TestQueryStringConstantCacheBuster(unittest.TestCase):
+ def _makeOne(self, param=None):
+ from pyramid.static import QueryStringConstantCacheBuster as cls
+
+ if param:
+ inst = cls('foo', param)
+ else:
+ inst = cls('foo')
+ return inst
+
+ def test_token(self):
+ fut = self._makeOne().tokenize
+ self.assertEqual(fut(None, 'whatever', None), 'foo')
+
+ def test_it(self):
+ fut = self._makeOne()
+ self.assertEqual(
+ fut('foo', 'bar', {}), ('bar', {'_query': {'x': 'foo'}})
+ )
+
+ def test_change_param(self):
+ fut = self._makeOne('y')
+ self.assertEqual(
+ fut('foo', 'bar', {}), ('bar', {'_query': {'y': 'foo'}})
+ )
+
+ def test_query_is_already_tuples(self):
+ fut = self._makeOne()
+ self.assertEqual(
+ fut('foo', 'bar', {'_query': [('a', 'b')]}),
+ ('bar', {'_query': (('a', 'b'), ('x', 'foo'))}),
+ )
+
+ def test_query_is_tuple_of_tuples(self):
+ fut = self._makeOne()
+ self.assertEqual(
+ fut('foo', 'bar', {'_query': (('a', 'b'),)}),
+ ('bar', {'_query': (('a', 'b'), ('x', 'foo'))}),
+ )
+
+
+class TestManifestCacheBuster(unittest.TestCase):
+ def _makeOne(self, path, **kw):
+ from pyramid.static import ManifestCacheBuster as cls
+
+ return cls(path, **kw)
+
+ def test_it(self):
+ manifest_path = os.path.join(here, 'fixtures', 'manifest.json')
+ fut = self._makeOne(manifest_path)
+ self.assertEqual(fut('foo', 'bar', {}), ('bar', {}))
+ self.assertEqual(
+ fut('foo', 'css/main.css', {}), ('css/main-test.css', {})
+ )
+
+ def test_it_with_relspec(self):
+ fut = self._makeOne('fixtures/manifest.json')
+ self.assertEqual(fut('foo', 'bar', {}), ('bar', {}))
+ self.assertEqual(
+ fut('foo', 'css/main.css', {}), ('css/main-test.css', {})
+ )
+
+ def test_it_with_absspec(self):
+ fut = self._makeOne('tests:fixtures/manifest.json')
+ self.assertEqual(fut('foo', 'bar', {}), ('bar', {}))
+ self.assertEqual(
+ fut('foo', 'css/main.css', {}), ('css/main-test.css', {})
+ )
+
+ def test_reload(self):
+ manifest_path = os.path.join(here, 'fixtures', 'manifest.json')
+ new_manifest_path = os.path.join(here, 'fixtures', 'manifest2.json')
+ inst = self._makeOne('foo', reload=True)
+ inst.getmtime = lambda *args, **kwargs: 0
+ fut = inst
+
+ # test without a valid manifest
+ self.assertEqual(fut('foo', 'css/main.css', {}), ('css/main.css', {}))
+
+ # swap to a real manifest, setting mtime to 0
+ inst.manifest_path = manifest_path
+ self.assertEqual(
+ fut('foo', 'css/main.css', {}), ('css/main-test.css', {})
+ )
+
+ # ensure switching the path doesn't change the result
+ inst.manifest_path = new_manifest_path
+ self.assertEqual(
+ fut('foo', 'css/main.css', {}), ('css/main-test.css', {})
+ )
+
+ # update mtime, should cause a reload
+ inst.getmtime = lambda *args, **kwargs: 1
+ self.assertEqual(
+ fut('foo', 'css/main.css', {}), ('css/main-678b7c80.css', {})
+ )
+
+ def test_invalid_manifest(self):
+ self.assertRaises(IOError, lambda: self._makeOne('foo'))
+
+ def test_invalid_manifest_with_reload(self):
+ inst = self._makeOne('foo', reload=True)
+ self.assertEqual(inst.manifest, {})
+
+
+class DummyContext:
+ pass
+
+
+class DummyStartResponse:
+ status = ()
+ headers = ()
+
+ def __call__(self, status, headers):
+ self.status = status
+ self.headers = headers
diff --git a/tests/test_testing.py b/tests/test_testing.py
new file mode 100644
index 000000000..16c94ee19
--- /dev/null
+++ b/tests/test_testing.py
@@ -0,0 +1,789 @@
+import unittest
+from zope.component import getSiteManager
+from zope.interface import Interface
+from zope.interface import implementer
+from pyramid import testing
+
+
+class TestDummyRootFactory(unittest.TestCase):
+ def _makeOne(self, environ):
+ from pyramid.testing import DummyRootFactory
+
+ return DummyRootFactory(environ)
+
+ def test_it(self):
+ environ = {'bfg.routes.matchdict': {'a': 1}}
+ factory = self._makeOne(environ)
+ self.assertEqual(factory.a, 1)
+
+
+class TestDummySecurityPolicy(unittest.TestCase):
+ def _getTargetClass(self):
+ from pyramid.testing import DummySecurityPolicy
+
+ return DummySecurityPolicy
+
+ def _makeOne(self, userid=None, groupids=(), permissive=True):
+ klass = self._getTargetClass()
+ return klass(userid, groupids, permissive)
+
+ def test_authenticated_userid(self):
+ policy = self._makeOne('user')
+ self.assertEqual(policy.authenticated_userid(None), 'user')
+
+ def test_unauthenticated_userid(self):
+ policy = self._makeOne('user')
+ self.assertEqual(policy.unauthenticated_userid(None), 'user')
+
+ def test_effective_principals_userid(self):
+ policy = self._makeOne('user', ('group1',))
+ from pyramid.security import Everyone
+ from pyramid.security import Authenticated
+
+ self.assertEqual(
+ policy.effective_principals(None),
+ [Everyone, Authenticated, 'user', 'group1'],
+ )
+
+ def test_effective_principals_nouserid(self):
+ policy = self._makeOne()
+ from pyramid.security import Everyone
+
+ self.assertEqual(policy.effective_principals(None), [Everyone])
+
+ def test_permits(self):
+ policy = self._makeOne()
+ self.assertEqual(policy.permits(None, None, None), True)
+
+ def test_principals_allowed_by_permission(self):
+ policy = self._makeOne('user', ('group1',))
+ from pyramid.security import Everyone
+ from pyramid.security import Authenticated
+
+ result = policy.principals_allowed_by_permission(None, None)
+ self.assertEqual(result, [Everyone, Authenticated, 'user', 'group1'])
+
+ def test_forget(self):
+ policy = self._makeOne()
+ self.assertEqual(policy.forget(None), [])
+
+ def test_remember(self):
+ policy = self._makeOne()
+ self.assertEqual(policy.remember(None, None), [])
+
+
+class TestDummyResource(unittest.TestCase):
+ def _getTargetClass(self):
+ from pyramid.testing import DummyResource
+
+ return DummyResource
+
+ def _makeOne(self, name=None, parent=None, **kw):
+ klass = self._getTargetClass()
+ return klass(name, parent, **kw)
+
+ def test__setitem__and__getitem__and__delitem__and__contains__and_get(
+ self
+ ):
+ class Dummy:
+ pass
+
+ dummy = Dummy()
+ resource = self._makeOne()
+ resource['abc'] = dummy
+ self.assertEqual(dummy.__name__, 'abc')
+ self.assertEqual(dummy.__parent__, resource)
+ self.assertEqual(resource['abc'], dummy)
+ self.assertEqual(resource.get('abc'), dummy)
+ self.assertRaises(KeyError, resource.__getitem__, 'none')
+ self.assertTrue('abc' in resource)
+ del resource['abc']
+ self.assertFalse('abc' in resource)
+ self.assertEqual(resource.get('abc', 'foo'), 'foo')
+ self.assertEqual(resource.get('abc'), None)
+
+ def test_extra_params(self):
+ resource = self._makeOne(foo=1)
+ self.assertEqual(resource.foo, 1)
+
+ def test_clone(self):
+ resource = self._makeOne('name', 'parent', foo=1, bar=2)
+ clone = resource.clone('name2', 'parent2', bar=1)
+ self.assertEqual(clone.bar, 1)
+ self.assertEqual(clone.__name__, 'name2')
+ self.assertEqual(clone.__parent__, 'parent2')
+ self.assertEqual(clone.foo, 1)
+
+ def test_keys_items_values_len(self):
+ class Dummy:
+ pass
+
+ resource = self._makeOne()
+ resource['abc'] = Dummy()
+ resource['def'] = Dummy()
+ L = list
+ self.assertEqual(L(resource.values()), L(resource.subs.values()))
+ self.assertEqual(L(resource.items()), L(resource.subs.items()))
+ self.assertEqual(L(resource.keys()), L(resource.subs.keys()))
+ self.assertEqual(len(resource), 2)
+
+ def test_nonzero(self):
+ resource = self._makeOne()
+ self.assertEqual(resource.__nonzero__(), True)
+
+ def test_bool(self):
+ resource = self._makeOne()
+ self.assertEqual(resource.__bool__(), True)
+
+ def test_ctor_with__provides__(self):
+ resource = self._makeOne(__provides__=IDummy)
+ self.assertTrue(IDummy.providedBy(resource))
+
+
+class TestDummyRequest(unittest.TestCase):
+ def _getTargetClass(self):
+ from pyramid.testing import DummyRequest
+
+ return DummyRequest
+
+ def _makeOne(self, *arg, **kw):
+ return self._getTargetClass()(*arg, **kw)
+
+ def test_params(self):
+ request = self._makeOne(
+ params={'say': 'Hello'},
+ environ={'PATH_INFO': '/foo'},
+ headers={'X-Foo': 'YUP'},
+ )
+ self.assertEqual(request.params['say'], 'Hello')
+ self.assertEqual(request.GET['say'], 'Hello')
+ self.assertEqual(request.POST['say'], 'Hello')
+ self.assertEqual(request.headers['X-Foo'], 'YUP')
+ self.assertEqual(request.environ['PATH_INFO'], '/foo')
+
+ def test_defaults(self):
+ from pyramid.threadlocal import get_current_registry
+ from pyramid.testing import DummySession
+
+ request = self._makeOne()
+ self.assertEqual(request.method, 'GET')
+ self.assertEqual(request.application_url, 'http://example.com')
+ self.assertEqual(request.host_url, 'http://example.com')
+ self.assertEqual(request.path_url, 'http://example.com')
+ self.assertEqual(request.url, 'http://example.com')
+ self.assertEqual(request.host, 'example.com:80')
+ self.assertEqual(request.content_length, 0)
+ self.assertEqual(request.environ.get('PATH_INFO'), None)
+ self.assertEqual(request.headers.get('X-Foo'), None)
+ self.assertEqual(request.params.get('foo'), None)
+ self.assertEqual(request.GET.get('foo'), None)
+ self.assertEqual(request.POST.get('foo'), None)
+ self.assertEqual(request.cookies.get('type'), None)
+ self.assertEqual(request.path, '/')
+ self.assertEqual(request.path_info, '/')
+ self.assertEqual(request.script_name, '')
+ self.assertEqual(request.path_qs, '')
+ self.assertEqual(request.view_name, '')
+ self.assertEqual(request.subpath, ())
+ self.assertEqual(request.context, None)
+ self.assertEqual(request.root, None)
+ self.assertEqual(request.virtual_root, None)
+ self.assertEqual(request.virtual_root_path, ())
+ self.assertEqual(request.registry, get_current_registry())
+ self.assertEqual(request.session.__class__, DummySession)
+
+ def test_params_explicit(self):
+ request = self._makeOne(params={'foo': 'bar'})
+ self.assertEqual(request.params['foo'], 'bar')
+ self.assertEqual(request.GET['foo'], 'bar')
+ self.assertEqual(request.POST['foo'], 'bar')
+
+ def test_environ_explicit(self):
+ request = self._makeOne(environ={'PATH_INFO': '/foo'})
+ self.assertEqual(request.environ['PATH_INFO'], '/foo')
+
+ def test_headers_explicit(self):
+ request = self._makeOne(headers={'X-Foo': 'YUP'})
+ self.assertEqual(request.headers['X-Foo'], 'YUP')
+
+ def test_path_explicit(self):
+ request = self._makeOne(path='/abc')
+ self.assertEqual(request.path, '/abc')
+
+ def test_cookies_explicit(self):
+ request = self._makeOne(cookies={'type': 'gingersnap'})
+ self.assertEqual(request.cookies['type'], 'gingersnap')
+
+ def test_post_explicit(self):
+ POST = {'foo': 'bar', 'baz': 'qux'}
+ request = self._makeOne(post=POST)
+ self.assertEqual(request.method, 'POST')
+ self.assertEqual(request.POST, POST)
+ # N.B.: Unlike a normal request, passing 'post' should *not* put
+ # explict POST data into params: doing so masks a possible
+ # XSS bug in the app. Tests for apps which don't care about
+ # the distinction should just use 'params'.
+ self.assertEqual(request.params, {})
+
+ def test_post_empty_shadows_params(self):
+ request = self._makeOne(params={'foo': 'bar'}, post={})
+ self.assertEqual(request.method, 'POST')
+ self.assertEqual(request.params.get('foo'), 'bar')
+ self.assertEqual(request.POST.get('foo'), None)
+
+ def test_kwargs(self):
+ request = self._makeOne(water=1)
+ self.assertEqual(request.water, 1)
+
+ def test_add_response_callback(self):
+ request = self._makeOne()
+ request.add_response_callback(1)
+ self.assertEqual(list(request.response_callbacks), [1])
+
+ def test_registry_is_config_registry_when_setup_is_called_after_ctor(self):
+ # see https://github.com/Pylons/pyramid/issues/165
+ from pyramid.registry import Registry
+ from pyramid.config import Configurator
+
+ request = self._makeOne()
+ try:
+ registry = Registry('this_test')
+ config = Configurator(registry=registry)
+ config.begin()
+ self.assertTrue(request.registry is registry)
+ finally:
+ config.end()
+
+ def test_set_registry(self):
+ request = self._makeOne()
+ request.registry = 'abc'
+ self.assertEqual(request.registry, 'abc')
+
+ def test_del_registry(self):
+ # see https://github.com/Pylons/pyramid/issues/165
+ from pyramid.registry import Registry
+ from pyramid.config import Configurator
+
+ request = self._makeOne()
+ request.registry = 'abc'
+ self.assertEqual(request.registry, 'abc')
+ del request.registry
+ try:
+ registry = Registry('this_test')
+ config = Configurator(registry=registry)
+ config.begin()
+ self.assertTrue(request.registry is registry)
+ finally:
+ config.end()
+
+ def test_response_with_responsefactory(self):
+ from pyramid.registry import Registry
+ from pyramid.interfaces import IResponseFactory
+
+ registry = Registry('this_test')
+
+ class ResponseFactory(object):
+ pass
+
+ registry.registerUtility(lambda r: ResponseFactory(), IResponseFactory)
+ request = self._makeOne()
+ request.registry = registry
+ resp = request.response
+ self.assertEqual(resp.__class__, ResponseFactory)
+ self.assertTrue(request.response is resp) # reified
+
+ def test_response_without_responsefactory(self):
+ from pyramid.registry import Registry
+ from pyramid.response import Response
+
+ registry = Registry('this_test')
+ request = self._makeOne()
+ request.registry = registry
+ resp = request.response
+ self.assertEqual(resp.__class__, Response)
+ self.assertTrue(request.response is resp) # reified
+
+ def test_default_accept(self):
+ request = self._makeOne()
+ self.assertEqual(
+ request.accept.acceptable_offers(['text/html']),
+ [('text/html', 1.0)],
+ )
+
+ request.accept = 'text/plain'
+ self.assertEqual(request.accept.acceptable_offers(['text/html']), [])
+
+ del request.accept
+ self.assertEqual(
+ request.accept.acceptable_offers(['text/html']),
+ [('text/html', 1.0)],
+ )
+
+ def test_accept__init__(self):
+ request = self._makeOne(accept='text/plain')
+ self.assertEqual(
+ request.accept.acceptable_offers(['text/html', 'text/plain']),
+ [('text/plain', 1.0)],
+ )
+
+
+class TestDummyTemplateRenderer(unittest.TestCase):
+ def _getTargetClass(self,):
+ from pyramid.testing import DummyTemplateRenderer
+
+ return DummyTemplateRenderer
+
+ def _makeOne(self, string_response=''):
+ return self._getTargetClass()(string_response=string_response)
+
+ def test_implementation(self):
+ renderer = self._makeOne()
+ impl = renderer.implementation()
+ impl(a=1, b=2)
+ self.assertEqual(renderer._implementation._received['a'], 1)
+ self.assertEqual(renderer._implementation._received['b'], 2)
+
+ def test_getattr(self):
+ renderer = self._makeOne()
+ renderer({'a': 1})
+ self.assertEqual(renderer.a, 1)
+ self.assertRaises(AttributeError, renderer.__getattr__, 'b')
+
+ def test_assert_(self):
+ renderer = self._makeOne()
+ renderer({'a': 1, 'b': 2})
+ self.assertRaises(AssertionError, renderer.assert_, c=1)
+ self.assertRaises(AssertionError, renderer.assert_, b=3)
+ self.assertTrue(renderer.assert_(a=1, b=2))
+
+ def test_nondefault_string_response(self):
+ renderer = self._makeOne('abc')
+ result = renderer({'a': 1, 'b': 2})
+ self.assertEqual(result, 'abc')
+
+
+class Test_setUp(unittest.TestCase):
+ def _callFUT(self, **kw):
+ from pyramid.testing import setUp
+
+ return setUp(**kw)
+
+ def tearDown(self):
+ from pyramid.threadlocal import manager
+
+ manager.clear()
+ getSiteManager.reset()
+
+ def _assertSMHook(self, hook):
+ result = getSiteManager.sethook(None)
+ self.assertEqual(result, hook)
+
+ def test_it_defaults(self):
+ from pyramid.threadlocal import manager
+ from pyramid.threadlocal import get_current_registry
+ from pyramid.registry import Registry
+
+ old = True
+ manager.push(old)
+ config = self._callFUT()
+ current = manager.get()
+ self.assertFalse(current is old)
+ self.assertEqual(config.registry, current['registry'])
+ self.assertEqual(current['registry'].__class__, Registry)
+ self.assertEqual(current['request'], None)
+ self.assertEqual(config.package.__name__, 'tests')
+ self._assertSMHook(get_current_registry)
+
+ def test_it_with_registry(self):
+ from pyramid.registry import Registry
+ from pyramid.threadlocal import manager
+
+ registry = Registry()
+ self._callFUT(registry=registry)
+ current = manager.get()
+ self.assertEqual(current['registry'], registry)
+
+ def test_it_with_request(self):
+ from pyramid.threadlocal import manager
+
+ request = object()
+ self._callFUT(request=request)
+ current = manager.get()
+ self.assertEqual(current['request'], request)
+
+ def test_it_with_package(self):
+ config = self._callFUT(package='pyramid')
+ self.assertEqual(config.package.__name__, 'pyramid')
+
+ def test_it_with_hook_zca_false(self):
+ from pyramid.registry import Registry
+
+ registry = Registry()
+ self._callFUT(registry=registry, hook_zca=False)
+ sm = getSiteManager()
+ self.assertFalse(sm is registry)
+
+ def test_it_with_settings_passed_explicit_registry(self):
+ from pyramid.registry import Registry
+
+ registry = Registry()
+ self._callFUT(registry=registry, hook_zca=False, settings=dict(a=1))
+ self.assertEqual(registry.settings['a'], 1)
+
+ def test_it_with_settings_passed_implicit_registry(self):
+ config = self._callFUT(hook_zca=False, settings=dict(a=1))
+ self.assertEqual(config.registry.settings['a'], 1)
+
+
+class Test_cleanUp(Test_setUp):
+ def _callFUT(self, *arg, **kw):
+ from pyramid.testing import cleanUp
+
+ return cleanUp(*arg, **kw)
+
+
+class Test_tearDown(unittest.TestCase):
+ def _callFUT(self, **kw):
+ from pyramid.testing import tearDown
+
+ return tearDown(**kw)
+
+ def tearDown(self):
+ from pyramid.threadlocal import manager
+
+ manager.clear()
+ getSiteManager.reset()
+
+ def _assertSMHook(self, hook):
+ result = getSiteManager.sethook(None)
+ self.assertEqual(result, hook)
+
+ def _setSMHook(self, hook):
+ getSiteManager.sethook(hook)
+
+ def test_defaults(self):
+ from pyramid.threadlocal import manager
+
+ registry = DummyRegistry()
+ old = {'registry': registry}
+ hook = lambda *arg: None
+ try:
+ self._setSMHook(hook)
+ manager.push(old)
+ self._callFUT()
+ current = manager.get()
+ self.assertNotEqual(current, old)
+ self.assertEqual(registry.inited, 2)
+ finally:
+ result = getSiteManager.sethook(None)
+ self.assertNotEqual(result, hook)
+
+ def test_registry_cannot_be_inited(self):
+ from pyramid.threadlocal import manager
+
+ registry = DummyRegistry()
+
+ def raiseit(name):
+ raise TypeError
+
+ registry.__init__ = raiseit
+ old = {'registry': registry}
+ try:
+ manager.push(old)
+ self._callFUT() # doesn't blow up
+ current = manager.get()
+ self.assertNotEqual(current, old)
+ self.assertEqual(registry.inited, 1)
+ finally:
+ manager.clear()
+
+ def test_unhook_zc_false(self):
+ hook = lambda *arg: None
+ try:
+ self._setSMHook(hook)
+ self._callFUT(unhook_zca=False)
+ finally:
+ self._assertSMHook(hook)
+
+
+class TestDummyRendererFactory(unittest.TestCase):
+ def _makeOne(self, name, factory):
+ from pyramid.testing import DummyRendererFactory
+
+ return DummyRendererFactory(name, factory)
+
+ def test_add_no_colon(self):
+ f = self._makeOne('name', None)
+ f.add('spec', 'renderer')
+ self.assertEqual(f.renderers['spec'], 'renderer')
+
+ def test_add_with_colon(self):
+ f = self._makeOne('name', None)
+ f.add('spec:spec2', 'renderer')
+ self.assertEqual(f.renderers['spec:spec2'], 'renderer')
+ self.assertEqual(f.renderers['spec2'], 'renderer')
+
+ def test_call(self):
+ f = self._makeOne('name', None)
+ f.renderers['spec'] = 'renderer'
+ info = DummyRendererInfo({'name': 'spec'})
+ self.assertEqual(f(info), 'renderer')
+
+ def test_call2(self):
+ f = self._makeOne('name', None)
+ f.renderers['spec'] = 'renderer'
+ info = DummyRendererInfo({'name': 'spec:spec'})
+ self.assertEqual(f(info), 'renderer')
+
+ def test_call3(self):
+ def factory(spec):
+ return 'renderer'
+
+ f = self._makeOne('name', factory)
+ info = DummyRendererInfo({'name': 'spec'})
+ self.assertEqual(f(info), 'renderer')
+
+ def test_call_miss(self):
+ f = self._makeOne('name', None)
+ info = DummyRendererInfo({'name': 'spec'})
+ self.assertRaises(KeyError, f, info)
+
+
+class TestMockTemplate(unittest.TestCase):
+ def _makeOne(self, response):
+ from pyramid.testing import MockTemplate
+
+ return MockTemplate(response)
+
+ def test_getattr(self):
+ template = self._makeOne(None)
+ self.assertEqual(template.foo, template)
+
+ def test_getitem(self):
+ template = self._makeOne(None)
+ self.assertEqual(template['foo'], template)
+
+ def test_call(self):
+ template = self._makeOne('123')
+ self.assertEqual(template(), '123')
+
+
+class Test_skip_on(unittest.TestCase):
+ def setUp(self):
+ from pyramid.testing import skip_on
+
+ self.os_name = skip_on.os_name
+ skip_on.os_name = 'wrong'
+
+ def tearDown(self):
+ from pyramid.testing import skip_on
+
+ skip_on.os_name = self.os_name
+
+ def _callFUT(self, *platforms):
+ from pyramid.testing import skip_on
+
+ return skip_on(*platforms)
+
+ def test_wrong_platform(self):
+ def foo(): # pragma: no cover
+ return True
+
+ decorated = self._callFUT('wrong')(foo)
+ self.assertEqual(decorated(), None)
+
+ def test_ok_platform(self):
+ def foo():
+ return True
+
+ decorated = self._callFUT('ok')(foo)
+ self.assertEqual(decorated(), True)
+
+
+class TestDummySession(unittest.TestCase):
+ def _makeOne(self):
+ from pyramid.testing import DummySession
+
+ return DummySession()
+
+ @testing.skip_on(
+ 'pypy'
+ ) # see https://github.com/Pylons/pyramid/issues/3237
+ def test_instance_conforms(self):
+ from zope.interface.verify import verifyObject
+ from pyramid.interfaces import ISession
+
+ session = self._makeOne()
+ verifyObject(ISession, session)
+
+ def test_changed(self):
+ session = self._makeOne()
+ self.assertEqual(session.changed(), None)
+
+ def test_invalidate(self):
+ session = self._makeOne()
+ session['a'] = 1
+ self.assertEqual(session.invalidate(), None)
+ self.assertFalse('a' in session)
+
+ def test_flash_default(self):
+ session = self._makeOne()
+ session.flash('msg1')
+ session.flash('msg2')
+ self.assertEqual(session['_f_'], ['msg1', 'msg2'])
+
+ def test_flash_mixed(self):
+ session = self._makeOne()
+ session.flash('warn1', 'warn')
+ session.flash('warn2', 'warn')
+ session.flash('err1', 'error')
+ session.flash('err2', 'error')
+ self.assertEqual(session['_f_warn'], ['warn1', 'warn2'])
+
+ def test_pop_flash_default_queue(self):
+ session = self._makeOne()
+ queue = ['one', 'two']
+ session['_f_'] = queue
+ result = session.pop_flash()
+ self.assertEqual(result, queue)
+ self.assertEqual(session.get('_f_'), None)
+
+ def test_pop_flash_nodefault_queue(self):
+ session = self._makeOne()
+ queue = ['one', 'two']
+ session['_f_error'] = queue
+ result = session.pop_flash('error')
+ self.assertEqual(result, queue)
+ self.assertEqual(session.get('_f_error'), None)
+
+ def test_peek_flash_default_queue(self):
+ session = self._makeOne()
+ queue = ['one', 'two']
+ session['_f_'] = queue
+ result = session.peek_flash()
+ self.assertEqual(result, queue)
+ self.assertEqual(session.get('_f_'), queue)
+
+ def test_peek_flash_nodefault_queue(self):
+ session = self._makeOne()
+ queue = ['one', 'two']
+ session['_f_error'] = queue
+ result = session.peek_flash('error')
+ self.assertEqual(result, queue)
+ self.assertEqual(session.get('_f_error'), queue)
+
+ def test_new_csrf_token(self):
+ session = self._makeOne()
+ token = session.new_csrf_token()
+ self.assertEqual(token, session['_csrft_'])
+
+ def test_get_csrf_token(self):
+ session = self._makeOne()
+ session['_csrft_'] = 'token'
+ token = session.get_csrf_token()
+ self.assertEqual(token, 'token')
+ self.assertTrue('_csrft_' in session)
+
+ def test_get_csrf_token_generates_token(self):
+ session = self._makeOne()
+ token = session.get_csrf_token()
+ self.assertNotEqual(token, None)
+ self.assertTrue(len(token) >= 1)
+
+
+class IDummy(Interface):
+ pass
+
+
+@implementer(IDummy)
+class DummyEvent:
+ pass
+
+
+class DummyFactory:
+ def __init__(self, environ):
+ """ """
+
+
+class DummyRegistry(object):
+ inited = 0
+ __name__ = 'name'
+
+ def __init__(self, name=''):
+ self.inited = self.inited + 1
+
+
+class DummyRendererInfo(object):
+ def __init__(self, kw):
+ self.__dict__.update(kw)
+
+
+class Test_testConfig(unittest.TestCase):
+ def _setUp(self, **kw):
+ self._log.append(('setUp', kw))
+ return 'fake config'
+
+ def _tearDown(self, **kw):
+ self._log.append(('tearDown', kw))
+
+ def setUp(self):
+ from pyramid import testing
+
+ self._log = []
+ self._orig_setUp = testing.setUp
+ testing.setUp = self._setUp
+ self._orig_tearDown = testing.tearDown
+ testing.tearDown = self._tearDown
+
+ def tearDown(self):
+ from pyramid import testing
+
+ testing.setUp = self._orig_setUp
+ testing.tearDown = self._orig_tearDown
+
+ def _callFUT(self, inner, **kw):
+ from pyramid.testing import testConfig
+
+ with testConfig(**kw) as config:
+ inner(config)
+
+ def test_ok_calls(self):
+ self.assertEqual(self._log, [])
+
+ def inner(config):
+ self.assertEqual(
+ self._log,
+ [
+ (
+ 'setUp',
+ {
+ 'autocommit': True,
+ 'hook_zca': True,
+ 'registry': None,
+ 'request': None,
+ 'settings': None,
+ },
+ )
+ ],
+ )
+ self._log.pop()
+
+ self._callFUT(inner)
+ self.assertEqual(self._log, [('tearDown', {'unhook_zca': True})])
+
+ def test_teardown_called_on_exception(self):
+ class TestException(Exception):
+ pass
+
+ def inner(config):
+ self._log = []
+ raise TestException('oops')
+
+ self.assertRaises(TestException, self._callFUT, inner)
+ self.assertEqual(self._log[0][0], 'tearDown')
+
+ def test_ok_get_config(self):
+ def inner(config):
+ self.assertEqual(config, 'fake config')
+
+ self._callFUT(inner)
diff --git a/tests/test_threadlocal.py b/tests/test_threadlocal.py
new file mode 100644
index 000000000..487c7f4f2
--- /dev/null
+++ b/tests/test_threadlocal.py
@@ -0,0 +1,105 @@
+from pyramid import testing
+import unittest
+
+
+class TestThreadLocalManager(unittest.TestCase):
+ def setUp(self):
+ testing.setUp()
+
+ def tearDown(self):
+ testing.tearDown()
+
+ def _getTargetClass(self):
+ from pyramid.threadlocal import ThreadLocalManager
+
+ return ThreadLocalManager
+
+ def _makeOne(self, default=lambda *x: 1):
+ return self._getTargetClass()(default)
+
+ def test_init(self):
+ local = self._makeOne()
+ self.assertEqual(local.stack, [])
+ self.assertEqual(local.get(), 1)
+
+ def test_default(self):
+ def thedefault():
+ return '123'
+
+ local = self._makeOne(thedefault)
+ self.assertEqual(local.stack, [])
+ self.assertEqual(local.get(), '123')
+
+ def test_push_and_pop(self):
+ local = self._makeOne()
+ local.push(True)
+ self.assertEqual(local.get(), True)
+ self.assertEqual(local.pop(), True)
+ self.assertEqual(local.pop(), None)
+ self.assertEqual(local.get(), 1)
+
+ def test_set_get_and_clear(self):
+ local = self._makeOne()
+ local.set(None)
+ self.assertEqual(local.stack, [None])
+ self.assertEqual(local.get(), None)
+ local.clear()
+ self.assertEqual(local.get(), 1)
+ local.clear()
+ self.assertEqual(local.get(), 1)
+
+
+class TestGetCurrentRequest(unittest.TestCase):
+ def _callFUT(self):
+ from pyramid.threadlocal import get_current_request
+
+ return get_current_request()
+
+ def test_it_None(self):
+ request = self._callFUT()
+ self.assertEqual(request, None)
+
+ def test_it(self):
+ from pyramid.threadlocal import manager
+
+ request = object()
+ try:
+ manager.push({'request': request})
+ self.assertEqual(self._callFUT(), request)
+ finally:
+ manager.pop()
+ self.assertEqual(self._callFUT(), None)
+
+
+class GetCurrentRegistryTests(unittest.TestCase):
+ def setUp(self):
+ testing.setUp()
+
+ def tearDown(self):
+ testing.tearDown()
+
+ def _callFUT(self):
+ from pyramid.threadlocal import get_current_registry
+
+ return get_current_registry()
+
+ def test_it(self):
+ from pyramid.threadlocal import manager
+
+ try:
+ manager.push({'registry': 123})
+ self.assertEqual(self._callFUT(), 123)
+ finally:
+ manager.pop()
+
+
+class GetCurrentRegistryWithoutTestingRegistry(unittest.TestCase):
+ def _callFUT(self):
+ from pyramid.threadlocal import get_current_registry
+
+ return get_current_registry()
+
+ def test_it(self):
+ from pyramid.registry import global_registry
+
+ self.assertEqual(self._callFUT(), global_registry)
diff --git a/tests/test_traversal.py b/tests/test_traversal.py
new file mode 100644
index 000000000..61e480cbc
--- /dev/null
+++ b/tests/test_traversal.py
@@ -0,0 +1,1313 @@
+# -*- coding: utf-8 -*-
+import unittest
+
+from pyramid.testing import cleanUp
+
+from pyramid.compat import text_, native_, text_type, url_quote, PY2
+
+
+class TraversalPathTests(unittest.TestCase):
+ def _callFUT(self, path):
+ from pyramid.traversal import traversal_path
+
+ return traversal_path(path)
+
+ def test_utf8(self):
+ la = b'La Pe\xc3\xb1a'
+ encoded = url_quote(la)
+ decoded = text_(la, 'utf-8')
+ path = '/'.join([encoded, encoded])
+ result = self._callFUT(path)
+ self.assertEqual(result, (decoded, decoded))
+
+ def test_utf16(self):
+ from pyramid.exceptions import URLDecodeError
+
+ la = text_(b'La Pe\xc3\xb1a', 'utf-8').encode('utf-16')
+ encoded = url_quote(la)
+ path = '/'.join([encoded, encoded])
+ self.assertRaises(URLDecodeError, self._callFUT, path)
+
+ def test_unicode_highorder_chars(self):
+ path = text_('/%E6%B5%81%E8%A1%8C%E8%B6%8B%E5%8A%BF')
+ self.assertEqual(
+ self._callFUT(path),
+ (text_('\u6d41\u884c\u8d8b\u52bf', 'unicode_escape'),),
+ )
+
+ def test_element_urllquoted(self):
+ self.assertEqual(
+ self._callFUT('/foo/space%20thing/bar'),
+ (text_('foo'), text_('space thing'), text_('bar')),
+ )
+
+ def test_unicode_undecodeable_to_ascii(self):
+ path = text_(b'/La Pe\xc3\xb1a', 'utf-8')
+ self.assertRaises(UnicodeEncodeError, self._callFUT, path)
+
+
+class TraversalPathInfoTests(unittest.TestCase):
+ def _callFUT(self, path):
+ from pyramid.traversal import traversal_path_info
+
+ return traversal_path_info(path)
+
+ def test_path_startswith_endswith(self):
+ self.assertEqual(self._callFUT('/foo/'), (text_('foo'),))
+
+ def test_empty_elements(self):
+ self.assertEqual(self._callFUT('foo///'), (text_('foo'),))
+
+ def test_onedot(self):
+ self.assertEqual(
+ self._callFUT('foo/./bar'), (text_('foo'), text_('bar'))
+ )
+
+ def test_twodots(self):
+ self.assertEqual(self._callFUT('foo/../bar'), (text_('bar'),))
+
+ def test_twodots_at_start(self):
+ self.assertEqual(self._callFUT('../../bar'), (text_('bar'),))
+
+ def test_segments_are_unicode(self):
+ result = self._callFUT('/foo/bar')
+ self.assertEqual(type(result[0]), text_type)
+ self.assertEqual(type(result[1]), text_type)
+
+ def test_same_value_returned_if_cached(self):
+ result1 = self._callFUT('/foo/bar')
+ result2 = self._callFUT('/foo/bar')
+ self.assertEqual(result1, (text_('foo'), text_('bar')))
+ self.assertEqual(result2, (text_('foo'), text_('bar')))
+
+ def test_unicode_simple(self):
+ path = text_('/abc')
+ self.assertEqual(self._callFUT(path), (text_('abc'),))
+
+ def test_highorder(self):
+ la = b'La Pe\xc3\xb1a'
+ latin1 = native_(la)
+ result = self._callFUT(latin1)
+ self.assertEqual(result, (text_(la, 'utf-8'),))
+
+ def test_highorder_undecodeable(self):
+ from pyramid.exceptions import URLDecodeError
+
+ la = text_(b'La Pe\xc3\xb1a', 'utf-8')
+ notlatin1 = native_(la)
+ self.assertRaises(URLDecodeError, self._callFUT, notlatin1)
+
+
+class ResourceTreeTraverserTests(unittest.TestCase):
+ def setUp(self):
+ cleanUp()
+
+ def tearDown(self):
+ cleanUp()
+
+ def _getTargetClass(self):
+ from pyramid.traversal import ResourceTreeTraverser
+
+ return ResourceTreeTraverser
+
+ def _makeOne(self, *arg, **kw):
+ klass = self._getTargetClass()
+ return klass(*arg, **kw)
+
+ def _getEnviron(self, **kw):
+ environ = {}
+ environ.update(kw)
+ return environ
+
+ def test_class_conforms_to_ITraverser(self):
+ from zope.interface.verify import verifyClass
+ from pyramid.interfaces import ITraverser
+
+ verifyClass(ITraverser, self._getTargetClass())
+
+ def test_instance_conforms_to_ITraverser(self):
+ from zope.interface.verify import verifyObject
+ from pyramid.interfaces import ITraverser
+
+ context = DummyContext()
+ verifyObject(ITraverser, self._makeOne(context))
+
+ def test_call_with_empty_pathinfo(self):
+ policy = self._makeOne(None)
+ environ = self._getEnviron()
+ request = DummyRequest(environ, path_info='')
+ result = policy(request)
+ self.assertEqual(result['context'], None)
+ self.assertEqual(result['view_name'], '')
+ self.assertEqual(result['subpath'], ())
+ self.assertEqual(result['traversed'], ())
+ self.assertEqual(result['root'], policy.root)
+ self.assertEqual(result['virtual_root'], policy.root)
+ self.assertEqual(result['virtual_root_path'], ())
+
+ def test_call_with_pathinfo_KeyError(self):
+ policy = self._makeOne(None)
+ environ = self._getEnviron()
+ request = DummyRequest(environ, toraise=KeyError)
+ result = policy(request)
+ self.assertEqual(result['context'], None)
+ self.assertEqual(result['view_name'], '')
+ self.assertEqual(result['subpath'], ())
+ self.assertEqual(result['traversed'], ())
+ self.assertEqual(result['root'], policy.root)
+ self.assertEqual(result['virtual_root'], policy.root)
+ self.assertEqual(result['virtual_root_path'], ())
+
+ def test_call_with_pathinfo_highorder(self):
+ path = text_(b'/Qu\xc3\xa9bec', 'utf-8')
+ foo = DummyContext(None, path)
+ root = DummyContext(foo, 'root')
+ policy = self._makeOne(root)
+ environ = self._getEnviron()
+ request = DummyRequest(environ, path_info=path)
+ result = policy(request)
+ self.assertEqual(result['context'], foo)
+ self.assertEqual(result['view_name'], '')
+ self.assertEqual(result['subpath'], ())
+ self.assertEqual(result['traversed'], (path[1:],))
+ self.assertEqual(result['root'], policy.root)
+ self.assertEqual(result['virtual_root'], policy.root)
+ self.assertEqual(result['virtual_root_path'], ())
+
+ def test_call_pathel_with_no_getitem(self):
+ policy = self._makeOne(None)
+ environ = self._getEnviron()
+ request = DummyRequest(environ, path_info=text_('/foo/bar'))
+ result = policy(request)
+ self.assertEqual(result['context'], None)
+ self.assertEqual(result['view_name'], 'foo')
+ self.assertEqual(result['subpath'], ('bar',))
+ self.assertEqual(result['traversed'], ())
+ self.assertEqual(result['root'], policy.root)
+ self.assertEqual(result['virtual_root'], policy.root)
+ self.assertEqual(result['virtual_root_path'], ())
+
+ def test_call_withconn_getitem_emptypath_nosubpath(self):
+ root = DummyContext()
+ policy = self._makeOne(root)
+ environ = self._getEnviron()
+ request = DummyRequest(environ, path_info=text_(''))
+ result = policy(request)
+ self.assertEqual(result['context'], root)
+ self.assertEqual(result['view_name'], '')
+ self.assertEqual(result['subpath'], ())
+ self.assertEqual(result['traversed'], ())
+ self.assertEqual(result['root'], root)
+ self.assertEqual(result['virtual_root'], root)
+ self.assertEqual(result['virtual_root_path'], ())
+
+ def test_call_withconn_getitem_withpath_nosubpath(self):
+ foo = DummyContext()
+ root = DummyContext(foo)
+ policy = self._makeOne(root)
+ environ = self._getEnviron()
+ request = DummyRequest(environ, path_info=text_('/foo/bar'))
+ result = policy(request)
+ self.assertEqual(result['context'], foo)
+ self.assertEqual(result['view_name'], 'bar')
+ self.assertEqual(result['subpath'], ())
+ self.assertEqual(result['traversed'], (text_('foo'),))
+ self.assertEqual(result['root'], root)
+ self.assertEqual(result['virtual_root'], root)
+ self.assertEqual(result['virtual_root_path'], ())
+
+ def test_call_withconn_getitem_withpath_withsubpath(self):
+ foo = DummyContext()
+ root = DummyContext(foo)
+ policy = self._makeOne(root)
+ environ = self._getEnviron()
+ request = DummyRequest(environ, path_info=text_('/foo/bar/baz/buz'))
+ result = policy(request)
+ self.assertEqual(result['context'], foo)
+ self.assertEqual(result['view_name'], 'bar')
+ self.assertEqual(result['subpath'], ('baz', 'buz'))
+ self.assertEqual(result['traversed'], (text_('foo'),))
+ self.assertEqual(result['root'], root)
+ self.assertEqual(result['virtual_root'], root)
+ self.assertEqual(result['virtual_root_path'], ())
+
+ def test_call_with_explicit_viewname(self):
+ foo = DummyContext()
+ root = DummyContext(foo)
+ policy = self._makeOne(root)
+ environ = self._getEnviron()
+ request = DummyRequest(environ, path_info=text_('/@@foo'))
+ result = policy(request)
+ self.assertEqual(result['context'], root)
+ self.assertEqual(result['view_name'], 'foo')
+ self.assertEqual(result['subpath'], ())
+ self.assertEqual(result['traversed'], ())
+ self.assertEqual(result['root'], root)
+ self.assertEqual(result['virtual_root'], root)
+ self.assertEqual(result['virtual_root_path'], ())
+
+ def test_call_with_vh_root(self):
+ environ = self._getEnviron(HTTP_X_VHM_ROOT='/foo/bar')
+ baz = DummyContext(None, 'baz')
+ bar = DummyContext(baz, 'bar')
+ foo = DummyContext(bar, 'foo')
+ root = DummyContext(foo, 'root')
+ policy = self._makeOne(root)
+ request = DummyRequest(environ, path_info=text_('/baz'))
+ result = policy(request)
+ self.assertEqual(result['context'], baz)
+ self.assertEqual(result['view_name'], '')
+ self.assertEqual(result['subpath'], ())
+ self.assertEqual(
+ result['traversed'], (text_('foo'), text_('bar'), text_('baz'))
+ )
+ self.assertEqual(result['root'], root)
+ self.assertEqual(result['virtual_root'], bar)
+ self.assertEqual(
+ result['virtual_root_path'], (text_('foo'), text_('bar'))
+ )
+
+ def test_call_with_vh_root2(self):
+ environ = self._getEnviron(HTTP_X_VHM_ROOT='/foo')
+ baz = DummyContext(None, 'baz')
+ bar = DummyContext(baz, 'bar')
+ foo = DummyContext(bar, 'foo')
+ root = DummyContext(foo, 'root')
+ policy = self._makeOne(root)
+ request = DummyRequest(environ, path_info=text_('/bar/baz'))
+ result = policy(request)
+ self.assertEqual(result['context'], baz)
+ self.assertEqual(result['view_name'], '')
+ self.assertEqual(result['subpath'], ())
+ self.assertEqual(
+ result['traversed'], (text_('foo'), text_('bar'), text_('baz'))
+ )
+ self.assertEqual(result['root'], root)
+ self.assertEqual(result['virtual_root'], foo)
+ self.assertEqual(result['virtual_root_path'], (text_('foo'),))
+
+ def test_call_with_vh_root3(self):
+ environ = self._getEnviron(HTTP_X_VHM_ROOT='/')
+ baz = DummyContext()
+ bar = DummyContext(baz)
+ foo = DummyContext(bar)
+ root = DummyContext(foo)
+ policy = self._makeOne(root)
+ request = DummyRequest(environ, path_info=text_('/foo/bar/baz'))
+ result = policy(request)
+ self.assertEqual(result['context'], baz)
+ self.assertEqual(result['view_name'], '')
+ self.assertEqual(result['subpath'], ())
+ self.assertEqual(
+ result['traversed'], (text_('foo'), text_('bar'), text_('baz'))
+ )
+ self.assertEqual(result['root'], root)
+ self.assertEqual(result['virtual_root'], root)
+ self.assertEqual(result['virtual_root_path'], ())
+
+ def test_call_with_vh_root4(self):
+ environ = self._getEnviron(HTTP_X_VHM_ROOT='/foo/bar/baz')
+ baz = DummyContext(None, 'baz')
+ bar = DummyContext(baz, 'bar')
+ foo = DummyContext(bar, 'foo')
+ root = DummyContext(foo, 'root')
+ policy = self._makeOne(root)
+ request = DummyRequest(environ, path_info=text_('/'))
+ result = policy(request)
+ self.assertEqual(result['context'], baz)
+ self.assertEqual(result['view_name'], '')
+ self.assertEqual(result['subpath'], ())
+ self.assertEqual(
+ result['traversed'], (text_('foo'), text_('bar'), text_('baz'))
+ )
+ self.assertEqual(result['root'], root)
+ self.assertEqual(result['virtual_root'], baz)
+ self.assertEqual(
+ result['virtual_root_path'],
+ (text_('foo'), text_('bar'), text_('baz')),
+ )
+
+ def test_call_with_vh_root_path_root(self):
+ policy = self._makeOne(None)
+ environ = self._getEnviron(HTTP_X_VHM_ROOT='/')
+ request = DummyRequest(environ, path_info=text_('/'))
+ result = policy(request)
+ self.assertEqual(result['context'], None)
+ self.assertEqual(result['view_name'], '')
+ self.assertEqual(result['subpath'], ())
+ self.assertEqual(result['traversed'], ())
+ self.assertEqual(result['root'], policy.root)
+ self.assertEqual(result['virtual_root'], policy.root)
+ self.assertEqual(result['virtual_root_path'], ())
+
+ def test_call_with_vh_root_highorder(self):
+ path = text_(b'Qu\xc3\xa9bec', 'utf-8')
+ bar = DummyContext(None, 'bar')
+ foo = DummyContext(bar, path)
+ root = DummyContext(foo, 'root')
+ policy = self._makeOne(root)
+ if PY2:
+ vhm_root = b'/Qu\xc3\xa9bec'
+ else:
+ vhm_root = b'/Qu\xc3\xa9bec'.decode('latin-1')
+ environ = self._getEnviron(HTTP_X_VHM_ROOT=vhm_root)
+ request = DummyRequest(environ, path_info=text_('/bar'))
+ result = policy(request)
+ self.assertEqual(result['context'], bar)
+ self.assertEqual(result['view_name'], '')
+ self.assertEqual(result['subpath'], ())
+ self.assertEqual(result['traversed'], (path, text_('bar')))
+ self.assertEqual(result['root'], policy.root)
+ self.assertEqual(result['virtual_root'], foo)
+ self.assertEqual(result['virtual_root_path'], (path,))
+
+ def test_path_info_raises_unicodedecodeerror(self):
+ from pyramid.exceptions import URLDecodeError
+
+ foo = DummyContext()
+ root = DummyContext(foo)
+ policy = self._makeOne(root)
+ environ = self._getEnviron()
+ toraise = UnicodeDecodeError('ascii', b'a', 2, 3, '5')
+ request = DummyRequest(environ, toraise=toraise)
+ request.matchdict = None
+ self.assertRaises(URLDecodeError, policy, request)
+
+ def test_withroute_nothingfancy(self):
+ resource = DummyContext()
+ traverser = self._makeOne(resource)
+ request = DummyRequest({})
+ request.matchdict = {}
+ result = traverser(request)
+ self.assertEqual(result['context'], resource)
+ self.assertEqual(result['view_name'], '')
+ self.assertEqual(result['subpath'], ())
+ self.assertEqual(result['traversed'], ())
+ self.assertEqual(result['root'], resource)
+ self.assertEqual(result['virtual_root'], resource)
+ self.assertEqual(result['virtual_root_path'], ())
+
+ def test_withroute_with_subpath_string(self):
+ resource = DummyContext()
+ traverser = self._makeOne(resource)
+ matchdict = {'subpath': '/a/b/c'}
+ request = DummyRequest({})
+ request.matchdict = matchdict
+ result = traverser(request)
+ self.assertEqual(result['context'], resource)
+ self.assertEqual(result['view_name'], '')
+ self.assertEqual(result['subpath'], ('a', 'b', 'c'))
+ self.assertEqual(result['traversed'], ())
+ self.assertEqual(result['root'], resource)
+ self.assertEqual(result['virtual_root'], resource)
+ self.assertEqual(result['virtual_root_path'], ())
+
+ def test_withroute_with_subpath_tuple(self):
+ resource = DummyContext()
+ traverser = self._makeOne(resource)
+ matchdict = {'subpath': ('a', 'b', 'c')}
+ request = DummyRequest({})
+ request.matchdict = matchdict
+ result = traverser(request)
+ self.assertEqual(result['context'], resource)
+ self.assertEqual(result['view_name'], '')
+ self.assertEqual(result['subpath'], ('a', 'b', 'c'))
+ self.assertEqual(result['traversed'], ())
+ self.assertEqual(result['root'], resource)
+ self.assertEqual(result['virtual_root'], resource)
+ self.assertEqual(result['virtual_root_path'], ())
+
+ def test_withroute_and_traverse_string(self):
+ resource = DummyContext()
+ traverser = self._makeOne(resource)
+ matchdict = {'traverse': text_('foo/bar')}
+ request = DummyRequest({})
+ request.matchdict = matchdict
+ result = traverser(request)
+ self.assertEqual(result['context'], resource)
+ self.assertEqual(result['view_name'], 'foo')
+ self.assertEqual(result['subpath'], ('bar',))
+ self.assertEqual(result['traversed'], ())
+ self.assertEqual(result['root'], resource)
+ self.assertEqual(result['virtual_root'], resource)
+ self.assertEqual(result['virtual_root_path'], ())
+
+ def test_withroute_and_traverse_tuple(self):
+ resource = DummyContext()
+ traverser = self._makeOne(resource)
+ matchdict = {'traverse': ('foo', 'bar')}
+ request = DummyRequest({})
+ request.matchdict = matchdict
+ result = traverser(request)
+ self.assertEqual(result['context'], resource)
+ self.assertEqual(result['view_name'], 'foo')
+ self.assertEqual(result['subpath'], ('bar',))
+ self.assertEqual(result['traversed'], ())
+ self.assertEqual(result['root'], resource)
+ self.assertEqual(result['virtual_root'], resource)
+ self.assertEqual(result['virtual_root_path'], ())
+
+ def test_withroute_and_traverse_empty(self):
+ resource = DummyContext()
+ traverser = self._makeOne(resource)
+ matchdict = {'traverse': ''}
+ request = DummyRequest({})
+ request.matchdict = matchdict
+ result = traverser(request)
+ self.assertEqual(result['context'], resource)
+ self.assertEqual(result['view_name'], '')
+ self.assertEqual(result['subpath'], ())
+ self.assertEqual(result['traversed'], ())
+ self.assertEqual(result['root'], resource)
+ self.assertEqual(result['virtual_root'], resource)
+ self.assertEqual(result['virtual_root_path'], ())
+
+ def test_withroute_and_traverse_and_vroot(self):
+ abc = DummyContext()
+ resource = DummyContext(next=abc)
+ environ = self._getEnviron(HTTP_X_VHM_ROOT='/abc')
+ request = DummyRequest(environ)
+ traverser = self._makeOne(resource)
+ matchdict = {'traverse': text_('/foo/bar')}
+ request.matchdict = matchdict
+ result = traverser(request)
+ self.assertEqual(result['context'], abc)
+ self.assertEqual(result['view_name'], 'foo')
+ self.assertEqual(result['subpath'], ('bar',))
+ self.assertEqual(result['traversed'], ('abc', 'foo'))
+ self.assertEqual(result['root'], resource)
+ self.assertEqual(result['virtual_root'], abc)
+ self.assertEqual(result['virtual_root_path'], ('abc',))
+
+
+class FindInterfaceTests(unittest.TestCase):
+ def _callFUT(self, context, iface):
+ from pyramid.traversal import find_interface
+
+ return find_interface(context, iface)
+
+ def test_it_interface(self):
+ baz = DummyContext()
+ bar = DummyContext(baz)
+ foo = DummyContext(bar)
+ root = DummyContext(foo)
+ root.__parent__ = None
+ root.__name__ = 'root'
+ foo.__parent__ = root
+ foo.__name__ = 'foo'
+ bar.__parent__ = foo
+ bar.__name__ = 'bar'
+ baz.__parent__ = bar
+ baz.__name__ = 'baz'
+ from zope.interface import directlyProvides
+ from zope.interface import Interface
+
+ class IFoo(Interface):
+ pass
+
+ directlyProvides(root, IFoo)
+ result = self._callFUT(baz, IFoo)
+ self.assertEqual(result.__name__, 'root')
+
+ def test_it_class(self):
+ class DummyRoot(object):
+ def __init__(self, child):
+ self.child = child
+
+ baz = DummyContext()
+ bar = DummyContext(baz)
+ foo = DummyContext(bar)
+ root = DummyRoot(foo)
+ root.__parent__ = None
+ root.__name__ = 'root'
+ foo.__parent__ = root
+ foo.__name__ = 'foo'
+ bar.__parent__ = foo
+ bar.__name__ = 'bar'
+ baz.__parent__ = bar
+ baz.__name__ = 'baz'
+ result = self._callFUT(baz, DummyRoot)
+ self.assertEqual(result.__name__, 'root')
+
+
+class FindRootTests(unittest.TestCase):
+ def _callFUT(self, context):
+ from pyramid.traversal import find_root
+
+ return find_root(context)
+
+ def test_it(self):
+ dummy = DummyContext()
+ baz = DummyContext()
+ baz.__parent__ = dummy
+ baz.__name__ = 'baz'
+ dummy.__parent__ = None
+ dummy.__name__ = None
+ result = self._callFUT(baz)
+ self.assertEqual(result, dummy)
+
+
+class FindResourceTests(unittest.TestCase):
+ def _callFUT(self, context, name):
+ from pyramid.traversal import find_resource
+
+ return find_resource(context, name)
+
+ def _registerTraverser(self, traverser):
+ from pyramid.threadlocal import get_current_registry
+
+ reg = get_current_registry()
+ from pyramid.interfaces import ITraverser
+ from zope.interface import Interface
+
+ reg.registerAdapter(traverser, (Interface,), ITraverser)
+
+ def test_list(self):
+ resource = DummyContext()
+ traverser = make_traverser({'context': resource, 'view_name': ''})
+ self._registerTraverser(traverser)
+ result = self._callFUT(resource, [''])
+ self.assertEqual(result, resource)
+ self.assertEqual(resource.request.environ['PATH_INFO'], '/')
+
+ def test_generator(self):
+ resource = DummyContext()
+ traverser = make_traverser({'context': resource, 'view_name': ''})
+ self._registerTraverser(traverser)
+
+ def foo():
+ yield ''
+
+ result = self._callFUT(resource, foo())
+ self.assertEqual(result, resource)
+ self.assertEqual(resource.request.environ['PATH_INFO'], '/')
+
+ def test_self_string_found(self):
+ resource = DummyContext()
+ traverser = make_traverser({'context': resource, 'view_name': ''})
+ self._registerTraverser(traverser)
+ result = self._callFUT(resource, '')
+ self.assertEqual(result, resource)
+ self.assertEqual(resource.request.environ['PATH_INFO'], '')
+
+ def test_self_tuple_found(self):
+ resource = DummyContext()
+ traverser = make_traverser({'context': resource, 'view_name': ''})
+ self._registerTraverser(traverser)
+ result = self._callFUT(resource, ())
+ self.assertEqual(result, resource)
+ self.assertEqual(resource.request.environ['PATH_INFO'], '')
+
+ def test_relative_string_found(self):
+ resource = DummyContext()
+ baz = DummyContext()
+ traverser = make_traverser({'context': baz, 'view_name': ''})
+ self._registerTraverser(traverser)
+ result = self._callFUT(resource, 'baz')
+ self.assertEqual(result, baz)
+ self.assertEqual(resource.request.environ['PATH_INFO'], 'baz')
+
+ def test_relative_tuple_found(self):
+ resource = DummyContext()
+ baz = DummyContext()
+ traverser = make_traverser({'context': baz, 'view_name': ''})
+ self._registerTraverser(traverser)
+ result = self._callFUT(resource, ('baz',))
+ self.assertEqual(result, baz)
+ self.assertEqual(resource.request.environ['PATH_INFO'], 'baz')
+
+ def test_relative_string_notfound(self):
+ resource = DummyContext()
+ baz = DummyContext()
+ traverser = make_traverser({'context': baz, 'view_name': 'bar'})
+ self._registerTraverser(traverser)
+ self.assertRaises(KeyError, self._callFUT, resource, 'baz')
+ self.assertEqual(resource.request.environ['PATH_INFO'], 'baz')
+
+ def test_relative_tuple_notfound(self):
+ resource = DummyContext()
+ baz = DummyContext()
+ traverser = make_traverser({'context': baz, 'view_name': 'bar'})
+ self._registerTraverser(traverser)
+ self.assertRaises(KeyError, self._callFUT, resource, ('baz',))
+ self.assertEqual(resource.request.environ['PATH_INFO'], 'baz')
+
+ def test_absolute_string_found(self):
+ root = DummyContext()
+ resource = DummyContext()
+ resource.__parent__ = root
+ resource.__name__ = 'baz'
+ traverser = make_traverser({'context': root, 'view_name': ''})
+ self._registerTraverser(traverser)
+ result = self._callFUT(resource, '/')
+ self.assertEqual(result, root)
+ self.assertEqual(root.wascontext, True)
+ self.assertEqual(root.request.environ['PATH_INFO'], '/')
+
+ def test_absolute_tuple_found(self):
+ root = DummyContext()
+ resource = DummyContext()
+ resource.__parent__ = root
+ resource.__name__ = 'baz'
+ traverser = make_traverser({'context': root, 'view_name': ''})
+ self._registerTraverser(traverser)
+ result = self._callFUT(resource, ('',))
+ self.assertEqual(result, root)
+ self.assertEqual(root.wascontext, True)
+ self.assertEqual(root.request.environ['PATH_INFO'], '/')
+
+ def test_absolute_string_notfound(self):
+ root = DummyContext()
+ resource = DummyContext()
+ resource.__parent__ = root
+ resource.__name__ = 'baz'
+ traverser = make_traverser({'context': root, 'view_name': 'fuz'})
+ self._registerTraverser(traverser)
+ self.assertRaises(KeyError, self._callFUT, resource, '/')
+ self.assertEqual(root.wascontext, True)
+ self.assertEqual(root.request.environ['PATH_INFO'], '/')
+
+ def test_absolute_tuple_notfound(self):
+ root = DummyContext()
+ resource = DummyContext()
+ resource.__parent__ = root
+ resource.__name__ = 'baz'
+ traverser = make_traverser({'context': root, 'view_name': 'fuz'})
+ self._registerTraverser(traverser)
+ self.assertRaises(KeyError, self._callFUT, resource, ('',))
+ self.assertEqual(root.wascontext, True)
+ self.assertEqual(root.request.environ['PATH_INFO'], '/')
+
+ def test_absolute_unicode_found(self):
+ # test for bug wiggy found in wild, traceback stack:
+ # root = u'/%E6%B5%81%E8%A1%8C%E8%B6%8B%E5%8A%BF'
+ # wiggy's code: section=find_resource(page, root)
+ # find_resource L76: D = traverse(resource, path)
+ # traverse L291: return traverser(request)
+ # __call__ line 568: vpath_tuple = traversal_path(vpath)
+ # lru_cached line 91: f(*arg)
+ # traversal_path line 443: path.encode('ascii')
+ # UnicodeEncodeError: 'ascii' codec can't encode characters in
+ # position 1-12: ordinal not in range(128)
+ #
+ # solution: encode string to ascii in pyramid.traversal.traverse
+ # before passing it along to webob as path_info
+ from pyramid.traversal import ResourceTreeTraverser
+
+ unprintable = DummyContext()
+ root = DummyContext(unprintable)
+ unprintable.__parent__ = root
+ unprintable.__name__ = text_(
+ b'/\xe6\xb5\x81\xe8\xa1\x8c\xe8\xb6\x8b\xe5\x8a\xbf', 'utf-8'
+ )
+ root.__parent__ = None
+ root.__name__ = None
+ traverser = ResourceTreeTraverser
+ self._registerTraverser(traverser)
+ result = self._callFUT(
+ root, text_(b'/%E6%B5%81%E8%A1%8C%E8%B6%8B%E5%8A%BF')
+ )
+ self.assertEqual(result, unprintable)
+
+
+class ResourcePathTests(unittest.TestCase):
+ def _callFUT(self, resource, *elements):
+ from pyramid.traversal import resource_path
+
+ return resource_path(resource, *elements)
+
+ def test_it(self):
+ baz = DummyContext()
+ bar = DummyContext(baz)
+ foo = DummyContext(bar)
+ root = DummyContext(foo)
+ root.__parent__ = None
+ root.__name__ = None
+ foo.__parent__ = root
+ foo.__name__ = 'foo '
+ bar.__parent__ = foo
+ bar.__name__ = 'bar'
+ baz.__parent__ = bar
+ baz.__name__ = 'baz'
+ result = self._callFUT(baz, 'this/theotherthing', 'that')
+ self.assertEqual(result, '/foo%20/bar/baz/this%2Ftheotherthing/that')
+
+ def test_root_default(self):
+ root = DummyContext()
+ root.__parent__ = None
+ root.__name__ = None
+ result = self._callFUT(root)
+ self.assertEqual(result, '/')
+
+ def test_root_default_emptystring(self):
+ root = DummyContext()
+ root.__parent__ = None
+ root.__name__ = ''
+ result = self._callFUT(root)
+ self.assertEqual(result, '/')
+
+ def test_root_object_nonnull_name_direct(self):
+ root = DummyContext()
+ root.__parent__ = None
+ root.__name__ = 'flubadub'
+ result = self._callFUT(root)
+ self.assertEqual(result, 'flubadub') # insane case
+
+ def test_root_object_nonnull_name_indirect(self):
+ root = DummyContext()
+ root.__parent__ = None
+ root.__name__ = 'flubadub'
+ other = DummyContext()
+ other.__parent__ = root
+ other.__name__ = 'barker'
+ result = self._callFUT(other)
+ self.assertEqual(result, 'flubadub/barker') # insane case
+
+ def test_nonroot_default(self):
+ root = DummyContext()
+ root.__parent__ = None
+ root.__name__ = None
+ other = DummyContext()
+ other.__parent__ = root
+ other.__name__ = 'other'
+ result = self._callFUT(other)
+ self.assertEqual(result, '/other')
+
+ def test_path_with_None_itermediate_names(self):
+ root = DummyContext()
+ root.__parent__ = None
+ root.__name__ = None
+ other = DummyContext()
+ other.__parent__ = root
+ other.__name__ = None
+ other2 = DummyContext()
+ other2.__parent__ = other
+ other2.__name__ = 'other2'
+ result = self._callFUT(other2)
+ self.assertEqual(result, '//other2')
+
+
+class ResourcePathTupleTests(unittest.TestCase):
+ def _callFUT(self, resource, *elements):
+ from pyramid.traversal import resource_path_tuple
+
+ return resource_path_tuple(resource, *elements)
+
+ def test_it(self):
+ baz = DummyContext()
+ bar = DummyContext(baz)
+ foo = DummyContext(bar)
+ root = DummyContext(foo)
+ root.__parent__ = None
+ root.__name__ = None
+ foo.__parent__ = root
+ foo.__name__ = 'foo '
+ bar.__parent__ = foo
+ bar.__name__ = 'bar'
+ baz.__parent__ = bar
+ baz.__name__ = 'baz'
+ result = self._callFUT(baz, 'this/theotherthing', 'that')
+ self.assertEqual(
+ result, ('', 'foo ', 'bar', 'baz', 'this/theotherthing', 'that')
+ )
+
+ def test_root_default(self):
+ root = DummyContext()
+ root.__parent__ = None
+ root.__name__ = None
+ result = self._callFUT(root)
+ self.assertEqual(result, ('',))
+
+ def test_root_default_emptystring_name(self):
+ root = DummyContext()
+ root.__parent__ = None
+ root.__name__ = ''
+ other = DummyContext()
+ other.__parent__ = root
+ other.__name__ = 'other'
+ result = self._callFUT(other)
+ self.assertEqual(result, ('', 'other'))
+
+ def test_nonroot_default(self):
+ root = DummyContext()
+ root.__parent__ = None
+ root.__name__ = None
+ other = DummyContext()
+ other.__parent__ = root
+ other.__name__ = 'other'
+ result = self._callFUT(other)
+ self.assertEqual(result, ('', 'other'))
+
+ def test_path_with_None_itermediate_names(self):
+ root = DummyContext()
+ root.__parent__ = None
+ root.__name__ = None
+ other = DummyContext()
+ other.__parent__ = root
+ other.__name__ = None
+ other2 = DummyContext()
+ other2.__parent__ = other
+ other2.__name__ = 'other2'
+ result = self._callFUT(other2)
+ self.assertEqual(result, ('', '', 'other2'))
+
+
+class QuotePathSegmentTests(unittest.TestCase):
+ def _callFUT(self, s):
+ from pyramid.traversal import quote_path_segment
+
+ return quote_path_segment(s)
+
+ def test_unicode(self):
+ la = text_(b'/La Pe\xc3\xb1a', 'utf-8')
+ result = self._callFUT(la)
+ self.assertEqual(result, '%2FLa%20Pe%C3%B1a')
+
+ def test_string(self):
+ s = '/ hello!'
+ result = self._callFUT(s)
+ self.assertEqual(result, '%2F%20hello!')
+
+ def test_int(self):
+ s = 12345
+ result = self._callFUT(s)
+ self.assertEqual(result, '12345')
+
+ def test_long(self):
+ from pyramid.compat import long
+ import sys
+
+ s = long(sys.maxsize + 1)
+ result = self._callFUT(s)
+ expected = str(s)
+ self.assertEqual(result, expected)
+
+ def test_other(self):
+ class Foo(object):
+ def __str__(self):
+ return 'abc'
+
+ s = Foo()
+ result = self._callFUT(s)
+ self.assertEqual(result, 'abc')
+
+
+class ResourceURLTests(unittest.TestCase):
+ def _makeOne(self, context, url):
+ return self._getTargetClass()(context, url)
+
+ def _getTargetClass(self):
+ from pyramid.traversal import ResourceURL
+
+ return ResourceURL
+
+ def test_instance_conforms_to_IResourceURL(self):
+ from pyramid.interfaces import IResourceURL
+ from zope.interface.verify import verifyObject
+
+ context = DummyContext()
+ request = DummyRequest()
+ verifyObject(IResourceURL, self._makeOne(context, request))
+
+ def test_IResourceURL_attributes_with_vroot(self):
+ from pyramid.interfaces import VH_ROOT_KEY
+
+ root = DummyContext()
+ root.__parent__ = None
+ root.__name__ = None
+ one = DummyContext()
+ one.__parent__ = root
+ one.__name__ = 'one'
+ two = DummyContext()
+ two.__parent__ = one
+ two.__name__ = 'two'
+ environ = {VH_ROOT_KEY: '/one'}
+ request = DummyRequest(environ)
+ context_url = self._makeOne(two, request)
+ self.assertEqual(context_url.physical_path, '/one/two/')
+ self.assertEqual(context_url.virtual_path, '/two/')
+ self.assertEqual(
+ context_url.physical_path_tuple, ('', 'one', 'two', '')
+ )
+ self.assertEqual(context_url.virtual_path_tuple, ('', 'two', ''))
+
+ def test_IResourceURL_attributes_vroot_ends_with_slash(self):
+ from pyramid.interfaces import VH_ROOT_KEY
+
+ root = DummyContext()
+ root.__parent__ = None
+ root.__name__ = None
+ one = DummyContext()
+ one.__parent__ = root
+ one.__name__ = 'one'
+ two = DummyContext()
+ two.__parent__ = one
+ two.__name__ = 'two'
+ environ = {VH_ROOT_KEY: '/one/'}
+ request = DummyRequest(environ)
+ context_url = self._makeOne(two, request)
+ self.assertEqual(context_url.physical_path, '/one/two/')
+ self.assertEqual(context_url.virtual_path, '/two/')
+ self.assertEqual(
+ context_url.physical_path_tuple, ('', 'one', 'two', '')
+ )
+ self.assertEqual(context_url.virtual_path_tuple, ('', 'two', ''))
+
+ def test_IResourceURL_attributes_no_vroot(self):
+ root = DummyContext()
+ root.__parent__ = None
+ root.__name__ = None
+ one = DummyContext()
+ one.__parent__ = root
+ one.__name__ = 'one'
+ two = DummyContext()
+ two.__parent__ = one
+ two.__name__ = 'two'
+ environ = {}
+ request = DummyRequest(environ)
+ context_url = self._makeOne(two, request)
+ self.assertEqual(context_url.physical_path, '/one/two/')
+ self.assertEqual(context_url.virtual_path, '/one/two/')
+ self.assertEqual(
+ context_url.physical_path_tuple, ('', 'one', 'two', '')
+ )
+ self.assertEqual(
+ context_url.virtual_path_tuple, ('', 'one', 'two', '')
+ )
+
+
+class TestVirtualRoot(unittest.TestCase):
+ def setUp(self):
+ cleanUp()
+
+ def tearDown(self):
+ cleanUp()
+
+ def _callFUT(self, resource, request):
+ from pyramid.traversal import virtual_root
+
+ return virtual_root(resource, request)
+
+ def _registerTraverser(self, traverser):
+ from pyramid.threadlocal import get_current_registry
+
+ reg = get_current_registry()
+ from pyramid.interfaces import ITraverser
+ from zope.interface import Interface
+
+ reg.registerAdapter(traverser, (Interface,), ITraverser)
+
+ def test_virtual_root_no_virtual_root_path(self):
+ root = DummyContext()
+ root.__name__ = None
+ root.__parent__ = None
+ one = DummyContext()
+ one.__name__ = 'one'
+ one.__parent__ = root
+ request = DummyRequest()
+ result = self._callFUT(one, request)
+ self.assertEqual(result, root)
+
+ def test_virtual_root_no_virtual_root_path_with_root_on_request(self):
+ context = DummyContext()
+ context.__parent__ = None
+ request = DummyRequest()
+ request.root = DummyContext()
+ result = self._callFUT(context, request)
+ self.assertEqual(result, request.root)
+
+ def test_virtual_root_with_virtual_root_path(self):
+ from pyramid.interfaces import VH_ROOT_KEY
+
+ root = DummyContext()
+ root.__parent__ = None
+ context = DummyContext()
+ context.__name__ = 'one'
+ context.__parent__ = root
+ traversed_to = DummyContext()
+ environ = {VH_ROOT_KEY: '/one'}
+ request = DummyRequest(environ)
+ traverser = make_traverser({'context': traversed_to, 'view_name': ''})
+ self._registerTraverser(traverser)
+ result = self._callFUT(context, request)
+ self.assertEqual(result, traversed_to)
+ self.assertEqual(root.request.environ['PATH_INFO'], '/one')
+
+ def test_default(self):
+ context = DummyContext()
+ request = _makeRequest()
+ request.environ['PATH_INFO'] = '/'
+ result = self._callFUT(context, request)
+ self.assertEqual(result, context)
+
+ def test_default_no_registry_on_request(self):
+ context = DummyContext()
+ request = _makeRequest()
+ del request.registry
+ request.environ['PATH_INFO'] = '/'
+ result = self._callFUT(context, request)
+ self.assertEqual(result, context)
+
+
+class TraverseTests(unittest.TestCase):
+ def setUp(self):
+ cleanUp()
+
+ def tearDown(self):
+ cleanUp()
+
+ def _callFUT(self, context, name):
+ from pyramid.traversal import traverse
+
+ return traverse(context, name)
+
+ def _registerTraverser(self, traverser):
+ from pyramid.threadlocal import get_current_registry
+
+ reg = get_current_registry()
+ from pyramid.interfaces import ITraverser
+ from zope.interface import Interface
+
+ reg.registerAdapter(traverser, (Interface,), ITraverser)
+
+ def test_request_has_registry(self):
+ from pyramid.threadlocal import get_current_registry
+
+ resource = DummyContext()
+ traverser = make_traverser({'context': resource, 'view_name': ''})
+ self._registerTraverser(traverser)
+ self._callFUT(resource, [''])
+ self.assertEqual(resource.request.registry, get_current_registry())
+
+ def test_list(self):
+ resource = DummyContext()
+ traverser = make_traverser({'context': resource, 'view_name': ''})
+ self._registerTraverser(traverser)
+ self._callFUT(resource, [''])
+ self.assertEqual(resource.request.environ['PATH_INFO'], '/')
+
+ def test_generator(self):
+ resource = DummyContext()
+ traverser = make_traverser({'context': resource, 'view_name': ''})
+ self._registerTraverser(traverser)
+
+ def foo():
+ yield ''
+
+ self._callFUT(resource, foo())
+ self.assertEqual(resource.request.environ['PATH_INFO'], '/')
+
+ def test_self_string_found(self):
+ resource = DummyContext()
+ traverser = make_traverser({'context': resource, 'view_name': ''})
+ self._registerTraverser(traverser)
+ self._callFUT(resource, '')
+ self.assertEqual(resource.request.environ['PATH_INFO'], '')
+
+ def test_self_unicode_found(self):
+ resource = DummyContext()
+ traverser = make_traverser({'context': resource, 'view_name': ''})
+ self._registerTraverser(traverser)
+ self._callFUT(resource, text_(''))
+ self.assertEqual(resource.request.environ['PATH_INFO'], '')
+
+ def test_self_tuple_found(self):
+ resource = DummyContext()
+ traverser = make_traverser({'context': resource, 'view_name': ''})
+ self._registerTraverser(traverser)
+ self._callFUT(resource, ())
+ self.assertEqual(resource.request.environ['PATH_INFO'], '')
+
+ def test_relative_string_found(self):
+ resource = DummyContext()
+ baz = DummyContext()
+ traverser = make_traverser({'context': baz, 'view_name': ''})
+ self._registerTraverser(traverser)
+ self._callFUT(resource, 'baz')
+ self.assertEqual(resource.request.environ['PATH_INFO'], 'baz')
+
+ def test_relative_tuple_found(self):
+ resource = DummyContext()
+ baz = DummyContext()
+ traverser = make_traverser({'context': baz, 'view_name': ''})
+ self._registerTraverser(traverser)
+ self._callFUT(resource, ('baz',))
+ self.assertEqual(resource.request.environ['PATH_INFO'], 'baz')
+
+ def test_absolute_string_found(self):
+ root = DummyContext()
+ resource = DummyContext()
+ resource.__parent__ = root
+ resource.__name__ = 'baz'
+ traverser = make_traverser({'context': root, 'view_name': ''})
+ self._registerTraverser(traverser)
+ self._callFUT(resource, '/')
+ self.assertEqual(root.wascontext, True)
+ self.assertEqual(root.request.environ['PATH_INFO'], '/')
+
+ def test_absolute_tuple_found(self):
+ root = DummyContext()
+ resource = DummyContext()
+ resource.__parent__ = root
+ resource.__name__ = 'baz'
+ traverser = make_traverser({'context': root, 'view_name': ''})
+ self._registerTraverser(traverser)
+ self._callFUT(resource, ('',))
+ self.assertEqual(root.wascontext, True)
+ self.assertEqual(root.request.environ['PATH_INFO'], '/')
+
+ def test_empty_sequence(self):
+ root = DummyContext()
+ resource = DummyContext()
+ resource.__parent__ = root
+ resource.__name__ = 'baz'
+ traverser = make_traverser({'context': root, 'view_name': ''})
+ self._registerTraverser(traverser)
+ self._callFUT(resource, [])
+ self.assertEqual(resource.wascontext, True)
+ self.assertEqual(resource.request.environ['PATH_INFO'], '')
+
+ def test_default_traverser(self):
+ resource = DummyContext()
+ result = self._callFUT(resource, '')
+ self.assertEqual(result['view_name'], '')
+ self.assertEqual(result['context'], resource)
+
+ def test_requestfactory_overridden(self):
+ from pyramid.interfaces import IRequestFactory
+ from pyramid.request import Request
+ from pyramid.threadlocal import get_current_registry
+
+ reg = get_current_registry()
+
+ class MyRequest(Request):
+ pass
+
+ reg.registerUtility(MyRequest, IRequestFactory)
+ resource = DummyContext()
+ traverser = make_traverser({'context': resource, 'view_name': ''})
+ self._registerTraverser(traverser)
+ self._callFUT(resource, [''])
+ self.assertEqual(resource.request.__class__, MyRequest)
+
+
+class TestDefaultRootFactory(unittest.TestCase):
+ def _getTargetClass(self):
+ from pyramid.traversal import DefaultRootFactory
+
+ return DefaultRootFactory
+
+ def _makeOne(self, environ):
+ return self._getTargetClass()(environ)
+
+ def test_it(self):
+ class DummyRequest(object):
+ pass
+
+ root = self._makeOne(DummyRequest())
+ self.assertEqual(root.__parent__, None)
+ self.assertEqual(root.__name__, None)
+
+
+class Test__join_path_tuple(unittest.TestCase):
+ def _callFUT(self, tup):
+ from pyramid.traversal import _join_path_tuple
+
+ return _join_path_tuple(tup)
+
+ def test_empty_tuple(self):
+ # tests "or '/'" case
+ result = self._callFUT(())
+ self.assertEqual(result, '/')
+
+ def test_nonempty_tuple(self):
+ result = self._callFUT(('x',))
+ self.assertEqual(result, 'x')
+
+ def test_segments_with_unsafes(self):
+ safe_segments = tuple(
+ u"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
+ u"-._~!$&'()*+,;=:@"
+ )
+ result = self._callFUT(safe_segments)
+ self.assertEqual(result, u'/'.join(safe_segments))
+ unsafe_segments = tuple(
+ chr(i) for i in range(0x20, 0x80) if not chr(i) in safe_segments
+ ) + (u'あ',)
+ result = self._callFUT(unsafe_segments)
+ self.assertEqual(
+ result,
+ u'/'.join(
+ ''.join(
+ '%%%02X' % (ord(c) if isinstance(c, str) else c)
+ for c in unsafe_segment.encode('utf-8')
+ )
+ for unsafe_segment in unsafe_segments
+ ),
+ )
+
+
+def make_traverser(result):
+ class DummyTraverser(object):
+ def __init__(self, context):
+ self.context = context
+ context.wascontext = True
+
+ def __call__(self, request):
+ self.context.request = request
+ return result
+
+ return DummyTraverser
+
+
+class DummyContext(object):
+ __parent__ = None
+
+ def __init__(self, next=None, name=None):
+ self.next = next
+ self.__name__ = name
+
+ def __getitem__(self, name):
+ if self.next is None:
+ raise KeyError(name)
+ return self.next
+
+ def __repr__(self):
+ return '<DummyContext with name %s at id %s>' % (
+ self.__name__,
+ id(self),
+ )
+
+
+class DummyRequest:
+
+ application_url = (
+ 'http://example.com:5432'
+ ) # app_url never ends with slash
+ matchdict = None
+ matched_route = None
+
+ def __init__(self, environ=None, path_info=text_('/'), toraise=None):
+ if environ is None:
+ environ = {}
+ self.environ = environ
+ self._set_path_info(path_info)
+ self.toraise = toraise
+
+ def _get_path_info(self):
+ if self.toraise:
+ raise self.toraise
+ return self._path_info
+
+ def _set_path_info(self, v):
+ self._path_info = v
+
+ path_info = property(_get_path_info, _set_path_info)
+
+
+def _makeRequest(environ=None):
+ from pyramid.registry import Registry
+
+ request = DummyRequest()
+ request.registry = Registry()
+ return request
diff --git a/tests/test_tweens.py b/tests/test_tweens.py
new file mode 100644
index 000000000..054f4360d
--- /dev/null
+++ b/tests/test_tweens.py
@@ -0,0 +1,108 @@
+import unittest
+from pyramid import testing
+
+
+class Test_excview_tween_factory(unittest.TestCase):
+ def setUp(self):
+ self.config = testing.setUp()
+
+ def tearDown(self):
+ testing.tearDown()
+
+ def _makeOne(self, handler, registry=None):
+ from pyramid.tweens import excview_tween_factory
+
+ if registry is None:
+ registry = self.config.registry
+ return excview_tween_factory(handler, registry)
+
+ def test_it_passthrough_no_exception(self):
+ dummy_response = DummyResponse()
+
+ def handler(request):
+ return dummy_response
+
+ tween = self._makeOne(handler)
+ request = DummyRequest()
+ result = tween(request)
+ self.assertTrue(result is dummy_response)
+ self.assertIsNone(request.exception)
+ self.assertIsNone(request.exc_info)
+
+ def test_it_catches_notfound(self):
+ from pyramid.request import Request
+ from pyramid.httpexceptions import HTTPNotFound
+
+ self.config.add_notfound_view(lambda exc, request: exc)
+
+ def handler(request):
+ raise HTTPNotFound
+
+ tween = self._makeOne(handler)
+ request = Request.blank('/')
+ request.registry = self.config.registry
+ result = tween(request)
+ self.assertEqual(result.status, '404 Not Found')
+ self.assertIsInstance(request.exception, HTTPNotFound)
+ self.assertEqual(request.exception, request.exc_info[1])
+
+ def test_it_catches_with_predicate(self):
+ from pyramid.request import Request
+ from pyramid.response import Response
+
+ def excview(request):
+ return Response('foo')
+
+ self.config.add_view(excview, context=ValueError, request_method='GET')
+
+ def handler(request):
+ raise ValueError
+
+ tween = self._makeOne(handler)
+ request = Request.blank('/')
+ request.registry = self.config.registry
+ result = tween(request)
+ self.assertTrue(b'foo' in result.body)
+ self.assertIsInstance(request.exception, ValueError)
+ self.assertEqual(request.exception, request.exc_info[1])
+
+ def test_it_reraises_on_mismatch(self):
+ from pyramid.request import Request
+
+ def excview(request): # pragma: no cover
+ pass
+
+ self.config.add_view(excview, context=ValueError, request_method='GET')
+
+ def handler(request):
+ raise ValueError
+
+ tween = self._makeOne(handler)
+ request = Request.blank('/')
+ request.registry = self.config.registry
+ request.method = 'POST'
+ self.assertRaises(ValueError, lambda: tween(request))
+ self.assertIsNone(request.exception)
+ self.assertIsNone(request.exc_info)
+
+ def test_it_reraises_on_no_match(self):
+ from pyramid.request import Request
+
+ def handler(request):
+ raise ValueError
+
+ tween = self._makeOne(handler)
+ request = Request.blank('/')
+ request.registry = self.config.registry
+ self.assertRaises(ValueError, lambda: tween(request))
+ self.assertIsNone(request.exception)
+ self.assertIsNone(request.exc_info)
+
+
+class DummyRequest:
+ exception = None
+ exc_info = None
+
+
+class DummyResponse:
+ pass
diff --git a/tests/test_url.py b/tests/test_url.py
new file mode 100644
index 000000000..94a0a61c9
--- /dev/null
+++ b/tests/test_url.py
@@ -0,0 +1,1453 @@
+import os
+import unittest
+
+from pyramid import testing
+
+from pyramid.compat import text_, WIN
+
+
+class TestURLMethodsMixin(unittest.TestCase):
+ def setUp(self):
+ self.config = testing.setUp()
+
+ def tearDown(self):
+ testing.tearDown()
+
+ def _makeOne(self, environ=None):
+ from pyramid.url import URLMethodsMixin
+
+ if environ is None:
+ environ = {}
+
+ class Request(URLMethodsMixin):
+ application_url = 'http://example.com:5432'
+ script_name = ''
+
+ def __init__(self, environ):
+ self.environ = environ
+
+ request = Request(environ)
+ request.registry = self.config.registry
+ return request
+
+ def _registerResourceURL(self, reg):
+ from pyramid.interfaces import IResourceURL
+ from zope.interface import Interface
+
+ class DummyResourceURL(object):
+ physical_path = '/context/'
+ virtual_path = '/context/'
+
+ def __init__(self, context, request):
+ pass
+
+ reg.registerAdapter(
+ DummyResourceURL, (Interface, Interface), IResourceURL
+ )
+ return DummyResourceURL
+
+ def test_resource_url_root_default(self):
+ request = self._makeOne()
+ self._registerResourceURL(request.registry)
+ root = DummyContext()
+ result = request.resource_url(root)
+ self.assertEqual(result, 'http://example.com:5432/context/')
+
+ def test_resource_url_extra_args(self):
+ request = self._makeOne()
+ self._registerResourceURL(request.registry)
+ context = DummyContext()
+ result = request.resource_url(context, 'this/theotherthing', 'that')
+ self.assertEqual(
+ result, 'http://example.com:5432/context/this%2Ftheotherthing/that'
+ )
+
+ def test_resource_url_unicode_in_element_names(self):
+ request = self._makeOne()
+ self._registerResourceURL(request.registry)
+ uc = text_(b'La Pe\xc3\xb1a', 'utf-8')
+ context = DummyContext()
+ result = request.resource_url(context, uc)
+ self.assertEqual(
+ result, 'http://example.com:5432/context/La%20Pe%C3%B1a'
+ )
+
+ def test_resource_url_at_sign_in_element_names(self):
+ request = self._makeOne()
+ self._registerResourceURL(request.registry)
+ context = DummyContext()
+ result = request.resource_url(context, '@@myview')
+ self.assertEqual(result, 'http://example.com:5432/context/@@myview')
+
+ def test_resource_url_element_names_url_quoted(self):
+ request = self._makeOne()
+ self._registerResourceURL(request.registry)
+ context = DummyContext()
+ result = request.resource_url(context, 'a b c')
+ self.assertEqual(result, 'http://example.com:5432/context/a%20b%20c')
+
+ def test_resource_url_with_query_str(self):
+ request = self._makeOne()
+ self._registerResourceURL(request.registry)
+ context = DummyContext()
+ result = request.resource_url(context, 'a', query='(openlayers)')
+ self.assertEqual(
+ result, 'http://example.com:5432/context/a?(openlayers)'
+ )
+
+ def test_resource_url_with_query_dict(self):
+ request = self._makeOne()
+ self._registerResourceURL(request.registry)
+ context = DummyContext()
+ uc = text_(b'La Pe\xc3\xb1a', 'utf-8')
+ result = request.resource_url(context, 'a', query={'a': uc})
+ self.assertEqual(
+ result, 'http://example.com:5432/context/a?a=La+Pe%C3%B1a'
+ )
+
+ def test_resource_url_with_query_seq(self):
+ request = self._makeOne()
+ self._registerResourceURL(request.registry)
+ context = DummyContext()
+ uc = text_(b'La Pe\xc3\xb1a', 'utf-8')
+ result = request.resource_url(
+ context, 'a', query=[('a', 'hi there'), ('b', uc)]
+ )
+ 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_with_query_None(self):
+ request = self._makeOne()
+ self._registerResourceURL(request.registry)
+ context = DummyContext()
+ result = request.resource_url(context, 'a', query=None)
+ 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)
+ context = DummyContext()
+ result = request.resource_url(context, anchor='a')
+ self.assertEqual(result, 'http://example.com:5432/context/#a')
+
+ def test_resource_url_anchor_is_after_elements_when_no_qs(self):
+ request = self._makeOne()
+ self._registerResourceURL(request.registry)
+ context = DummyContext()
+ result = request.resource_url(context, 'a', anchor='b')
+ self.assertEqual(result, 'http://example.com:5432/context/a#b')
+
+ def test_resource_url_anchor_is_after_qs_when_qs_is_present(self):
+ request = self._makeOne()
+ self._registerResourceURL(request.registry)
+ context = DummyContext()
+ result = request.resource_url(
+ context, 'a', query={'b': 'c'}, anchor='d'
+ )
+ self.assertEqual(result, 'http://example.com:5432/context/a?b=c#d')
+
+ def test_resource_url_anchor_is_encoded_utf8_if_unicode(self):
+ request = self._makeOne()
+ self._registerResourceURL(request.registry)
+ context = DummyContext()
+ uc = text_(b'La Pe\xc3\xb1a', 'utf-8')
+ result = request.resource_url(context, anchor=uc)
+ self.assertEqual(
+ result, 'http://example.com:5432/context/#La%20Pe%C3%B1a'
+ )
+
+ def test_resource_url_anchor_is_urlencoded_safe(self):
+ request = self._makeOne()
+ self._registerResourceURL(request.registry)
+ context = DummyContext()
+ result = request.resource_url(context, anchor=' /#?&+')
+ self.assertEqual(result, 'http://example.com:5432/context/#%20/%23?&+')
+
+ def test_resource_url_anchor_is_None(self):
+ request = self._makeOne()
+ self._registerResourceURL(request.registry)
+ context = DummyContext()
+ result = request.resource_url(context, anchor=None)
+ self.assertEqual(result, 'http://example.com:5432/context/')
+
+ def test_resource_url_no_IResourceURL_registered(self):
+ # falls back to ResourceURL
+ root = DummyContext()
+ root.__name__ = ''
+ root.__parent__ = None
+ request = self._makeOne()
+ request.environ = {}
+ result = request.resource_url(root)
+ self.assertEqual(result, 'http://example.com:5432/')
+
+ def test_resource_url_no_registry_on_request(self):
+ request = self._makeOne()
+ self._registerResourceURL(request.registry)
+ del request.registry
+ root = DummyContext()
+ result = request.resource_url(root)
+ self.assertEqual(result, 'http://example.com:5432/context/')
+
+ def test_resource_url_with_app_url(self):
+ request = self._makeOne()
+ self._registerResourceURL(request.registry)
+ root = DummyContext()
+ result = request.resource_url(root, app_url='http://somewhere.com')
+ self.assertEqual(result, 'http://somewhere.com/context/')
+
+ def test_resource_url_with_scheme(self):
+ environ = {
+ 'wsgi.url_scheme': 'http',
+ 'SERVER_PORT': '8080',
+ 'SERVER_NAME': 'example.com',
+ }
+ request = self._makeOne(environ)
+ self._registerResourceURL(request.registry)
+ root = DummyContext()
+ result = request.resource_url(root, scheme='https')
+ self.assertEqual(result, 'https://example.com/context/')
+
+ def test_resource_url_with_host(self):
+ environ = {
+ 'wsgi.url_scheme': 'http',
+ 'SERVER_PORT': '8080',
+ 'SERVER_NAME': 'example.com',
+ }
+ request = self._makeOne(environ)
+ self._registerResourceURL(request.registry)
+ root = DummyContext()
+ result = request.resource_url(root, host='someotherhost.com')
+ self.assertEqual(result, 'http://someotherhost.com:8080/context/')
+
+ def test_resource_url_with_port(self):
+ environ = {
+ 'wsgi.url_scheme': 'http',
+ 'SERVER_PORT': '8080',
+ 'SERVER_NAME': 'example.com',
+ }
+ request = self._makeOne(environ)
+ self._registerResourceURL(request.registry)
+ root = DummyContext()
+ result = request.resource_url(root, port='8181')
+ self.assertEqual(result, 'http://example.com:8181/context/')
+
+ def test_resource_url_with_local_url(self):
+ environ = {
+ 'wsgi.url_scheme': 'http',
+ 'SERVER_PORT': '8080',
+ 'SERVER_NAME': 'example.com',
+ }
+ request = self._makeOne(environ)
+ self._registerResourceURL(request.registry)
+ root = DummyContext()
+
+ def resource_url(req, info):
+ self.assertEqual(req, request)
+ self.assertEqual(info['virtual_path'], '/context/')
+ self.assertEqual(info['physical_path'], '/context/')
+ self.assertEqual(info['app_url'], 'http://example.com:5432')
+ return 'http://example.com/contextabc/'
+
+ root.__resource_url__ = resource_url
+ result = request.resource_url(root)
+ self.assertEqual(result, 'http://example.com/contextabc/')
+
+ def test_resource_url_with_route_name_no_remainder_on_adapter(self):
+ from pyramid.interfaces import IRoutesMapper
+
+ environ = {
+ 'wsgi.url_scheme': 'http',
+ 'SERVER_PORT': '8080',
+ 'SERVER_NAME': 'example.com',
+ }
+ request = self._makeOne(environ)
+ adapter = self._registerResourceURL(request.registry)
+ # no virtual_path_tuple on adapter
+ adapter.virtual_path = '/a/b/c/'
+ route = DummyRoute('/1/2/3')
+ mapper = DummyRoutesMapper(route)
+ request.registry.registerUtility(mapper, IRoutesMapper)
+ root = DummyContext()
+ result = request.resource_url(root, route_name='foo')
+ self.assertEqual(result, 'http://example.com:5432/1/2/3')
+ self.assertEqual(route.kw, {'traverse': ('', 'a', 'b', 'c', '')})
+
+ def test_resource_url_with_route_name_remainder_on_adapter(self):
+ from pyramid.interfaces import IRoutesMapper
+
+ environ = {
+ 'wsgi.url_scheme': 'http',
+ 'SERVER_PORT': '8080',
+ 'SERVER_NAME': 'example.com',
+ }
+ request = self._makeOne(environ)
+ adapter = self._registerResourceURL(request.registry)
+ # virtual_path_tuple on adapter
+ adapter.virtual_path_tuple = ('', 'a', 'b', 'c', '')
+ route = DummyRoute('/1/2/3')
+ mapper = DummyRoutesMapper(route)
+ request.registry.registerUtility(mapper, IRoutesMapper)
+ root = DummyContext()
+ result = request.resource_url(root, route_name='foo')
+ self.assertEqual(result, 'http://example.com:5432/1/2/3')
+ self.assertEqual(route.kw, {'traverse': ('', 'a', 'b', 'c', '')})
+
+ def test_resource_url_with_route_name_and_app_url(self):
+ from pyramid.interfaces import IRoutesMapper
+
+ environ = {
+ 'wsgi.url_scheme': 'http',
+ 'SERVER_PORT': '8080',
+ 'SERVER_NAME': 'example.com',
+ }
+ request = self._makeOne(environ)
+ adapter = self._registerResourceURL(request.registry)
+ # virtual_path_tuple on adapter
+ adapter.virtual_path_tuple = ('', 'a', 'b', 'c', '')
+ route = DummyRoute('/1/2/3')
+ mapper = DummyRoutesMapper(route)
+ request.registry.registerUtility(mapper, IRoutesMapper)
+ root = DummyContext()
+ result = request.resource_url(
+ root, route_name='foo', app_url='app_url'
+ )
+ self.assertEqual(result, 'app_url/1/2/3')
+ self.assertEqual(route.kw, {'traverse': ('', 'a', 'b', 'c', '')})
+
+ def test_resource_url_with_route_name_and_scheme_host_port_etc(self):
+ from pyramid.interfaces import IRoutesMapper
+
+ environ = {
+ 'wsgi.url_scheme': 'http',
+ 'SERVER_PORT': '8080',
+ 'SERVER_NAME': 'example.com',
+ }
+ request = self._makeOne(environ)
+ adapter = self._registerResourceURL(request.registry)
+ # virtual_path_tuple on adapter
+ adapter.virtual_path_tuple = ('', 'a', 'b', 'c', '')
+ route = DummyRoute('/1/2/3')
+ mapper = DummyRoutesMapper(route)
+ request.registry.registerUtility(mapper, IRoutesMapper)
+ root = DummyContext()
+ result = request.resource_url(
+ root,
+ route_name='foo',
+ scheme='scheme',
+ host='host',
+ port='port',
+ query={'a': '1'},
+ anchor='anchor',
+ )
+ self.assertEqual(result, 'scheme://host:port/1/2/3?a=1#anchor')
+ self.assertEqual(route.kw, {'traverse': ('', 'a', 'b', 'c', '')})
+
+ def test_resource_url_with_route_name_and_route_kwargs(self):
+ from pyramid.interfaces import IRoutesMapper
+
+ environ = {
+ 'wsgi.url_scheme': 'http',
+ 'SERVER_PORT': '8080',
+ 'SERVER_NAME': 'example.com',
+ }
+ request = self._makeOne(environ)
+ adapter = self._registerResourceURL(request.registry)
+ # virtual_path_tuple on adapter
+ adapter.virtual_path_tuple = ('', 'a', 'b', 'c', '')
+ route = DummyRoute('/1/2/3')
+ mapper = DummyRoutesMapper(route)
+ request.registry.registerUtility(mapper, IRoutesMapper)
+ root = DummyContext()
+ result = request.resource_url(
+ root, route_name='foo', route_kw={'a': '1', 'b': '2'}
+ )
+ self.assertEqual(result, 'http://example.com:5432/1/2/3')
+ self.assertEqual(
+ route.kw, {'traverse': ('', 'a', 'b', 'c', ''), 'a': '1', 'b': '2'}
+ )
+
+ def test_resource_url_with_route_name_and_elements(self):
+ from pyramid.interfaces import IRoutesMapper
+
+ environ = {
+ 'wsgi.url_scheme': 'http',
+ 'SERVER_PORT': '8080',
+ 'SERVER_NAME': 'example.com',
+ }
+ request = self._makeOne(environ)
+ adapter = self._registerResourceURL(request.registry)
+ # virtual_path_tuple on adapter
+ adapter.virtual_path_tuple = ('', 'a', 'b', 'c', '')
+ route = DummyRoute('/1/2/3')
+ mapper = DummyRoutesMapper(route)
+ request.registry.registerUtility(mapper, IRoutesMapper)
+ root = DummyContext()
+ result = request.resource_url(root, 'e1', 'e2', route_name='foo')
+ self.assertEqual(result, 'http://example.com:5432/1/2/3/e1/e2')
+ self.assertEqual(route.kw, {'traverse': ('', 'a', 'b', 'c', '')})
+
+ def test_resource_url_with_route_name_and_remainder_name(self):
+ from pyramid.interfaces import IRoutesMapper
+
+ environ = {
+ 'wsgi.url_scheme': 'http',
+ 'SERVER_PORT': '8080',
+ 'SERVER_NAME': 'example.com',
+ }
+ request = self._makeOne(environ)
+ adapter = self._registerResourceURL(request.registry)
+ # virtual_path_tuple on adapter
+ adapter.virtual_path_tuple = ('', 'a', 'b', 'c', '')
+ route = DummyRoute('/1/2/3')
+ mapper = DummyRoutesMapper(route)
+ request.registry.registerUtility(mapper, IRoutesMapper)
+ root = DummyContext()
+ result = request.resource_url(
+ root, route_name='foo', route_remainder_name='fred'
+ )
+ self.assertEqual(result, 'http://example.com:5432/1/2/3')
+ self.assertEqual(route.kw, {'fred': ('', 'a', 'b', 'c', '')})
+
+ def test_resource_path(self):
+ request = self._makeOne()
+ self._registerResourceURL(request.registry)
+ root = DummyContext()
+ result = request.resource_path(root)
+ self.assertEqual(result, '/context/')
+
+ def test_resource_path_kwarg(self):
+ request = self._makeOne()
+ self._registerResourceURL(request.registry)
+ root = DummyContext()
+ result = request.resource_path(root, anchor='abc')
+ self.assertEqual(result, '/context/#abc')
+
+ def test_route_url_with_elements(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', 'extra1', 'extra2')
+ self.assertEqual(result, 'http://example.com:5432/1/2/3/extra1/extra2')
+
+ def test_route_url_with_elements_path_endswith_slash(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', 'extra1', 'extra2')
+ self.assertEqual(result, 'http://example.com:5432/1/2/3/extra1/extra2')
+
+ def test_route_url_no_elements(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', a=1, b=2, c=3, _query={'a': 1}, _anchor=text_(b"foo")
+ )
+ self.assertEqual(result, 'http://example.com:5432/1/2/3?a=1#foo')
+
+ def test_route_url_with_query_None(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', a=1, b=2, c=3, _query=None)
+ self.assertEqual(result, 'http://example.com:5432/1/2/3')
+
+ def test_route_url_with_anchor_binary(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', _anchor=b"La Pe\xc3\xb1a")
+
+ self.assertEqual(
+ result, 'http://example.com:5432/1/2/3#La%20Pe%C3%B1a'
+ )
+
+ def test_route_url_with_anchor_unicode(self):
+ from pyramid.interfaces import IRoutesMapper
+
+ request = self._makeOne()
+ mapper = DummyRoutesMapper(route=DummyRoute('/1/2/3'))
+ request.registry.registerUtility(mapper, IRoutesMapper)
+ anchor = text_(b'La Pe\xc3\xb1a', 'utf-8')
+ result = request.route_url('flub', _anchor=anchor)
+
+ self.assertEqual(
+ result, 'http://example.com:5432/1/2/3#La%20Pe%C3%B1a'
+ )
+
+ def test_route_url_with_anchor_None(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', _anchor=None)
+
+ self.assertEqual(result, 'http://example.com:5432/1/2/3')
+
+ def test_route_url_with_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={'q': '1'})
+ self.assertEqual(result, 'http://example.com:5432/1/2/3?q=1')
+
+ def test_route_url_with_query_str(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='(openlayers)')
+ self.assertEqual(result, 'http://example.com:5432/1/2/3?(openlayers)')
+
+ 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()
+ mapper = DummyRoutesMapper(route=DummyRoute('/1/2/3'))
+ request.registry.registerUtility(mapper, IRoutesMapper)
+ result = request.route_url('flub', _app_url='http://example2.com')
+ self.assertEqual(result, 'http://example2.com/1/2/3')
+
+ def test_route_url_with_host(self):
+ from pyramid.interfaces import IRoutesMapper
+
+ environ = {'wsgi.url_scheme': 'http', 'SERVER_PORT': '5432'}
+ request = self._makeOne(environ)
+ mapper = DummyRoutesMapper(route=DummyRoute('/1/2/3'))
+ request.registry.registerUtility(mapper, IRoutesMapper)
+ result = request.route_url('flub', _host='someotherhost.com')
+ self.assertEqual(result, 'http://someotherhost.com:5432/1/2/3')
+
+ def test_route_url_with_port(self):
+ from pyramid.interfaces import IRoutesMapper
+
+ environ = {
+ 'wsgi.url_scheme': 'http',
+ 'SERVER_PORT': '5432',
+ 'SERVER_NAME': 'example.com',
+ }
+ request = self._makeOne(environ)
+ mapper = DummyRoutesMapper(route=DummyRoute('/1/2/3'))
+ request.registry.registerUtility(mapper, IRoutesMapper)
+ result = request.route_url('flub', _port='8080')
+ self.assertEqual(result, 'http://example.com:8080/1/2/3')
+
+ def test_route_url_with_scheme(self):
+ from pyramid.interfaces import IRoutesMapper
+
+ environ = {
+ 'wsgi.url_scheme': 'http',
+ 'SERVER_PORT': '5432',
+ 'SERVER_NAME': 'example.com',
+ }
+ request = self._makeOne(environ)
+ mapper = DummyRoutesMapper(route=DummyRoute('/1/2/3'))
+ request.registry.registerUtility(mapper, IRoutesMapper)
+ result = request.route_url('flub', _scheme='https')
+ self.assertEqual(result, 'https://example.com/1/2/3')
+
+ def test_route_url_generation_error(self):
+ from pyramid.interfaces import IRoutesMapper
+
+ request = self._makeOne()
+ mapper = DummyRoutesMapper(raise_exc=KeyError)
+ request.registry.registerUtility(mapper, IRoutesMapper)
+ mapper.raise_exc = KeyError
+ self.assertRaises(KeyError, request.route_url, 'flub', request, a=1)
+
+ def test_route_url_generate_doesnt_receive_query_or_anchor(self):
+ from pyramid.interfaces import IRoutesMapper
+
+ request = self._makeOne()
+ route = DummyRoute(result='')
+ mapper = DummyRoutesMapper(route=route)
+ request.registry.registerUtility(mapper, IRoutesMapper)
+ result = request.route_url('flub', _query=dict(name='some_name'))
+ self.assertEqual(route.kw, {}) # shouldnt have anchor/query
+ self.assertEqual(result, 'http://example.com:5432?name=some_name')
+
+ def test_route_url_with_pregenerator(self):
+ from pyramid.interfaces import IRoutesMapper
+
+ request = self._makeOne()
+ route = DummyRoute(result='/1/2/3')
+
+ def pregenerator(request, elements, kw):
+ return ('a',), {'_app_url': 'http://example2.com'}
+
+ route.pregenerator = pregenerator
+ mapper = DummyRoutesMapper(route=route)
+ request.registry.registerUtility(mapper, IRoutesMapper)
+ result = request.route_url('flub')
+ self.assertEqual(result, 'http://example2.com/1/2/3/a')
+ self.assertEqual(route.kw, {}) # shouldnt have anchor/query
+
+ def test_route_url_with_anchor_app_url_elements_and_query(self):
+ from pyramid.interfaces import IRoutesMapper
+
+ request = self._makeOne()
+ mapper = DummyRoutesMapper(route=DummyRoute(result='/1/2/3'))
+ request.registry.registerUtility(mapper, IRoutesMapper)
+ result = request.route_url(
+ 'flub',
+ 'element1',
+ _app_url='http://example2.com',
+ _anchor='anchor',
+ _query={'q': '1'},
+ )
+ self.assertEqual(
+ result, 'http://example2.com/1/2/3/element1?q=1#anchor'
+ )
+
+ def test_route_url_integration_with_real_request(self):
+ # to try to replicate https://github.com/Pylons/pyramid/issues/213
+ from pyramid.interfaces import IRoutesMapper
+ from pyramid.request import Request
+
+ request = Request.blank('/')
+ request.registry = self.config.registry
+ mapper = DummyRoutesMapper(route=DummyRoute('/1/2/3'))
+ request.registry.registerUtility(mapper, IRoutesMapper)
+ result = request.route_url('flub', 'extra1', 'extra2')
+ self.assertEqual(result, 'http://localhost/1/2/3/extra1/extra2')
+
+ def test_current_route_url_current_request_has_no_route(self):
+ request = self._makeOne()
+ self.assertRaises(ValueError, request.current_route_url)
+
+ def test_current_route_url_with_elements_query_and_anchor(self):
+ from pyramid.interfaces import IRoutesMapper
+
+ request = self._makeOne()
+ route = DummyRoute('/1/2/3')
+ mapper = DummyRoutesMapper(route=route)
+ request.matched_route = route
+ request.matchdict = {}
+ request.registry.registerUtility(mapper, IRoutesMapper)
+ result = request.current_route_url(
+ 'extra1', 'extra2', _query={'a': 1}, _anchor=text_(b"foo")
+ )
+ self.assertEqual(
+ result, 'http://example.com:5432/1/2/3/extra1/extra2?a=1#foo'
+ )
+
+ def test_current_route_url_with_route_name(self):
+ from pyramid.interfaces import IRoutesMapper
+
+ request = self._makeOne()
+ route = DummyRoute('/1/2/3')
+ mapper = DummyRoutesMapper(route=route)
+ request.matched_route = route
+ request.matchdict = {}
+ request.registry.registerUtility(mapper, IRoutesMapper)
+ result = request.current_route_url(
+ 'extra1',
+ 'extra2',
+ _query={'a': 1},
+ _anchor=text_(b"foo"),
+ _route_name='bar',
+ )
+ self.assertEqual(
+ result, 'http://example.com:5432/1/2/3/extra1/extra2?a=1#foo'
+ )
+
+ def test_current_route_url_with_request_query(self):
+ from pyramid.interfaces import IRoutesMapper
+ from webob.multidict import GetDict
+
+ request = self._makeOne()
+ request.GET = GetDict([('q', '123')], {})
+ route = DummyRoute('/1/2/3')
+ mapper = DummyRoutesMapper(route=route)
+ request.matched_route = route
+ request.matchdict = {}
+ request.registry.registerUtility(mapper, IRoutesMapper)
+ result = request.current_route_url()
+ self.assertEqual(result, 'http://example.com:5432/1/2/3?q=123')
+
+ def test_current_route_url_with_request_query_duplicate_entries(self):
+ from pyramid.interfaces import IRoutesMapper
+ from webob.multidict import GetDict
+
+ request = self._makeOne()
+ request.GET = GetDict(
+ [('q', '123'), ('b', '2'), ('b', '2'), ('q', '456')], {}
+ )
+ route = DummyRoute('/1/2/3')
+ mapper = DummyRoutesMapper(route=route)
+ request.matched_route = route
+ request.matchdict = {}
+ request.registry.registerUtility(mapper, IRoutesMapper)
+ result = request.current_route_url()
+ self.assertEqual(
+ result, 'http://example.com:5432/1/2/3?q=123&b=2&b=2&q=456'
+ )
+
+ def test_current_route_url_with_query_override(self):
+ from pyramid.interfaces import IRoutesMapper
+ from webob.multidict import GetDict
+
+ request = self._makeOne()
+ request.GET = GetDict([('q', '123')], {})
+ route = DummyRoute('/1/2/3')
+ mapper = DummyRoutesMapper(route=route)
+ request.matched_route = route
+ request.matchdict = {}
+ request.registry.registerUtility(mapper, IRoutesMapper)
+ result = request.current_route_url(_query={'a': 1})
+ self.assertEqual(result, 'http://example.com:5432/1/2/3?a=1')
+
+ def test_current_route_path(self):
+ from pyramid.interfaces import IRoutesMapper
+
+ request = self._makeOne()
+ route = DummyRoute('/1/2/3')
+ mapper = DummyRoutesMapper(route=route)
+ request.matched_route = route
+ request.matchdict = {}
+ request.script_name = '/script_name'
+ request.registry.registerUtility(mapper, IRoutesMapper)
+ result = request.current_route_path(
+ 'extra1', 'extra2', _query={'a': 1}, _anchor=text_(b"foo")
+ )
+ self.assertEqual(result, '/script_name/1/2/3/extra1/extra2?a=1#foo')
+
+ def test_route_path_with_elements(self):
+ from pyramid.interfaces import IRoutesMapper
+
+ request = self._makeOne()
+ mapper = DummyRoutesMapper(route=DummyRoute('/1/2/3'))
+ request.registry.registerUtility(mapper, IRoutesMapper)
+ request.script_name = ''
+ result = request.route_path(
+ 'flub',
+ 'extra1',
+ 'extra2',
+ a=1,
+ b=2,
+ c=3,
+ _query={'a': 1},
+ _anchor=text_(b"foo"),
+ )
+ self.assertEqual(result, '/1/2/3/extra1/extra2?a=1#foo')
+
+ def test_route_path_with_script_name(self):
+ from pyramid.interfaces import IRoutesMapper
+
+ request = self._makeOne()
+ request.script_name = '/foo'
+ mapper = DummyRoutesMapper(route=DummyRoute('/1/2/3'))
+ request.registry.registerUtility(mapper, IRoutesMapper)
+ result = request.route_path(
+ 'flub',
+ 'extra1',
+ 'extra2',
+ a=1,
+ b=2,
+ c=3,
+ _query={'a': 1},
+ _anchor=text_(b"foo"),
+ )
+ self.assertEqual(result, '/foo/1/2/3/extra1/extra2?a=1#foo')
+
+ def test_static_url_staticurlinfo_notfound(self):
+ request = self._makeOne()
+ self.assertRaises(ValueError, request.static_url, 'static/foo.css')
+
+ def test_static_url_abspath(self):
+ from pyramid.interfaces import IStaticURLInfo
+
+ request = self._makeOne()
+ info = DummyStaticURLInfo('abc')
+ registry = request.registry
+ registry.registerUtility(info, IStaticURLInfo)
+ abspath = makeabs('static', 'foo.css')
+ result = request.static_url(abspath)
+ self.assertEqual(result, 'abc')
+ self.assertEqual(
+ info.args, (makeabs('static', 'foo.css'), request, {})
+ )
+ request = self._makeOne()
+
+ def test_static_url_found_rel(self):
+ from pyramid.interfaces import IStaticURLInfo
+
+ request = self._makeOne()
+ info = DummyStaticURLInfo('abc')
+ request.registry.registerUtility(info, IStaticURLInfo)
+ result = request.static_url('static/foo.css')
+ self.assertEqual(result, 'abc')
+ self.assertEqual(info.args, ('tests:static/foo.css', request, {}))
+
+ def test_static_url_abs(self):
+ from pyramid.interfaces import IStaticURLInfo
+
+ request = self._makeOne()
+ info = DummyStaticURLInfo('abc')
+ request.registry.registerUtility(info, IStaticURLInfo)
+ result = request.static_url('tests:static/foo.css')
+ self.assertEqual(result, 'abc')
+ self.assertEqual(info.args, ('tests:static/foo.css', request, {}))
+
+ def test_static_url_found_abs_no_registry_on_request(self):
+ from pyramid.interfaces import IStaticURLInfo
+
+ request = self._makeOne()
+ registry = request.registry
+ info = DummyStaticURLInfo('abc')
+ registry.registerUtility(info, IStaticURLInfo)
+ del request.registry
+ result = request.static_url('tests:static/foo.css')
+ self.assertEqual(result, 'abc')
+ self.assertEqual(info.args, ('tests:static/foo.css', request, {}))
+
+ def test_static_url_abspath_integration_with_staticurlinfo(self):
+ from pyramid.interfaces import IStaticURLInfo
+ from pyramid.config.views import StaticURLInfo
+
+ info = StaticURLInfo()
+ here = os.path.abspath(os.path.dirname(__file__))
+ info.add(self.config, 'absstatic', here)
+ request = self._makeOne()
+ registry = request.registry
+ registry.registerUtility(info, IStaticURLInfo)
+ abspath = os.path.join(here, 'test_url.py')
+ result = request.static_url(abspath)
+ self.assertEqual(
+ result, 'http://example.com:5432/absstatic/test_url.py'
+ )
+
+ def test_static_url_noscheme_uses_scheme_from_request(self):
+ from pyramid.interfaces import IStaticURLInfo
+ from pyramid.config.views import StaticURLInfo
+
+ info = StaticURLInfo()
+ here = os.path.abspath(os.path.dirname(__file__))
+ info.add(self.config, '//subdomain.example.com/static', here)
+ request = self._makeOne({'wsgi.url_scheme': 'https'})
+ registry = request.registry
+ registry.registerUtility(info, IStaticURLInfo)
+ abspath = os.path.join(here, 'test_url.py')
+ result = request.static_url(abspath)
+ self.assertEqual(
+ result, 'https://subdomain.example.com/static/test_url.py'
+ )
+
+ def test_static_path_abspath(self):
+ from pyramid.interfaces import IStaticURLInfo
+
+ request = self._makeOne()
+ request.script_name = '/foo'
+ info = DummyStaticURLInfo('abc')
+ registry = request.registry
+ registry.registerUtility(info, IStaticURLInfo)
+ abspath = makeabs('static', 'foo.css')
+ result = request.static_path(abspath)
+ self.assertEqual(result, 'abc')
+ self.assertEqual(
+ info.args,
+ (makeabs('static', 'foo.css'), request, {'_app_url': '/foo'}),
+ )
+
+ def test_static_path_found_rel(self):
+ from pyramid.interfaces import IStaticURLInfo
+
+ request = self._makeOne()
+ request.script_name = '/foo'
+ info = DummyStaticURLInfo('abc')
+ request.registry.registerUtility(info, IStaticURLInfo)
+ result = request.static_path('static/foo.css')
+ self.assertEqual(result, 'abc')
+ self.assertEqual(
+ info.args, ('tests:static/foo.css', request, {'_app_url': '/foo'})
+ )
+
+ def test_static_path_abs(self):
+ from pyramid.interfaces import IStaticURLInfo
+
+ request = self._makeOne()
+ request.script_name = '/foo'
+ info = DummyStaticURLInfo('abc')
+ request.registry.registerUtility(info, IStaticURLInfo)
+ result = request.static_path('tests:static/foo.css')
+ self.assertEqual(result, 'abc')
+ self.assertEqual(
+ info.args, ('tests:static/foo.css', request, {'_app_url': '/foo'})
+ )
+
+ def test_static_path(self):
+ from pyramid.interfaces import IStaticURLInfo
+
+ request = self._makeOne()
+ request.script_name = '/foo'
+ info = DummyStaticURLInfo('abc')
+ request.registry.registerUtility(info, IStaticURLInfo)
+ result = request.static_path('static/foo.css')
+ self.assertEqual(result, 'abc')
+ self.assertEqual(
+ info.args, ('tests:static/foo.css', request, {'_app_url': '/foo'})
+ )
+
+ def test_partial_application_url_with_http_host_default_port_http(self):
+ environ = {'wsgi.url_scheme': 'http', 'HTTP_HOST': 'example.com:80'}
+ request = self._makeOne(environ)
+ result = request._partial_application_url()
+ self.assertEqual(result, 'http://example.com')
+
+ def test_partial_application_url_with_http_host_default_port_https(self):
+ environ = {'wsgi.url_scheme': 'https', 'HTTP_HOST': 'example.com:443'}
+ request = self._makeOne(environ)
+ result = request._partial_application_url()
+ self.assertEqual(result, 'https://example.com')
+
+ def test_partial_application_url_with_http_host_nondefault_port_http(self):
+ environ = {'wsgi.url_scheme': 'http', 'HTTP_HOST': 'example.com:8080'}
+ request = self._makeOne(environ)
+ result = request._partial_application_url()
+ self.assertEqual(result, 'http://example.com:8080')
+
+ def test_partial_application_url_with_http_host_nondefault_port_https(
+ self
+ ):
+ environ = {'wsgi.url_scheme': 'https', 'HTTP_HOST': 'example.com:4443'}
+ request = self._makeOne(environ)
+ result = request._partial_application_url()
+ self.assertEqual(result, 'https://example.com:4443')
+
+ def test_partial_application_url_with_http_host_no_colon(self):
+ environ = {
+ 'wsgi.url_scheme': 'http',
+ 'HTTP_HOST': 'example.com',
+ 'SERVER_PORT': '80',
+ }
+ request = self._makeOne(environ)
+ result = request._partial_application_url()
+ self.assertEqual(result, 'http://example.com')
+
+ def test_partial_application_url_no_http_host(self):
+ environ = {
+ 'wsgi.url_scheme': 'http',
+ 'SERVER_NAME': 'example.com',
+ 'SERVER_PORT': '80',
+ }
+ request = self._makeOne(environ)
+ result = request._partial_application_url()
+ self.assertEqual(result, 'http://example.com')
+
+ def test_partial_application_replace_port(self):
+ environ = {
+ 'wsgi.url_scheme': 'http',
+ 'SERVER_NAME': 'example.com',
+ 'SERVER_PORT': '80',
+ }
+ request = self._makeOne(environ)
+ result = request._partial_application_url(port=8080)
+ self.assertEqual(result, 'http://example.com:8080')
+
+ def test_partial_application_replace_scheme_https_special_case(self):
+ environ = {
+ 'wsgi.url_scheme': 'http',
+ 'SERVER_NAME': 'example.com',
+ 'SERVER_PORT': '80',
+ }
+ request = self._makeOne(environ)
+ result = request._partial_application_url(scheme='https')
+ self.assertEqual(result, 'https://example.com')
+
+ def test_partial_application_replace_scheme_https_special_case_avoid(self):
+ environ = {
+ 'wsgi.url_scheme': 'http',
+ 'SERVER_NAME': 'example.com',
+ 'SERVER_PORT': '80',
+ }
+ request = self._makeOne(environ)
+ result = request._partial_application_url(scheme='https', port='8080')
+ self.assertEqual(result, 'https://example.com:8080')
+
+ def test_partial_application_replace_scheme_http_special_case(self):
+ environ = {
+ 'wsgi.url_scheme': 'https',
+ 'SERVER_NAME': 'example.com',
+ 'SERVER_PORT': '8080',
+ }
+ request = self._makeOne(environ)
+ result = request._partial_application_url(scheme='http')
+ self.assertEqual(result, 'http://example.com')
+
+ def test_partial_application_replace_scheme_http_special_case_avoid(self):
+ environ = {
+ 'wsgi.url_scheme': 'https',
+ 'SERVER_NAME': 'example.com',
+ 'SERVER_PORT': '8000',
+ }
+ request = self._makeOne(environ)
+ result = request._partial_application_url(scheme='http', port='8080')
+ self.assertEqual(result, 'http://example.com:8080')
+
+ def test_partial_application_replace_host_no_port(self):
+ environ = {
+ 'wsgi.url_scheme': 'http',
+ 'SERVER_NAME': 'example.com',
+ 'SERVER_PORT': '80',
+ }
+ request = self._makeOne(environ)
+ result = request._partial_application_url(host='someotherhost.com')
+ self.assertEqual(result, 'http://someotherhost.com')
+
+ def test_partial_application_replace_host_with_port(self):
+ environ = {
+ 'wsgi.url_scheme': 'http',
+ 'SERVER_NAME': 'example.com',
+ 'SERVER_PORT': '8000',
+ }
+ request = self._makeOne(environ)
+ result = request._partial_application_url(
+ host='someotherhost.com:8080'
+ )
+ self.assertEqual(result, 'http://someotherhost.com:8080')
+
+ def test_partial_application_replace_host_and_port(self):
+ environ = {
+ 'wsgi.url_scheme': 'http',
+ 'SERVER_NAME': 'example.com',
+ 'SERVER_PORT': '80',
+ }
+ request = self._makeOne(environ)
+ result = request._partial_application_url(
+ host='someotherhost.com:8080', port='8000'
+ )
+ self.assertEqual(result, 'http://someotherhost.com:8000')
+
+ def test_partial_application_replace_host_port_and_scheme(self):
+ environ = {
+ 'wsgi.url_scheme': 'http',
+ 'SERVER_NAME': 'example.com',
+ 'SERVER_PORT': '80',
+ }
+ request = self._makeOne(environ)
+ result = request._partial_application_url(
+ host='someotherhost.com:8080', port='8000', scheme='https'
+ )
+ self.assertEqual(result, 'https://someotherhost.com:8000')
+
+ def test_partial_application_url_with_custom_script_name(self):
+ environ = {
+ 'wsgi.url_scheme': 'http',
+ 'SERVER_NAME': 'example.com',
+ 'SERVER_PORT': '8000',
+ }
+ request = self._makeOne(environ)
+ request.script_name = '/abc'
+ result = request._partial_application_url()
+ self.assertEqual(result, 'http://example.com:8000/abc')
+
+
+class Test_route_url(unittest.TestCase):
+ def _callFUT(self, route_name, request, *elements, **kw):
+ from pyramid.url import route_url
+
+ return route_url(route_name, request, *elements, **kw)
+
+ def _makeRequest(self):
+ class Request(object):
+ def route_url(self, route_name, *elements, **kw):
+ self.route_name = route_name
+ self.elements = elements
+ self.kw = kw
+ return 'route url'
+
+ return Request()
+
+ def test_it(self):
+ request = self._makeRequest()
+ result = self._callFUT('abc', request, 'a', _app_url='')
+ self.assertEqual(result, 'route url')
+ self.assertEqual(request.route_name, 'abc')
+ self.assertEqual(request.elements, ('a',))
+ self.assertEqual(request.kw, {'_app_url': ''})
+
+
+class Test_route_path(unittest.TestCase):
+ def _callFUT(self, route_name, request, *elements, **kw):
+ from pyramid.url import route_path
+
+ return route_path(route_name, request, *elements, **kw)
+
+ def _makeRequest(self):
+ class Request(object):
+ def route_path(self, route_name, *elements, **kw):
+ self.route_name = route_name
+ self.elements = elements
+ self.kw = kw
+ return 'route path'
+
+ return Request()
+
+ def test_it(self):
+ request = self._makeRequest()
+ result = self._callFUT('abc', request, 'a', _app_url='')
+ self.assertEqual(result, 'route path')
+ self.assertEqual(request.route_name, 'abc')
+ self.assertEqual(request.elements, ('a',))
+ self.assertEqual(request.kw, {'_app_url': ''})
+
+
+class Test_resource_url(unittest.TestCase):
+ def _callFUT(self, resource, request, *elements, **kw):
+ from pyramid.url import resource_url
+
+ return resource_url(resource, request, *elements, **kw)
+
+ def _makeRequest(self):
+ class Request(object):
+ def resource_url(self, resource, *elements, **kw):
+ self.resource = resource
+ self.elements = elements
+ self.kw = kw
+ return 'resource url'
+
+ return Request()
+
+ def test_it(self):
+ request = self._makeRequest()
+ result = self._callFUT('abc', request, 'a', _app_url='')
+ self.assertEqual(result, 'resource url')
+ self.assertEqual(request.resource, 'abc')
+ self.assertEqual(request.elements, ('a',))
+ self.assertEqual(request.kw, {'_app_url': ''})
+
+
+class Test_static_url(unittest.TestCase):
+ def _callFUT(self, path, request, **kw):
+ from pyramid.url import static_url
+
+ return static_url(path, request, **kw)
+
+ def _makeRequest(self):
+ class Request(object):
+ def static_url(self, path, **kw):
+ self.path = path
+ self.kw = kw
+ return 'static url'
+
+ return Request()
+
+ def test_it_abs(self):
+ request = self._makeRequest()
+ result = self._callFUT('/foo/bar/abc', request, _app_url='')
+ self.assertEqual(result, 'static url')
+ self.assertEqual(request.path, '/foo/bar/abc')
+ self.assertEqual(request.kw, {'_app_url': ''})
+
+ def test_it_absspec(self):
+ request = self._makeRequest()
+ result = self._callFUT('foo:abc', request, _anchor='anchor')
+ self.assertEqual(result, 'static url')
+ self.assertEqual(request.path, 'foo:abc')
+ self.assertEqual(request.kw, {'_anchor': 'anchor'})
+
+ def test_it_rel(self):
+ request = self._makeRequest()
+ result = self._callFUT('abc', request, _app_url='')
+ self.assertEqual(result, 'static url')
+ self.assertEqual(request.path, 'tests:abc')
+ self.assertEqual(request.kw, {'_app_url': ''})
+
+
+class Test_static_path(unittest.TestCase):
+ def _callFUT(self, path, request, **kw):
+ from pyramid.url import static_path
+
+ return static_path(path, request, **kw)
+
+ def _makeRequest(self):
+ class Request(object):
+ def static_path(self, path, **kw):
+ self.path = path
+ self.kw = kw
+ return 'static path'
+
+ return Request()
+
+ def test_it_abs(self):
+ request = self._makeRequest()
+ result = self._callFUT('/foo/bar/abc', request, _anchor='anchor')
+ self.assertEqual(result, 'static path')
+ self.assertEqual(request.path, '/foo/bar/abc')
+ self.assertEqual(request.kw, {'_anchor': 'anchor'})
+
+ def test_it_absspec(self):
+ request = self._makeRequest()
+ result = self._callFUT('foo:abc', request, _anchor='anchor')
+ self.assertEqual(result, 'static path')
+ self.assertEqual(request.path, 'foo:abc')
+ self.assertEqual(request.kw, {'_anchor': 'anchor'})
+
+ def test_it_rel(self):
+ request = self._makeRequest()
+ result = self._callFUT('abc', request, _app_url='')
+ self.assertEqual(result, 'static path')
+ self.assertEqual(request.path, 'tests:abc')
+ self.assertEqual(request.kw, {'_app_url': ''})
+
+
+class Test_current_route_url(unittest.TestCase):
+ def _callFUT(self, request, *elements, **kw):
+ from pyramid.url import current_route_url
+
+ return current_route_url(request, *elements, **kw)
+
+ def _makeRequest(self):
+ class Request(object):
+ def current_route_url(self, *elements, **kw):
+ self.elements = elements
+ self.kw = kw
+ return 'current route url'
+
+ return Request()
+
+ def test_it(self):
+ request = self._makeRequest()
+ result = self._callFUT(request, 'abc', _app_url='')
+ self.assertEqual(result, 'current route url')
+ self.assertEqual(request.elements, ('abc',))
+ self.assertEqual(request.kw, {'_app_url': ''})
+
+
+class Test_current_route_path(unittest.TestCase):
+ def _callFUT(self, request, *elements, **kw):
+ from pyramid.url import current_route_path
+
+ return current_route_path(request, *elements, **kw)
+
+ def _makeRequest(self):
+ class Request(object):
+ def current_route_path(self, *elements, **kw):
+ self.elements = elements
+ self.kw = kw
+ return 'current route path'
+
+ return Request()
+
+ def test_it(self):
+ request = self._makeRequest()
+ result = self._callFUT(request, 'abc', _anchor='abc')
+ self.assertEqual(result, 'current route path')
+ self.assertEqual(request.elements, ('abc',))
+ self.assertEqual(request.kw, {'_anchor': 'abc'})
+
+
+class Test_external_static_url_integration(unittest.TestCase):
+ def setUp(self):
+ self.config = testing.setUp()
+
+ def tearDown(self):
+ testing.tearDown()
+
+ def _makeRequest(self):
+ from pyramid.request import Request
+
+ return Request.blank('/')
+
+ def test_generate_external_url(self):
+ self.config.add_route('acme', 'https://acme.org/path/{foo}')
+ request = self._makeRequest()
+ request.registry = self.config.registry
+ self.assertEqual(
+ request.route_url('acme', foo='bar'), 'https://acme.org/path/bar'
+ )
+
+ def test_generate_external_url_without_scheme(self):
+ self.config.add_route('acme', '//acme.org/path/{foo}')
+ request = self._makeRequest()
+ request.registry = self.config.registry
+ self.assertEqual(
+ request.route_url('acme', foo='bar'), 'http://acme.org/path/bar'
+ )
+
+ def test_generate_external_url_with_explicit_scheme(self):
+ self.config.add_route('acme', '//acme.org/path/{foo}')
+ request = self._makeRequest()
+ request.registry = self.config.registry
+ self.assertEqual(
+ request.route_url('acme', foo='bar', _scheme='https'),
+ 'https://acme.org/path/bar',
+ )
+
+ def test_generate_external_url_with_explicit_app_url(self):
+ self.config.add_route('acme', 'http://acme.org/path/{foo}')
+ request = self._makeRequest()
+ request.registry = self.config.registry
+ self.assertRaises(
+ ValueError,
+ request.route_url,
+ 'acme',
+ foo='bar',
+ _app_url='http://fakeme.com',
+ )
+
+ def test_generate_external_url_route_path(self):
+ self.config.add_route('acme', 'https://acme.org/path/{foo}')
+ request = self._makeRequest()
+ request.registry = self.config.registry
+ self.assertRaises(ValueError, request.route_path, 'acme', foo='bar')
+
+ def test_generate_external_url_with_pregenerator(self):
+ def pregenerator(request, elements, kw):
+ kw['_query'] = {'q': 'foo'}
+ return elements, kw
+
+ self.config.add_route(
+ 'acme', 'https://acme.org/path/{foo}', pregenerator=pregenerator
+ )
+ request = self._makeRequest()
+ request.registry = self.config.registry
+ self.assertEqual(
+ request.route_url('acme', foo='bar'),
+ 'https://acme.org/path/bar?q=foo',
+ )
+
+ def test_external_url_with_route_prefix(self):
+ def includeme(config):
+ config.add_route('acme', '//acme.org/{foo}')
+
+ self.config.include(includeme, route_prefix='some_prefix')
+ request = self._makeRequest()
+ request.registry = self.config.registry
+ self.assertEqual(
+ request.route_url('acme', foo='bar'), 'http://acme.org/bar'
+ )
+
+
+class Test_with_route_prefix(unittest.TestCase):
+ def setUp(self):
+ self.config = testing.setUp()
+
+ def tearDown(self):
+ testing.tearDown()
+
+ def _makeRequest(self, route):
+ from pyramid.request import Request
+
+ return Request.blank(route)
+
+ def test_old_route_is_preserved(self):
+ self.config.route_prefix = 'old_prefix'
+ with self.config.route_prefix_context('new_addon'):
+ assert 'new_addon' in self.config.route_prefix
+
+ assert 'old_prefix' == self.config.route_prefix
+
+ def test_route_prefix_none(self):
+ self.config.route_prefix = 'old_prefix'
+ with self.config.route_prefix_context(None):
+ assert 'old_prefix' == self.config.route_prefix
+
+ assert 'old_prefix' == self.config.route_prefix
+
+ def test_route_prefix_empty(self):
+ self.config.route_prefix = 'old_prefix'
+ with self.config.route_prefix_context(''):
+ assert 'old_prefix' == self.config.route_prefix
+
+ assert 'old_prefix' == self.config.route_prefix
+
+ def test_route_has_prefix(self):
+ with self.config.route_prefix_context('bar'):
+ self.config.add_route('acme', '/foo')
+ request = self._makeRequest('/')
+ self.assertEqual(request.route_url('acme'), 'http://localhost/bar/foo')
+
+ def test_route_does_not_have_prefix(self):
+ with self.config.route_prefix_context('bar'):
+ pass
+
+ self.config.add_route('acme', '/foo')
+ request = self._makeRequest('/')
+ self.assertEqual(request.route_url('acme'), 'http://localhost/foo')
+
+ def test_error_reset_prefix(self):
+ self.config.route_prefix = 'old_prefix'
+
+ try:
+ with self.config.route_prefix_context('new_prefix'):
+ raise RuntimeError
+ except RuntimeError:
+ pass
+
+ assert self.config.route_prefix == 'old_prefix'
+
+
+class DummyContext(object):
+ def __init__(self, next=None):
+ self.next = next
+
+
+class DummyRoutesMapper:
+ raise_exc = None
+
+ def __init__(self, route=None, raise_exc=False):
+ self.route = route
+
+ def get_route(self, route_name):
+ return self.route
+
+
+class DummyRoute:
+ pregenerator = None
+ name = 'route'
+
+ def __init__(self, result='/1/2/3'):
+ self.result = result
+
+ def generate(self, kw):
+ self.kw = kw
+ return self.result
+
+
+class DummyStaticURLInfo:
+ def __init__(self, result):
+ self.result = result
+
+ def generate(self, path, request, **kw):
+ self.args = path, request, kw
+ return self.result
+
+
+def makeabs(*elements):
+ if WIN: # pragma: no cover
+ return r'c:\\' + os.path.sep.join(elements)
+ else:
+ return os.path.sep + os.path.sep.join(elements)
diff --git a/tests/test_urldispatch.py b/tests/test_urldispatch.py
new file mode 100644
index 000000000..772250e89
--- /dev/null
+++ b/tests/test_urldispatch.py
@@ -0,0 +1,655 @@
+import unittest
+from pyramid import testing
+from pyramid.compat import text_, PY2
+
+
+class TestRoute(unittest.TestCase):
+ def _getTargetClass(self):
+ from pyramid.urldispatch import Route
+
+ return Route
+
+ def _makeOne(self, *arg):
+ return self._getTargetClass()(*arg)
+
+ def test_provides_IRoute(self):
+ from pyramid.interfaces import IRoute
+ from zope.interface.verify import verifyObject
+
+ verifyObject(IRoute, self._makeOne('name', 'pattern'))
+
+ def test_ctor(self):
+ import types
+
+ route = self._makeOne('name', ':path', 'factory')
+ self.assertEqual(route.pattern, ':path')
+ self.assertEqual(route.path, ':path')
+ self.assertEqual(route.name, 'name')
+ self.assertEqual(route.factory, 'factory')
+ self.assertIsInstance(route.generate, types.FunctionType)
+ self.assertIsInstance(route.match, types.FunctionType)
+
+ def test_ctor_defaults(self):
+ import types
+
+ route = self._makeOne('name', ':path')
+ self.assertEqual(route.pattern, ':path')
+ self.assertEqual(route.path, ':path')
+ self.assertEqual(route.name, 'name')
+ self.assertEqual(route.factory, None)
+ self.assertIsInstance(route.generate, types.FunctionType)
+ self.assertIsInstance(route.match, types.FunctionType)
+
+ def test_match(self):
+ route = self._makeOne('name', ':path')
+ self.assertEqual(route.match('/whatever'), {'path': 'whatever'})
+
+ def test_generate(self):
+ route = self._makeOne('name', ':path')
+ self.assertEqual(route.generate({'path': 'abc'}), '/abc')
+
+
+class RoutesMapperTests(unittest.TestCase):
+ def setUp(self):
+ testing.setUp()
+
+ def tearDown(self):
+ testing.tearDown()
+
+ def _getRequest(self, **kw):
+ from pyramid.threadlocal import get_current_registry
+
+ environ = {'SERVER_NAME': 'localhost', 'wsgi.url_scheme': 'http'}
+ environ.update(kw)
+ request = DummyRequest(environ)
+ reg = get_current_registry()
+ request.registry = reg
+ return request
+
+ def _getTargetClass(self):
+ from pyramid.urldispatch import RoutesMapper
+
+ return RoutesMapper
+
+ def _makeOne(self):
+ klass = self._getTargetClass()
+ return klass()
+
+ def test_provides_IRoutesMapper(self):
+ from pyramid.interfaces import IRoutesMapper
+ from zope.interface.verify import verifyObject
+
+ verifyObject(IRoutesMapper, self._makeOne())
+
+ def test_no_route_matches(self):
+ mapper = self._makeOne()
+ request = self._getRequest(PATH_INFO='/')
+ result = mapper(request)
+ self.assertEqual(result['match'], None)
+ self.assertEqual(result['route'], None)
+
+ def test_connect_name_exists_removes_old(self):
+ mapper = self._makeOne()
+ mapper.connect('foo', 'archives/:action/:article')
+ mapper.connect('foo', 'archives/:action/:article2')
+ self.assertEqual(len(mapper.routelist), 1)
+ self.assertEqual(len(mapper.routes), 1)
+ self.assertEqual(
+ mapper.routes['foo'].pattern, 'archives/:action/:article2'
+ )
+ self.assertEqual(
+ mapper.routelist[0].pattern, 'archives/:action/:article2'
+ )
+
+ def test_connect_static(self):
+ mapper = self._makeOne()
+ mapper.connect('foo', 'archives/:action/:article', static=True)
+ self.assertEqual(len(mapper.routelist), 0)
+ self.assertEqual(len(mapper.routes), 1)
+ self.assertEqual(
+ mapper.routes['foo'].pattern, 'archives/:action/:article'
+ )
+
+ def test_connect_static_overridden(self):
+ mapper = self._makeOne()
+ mapper.connect('foo', 'archives/:action/:article', static=True)
+ self.assertEqual(len(mapper.routelist), 0)
+ self.assertEqual(len(mapper.routes), 1)
+ self.assertEqual(
+ mapper.routes['foo'].pattern, 'archives/:action/:article'
+ )
+ mapper.connect('foo', 'archives/:action/:article2')
+ self.assertEqual(len(mapper.routelist), 1)
+ self.assertEqual(len(mapper.routes), 1)
+ self.assertEqual(
+ mapper.routes['foo'].pattern, 'archives/:action/:article2'
+ )
+ self.assertEqual(
+ mapper.routelist[0].pattern, 'archives/:action/:article2'
+ )
+
+ def test___call__pathinfo_cant_be_decoded(self):
+ from pyramid.exceptions import URLDecodeError
+
+ mapper = self._makeOne()
+ if PY2:
+ path_info = b'\xff\xfe\xe6\x00'
+ else:
+ path_info = b'\xff\xfe\xe6\x00'.decode('latin-1')
+ request = self._getRequest(PATH_INFO=path_info)
+ self.assertRaises(URLDecodeError, mapper, request)
+
+ def test___call__route_matches(self):
+ mapper = self._makeOne()
+ mapper.connect('foo', 'archives/:action/:article')
+ request = self._getRequest(PATH_INFO='/archives/action1/article1')
+ result = mapper(request)
+ self.assertEqual(result['route'], mapper.routes['foo'])
+ self.assertEqual(result['match']['action'], 'action1')
+ self.assertEqual(result['match']['article'], 'article1')
+
+ def test___call__route_matches_with_predicates(self):
+ mapper = self._makeOne()
+ mapper.connect(
+ 'foo', 'archives/:action/:article', predicates=[lambda *arg: True]
+ )
+ request = self._getRequest(PATH_INFO='/archives/action1/article1')
+ result = mapper(request)
+ self.assertEqual(result['route'], mapper.routes['foo'])
+ self.assertEqual(result['match']['action'], 'action1')
+ self.assertEqual(result['match']['article'], 'article1')
+
+ def test___call__route_fails_to_match_with_predicates(self):
+ mapper = self._makeOne()
+ mapper.connect(
+ 'foo',
+ 'archives/:action/article1',
+ predicates=[lambda *arg: True, lambda *arg: False],
+ )
+ mapper.connect('bar', 'archives/:action/:article')
+ request = self._getRequest(PATH_INFO='/archives/action1/article1')
+ result = mapper(request)
+ self.assertEqual(result['route'], mapper.routes['bar'])
+ self.assertEqual(result['match']['action'], 'action1')
+ self.assertEqual(result['match']['article'], 'article1')
+
+ def test___call__custom_predicate_gets_info(self):
+ mapper = self._makeOne()
+
+ def pred(info, request):
+ self.assertEqual(info['match'], {'action': 'action1'})
+ self.assertEqual(info['route'], mapper.routes['foo'])
+ return True
+
+ mapper.connect('foo', 'archives/:action/article1', predicates=[pred])
+ request = self._getRequest(PATH_INFO='/archives/action1/article1')
+ mapper(request)
+
+ def test_cc_bug(self):
+ # "unordered" as reported in IRC by author of
+ # http://labs.creativecommons.org/2010/01/13/cc-engine-and-web-non-frameworks/
+ mapper = self._makeOne()
+ mapper.connect('rdf', 'licenses/:license_code/:license_version/rdf')
+ mapper.connect(
+ 'juri', 'licenses/:license_code/:license_version/:jurisdiction'
+ )
+
+ request = self._getRequest(PATH_INFO='/licenses/1/v2/rdf')
+ result = mapper(request)
+ self.assertEqual(result['route'], mapper.routes['rdf'])
+ self.assertEqual(result['match']['license_code'], '1')
+ self.assertEqual(result['match']['license_version'], 'v2')
+
+ request = self._getRequest(PATH_INFO='/licenses/1/v2/usa')
+ result = mapper(request)
+ self.assertEqual(result['route'], mapper.routes['juri'])
+ self.assertEqual(result['match']['license_code'], '1')
+ self.assertEqual(result['match']['license_version'], 'v2')
+ self.assertEqual(result['match']['jurisdiction'], 'usa')
+
+ def test___call__root_route_matches(self):
+ mapper = self._makeOne()
+ mapper.connect('root', '')
+ request = self._getRequest(PATH_INFO='/')
+ result = mapper(request)
+ self.assertEqual(result['route'], mapper.routes['root'])
+ self.assertEqual(result['match'], {})
+
+ def test___call__root_route_matches2(self):
+ mapper = self._makeOne()
+ mapper.connect('root', '/')
+ request = self._getRequest(PATH_INFO='/')
+ result = mapper(request)
+ self.assertEqual(result['route'], mapper.routes['root'])
+ self.assertEqual(result['match'], {})
+
+ def test___call__root_route_when_path_info_empty(self):
+ mapper = self._makeOne()
+ mapper.connect('root', '/')
+ request = self._getRequest(PATH_INFO='')
+ result = mapper(request)
+ self.assertEqual(result['route'], mapper.routes['root'])
+ self.assertEqual(result['match'], {})
+
+ def test___call__root_route_when_path_info_notempty(self):
+ mapper = self._makeOne()
+ mapper.connect('root', '/')
+ request = self._getRequest(PATH_INFO='/')
+ result = mapper(request)
+ self.assertEqual(result['route'], mapper.routes['root'])
+ self.assertEqual(result['match'], {})
+
+ def test___call__no_path_info(self):
+ mapper = self._makeOne()
+ mapper.connect('root', '/')
+ request = self._getRequest()
+ result = mapper(request)
+ self.assertEqual(result['route'], mapper.routes['root'])
+ self.assertEqual(result['match'], {})
+
+ def test_has_routes(self):
+ mapper = self._makeOne()
+ self.assertEqual(mapper.has_routes(), False)
+ mapper.connect('whatever', 'archives/:action/:article')
+ self.assertEqual(mapper.has_routes(), True)
+
+ def test_get_routes(self):
+ from pyramid.urldispatch import Route
+
+ mapper = self._makeOne()
+ self.assertEqual(mapper.get_routes(), [])
+ mapper.connect('whatever', 'archives/:action/:article')
+ routes = mapper.get_routes()
+ self.assertEqual(len(routes), 1)
+ self.assertEqual(routes[0].__class__, Route)
+
+ def test_get_route_matches(self):
+ mapper = self._makeOne()
+ mapper.connect('whatever', 'archives/:action/:article')
+ result = mapper.get_route('whatever')
+ self.assertEqual(result.pattern, 'archives/:action/:article')
+
+ def test_get_route_misses(self):
+ mapper = self._makeOne()
+ result = mapper.get_route('whatever')
+ self.assertEqual(result, None)
+
+ def test_generate(self):
+ mapper = self._makeOne()
+
+ def generator(kw):
+ return 123
+
+ route = DummyRoute(generator)
+ mapper.routes['abc'] = route
+ self.assertEqual(mapper.generate('abc', {}), 123)
+
+
+class TestCompileRoute(unittest.TestCase):
+ def _callFUT(self, pattern):
+ from pyramid.urldispatch import _compile_route
+
+ return _compile_route(pattern)
+
+ def test_no_star(self):
+ matcher, generator = self._callFUT('/foo/:baz/biz/:buz/bar')
+ self.assertEqual(
+ matcher('/foo/baz/biz/buz/bar'), {'baz': 'baz', 'buz': 'buz'}
+ )
+ self.assertEqual(matcher('foo/baz/biz/buz/bar'), None)
+ self.assertEqual(generator({'baz': 1, 'buz': 2}), '/foo/1/biz/2/bar')
+
+ def test_with_star(self):
+ matcher, generator = self._callFUT('/foo/:baz/biz/:buz/bar*traverse')
+ self.assertEqual(
+ matcher('/foo/baz/biz/buz/bar'),
+ {'baz': 'baz', 'buz': 'buz', 'traverse': ()},
+ )
+ self.assertEqual(
+ matcher('/foo/baz/biz/buz/bar/everything/else/here'),
+ {
+ 'baz': 'baz',
+ 'buz': 'buz',
+ 'traverse': ('everything', 'else', 'here'),
+ },
+ )
+ self.assertEqual(matcher('foo/baz/biz/buz/bar'), None)
+ self.assertEqual(
+ generator({'baz': 1, 'buz': 2, 'traverse': '/a/b'}),
+ '/foo/1/biz/2/bar/a/b',
+ )
+
+ def test_with_bracket_star(self):
+ matcher, generator = self._callFUT(
+ '/foo/{baz}/biz/{buz}/bar{remainder:.*}'
+ )
+ self.assertEqual(
+ matcher('/foo/baz/biz/buz/bar'),
+ {'baz': 'baz', 'buz': 'buz', 'remainder': ''},
+ )
+ self.assertEqual(
+ matcher('/foo/baz/biz/buz/bar/everything/else/here'),
+ {'baz': 'baz', 'buz': 'buz', 'remainder': '/everything/else/here'},
+ )
+ self.assertEqual(matcher('foo/baz/biz/buz/bar'), None)
+ self.assertEqual(
+ generator({'baz': 1, 'buz': 2, 'remainder': '/a/b'}),
+ '/foo/1/biz/2/bar/a/b',
+ )
+
+ def test_no_beginning_slash(self):
+ matcher, generator = self._callFUT('foo/:baz/biz/:buz/bar')
+ self.assertEqual(
+ matcher('/foo/baz/biz/buz/bar'), {'baz': 'baz', 'buz': 'buz'}
+ )
+ self.assertEqual(matcher('foo/baz/biz/buz/bar'), None)
+ self.assertEqual(generator({'baz': 1, 'buz': 2}), '/foo/1/biz/2/bar')
+
+ def test_custom_regex(self):
+ matcher, generator = self._callFUT(
+ 'foo/{baz}/biz/{buz:[^/\\.]+}.{bar}'
+ )
+ self.assertEqual(
+ matcher('/foo/baz/biz/buz.bar'),
+ {'baz': 'baz', 'buz': 'buz', 'bar': 'bar'},
+ )
+ self.assertEqual(matcher('foo/baz/biz/buz/bar'), None)
+ self.assertEqual(
+ generator({'baz': 1, 'buz': 2, 'bar': 'html'}), '/foo/1/biz/2.html'
+ )
+
+ def test_custom_regex_with_colons(self):
+ matcher, generator = self._callFUT(
+ 'foo/{baz}/biz/{buz:(?:[^/\\.]+)}.{bar}'
+ )
+ self.assertEqual(
+ matcher('/foo/baz/biz/buz.bar'),
+ {'baz': 'baz', 'buz': 'buz', 'bar': 'bar'},
+ )
+ self.assertEqual(matcher('foo/baz/biz/buz/bar'), None)
+ self.assertEqual(
+ generator({'baz': 1, 'buz': 2, 'bar': 'html'}), '/foo/1/biz/2.html'
+ )
+
+ def test_mixed_newstyle_oldstyle_pattern_defaults_to_newstyle(self):
+ # pattern: '\\/foo\\/(?P<baz>abc)\\/biz\\/(?P<buz>[^/]+)\\/bar$'
+ # note presence of :abc in pattern (oldstyle match)
+ matcher, generator = self._callFUT('foo/{baz:abc}/biz/{buz}/bar')
+ self.assertEqual(
+ matcher('/foo/abc/biz/buz/bar'), {'baz': 'abc', 'buz': 'buz'}
+ )
+ self.assertEqual(generator({'baz': 1, 'buz': 2}), '/foo/1/biz/2/bar')
+
+ def test_custom_regex_with_embedded_squigglies(self):
+ matcher, generator = self._callFUT('/{buz:\\d{4}}')
+ self.assertEqual(matcher('/2001'), {'buz': '2001'})
+ self.assertEqual(matcher('/200'), None)
+ self.assertEqual(generator({'buz': 2001}), '/2001')
+
+ def test_custom_regex_with_embedded_squigglies2(self):
+ matcher, generator = self._callFUT('/{buz:\\d{3,4}}')
+ self.assertEqual(matcher('/2001'), {'buz': '2001'})
+ self.assertEqual(matcher('/200'), {'buz': '200'})
+ self.assertEqual(matcher('/20'), None)
+ self.assertEqual(generator({'buz': 2001}), '/2001')
+
+ def test_custom_regex_with_embedded_squigglies3(self):
+ matcher, generator = self._callFUT(
+ '/{buz:(\\d{2}|\\d{4})-[a-zA-Z]{3,4}-\\d{2}}'
+ )
+ self.assertEqual(matcher('/2001-Nov-15'), {'buz': '2001-Nov-15'})
+ self.assertEqual(matcher('/99-June-10'), {'buz': '99-June-10'})
+ self.assertEqual(matcher('/2-Nov-15'), None)
+ self.assertEqual(matcher('/200-Nov-15'), None)
+ self.assertEqual(matcher('/2001-No-15'), None)
+ self.assertEqual(generator({'buz': '2001-Nov-15'}), '/2001-Nov-15')
+ self.assertEqual(generator({'buz': '99-June-10'}), '/99-June-10')
+
+ def test_pattern_with_high_order_literal(self):
+ pattern = text_(b'/La Pe\xc3\xb1a/{x}', 'utf-8')
+ matcher, generator = self._callFUT(pattern)
+ self.assertEqual(
+ matcher(text_(b'/La Pe\xc3\xb1a/x', 'utf-8')), {'x': 'x'}
+ )
+ self.assertEqual(generator({'x': '1'}), '/La%20Pe%C3%B1a/1')
+
+ def test_pattern_generate_with_high_order_dynamic(self):
+ pattern = '/{x}'
+ _, generator = self._callFUT(pattern)
+ self.assertEqual(
+ generator({'x': text_(b'La Pe\xc3\xb1a', 'utf-8')}),
+ '/La%20Pe%C3%B1a',
+ )
+
+ def test_docs_sample_generate(self):
+ # sample from urldispatch.rst
+ pattern = text_(b'/La Pe\xc3\xb1a/{city}', 'utf-8')
+ _, generator = self._callFUT(pattern)
+ self.assertEqual(
+ generator({'city': text_(b'Qu\xc3\xa9bec', 'utf-8')}),
+ '/La%20Pe%C3%B1a/Qu%C3%A9bec',
+ )
+
+ def test_generate_with_mixedtype_values(self):
+ pattern = '/{city}/{state}'
+ _, generator = self._callFUT(pattern)
+ result = generator(
+ {
+ 'city': text_(b'Qu\xc3\xa9bec', 'utf-8'),
+ 'state': b'La Pe\xc3\xb1a',
+ }
+ )
+ self.assertEqual(result, '/Qu%C3%A9bec/La%20Pe%C3%B1a')
+ # should be a native string
+ self.assertEqual(type(result), str)
+
+ def test_highorder_pattern_utf8(self):
+ pattern = b'/La Pe\xc3\xb1a/{city}'
+ self.assertRaises(ValueError, self._callFUT, pattern)
+
+ def test_generate_with_string_remainder_and_unicode_replacement(self):
+ pattern = text_(b'/abc*remainder', 'utf-8')
+ _, generator = self._callFUT(pattern)
+ result = generator(
+ {'remainder': text_(b'/Qu\xc3\xa9bec/La Pe\xc3\xb1a', 'utf-8')}
+ )
+ self.assertEqual(result, '/abc/Qu%C3%A9bec/La%20Pe%C3%B1a')
+ # should be a native string
+ self.assertEqual(type(result), str)
+
+ def test_generate_with_string_remainder_and_nonstring_replacement(self):
+ pattern = text_(b'/abc/*remainder', 'utf-8')
+ _, generator = self._callFUT(pattern)
+ result = generator({'remainder': None})
+ self.assertEqual(result, '/abc/None')
+ # should be a native string
+ self.assertEqual(type(result), str)
+
+
+class TestCompileRouteFunctional(unittest.TestCase):
+ def matches(self, pattern, path, expected):
+ from pyramid.urldispatch import _compile_route
+
+ matcher = _compile_route(pattern)[0]
+ result = matcher(path)
+ self.assertEqual(result, expected)
+
+ def generates(self, pattern, dict, result):
+ from pyramid.urldispatch import _compile_route
+
+ self.assertEqual(_compile_route(pattern)[1](dict), result)
+
+ def test_matcher_functional_notdynamic(self):
+ self.matches('/', '', None)
+ self.matches('', '', None)
+ self.matches('/', '/foo', None)
+ self.matches('/foo/', '/foo', None)
+ self.matches('', '/', {})
+ self.matches('/', '/', {})
+
+ def test_matcher_functional_newstyle(self):
+ self.matches('/{x}', '', None)
+ self.matches('/{x}', '/', None)
+ self.matches('/abc/{def}', '/abc/', None)
+ self.matches('/{x}', '/a', {'x': 'a'})
+ self.matches('zzz/{x}', '/zzz/abc', {'x': 'abc'})
+ self.matches(
+ 'zzz/{x}*traverse', '/zzz/abc', {'x': 'abc', 'traverse': ()}
+ )
+ self.matches(
+ 'zzz/{x}*traverse',
+ '/zzz/abc/def/g',
+ {'x': 'abc', 'traverse': ('def', 'g')},
+ )
+ self.matches('*traverse', '/zzz/abc', {'traverse': ('zzz', 'abc')})
+ self.matches('*traverse', '/zzz/ abc', {'traverse': ('zzz', ' abc')})
+ # '/La%20Pe%C3%B1a'
+ self.matches(
+ '{x}',
+ text_(b'/La Pe\xc3\xb1a', 'utf-8'),
+ {'x': text_(b'La Pe\xc3\xb1a', 'utf-8')},
+ )
+ # '/La%20Pe%C3%B1a/x'
+ self.matches(
+ '*traverse',
+ text_(b'/La Pe\xc3\xb1a/x'),
+ {'traverse': (text_(b'La Pe\xc3\xb1a'), 'x')},
+ )
+ self.matches('/foo/{id}.html', '/foo/bar.html', {'id': 'bar'})
+ self.matches(
+ '/{num:[0-9]+}/*traverse',
+ '/555/abc/def',
+ {'num': '555', 'traverse': ('abc', 'def')},
+ )
+ self.matches(
+ '/{num:[0-9]*}/*traverse',
+ '/555/abc/def',
+ {'num': '555', 'traverse': ('abc', 'def')},
+ )
+ self.matches('zzz/{_}', '/zzz/abc', {'_': 'abc'})
+ self.matches('zzz/{_abc}', '/zzz/abc', {'_abc': 'abc'})
+ self.matches('zzz/{abc_def}', '/zzz/abc', {'abc_def': 'abc'})
+
+ def test_matcher_functional_oldstyle(self):
+ self.matches('/:x', '', None)
+ self.matches('/:x', '/', None)
+ self.matches('/abc/:def', '/abc/', None)
+ self.matches('/:x', '/a', {'x': 'a'})
+ self.matches('zzz/:x', '/zzz/abc', {'x': 'abc'})
+ self.matches(
+ 'zzz/:x*traverse', '/zzz/abc', {'x': 'abc', 'traverse': ()}
+ )
+ self.matches(
+ 'zzz/:x*traverse',
+ '/zzz/abc/def/g',
+ {'x': 'abc', 'traverse': ('def', 'g')},
+ )
+ self.matches('*traverse', '/zzz/abc', {'traverse': ('zzz', 'abc')})
+ self.matches('*traverse', '/zzz/ abc', {'traverse': ('zzz', ' abc')})
+ # '/La%20Pe%C3%B1a'
+ # pattern, path, expected
+ self.matches(
+ ':x',
+ text_(b'/La Pe\xc3\xb1a', 'utf-8'),
+ {'x': text_(b'La Pe\xc3\xb1a', 'utf-8')},
+ )
+ # '/La%20Pe%C3%B1a/x'
+ self.matches(
+ '*traverse',
+ text_(b'/La Pe\xc3\xb1a/x', 'utf-8'),
+ {'traverse': (text_(b'La Pe\xc3\xb1a', 'utf-8'), 'x')},
+ )
+ self.matches('/foo/:id.html', '/foo/bar.html', {'id': 'bar'})
+ self.matches('/foo/:id_html', '/foo/bar_html', {'id_html': 'bar_html'})
+ self.matches('zzz/:_', '/zzz/abc', {'_': 'abc'})
+ self.matches('zzz/:_abc', '/zzz/abc', {'_abc': 'abc'})
+ self.matches('zzz/:abc_def', '/zzz/abc', {'abc_def': 'abc'})
+
+ def test_generator_functional_notdynamic(self):
+ self.generates('', {}, '/')
+ self.generates('/', {}, '/')
+
+ def test_generator_functional_newstyle(self):
+ self.generates('/{x}', {'x': ''}, '/')
+ self.generates('/{x}', {'x': 'a'}, '/a')
+ self.generates('/{x}', {'x': 'a/b/c'}, '/a/b/c')
+ self.generates('/{x}', {'x': ':@&+$,'}, '/:@&+$,')
+ self.generates('zzz/{x}', {'x': 'abc'}, '/zzz/abc')
+ self.generates(
+ 'zzz/{x}*traverse', {'x': 'abc', 'traverse': ''}, '/zzz/abc'
+ )
+ self.generates(
+ 'zzz/{x}*traverse',
+ {'x': 'abc', 'traverse': '/def/g'},
+ '/zzz/abc/def/g',
+ )
+ self.generates(
+ 'zzz/{x}*traverse',
+ {'x': ':@&+$,', 'traverse': '/:@&+$,'},
+ '/zzz/:@&+$,/:@&+$,',
+ )
+ self.generates(
+ '/{x}',
+ {'x': text_(b'/La Pe\xc3\xb1a', 'utf-8')},
+ '//La%20Pe%C3%B1a',
+ )
+ self.generates(
+ '/{x}*y',
+ {'x': text_(b'/La Pe\xc3\xb1a', 'utf-8'), 'y': '/rest/of/path'},
+ '//La%20Pe%C3%B1a/rest/of/path',
+ )
+ self.generates(
+ '*traverse',
+ {'traverse': ('a', text_(b'La Pe\xf1a'))},
+ '/a/La%20Pe%C3%B1a',
+ )
+ self.generates('/foo/{id}.html', {'id': 'bar'}, '/foo/bar.html')
+ self.generates('/foo/{_}', {'_': '20'}, '/foo/20')
+ self.generates('/foo/{_abc}', {'_abc': '20'}, '/foo/20')
+ self.generates('/foo/{abc_def}', {'abc_def': '20'}, '/foo/20')
+
+ def test_generator_functional_oldstyle(self):
+ self.generates('/:x', {'x': ''}, '/')
+ self.generates('/:x', {'x': 'a'}, '/a')
+ self.generates('zzz/:x', {'x': 'abc'}, '/zzz/abc')
+ self.generates(
+ 'zzz/:x*traverse', {'x': 'abc', 'traverse': ''}, '/zzz/abc'
+ )
+ self.generates(
+ 'zzz/:x*traverse',
+ {'x': 'abc', 'traverse': '/def/g'},
+ '/zzz/abc/def/g',
+ )
+ self.generates(
+ '/:x',
+ {'x': text_(b'/La Pe\xc3\xb1a', 'utf-8')},
+ '//La%20Pe%C3%B1a',
+ )
+ self.generates(
+ '/:x*y',
+ {'x': text_(b'/La Pe\xc3\xb1a', 'utf-8'), 'y': '/rest/of/path'},
+ '//La%20Pe%C3%B1a/rest/of/path',
+ )
+ self.generates(
+ '*traverse',
+ {'traverse': ('a', text_(b'La Pe\xf1a'))},
+ '/a/La%20Pe%C3%B1a',
+ )
+ self.generates('/foo/:id.html', {'id': 'bar'}, '/foo/bar.html')
+ self.generates('/foo/:_', {'_': '20'}, '/foo/20')
+ self.generates('/foo/:_abc', {'_abc': '20'}, '/foo/20')
+ self.generates('/foo/:abc_def', {'abc_def': '20'}, '/foo/20')
+
+
+class DummyContext(object):
+ """ """
+
+
+class DummyRequest(object):
+ def __init__(self, environ):
+ self.environ = environ
+
+
+class DummyRoute(object):
+ def __init__(self, generator):
+ self.generate = generator
diff --git a/tests/test_util.py b/tests/test_util.py
new file mode 100644
index 000000000..a36655f6f
--- /dev/null
+++ b/tests/test_util.py
@@ -0,0 +1,1242 @@
+import unittest
+from pyramid.compat import PY2, text_, bytes_
+
+
+class Test_InstancePropertyHelper(unittest.TestCase):
+ def _makeOne(self):
+ cls = self._getTargetClass()
+ return cls()
+
+ def _getTargetClass(self):
+ from pyramid.util import InstancePropertyHelper
+
+ return InstancePropertyHelper
+
+ def test_callable(self):
+ def worker(obj):
+ return obj.bar
+
+ foo = Dummy()
+ helper = self._getTargetClass()
+ helper.set_property(foo, worker)
+ foo.bar = 1
+ self.assertEqual(1, foo.worker)
+ foo.bar = 2
+ self.assertEqual(2, foo.worker)
+
+ def test_callable_with_name(self):
+ def worker(obj):
+ return obj.bar
+
+ foo = Dummy()
+ helper = self._getTargetClass()
+ helper.set_property(foo, worker, name='x')
+ foo.bar = 1
+ self.assertEqual(1, foo.x)
+ foo.bar = 2
+ self.assertEqual(2, foo.x)
+
+ def test_callable_with_reify(self):
+ def worker(obj):
+ return obj.bar
+
+ foo = Dummy()
+ helper = self._getTargetClass()
+ helper.set_property(foo, worker, reify=True)
+ foo.bar = 1
+ self.assertEqual(1, foo.worker)
+ foo.bar = 2
+ self.assertEqual(1, foo.worker)
+
+ def test_callable_with_name_reify(self):
+ def worker(obj):
+ return obj.bar
+
+ foo = Dummy()
+ helper = self._getTargetClass()
+ helper.set_property(foo, worker, name='x')
+ helper.set_property(foo, worker, name='y', reify=True)
+ foo.bar = 1
+ self.assertEqual(1, foo.y)
+ self.assertEqual(1, foo.x)
+ foo.bar = 2
+ self.assertEqual(2, foo.x)
+ self.assertEqual(1, foo.y)
+
+ def test_property_without_name(self):
+ def worker(obj): # pragma: no cover
+ pass
+
+ foo = Dummy()
+ helper = self._getTargetClass()
+ self.assertRaises(
+ ValueError, helper.set_property, foo, property(worker)
+ )
+
+ def test_property_with_name(self):
+ def worker(obj):
+ return obj.bar
+
+ foo = Dummy()
+ helper = self._getTargetClass()
+ helper.set_property(foo, property(worker), name='x')
+ foo.bar = 1
+ self.assertEqual(1, foo.x)
+ foo.bar = 2
+ self.assertEqual(2, foo.x)
+
+ def test_property_with_reify(self):
+ def worker(obj): # pragma: no cover
+ pass
+
+ foo = Dummy()
+ helper = self._getTargetClass()
+ self.assertRaises(
+ ValueError,
+ helper.set_property,
+ foo,
+ property(worker),
+ name='x',
+ reify=True,
+ )
+
+ def test_override_property(self):
+ def worker(obj): # pragma: no cover
+ pass
+
+ foo = Dummy()
+ helper = self._getTargetClass()
+ helper.set_property(foo, worker, name='x')
+
+ def doit():
+ foo.x = 1
+
+ self.assertRaises(AttributeError, doit)
+
+ def test_override_reify(self):
+ def worker(obj): # pragma: no cover
+ pass
+
+ foo = Dummy()
+ helper = self._getTargetClass()
+ helper.set_property(foo, worker, name='x', reify=True)
+ foo.x = 1
+ self.assertEqual(1, foo.x)
+ foo.x = 2
+ self.assertEqual(2, foo.x)
+
+ def test_reset_property(self):
+ foo = Dummy()
+ helper = self._getTargetClass()
+ helper.set_property(foo, lambda _: 1, name='x')
+ self.assertEqual(1, foo.x)
+ helper.set_property(foo, lambda _: 2, name='x')
+ self.assertEqual(2, foo.x)
+
+ def test_reset_reify(self):
+ """ This is questionable behavior, but may as well get notified
+ if it changes."""
+ foo = Dummy()
+ helper = self._getTargetClass()
+ helper.set_property(foo, lambda _: 1, name='x', reify=True)
+ self.assertEqual(1, foo.x)
+ helper.set_property(foo, lambda _: 2, name='x', reify=True)
+ self.assertEqual(1, foo.x)
+
+ def test_make_property(self):
+ from pyramid.decorator import reify
+
+ helper = self._getTargetClass()
+ name, fn = helper.make_property(lambda x: 1, name='x', reify=True)
+ self.assertEqual(name, 'x')
+ self.assertTrue(isinstance(fn, reify))
+
+ def test_apply_properties_with_iterable(self):
+ foo = Dummy()
+ helper = self._getTargetClass()
+ x = helper.make_property(lambda _: 1, name='x', reify=True)
+ y = helper.make_property(lambda _: 2, name='y')
+ helper.apply_properties(foo, [x, y])
+ self.assertEqual(1, foo.x)
+ self.assertEqual(2, foo.y)
+
+ def test_apply_properties_with_dict(self):
+ foo = Dummy()
+ helper = self._getTargetClass()
+ x_name, x_fn = helper.make_property(lambda _: 1, name='x', reify=True)
+ y_name, y_fn = helper.make_property(lambda _: 2, name='y')
+ helper.apply_properties(foo, {x_name: x_fn, y_name: y_fn})
+ self.assertEqual(1, foo.x)
+ self.assertEqual(2, foo.y)
+
+ def test_make_property_unicode(self):
+ from pyramid.compat import text_
+ from pyramid.exceptions import ConfigurationError
+
+ cls = self._getTargetClass()
+ if PY2:
+ name = text_(b'La Pe\xc3\xb1a', 'utf-8')
+ else:
+ name = b'La Pe\xc3\xb1a'
+
+ def make_bad_name():
+ cls.make_property(lambda x: 1, name=name, reify=True)
+
+ self.assertRaises(ConfigurationError, make_bad_name)
+
+ def test_add_property(self):
+ helper = self._makeOne()
+ helper.add_property(lambda obj: obj.bar, name='x', reify=True)
+ helper.add_property(lambda obj: obj.bar, name='y')
+ self.assertEqual(len(helper.properties), 2)
+ foo = Dummy()
+ helper.apply(foo)
+ foo.bar = 1
+ self.assertEqual(foo.x, 1)
+ self.assertEqual(foo.y, 1)
+ foo.bar = 2
+ self.assertEqual(foo.x, 1)
+ self.assertEqual(foo.y, 2)
+
+ def test_apply_multiple_times(self):
+ helper = self._makeOne()
+ helper.add_property(lambda obj: 1, name='x')
+ foo, bar = Dummy(), Dummy()
+ helper.apply(foo)
+ self.assertEqual(foo.x, 1)
+ helper.add_property(lambda obj: 2, name='x')
+ helper.apply(bar)
+ self.assertEqual(foo.x, 1)
+ self.assertEqual(bar.x, 2)
+
+
+class Test_InstancePropertyMixin(unittest.TestCase):
+ def _makeOne(self):
+ cls = self._getTargetClass()
+
+ class Foo(cls):
+ pass
+
+ return Foo()
+
+ def _getTargetClass(self):
+ from pyramid.util import InstancePropertyMixin
+
+ return InstancePropertyMixin
+
+ def test_callable(self):
+ def worker(obj):
+ return obj.bar
+
+ foo = self._makeOne()
+ foo.set_property(worker)
+ foo.bar = 1
+ self.assertEqual(1, foo.worker)
+ foo.bar = 2
+ self.assertEqual(2, foo.worker)
+
+ def test_callable_with_name(self):
+ def worker(obj):
+ return obj.bar
+
+ foo = self._makeOne()
+ foo.set_property(worker, name='x')
+ foo.bar = 1
+ self.assertEqual(1, foo.x)
+ foo.bar = 2
+ self.assertEqual(2, foo.x)
+
+ def test_callable_with_reify(self):
+ def worker(obj):
+ return obj.bar
+
+ foo = self._makeOne()
+ foo.set_property(worker, reify=True)
+ foo.bar = 1
+ self.assertEqual(1, foo.worker)
+ foo.bar = 2
+ self.assertEqual(1, foo.worker)
+
+ def test_callable_with_name_reify(self):
+ def worker(obj):
+ return obj.bar
+
+ foo = self._makeOne()
+ foo.set_property(worker, name='x')
+ foo.set_property(worker, name='y', reify=True)
+ foo.bar = 1
+ self.assertEqual(1, foo.y)
+ self.assertEqual(1, foo.x)
+ foo.bar = 2
+ self.assertEqual(2, foo.x)
+ self.assertEqual(1, foo.y)
+
+ def test_property_without_name(self):
+ def worker(obj): # pragma: no cover
+ pass
+
+ foo = self._makeOne()
+ self.assertRaises(ValueError, foo.set_property, property(worker))
+
+ def test_property_with_name(self):
+ def worker(obj):
+ return obj.bar
+
+ foo = self._makeOne()
+ foo.set_property(property(worker), name='x')
+ foo.bar = 1
+ self.assertEqual(1, foo.x)
+ foo.bar = 2
+ self.assertEqual(2, foo.x)
+
+ def test_property_with_reify(self):
+ def worker(obj): # pragma: no cover
+ pass
+
+ foo = self._makeOne()
+ self.assertRaises(
+ ValueError,
+ foo.set_property,
+ property(worker),
+ name='x',
+ reify=True,
+ )
+
+ def test_override_property(self):
+ def worker(obj): # pragma: no cover
+ pass
+
+ foo = self._makeOne()
+ foo.set_property(worker, name='x')
+
+ def doit():
+ foo.x = 1
+
+ self.assertRaises(AttributeError, doit)
+
+ def test_override_reify(self):
+ def worker(obj): # pragma: no cover
+ pass
+
+ foo = self._makeOne()
+ foo.set_property(worker, name='x', reify=True)
+ foo.x = 1
+ self.assertEqual(1, foo.x)
+ foo.x = 2
+ self.assertEqual(2, foo.x)
+
+ def test_reset_property(self):
+ foo = self._makeOne()
+ foo.set_property(lambda _: 1, name='x')
+ self.assertEqual(1, foo.x)
+ foo.set_property(lambda _: 2, name='x')
+ self.assertEqual(2, foo.x)
+
+ def test_reset_reify(self):
+ """ This is questionable behavior, but may as well get notified
+ if it changes."""
+ foo = self._makeOne()
+ foo.set_property(lambda _: 1, name='x', reify=True)
+ self.assertEqual(1, foo.x)
+ foo.set_property(lambda _: 2, name='x', reify=True)
+ self.assertEqual(1, foo.x)
+
+ def test_new_class_keeps_parent_module_name(self):
+ foo = self._makeOne()
+ self.assertEqual(foo.__module__, 'tests.test_util')
+ self.assertEqual(foo.__class__.__module__, 'tests.test_util')
+ foo.set_property(lambda _: 1, name='x', reify=True)
+ self.assertEqual(foo.__module__, 'tests.test_util')
+ self.assertEqual(foo.__class__.__module__, 'tests.test_util')
+
+
+class Test_WeakOrderedSet(unittest.TestCase):
+ def _makeOne(self):
+ from pyramid.config import WeakOrderedSet
+
+ return WeakOrderedSet()
+
+ def test_ctor(self):
+ wos = self._makeOne()
+ self.assertEqual(len(wos), 0)
+ self.assertEqual(wos.last, None)
+
+ def test_add_item(self):
+ wos = self._makeOne()
+ reg = Dummy()
+ wos.add(reg)
+ self.assertEqual(list(wos), [reg])
+ self.assertTrue(reg in wos)
+ self.assertEqual(wos.last, reg)
+
+ def test_add_multiple_items(self):
+ wos = self._makeOne()
+ reg1 = Dummy()
+ reg2 = Dummy()
+ wos.add(reg1)
+ wos.add(reg2)
+ self.assertEqual(len(wos), 2)
+ self.assertEqual(list(wos), [reg1, reg2])
+ self.assertTrue(reg1 in wos)
+ self.assertTrue(reg2 in wos)
+ self.assertEqual(wos.last, reg2)
+
+ def test_add_duplicate_items(self):
+ wos = self._makeOne()
+ reg = Dummy()
+ wos.add(reg)
+ wos.add(reg)
+ self.assertEqual(len(wos), 1)
+ self.assertEqual(list(wos), [reg])
+ self.assertTrue(reg in wos)
+ self.assertEqual(wos.last, reg)
+
+ def test_weakref_removal(self):
+ wos = self._makeOne()
+ reg = Dummy()
+ wos.add(reg)
+ wos.remove(reg)
+ self.assertEqual(len(wos), 0)
+ self.assertEqual(list(wos), [])
+ self.assertEqual(wos.last, None)
+
+ def test_last_updated(self):
+ wos = self._makeOne()
+ reg = Dummy()
+ reg2 = Dummy()
+ wos.add(reg)
+ wos.add(reg2)
+ wos.remove(reg2)
+ self.assertEqual(len(wos), 1)
+ self.assertEqual(list(wos), [reg])
+ self.assertEqual(wos.last, reg)
+
+ def test_empty(self):
+ wos = self._makeOne()
+ reg = Dummy()
+ reg2 = Dummy()
+ wos.add(reg)
+ wos.add(reg2)
+ wos.empty()
+ self.assertEqual(len(wos), 0)
+ self.assertEqual(list(wos), [])
+ self.assertEqual(wos.last, None)
+
+
+class Test_strings_differ(unittest.TestCase):
+ def _callFUT(self, *args, **kw):
+ from pyramid.util import strings_differ
+
+ return strings_differ(*args, **kw)
+
+ def test_it_bytes(self):
+ self.assertFalse(self._callFUT(b'foo', b'foo'))
+ self.assertTrue(self._callFUT(b'123', b'345'))
+ self.assertTrue(self._callFUT(b'1234', b'123'))
+ self.assertTrue(self._callFUT(b'123', b'1234'))
+
+ def test_it_native_str(self):
+ self.assertFalse(self._callFUT('123', '123'))
+ self.assertTrue(self._callFUT('123', '1234'))
+
+ def test_it_with_internal_comparator(self):
+ result = self._callFUT(b'foo', b'foo', compare_digest=None)
+ self.assertFalse(result)
+
+ result = self._callFUT(b'123', b'abc', compare_digest=None)
+ self.assertTrue(result)
+
+ def test_it_with_external_comparator(self):
+ class DummyComparator(object):
+ called = False
+
+ def __init__(self, ret_val):
+ self.ret_val = ret_val
+
+ def __call__(self, a, b):
+ self.called = True
+ return self.ret_val
+
+ dummy_compare = DummyComparator(True)
+ result = self._callFUT(b'foo', b'foo', compare_digest=dummy_compare)
+ self.assertTrue(dummy_compare.called)
+ self.assertFalse(result)
+
+ dummy_compare = DummyComparator(False)
+ result = self._callFUT(b'123', b'345', compare_digest=dummy_compare)
+ self.assertTrue(dummy_compare.called)
+ self.assertTrue(result)
+
+ dummy_compare = DummyComparator(False)
+ result = self._callFUT(b'abc', b'abc', compare_digest=dummy_compare)
+ self.assertTrue(dummy_compare.called)
+ self.assertTrue(result)
+
+
+class Test_object_description(unittest.TestCase):
+ def _callFUT(self, object):
+ from pyramid.util import object_description
+
+ return object_description(object)
+
+ def test_string(self):
+ self.assertEqual(self._callFUT('abc'), 'abc')
+
+ def test_int(self):
+ self.assertEqual(self._callFUT(1), '1')
+
+ def test_bool(self):
+ self.assertEqual(self._callFUT(True), 'True')
+
+ def test_None(self):
+ self.assertEqual(self._callFUT(None), 'None')
+
+ def test_float(self):
+ self.assertEqual(self._callFUT(1.2), '1.2')
+
+ def test_tuple(self):
+ self.assertEqual(self._callFUT(('a', 'b')), "('a', 'b')")
+
+ def test_set(self):
+ if PY2:
+ self.assertEqual(self._callFUT(set(['a'])), "set(['a'])")
+ else:
+ self.assertEqual(self._callFUT(set(['a'])), "{'a'}")
+
+ def test_list(self):
+ self.assertEqual(self._callFUT(['a']), "['a']")
+
+ def test_dict(self):
+ self.assertEqual(self._callFUT({'a': 1}), "{'a': 1}")
+
+ def test_nomodule(self):
+ o = object()
+ self.assertEqual(self._callFUT(o), 'object %s' % str(o))
+
+ def test_module(self):
+ import pyramid
+
+ self.assertEqual(self._callFUT(pyramid), 'module pyramid')
+
+ def test_method(self):
+ self.assertEqual(
+ self._callFUT(self.test_method),
+ 'method test_method of class tests.test_util.'
+ 'Test_object_description',
+ )
+
+ def test_class(self):
+ self.assertEqual(
+ self._callFUT(self.__class__),
+ 'class tests.test_util.Test_object_description',
+ )
+
+ def test_function(self):
+ self.assertEqual(
+ self._callFUT(dummyfunc), 'function tests.test_util.dummyfunc'
+ )
+
+ def test_instance(self):
+ inst = Dummy()
+ self.assertEqual(self._callFUT(inst), "object %s" % str(inst))
+
+ def test_shortened_repr(self):
+ inst = ['1'] * 1000
+ self.assertEqual(self._callFUT(inst), str(inst)[:100] + ' ... ]')
+
+
+class TestTopologicalSorter(unittest.TestCase):
+ def _makeOne(self, *arg, **kw):
+ from pyramid.util import TopologicalSorter
+
+ return TopologicalSorter(*arg, **kw)
+
+ def test_remove(self):
+ inst = self._makeOne()
+ inst.names.append('name')
+ inst.name2val['name'] = 1
+ inst.req_after.add('name')
+ inst.req_before.add('name')
+ inst.name2after['name'] = ('bob',)
+ inst.name2before['name'] = ('fred',)
+ inst.order.append(('bob', 'name'))
+ inst.order.append(('name', 'fred'))
+ inst.remove('name')
+ self.assertFalse(inst.names)
+ self.assertFalse(inst.req_before)
+ self.assertFalse(inst.req_after)
+ self.assertFalse(inst.name2before)
+ self.assertFalse(inst.name2after)
+ self.assertFalse(inst.name2val)
+ self.assertFalse(inst.order)
+
+ def test_add(self):
+ from pyramid.util import LAST
+
+ sorter = self._makeOne()
+ sorter.add('name', 'factory')
+ self.assertEqual(sorter.names, ['name'])
+ self.assertEqual(sorter.name2val, {'name': 'factory'})
+ self.assertEqual(sorter.order, [('name', LAST)])
+ sorter.add('name2', 'factory2')
+ self.assertEqual(sorter.names, ['name', 'name2'])
+ self.assertEqual(
+ sorter.name2val, {'name': 'factory', 'name2': 'factory2'}
+ )
+ self.assertEqual(sorter.order, [('name', LAST), ('name2', LAST)])
+ sorter.add('name3', 'factory3', before='name2')
+ self.assertEqual(sorter.names, ['name', 'name2', 'name3'])
+ self.assertEqual(
+ sorter.name2val,
+ {'name': 'factory', 'name2': 'factory2', 'name3': 'factory3'},
+ )
+ self.assertEqual(
+ sorter.order, [('name', LAST), ('name2', LAST), ('name3', 'name2')]
+ )
+
+ def test_sorted_ordering_1(self):
+ sorter = self._makeOne()
+ sorter.add('name1', 'factory1')
+ sorter.add('name2', 'factory2')
+ self.assertEqual(
+ sorter.sorted(), [('name1', 'factory1'), ('name2', 'factory2')]
+ )
+
+ def test_sorted_ordering_2(self):
+ from pyramid.util import FIRST
+
+ sorter = self._makeOne()
+ sorter.add('name1', 'factory1')
+ sorter.add('name2', 'factory2', after=FIRST)
+ self.assertEqual(
+ sorter.sorted(), [('name2', 'factory2'), ('name1', 'factory1')]
+ )
+
+ def test_sorted_ordering_3(self):
+ from pyramid.util import FIRST
+
+ sorter = self._makeOne()
+ add = sorter.add
+ add('auth', 'auth_factory', after='browserid')
+ add('dbt', 'dbt_factory')
+ add('retry', 'retry_factory', before='txnmgr', after='exceptionview')
+ add('browserid', 'browserid_factory')
+ add('txnmgr', 'txnmgr_factory', after='exceptionview')
+ add('exceptionview', 'excview_factory', after=FIRST)
+ self.assertEqual(
+ sorter.sorted(),
+ [
+ ('exceptionview', 'excview_factory'),
+ ('retry', 'retry_factory'),
+ ('txnmgr', 'txnmgr_factory'),
+ ('dbt', 'dbt_factory'),
+ ('browserid', 'browserid_factory'),
+ ('auth', 'auth_factory'),
+ ],
+ )
+
+ def test_sorted_ordering_4(self):
+ from pyramid.util import FIRST
+
+ sorter = self._makeOne()
+ add = sorter.add
+ add('exceptionview', 'excview_factory', after=FIRST)
+ add('auth', 'auth_factory', after='browserid')
+ add('retry', 'retry_factory', before='txnmgr', after='exceptionview')
+ add('browserid', 'browserid_factory')
+ add('txnmgr', 'txnmgr_factory', after='exceptionview')
+ add('dbt', 'dbt_factory')
+ self.assertEqual(
+ sorter.sorted(),
+ [
+ ('exceptionview', 'excview_factory'),
+ ('retry', 'retry_factory'),
+ ('txnmgr', 'txnmgr_factory'),
+ ('browserid', 'browserid_factory'),
+ ('auth', 'auth_factory'),
+ ('dbt', 'dbt_factory'),
+ ],
+ )
+
+ def test_sorted_ordering_5(self):
+ from pyramid.util import LAST, FIRST
+
+ sorter = self._makeOne()
+ add = sorter.add
+ add('exceptionview', 'excview_factory')
+ add('auth', 'auth_factory', after=FIRST)
+ add('retry', 'retry_factory', before='txnmgr', after='exceptionview')
+ add('browserid', 'browserid_factory', after=FIRST)
+ add('txnmgr', 'txnmgr_factory', after='exceptionview', before=LAST)
+ add('dbt', 'dbt_factory')
+ self.assertEqual(
+ sorter.sorted(),
+ [
+ ('browserid', 'browserid_factory'),
+ ('auth', 'auth_factory'),
+ ('exceptionview', 'excview_factory'),
+ ('retry', 'retry_factory'),
+ ('txnmgr', 'txnmgr_factory'),
+ ('dbt', 'dbt_factory'),
+ ],
+ )
+
+ def test_sorted_ordering_missing_before_partial(self):
+ from pyramid.exceptions import ConfigurationError
+
+ sorter = self._makeOne()
+ add = sorter.add
+ add('dbt', 'dbt_factory')
+ add('auth', 'auth_factory', after='browserid')
+ add('retry', 'retry_factory', before='txnmgr', after='exceptionview')
+ add('browserid', 'browserid_factory')
+ self.assertRaises(ConfigurationError, sorter.sorted)
+
+ def test_sorted_ordering_missing_after_partial(self):
+ from pyramid.exceptions import ConfigurationError
+
+ sorter = self._makeOne()
+ add = sorter.add
+ add('dbt', 'dbt_factory')
+ add('auth', 'auth_factory', after='txnmgr')
+ add('retry', 'retry_factory', before='dbt', after='exceptionview')
+ add('browserid', 'browserid_factory')
+ self.assertRaises(ConfigurationError, sorter.sorted)
+
+ def test_sorted_ordering_missing_before_and_after_partials(self):
+ from pyramid.exceptions import ConfigurationError
+
+ sorter = self._makeOne()
+ add = sorter.add
+ add('dbt', 'dbt_factory')
+ add('auth', 'auth_factory', after='browserid')
+ add('retry', 'retry_factory', before='foo', after='txnmgr')
+ add('browserid', 'browserid_factory')
+ self.assertRaises(ConfigurationError, sorter.sorted)
+
+ def test_sorted_ordering_missing_before_partial_with_fallback(self):
+ from pyramid.util import LAST
+
+ sorter = self._makeOne()
+ add = sorter.add
+ add('exceptionview', 'excview_factory', before=LAST)
+ add('auth', 'auth_factory', after='browserid')
+ add(
+ 'retry',
+ 'retry_factory',
+ before=('txnmgr', LAST),
+ after='exceptionview',
+ )
+ add('browserid', 'browserid_factory')
+ add('dbt', 'dbt_factory')
+ self.assertEqual(
+ sorter.sorted(),
+ [
+ ('exceptionview', 'excview_factory'),
+ ('retry', 'retry_factory'),
+ ('browserid', 'browserid_factory'),
+ ('auth', 'auth_factory'),
+ ('dbt', 'dbt_factory'),
+ ],
+ )
+
+ def test_sorted_ordering_missing_after_partial_with_fallback(self):
+ from pyramid.util import FIRST
+
+ sorter = self._makeOne()
+ add = sorter.add
+ add('exceptionview', 'excview_factory', after=FIRST)
+ add('auth', 'auth_factory', after=('txnmgr', 'browserid'))
+ add('retry', 'retry_factory', after='exceptionview')
+ add('browserid', 'browserid_factory')
+ add('dbt', 'dbt_factory')
+ self.assertEqual(
+ sorter.sorted(),
+ [
+ ('exceptionview', 'excview_factory'),
+ ('retry', 'retry_factory'),
+ ('browserid', 'browserid_factory'),
+ ('auth', 'auth_factory'),
+ ('dbt', 'dbt_factory'),
+ ],
+ )
+
+ def test_sorted_ordering_with_partial_fallbacks(self):
+ from pyramid.util import LAST
+
+ sorter = self._makeOne()
+ add = sorter.add
+ add('exceptionview', 'excview_factory', before=('wontbethere', LAST))
+ add('retry', 'retry_factory', after='exceptionview')
+ add(
+ 'browserid', 'browserid_factory', before=('wont2', 'exceptionview')
+ )
+ self.assertEqual(
+ sorter.sorted(),
+ [
+ ('browserid', 'browserid_factory'),
+ ('exceptionview', 'excview_factory'),
+ ('retry', 'retry_factory'),
+ ],
+ )
+
+ def test_sorted_ordering_with_multiple_matching_fallbacks(self):
+ from pyramid.util import LAST
+
+ sorter = self._makeOne()
+ add = sorter.add
+ add('exceptionview', 'excview_factory', before=LAST)
+ add('retry', 'retry_factory', after='exceptionview')
+ add(
+ 'browserid', 'browserid_factory', before=('retry', 'exceptionview')
+ )
+ self.assertEqual(
+ sorter.sorted(),
+ [
+ ('browserid', 'browserid_factory'),
+ ('exceptionview', 'excview_factory'),
+ ('retry', 'retry_factory'),
+ ],
+ )
+
+ def test_sorted_ordering_with_missing_fallbacks(self):
+ from pyramid.exceptions import ConfigurationError
+ from pyramid.util import LAST
+
+ sorter = self._makeOne()
+ add = sorter.add
+ add('exceptionview', 'excview_factory', before=LAST)
+ add('retry', 'retry_factory', after='exceptionview')
+ add('browserid', 'browserid_factory', before=('txnmgr', 'auth'))
+ self.assertRaises(ConfigurationError, sorter.sorted)
+
+ def test_sorted_ordering_conflict_direct(self):
+ from pyramid.exceptions import CyclicDependencyError
+
+ sorter = self._makeOne()
+ add = sorter.add
+ add('browserid', 'browserid_factory')
+ add('auth', 'auth_factory', before='browserid', after='browserid')
+ self.assertRaises(CyclicDependencyError, sorter.sorted)
+
+ def test_sorted_ordering_conflict_indirect(self):
+ from pyramid.exceptions import CyclicDependencyError
+
+ sorter = self._makeOne()
+ add = sorter.add
+ add('browserid', 'browserid_factory')
+ add('auth', 'auth_factory', before='browserid')
+ add('dbt', 'dbt_factory', after='browserid', before='auth')
+ self.assertRaises(CyclicDependencyError, sorter.sorted)
+
+
+class TestSentinel(unittest.TestCase):
+ def test_repr(self):
+ from pyramid.util import Sentinel
+
+ r = repr(Sentinel('ABC'))
+ self.assertEqual(r, 'ABC')
+
+
+class TestCallableName(unittest.TestCase):
+ def test_valid_ascii(self):
+ from pyramid.util import get_callable_name
+ from pyramid.compat import text_
+
+ if PY2:
+ name = text_(b'hello world', 'utf-8')
+ else:
+ name = b'hello world'
+
+ self.assertEqual(get_callable_name(name), 'hello world')
+
+ def test_invalid_ascii(self):
+ from pyramid.util import get_callable_name
+ from pyramid.compat import text_
+ from pyramid.exceptions import ConfigurationError
+
+ def get_bad_name():
+ if PY2:
+ name = text_(b'La Pe\xc3\xb1a', 'utf-8')
+ else:
+ name = b'La Pe\xc3\xb1a'
+
+ get_callable_name(name)
+
+ self.assertRaises(ConfigurationError, get_bad_name)
+
+
+class Test_hide_attrs(unittest.TestCase):
+ def _callFUT(self, obj, *attrs):
+ from pyramid.util import hide_attrs
+
+ return hide_attrs(obj, *attrs)
+
+ def _makeDummy(self):
+ from pyramid.decorator import reify
+
+ class Dummy(object):
+ x = 1
+
+ @reify
+ def foo(self):
+ return self.x
+
+ return Dummy()
+
+ def test_restores_attrs(self):
+ obj = self._makeDummy()
+ obj.bar = 'asdf'
+ orig_foo = obj.foo
+ with self._callFUT(obj, 'foo', 'bar'):
+ obj.foo = object()
+ obj.bar = 'nope'
+ self.assertEqual(obj.foo, orig_foo)
+ self.assertEqual(obj.bar, 'asdf')
+
+ def test_restores_attrs_on_exception(self):
+ obj = self._makeDummy()
+ orig_foo = obj.foo
+ try:
+ with self._callFUT(obj, 'foo'):
+ obj.foo = object()
+ raise RuntimeError()
+ except RuntimeError:
+ self.assertEqual(obj.foo, orig_foo)
+ else: # pragma: no cover
+ self.fail("RuntimeError not raised")
+
+ def test_restores_attrs_to_none(self):
+ obj = self._makeDummy()
+ obj.foo = None
+ with self._callFUT(obj, 'foo'):
+ obj.foo = object()
+ self.assertEqual(obj.foo, None)
+
+ def test_deletes_attrs(self):
+ obj = self._makeDummy()
+ with self._callFUT(obj, 'foo'):
+ obj.foo = object()
+ self.assertTrue('foo' not in obj.__dict__)
+
+ def test_does_not_delete_attr_if_no_attr_to_delete(self):
+ obj = self._makeDummy()
+ with self._callFUT(obj, 'foo'):
+ pass
+ self.assertTrue('foo' not in obj.__dict__)
+
+
+def dummyfunc(): # pragma: no cover
+ pass
+
+
+class Dummy(object):
+ pass
+
+
+class Test_is_same_domain(unittest.TestCase):
+ def _callFUT(self, *args, **kw):
+ from pyramid.util import is_same_domain
+
+ return is_same_domain(*args, **kw)
+
+ def test_it(self):
+ self.assertTrue(self._callFUT("example.com", "example.com"))
+ self.assertFalse(self._callFUT("evil.com", "example.com"))
+ self.assertFalse(self._callFUT("evil.example.com", "example.com"))
+ self.assertFalse(self._callFUT("example.com", ""))
+
+ def test_with_wildcard(self):
+ self.assertTrue(self._callFUT("example.com", ".example.com"))
+ self.assertTrue(self._callFUT("good.example.com", ".example.com"))
+
+ def test_with_port(self):
+ self.assertTrue(self._callFUT("example.com:8080", "example.com:8080"))
+ self.assertFalse(self._callFUT("example.com:8080", "example.com"))
+ self.assertFalse(self._callFUT("example.com", "example.com:8080"))
+
+
+class Test_make_contextmanager(unittest.TestCase):
+ def _callFUT(self, *args, **kw):
+ from pyramid.util import make_contextmanager
+
+ return make_contextmanager(*args, **kw)
+
+ def test_with_None(self):
+ mgr = self._callFUT(None)
+ with mgr() as ctx:
+ self.assertIsNone(ctx)
+
+ def test_with_generator(self):
+ def mygen(ctx):
+ yield ctx
+
+ mgr = self._callFUT(mygen)
+ with mgr('a') as ctx:
+ self.assertEqual(ctx, 'a')
+
+ def test_with_multiple_yield_generator(self):
+ def mygen():
+ yield 'a'
+ yield 'b'
+
+ mgr = self._callFUT(mygen)
+ try:
+ with mgr() as ctx:
+ self.assertEqual(ctx, 'a')
+ except RuntimeError:
+ pass
+ else: # pragma: no cover
+ raise AssertionError('expected raise from multiple yields')
+
+ def test_with_regular_fn(self):
+ def mygen():
+ return 'a'
+
+ mgr = self._callFUT(mygen)
+ with mgr() as ctx:
+ self.assertEqual(ctx, 'a')
+
+
+class Test_takes_one_arg(unittest.TestCase):
+ def _callFUT(self, view, attr=None, argname=None):
+ from pyramid.util import takes_one_arg
+
+ return takes_one_arg(view, attr=attr, argname=argname)
+
+ def test_requestonly_newstyle_class_no_init(self):
+ class foo(object):
+ """ """
+
+ self.assertFalse(self._callFUT(foo))
+
+ def test_requestonly_newstyle_class_init_toomanyargs(self):
+ class foo(object):
+ def __init__(self, context, request):
+ """ """
+
+ self.assertFalse(self._callFUT(foo))
+
+ def test_requestonly_newstyle_class_init_onearg_named_request(self):
+ class foo(object):
+ def __init__(self, request):
+ """ """
+
+ self.assertTrue(self._callFUT(foo))
+
+ def test_newstyle_class_init_onearg_named_somethingelse(self):
+ class foo(object):
+ def __init__(self, req):
+ """ """
+
+ self.assertTrue(self._callFUT(foo))
+
+ def test_newstyle_class_init_defaultargs_firstname_not_request(self):
+ class foo(object):
+ def __init__(self, context, request=None):
+ """ """
+
+ self.assertFalse(self._callFUT(foo))
+
+ def test_newstyle_class_init_defaultargs_firstname_request(self):
+ class foo(object):
+ def __init__(self, request, foo=1, bar=2):
+ """ """
+
+ self.assertTrue(self._callFUT(foo, argname='request'))
+
+ def test_newstyle_class_init_firstname_request_with_secondname(self):
+ class foo(object):
+ def __init__(self, request, two):
+ """ """
+
+ self.assertFalse(self._callFUT(foo))
+
+ def test_newstyle_class_init_noargs(self):
+ class foo(object):
+ def __init__():
+ """ """
+
+ self.assertFalse(self._callFUT(foo))
+
+ def test_oldstyle_class_no_init(self):
+ class foo:
+ """ """
+
+ self.assertFalse(self._callFUT(foo))
+
+ def test_oldstyle_class_init_toomanyargs(self):
+ class foo:
+ def __init__(self, context, request):
+ """ """
+
+ self.assertFalse(self._callFUT(foo))
+
+ def test_oldstyle_class_init_onearg_named_request(self):
+ class foo:
+ def __init__(self, request):
+ """ """
+
+ self.assertTrue(self._callFUT(foo))
+
+ def test_oldstyle_class_init_onearg_named_somethingelse(self):
+ class foo:
+ def __init__(self, req):
+ """ """
+
+ self.assertTrue(self._callFUT(foo))
+
+ def test_oldstyle_class_init_defaultargs_firstname_not_request(self):
+ class foo:
+ def __init__(self, context, request=None):
+ """ """
+
+ self.assertFalse(self._callFUT(foo))
+
+ def test_oldstyle_class_init_defaultargs_firstname_request(self):
+ class foo:
+ def __init__(self, request, foo=1, bar=2):
+ """ """
+
+ self.assertTrue(self._callFUT(foo, argname='request'), True)
+
+ def test_oldstyle_class_init_noargs(self):
+ class foo:
+ def __init__():
+ """ """
+
+ self.assertFalse(self._callFUT(foo))
+
+ def test_function_toomanyargs(self):
+ def foo(context, request):
+ """ """
+
+ self.assertFalse(self._callFUT(foo))
+
+ def test_function_with_attr_false(self):
+ def bar(context, request):
+ """ """
+
+ def foo(context, request):
+ """ """
+
+ foo.bar = bar
+ self.assertFalse(self._callFUT(foo, 'bar'))
+
+ def test_function_with_attr_true(self):
+ def bar(context, request):
+ """ """
+
+ def foo(request):
+ """ """
+
+ foo.bar = bar
+ self.assertTrue(self._callFUT(foo, 'bar'))
+
+ def test_function_onearg_named_request(self):
+ def foo(request):
+ """ """
+
+ self.assertTrue(self._callFUT(foo))
+
+ def test_function_onearg_named_somethingelse(self):
+ def foo(req):
+ """ """
+
+ self.assertTrue(self._callFUT(foo))
+
+ def test_function_defaultargs_firstname_not_request(self):
+ def foo(context, request=None):
+ """ """
+
+ self.assertFalse(self._callFUT(foo))
+
+ def test_function_defaultargs_firstname_request(self):
+ def foo(request, foo=1, bar=2):
+ """ """
+
+ self.assertTrue(self._callFUT(foo, argname='request'))
+
+ def test_function_noargs(self):
+ def foo():
+ """ """
+
+ self.assertFalse(self._callFUT(foo))
+
+ def test_instance_toomanyargs(self):
+ class Foo:
+ def __call__(self, context, request):
+ """ """
+
+ foo = Foo()
+ self.assertFalse(self._callFUT(foo))
+
+ def test_instance_defaultargs_onearg_named_request(self):
+ class Foo:
+ def __call__(self, request):
+ """ """
+
+ foo = Foo()
+ self.assertTrue(self._callFUT(foo))
+
+ def test_instance_defaultargs_onearg_named_somethingelse(self):
+ class Foo:
+ def __call__(self, req):
+ """ """
+
+ foo = Foo()
+ self.assertTrue(self._callFUT(foo))
+
+ def test_instance_defaultargs_firstname_not_request(self):
+ class Foo:
+ def __call__(self, context, request=None):
+ """ """
+
+ foo = Foo()
+ self.assertFalse(self._callFUT(foo))
+
+ def test_instance_defaultargs_firstname_request(self):
+ class Foo:
+ def __call__(self, request, foo=1, bar=2):
+ """ """
+
+ foo = Foo()
+ self.assertTrue(self._callFUT(foo, argname='request'), True)
+
+ def test_instance_nocall(self):
+ class Foo:
+ pass
+
+ foo = Foo()
+ self.assertFalse(self._callFUT(foo))
+
+ def test_method_onearg_named_request(self):
+ class Foo:
+ def method(self, request):
+ """ """
+
+ foo = Foo()
+ self.assertTrue(self._callFUT(foo.method))
+
+ def test_function_annotations(self):
+ def foo(bar):
+ """ """
+
+ # avoid SyntaxErrors in python2, this if effectively nop
+ getattr(foo, '__annotations__', {}).update({'bar': 'baz'})
+ self.assertTrue(self._callFUT(foo))
+
+
+class TestSimpleSerializer(unittest.TestCase):
+ def _makeOne(self):
+ from pyramid.util import SimpleSerializer
+
+ return SimpleSerializer()
+
+ def test_loads(self):
+ inst = self._makeOne()
+ self.assertEqual(inst.loads(b'abc'), text_('abc'))
+
+ def test_dumps(self):
+ inst = self._makeOne()
+ self.assertEqual(inst.dumps('abc'), bytes_('abc'))
diff --git a/tests/test_view.py b/tests/test_view.py
new file mode 100644
index 000000000..f82480169
--- /dev/null
+++ b/tests/test_view.py
@@ -0,0 +1,1279 @@
+import unittest
+from zope.interface import Interface
+from zope.interface import implementer
+import sys
+
+from pyramid import testing
+from pyramid.interfaces import IRequest
+from pyramid.interfaces import IResponse
+
+
+class BaseTest(object):
+ def setUp(self):
+ self.config = testing.setUp()
+
+ def tearDown(self):
+ testing.tearDown()
+
+ def _registerView(self, reg, app, name):
+ from pyramid.interfaces import IViewClassifier
+
+ for_ = (IViewClassifier, IRequest, IContext)
+ from pyramid.interfaces import IView
+
+ reg.registerAdapter(app, for_, IView, name)
+
+ def _makeEnviron(self, **extras):
+ environ = {
+ 'wsgi.url_scheme': 'http',
+ 'wsgi.version': (1, 0),
+ 'SERVER_NAME': 'localhost',
+ 'SERVER_PORT': '8080',
+ 'REQUEST_METHOD': 'GET',
+ 'PATH_INFO': '/',
+ }
+ environ.update(extras)
+ return environ
+
+ def _makeRequest(self, **environ):
+ from pyramid.request import Request
+ from pyramid.registry import Registry
+
+ environ = self._makeEnviron(**environ)
+ request = Request(environ)
+ request.registry = Registry()
+ return request
+
+ def _makeContext(self):
+ from zope.interface import directlyProvides
+
+ context = DummyContext()
+ directlyProvides(context, IContext)
+ return context
+
+
+class Test_notfound_view_config(BaseTest, unittest.TestCase):
+ def _makeOne(self, **kw):
+ from pyramid.view import notfound_view_config
+
+ return notfound_view_config(**kw)
+
+ def test_ctor(self):
+ inst = self._makeOne(
+ attr='attr', path_info='path_info', append_slash=True
+ )
+ self.assertEqual(
+ inst.__dict__,
+ {'attr': 'attr', 'path_info': 'path_info', 'append_slash': True},
+ )
+
+ def test_it_function(self):
+ def view(request): # pragma: no cover
+ pass
+
+ decorator = self._makeOne(
+ attr='attr', renderer='renderer', append_slash=True
+ )
+ venusian = DummyVenusian()
+ decorator.venusian = venusian
+ wrapped = decorator(view)
+ self.assertTrue(wrapped is view)
+ config = call_venusian(venusian)
+ settings = config.settings
+ self.assertEqual(
+ settings,
+ [
+ {
+ 'attr': 'attr',
+ 'venusian': venusian,
+ 'append_slash': True,
+ 'renderer': 'renderer',
+ '_info': 'codeinfo',
+ 'view': None,
+ }
+ ],
+ )
+
+ def test_it_class(self):
+ decorator = self._makeOne()
+ venusian = DummyVenusian()
+ decorator.venusian = venusian
+ decorator.venusian.info.scope = 'class'
+
+ class view(object):
+ pass
+
+ wrapped = decorator(view)
+ self.assertTrue(wrapped is view)
+ config = call_venusian(venusian)
+ settings = config.settings
+ self.assertEqual(len(settings), 1)
+ self.assertEqual(len(settings[0]), 4)
+ self.assertEqual(settings[0]['venusian'], venusian)
+ self.assertEqual(settings[0]['view'], None) # comes from call_venusian
+ self.assertEqual(settings[0]['attr'], 'view')
+ self.assertEqual(settings[0]['_info'], 'codeinfo')
+
+ def test_call_with_venusian_args(self):
+ decorator = self._makeOne(_depth=1, _category='foo')
+ venusian = DummyVenusian()
+ decorator.venusian = venusian
+
+ def foo(): # pragma: no cover
+ pass
+
+ decorator(foo)
+ attachments = venusian.attachments
+ category = attachments[0][2]
+ depth = attachments[0][3]
+ self.assertEqual(depth, 2)
+ self.assertEqual(category, 'foo')
+
+
+class Test_forbidden_view_config(BaseTest, unittest.TestCase):
+ def _makeOne(self, **kw):
+ from pyramid.view import forbidden_view_config
+
+ return forbidden_view_config(**kw)
+
+ def test_ctor(self):
+ inst = self._makeOne(attr='attr', path_info='path_info')
+ self.assertEqual(
+ inst.__dict__, {'attr': 'attr', 'path_info': 'path_info'}
+ )
+
+ def test_it_function(self):
+ def view(request): # pragma: no cover
+ pass
+
+ decorator = self._makeOne(attr='attr', renderer='renderer')
+ venusian = DummyVenusian()
+ decorator.venusian = venusian
+ wrapped = decorator(view)
+ self.assertTrue(wrapped is view)
+ config = call_venusian(venusian)
+ settings = config.settings
+ self.assertEqual(
+ settings,
+ [
+ {
+ 'attr': 'attr',
+ 'venusian': venusian,
+ 'renderer': 'renderer',
+ '_info': 'codeinfo',
+ 'view': None,
+ }
+ ],
+ )
+
+ def test_it_class(self):
+ decorator = self._makeOne()
+ venusian = DummyVenusian()
+ decorator.venusian = venusian
+ decorator.venusian.info.scope = 'class'
+
+ class view(object):
+ pass
+
+ wrapped = decorator(view)
+ self.assertTrue(wrapped is view)
+ config = call_venusian(venusian)
+ settings = config.settings
+ self.assertEqual(len(settings), 1)
+ self.assertEqual(len(settings[0]), 4)
+ self.assertEqual(settings[0]['venusian'], venusian)
+ self.assertEqual(settings[0]['view'], None) # comes from call_venusian
+ self.assertEqual(settings[0]['attr'], 'view')
+ self.assertEqual(settings[0]['_info'], 'codeinfo')
+
+ def test_call_with_venusian_args(self):
+ decorator = self._makeOne(_depth=1, _category='foo')
+ venusian = DummyVenusian()
+ decorator.venusian = venusian
+
+ def foo(): # pragma: no cover
+ pass
+
+ decorator(foo)
+ attachments = venusian.attachments
+ category = attachments[0][2]
+ depth = attachments[0][3]
+ self.assertEqual(depth, 2)
+ self.assertEqual(category, 'foo')
+
+
+class Test_exception_view_config(BaseTest, unittest.TestCase):
+ def _makeOne(self, *args, **kw):
+ from pyramid.view import exception_view_config
+
+ return exception_view_config(*args, **kw)
+
+ def test_ctor(self):
+ inst = self._makeOne(context=Exception, path_info='path_info')
+ self.assertEqual(
+ inst.__dict__, {'context': Exception, 'path_info': 'path_info'}
+ )
+
+ def test_ctor_positional_exception(self):
+ inst = self._makeOne(Exception, path_info='path_info')
+ self.assertEqual(
+ inst.__dict__, {'context': Exception, 'path_info': 'path_info'}
+ )
+
+ def test_ctor_positional_extras(self):
+ from pyramid.exceptions import ConfigurationError
+
+ self.assertRaises(
+ ConfigurationError, lambda: self._makeOne(Exception, True)
+ )
+
+ def test_it_function(self):
+ def view(request): # pragma: no cover
+ pass
+
+ decorator = self._makeOne(context=Exception, renderer='renderer')
+ venusian = DummyVenusian()
+ decorator.venusian = venusian
+ wrapped = decorator(view)
+ self.assertTrue(wrapped is view)
+ config = call_venusian(venusian)
+ settings = config.settings
+ self.assertEqual(
+ settings,
+ [
+ {
+ 'venusian': venusian,
+ 'context': Exception,
+ 'renderer': 'renderer',
+ '_info': 'codeinfo',
+ 'view': None,
+ }
+ ],
+ )
+
+ def test_it_class(self):
+ decorator = self._makeOne()
+ venusian = DummyVenusian()
+ decorator.venusian = venusian
+ decorator.venusian.info.scope = 'class'
+
+ class view(object):
+ pass
+
+ wrapped = decorator(view)
+ self.assertTrue(wrapped is view)
+ config = call_venusian(venusian)
+ settings = config.settings
+ self.assertEqual(len(settings), 1)
+ self.assertEqual(len(settings[0]), 4)
+ self.assertEqual(settings[0]['venusian'], venusian)
+ self.assertEqual(settings[0]['view'], None) # comes from call_venusian
+ self.assertEqual(settings[0]['attr'], 'view')
+ self.assertEqual(settings[0]['_info'], 'codeinfo')
+
+ def test_call_with_venusian_args(self):
+ decorator = self._makeOne(_depth=1, _category='foo')
+ venusian = DummyVenusian()
+ decorator.venusian = venusian
+
+ def foo(): # pragma: no cover
+ pass
+
+ decorator(foo)
+ attachments = venusian.attachments
+ category = attachments[0][2]
+ depth = attachments[0][3]
+ self.assertEqual(depth, 2)
+ self.assertEqual(category, 'foo')
+
+
+class RenderViewToResponseTests(BaseTest, unittest.TestCase):
+ def _callFUT(self, *arg, **kw):
+ from pyramid.view import render_view_to_response
+
+ return render_view_to_response(*arg, **kw)
+
+ def test_call_no_view_registered(self):
+ request = self._makeRequest()
+ context = self._makeContext()
+ result = self._callFUT(context, request, name='notregistered')
+ self.assertEqual(result, None)
+
+ def test_call_no_registry_on_request(self):
+ request = self._makeRequest()
+ del request.registry
+ context = self._makeContext()
+ result = self._callFUT(context, request, name='notregistered')
+ self.assertEqual(result, None)
+
+ def test_call_view_registered_secure(self):
+ request = self._makeRequest()
+ context = self._makeContext()
+ response = DummyResponse()
+ view = make_view(response)
+ self._registerView(request.registry, view, 'registered')
+ response = self._callFUT(
+ context, request, name='registered', secure=True
+ )
+ self.assertEqual(response.status, '200 OK')
+
+ def test_call_view_registered_insecure_no_call_permissive(self):
+ context = self._makeContext()
+ request = self._makeRequest()
+ response = DummyResponse()
+ view = make_view(response)
+ self._registerView(request.registry, view, 'registered')
+ response = self._callFUT(
+ context, request, name='registered', secure=False
+ )
+ self.assertEqual(response.status, '200 OK')
+
+ def test_call_view_registered_insecure_with_call_permissive(self):
+ context = self._makeContext()
+ request = self._makeRequest()
+ response = DummyResponse()
+ view = make_view(response)
+
+ def anotherview(context, request):
+ return DummyResponse('anotherview')
+
+ view.__call_permissive__ = anotherview
+ self._registerView(request.registry, view, 'registered')
+ response = self._callFUT(
+ context, request, name='registered', secure=False
+ )
+ self.assertEqual(response.status, '200 OK')
+ self.assertEqual(response.app_iter, ['anotherview'])
+
+ def test_call_view_with_request_iface_on_request(self):
+ # See https://github.com/Pylons/pyramid/issues/1643
+ from zope.interface import Interface
+
+ class IWontBeFound(Interface):
+ pass
+
+ context = self._makeContext()
+ request = self._makeRequest()
+ request.request_iface = IWontBeFound
+ response = DummyResponse('aview')
+ view = make_view(response)
+ self._registerView(request.registry, view, 'aview')
+ response = self._callFUT(context, request, name='aview')
+ self.assertEqual(response.status, '200 OK')
+ self.assertEqual(response.app_iter, ['aview'])
+
+
+class RenderViewToIterableTests(BaseTest, unittest.TestCase):
+ def _callFUT(self, *arg, **kw):
+ from pyramid.view import render_view_to_iterable
+
+ return render_view_to_iterable(*arg, **kw)
+
+ def test_call_no_view_registered(self):
+ request = self._makeRequest()
+ context = self._makeContext()
+ result = self._callFUT(context, request, name='notregistered')
+ self.assertEqual(result, None)
+
+ def test_call_view_registered_secure(self):
+ request = self._makeRequest()
+ context = self._makeContext()
+ response = DummyResponse()
+ view = make_view(response)
+ self._registerView(request.registry, view, 'registered')
+ iterable = self._callFUT(
+ context, request, name='registered', secure=True
+ )
+ self.assertEqual(iterable, ())
+
+ def test_call_view_registered_insecure_no_call_permissive(self):
+ context = self._makeContext()
+ request = self._makeRequest()
+ response = DummyResponse()
+ view = make_view(response)
+ self._registerView(request.registry, view, 'registered')
+ iterable = self._callFUT(
+ context, request, name='registered', secure=False
+ )
+ self.assertEqual(iterable, ())
+
+ def test_call_view_registered_insecure_with_call_permissive(self):
+ context = self._makeContext()
+ request = self._makeRequest()
+ response = DummyResponse()
+ view = make_view(response)
+
+ def anotherview(context, request):
+ return DummyResponse(b'anotherview')
+
+ view.__call_permissive__ = anotherview
+ self._registerView(request.registry, view, 'registered')
+ iterable = self._callFUT(
+ context, request, name='registered', secure=False
+ )
+ self.assertEqual(iterable, [b'anotherview'])
+
+ def test_verify_output_bytestring(self):
+ from pyramid.request import Request
+ from pyramid.config import Configurator
+ from pyramid.view import render_view
+ from webob.compat import text_type
+
+ config = Configurator(settings={})
+
+ def view(request):
+ request.response.text = text_type('<body></body>')
+ return request.response
+
+ config.add_view(name='test', view=view)
+ config.commit()
+
+ r = Request({})
+ r.registry = config.registry
+ self.assertEqual(render_view(object(), r, 'test'), b'<body></body>')
+
+ def test_call_request_has_no_registry(self):
+ request = self._makeRequest()
+ del request.registry
+ registry = self.config.registry
+ context = self._makeContext()
+ response = DummyResponse()
+ view = make_view(response)
+ self._registerView(registry, view, 'registered')
+ iterable = self._callFUT(
+ context, request, name='registered', secure=True
+ )
+ self.assertEqual(iterable, ())
+
+
+class RenderViewTests(BaseTest, unittest.TestCase):
+ def _callFUT(self, *arg, **kw):
+ from pyramid.view import render_view
+
+ return render_view(*arg, **kw)
+
+ def test_call_no_view_registered(self):
+ request = self._makeRequest()
+ context = self._makeContext()
+ result = self._callFUT(context, request, name='notregistered')
+ self.assertEqual(result, None)
+
+ def test_call_view_registered_secure(self):
+ request = self._makeRequest()
+ context = self._makeContext()
+ response = DummyResponse()
+ view = make_view(response)
+ self._registerView(request.registry, view, 'registered')
+ s = self._callFUT(context, request, name='registered', secure=True)
+ self.assertEqual(s, b'')
+
+ def test_call_view_registered_insecure_no_call_permissive(self):
+ context = self._makeContext()
+ request = self._makeRequest()
+ response = DummyResponse()
+ view = make_view(response)
+ self._registerView(request.registry, view, 'registered')
+ s = self._callFUT(context, request, name='registered', secure=False)
+ self.assertEqual(s, b'')
+
+ def test_call_view_registered_insecure_with_call_permissive(self):
+ context = self._makeContext()
+ request = self._makeRequest()
+ response = DummyResponse()
+ view = make_view(response)
+
+ def anotherview(context, request):
+ return DummyResponse(b'anotherview')
+
+ view.__call_permissive__ = anotherview
+ self._registerView(request.registry, view, 'registered')
+ s = self._callFUT(context, request, name='registered', secure=False)
+ self.assertEqual(s, b'anotherview')
+
+
+class TestViewConfigDecorator(unittest.TestCase):
+ def setUp(self):
+ testing.setUp()
+
+ def tearDown(self):
+ testing.tearDown()
+
+ def _getTargetClass(self):
+ from pyramid.view import view_config
+
+ return view_config
+
+ def _makeOne(self, *arg, **kw):
+ return self._getTargetClass()(*arg, **kw)
+
+ def test_create_defaults(self):
+ decorator = self._makeOne()
+ self.assertEqual(decorator.__dict__, {})
+
+ def test_create_context_trumps_for(self):
+ decorator = self._makeOne(context='123', for_='456')
+ self.assertEqual(decorator.context, '123')
+
+ def test_create_for_trumps_context_None(self):
+ decorator = self._makeOne(context=None, for_='456')
+ self.assertEqual(decorator.context, '456')
+
+ def test_create_nondefaults(self):
+ decorator = self._makeOne(
+ name=None,
+ request_type=None,
+ for_=None,
+ permission='foo',
+ mapper='mapper',
+ decorator='decorator',
+ match_param='match_param',
+ )
+ self.assertEqual(decorator.name, None)
+ self.assertEqual(decorator.request_type, None)
+ self.assertEqual(decorator.context, None)
+ self.assertEqual(decorator.permission, 'foo')
+ self.assertEqual(decorator.mapper, 'mapper')
+ self.assertEqual(decorator.decorator, 'decorator')
+ self.assertEqual(decorator.match_param, 'match_param')
+
+ def test_create_with_other_predicates(self):
+ decorator = self._makeOne(foo=1)
+ self.assertEqual(decorator.foo, 1)
+
+ def test_create_decorator_tuple(self):
+ decorator = self._makeOne(decorator=('decorator1', 'decorator2'))
+ self.assertEqual(decorator.decorator, ('decorator1', 'decorator2'))
+
+ def test_call_function(self):
+ decorator = self._makeOne()
+ venusian = DummyVenusian()
+ decorator.venusian = venusian
+
+ def foo(): # pragma: no cover
+ pass
+
+ wrapped = decorator(foo)
+ self.assertTrue(wrapped is foo)
+ config = call_venusian(venusian)
+ settings = config.settings
+ self.assertEqual(len(settings), 1)
+ self.assertEqual(len(settings), 1)
+ self.assertEqual(len(settings[0]), 3)
+ self.assertEqual(settings[0]['venusian'], venusian)
+ self.assertEqual(settings[0]['view'], None) # comes from call_venusian
+ self.assertEqual(settings[0]['_info'], 'codeinfo')
+
+ def test_call_class(self):
+ decorator = self._makeOne()
+ venusian = DummyVenusian()
+ decorator.venusian = venusian
+ decorator.venusian.info.scope = 'class'
+
+ class foo(object):
+ pass
+
+ wrapped = decorator(foo)
+ self.assertTrue(wrapped is foo)
+ config = call_venusian(venusian)
+ settings = config.settings
+ self.assertEqual(len(settings), 1)
+ self.assertEqual(len(settings[0]), 4)
+ self.assertEqual(settings[0]['venusian'], venusian)
+ self.assertEqual(settings[0]['view'], None) # comes from call_venusian
+ self.assertEqual(settings[0]['attr'], 'foo')
+ self.assertEqual(settings[0]['_info'], 'codeinfo')
+
+ def test_call_class_attr_already_set(self):
+ decorator = self._makeOne(attr='abc')
+ venusian = DummyVenusian()
+ decorator.venusian = venusian
+ decorator.venusian.info.scope = 'class'
+
+ class foo(object):
+ pass
+
+ wrapped = decorator(foo)
+ self.assertTrue(wrapped is foo)
+ config = call_venusian(venusian)
+ settings = config.settings
+ self.assertEqual(len(settings), 1)
+ self.assertEqual(len(settings[0]), 4)
+ self.assertEqual(settings[0]['venusian'], venusian)
+ self.assertEqual(settings[0]['view'], None) # comes from call_venusian
+ self.assertEqual(settings[0]['attr'], 'abc')
+ self.assertEqual(settings[0]['_info'], 'codeinfo')
+
+ def test_stacking(self):
+ decorator1 = self._makeOne(name='1')
+ venusian1 = DummyVenusian()
+ decorator1.venusian = venusian1
+ venusian2 = DummyVenusian()
+ decorator2 = self._makeOne(name='2')
+ decorator2.venusian = venusian2
+
+ def foo(): # pragma: no cover
+ pass
+
+ wrapped1 = decorator1(foo)
+ wrapped2 = decorator2(wrapped1)
+ self.assertTrue(wrapped1 is foo)
+ self.assertTrue(wrapped2 is foo)
+ config1 = call_venusian(venusian1)
+ self.assertEqual(len(config1.settings), 1)
+ self.assertEqual(config1.settings[0]['name'], '1')
+ config2 = call_venusian(venusian2)
+ self.assertEqual(len(config2.settings), 1)
+ self.assertEqual(config2.settings[0]['name'], '2')
+
+ def test_call_as_method(self):
+ decorator = self._makeOne()
+ venusian = DummyVenusian()
+ decorator.venusian = venusian
+ decorator.venusian.info.scope = 'class'
+
+ def foo(self): # pragma: no cover
+ pass
+
+ def bar(self): # pragma: no cover
+ pass
+
+ class foo(object):
+ foomethod = decorator(foo)
+ barmethod = decorator(bar)
+
+ config = call_venusian(venusian)
+ settings = config.settings
+ self.assertEqual(len(settings), 2)
+ self.assertEqual(settings[0]['attr'], 'foo')
+ self.assertEqual(settings[1]['attr'], 'bar')
+
+ def test_with_custom_predicates(self):
+ decorator = self._makeOne(custom_predicates=(1,))
+ venusian = DummyVenusian()
+ decorator.venusian = venusian
+
+ def foo(context, request): # pragma: no cover
+ pass
+
+ decorated = decorator(foo)
+ self.assertTrue(decorated is foo)
+ config = call_venusian(venusian)
+ settings = config.settings
+ self.assertEqual(settings[0]['custom_predicates'], (1,))
+
+ def test_call_with_renderer_string(self):
+ import tests
+
+ decorator = self._makeOne(renderer='fixtures/minimal.pt')
+ venusian = DummyVenusian()
+ decorator.venusian = venusian
+
+ def foo(): # pragma: no cover
+ pass
+
+ wrapped = decorator(foo)
+ self.assertTrue(wrapped is foo)
+ config = call_venusian(venusian)
+ settings = config.settings
+ self.assertEqual(len(settings), 1)
+ renderer = settings[0]['renderer']
+ self.assertEqual(renderer, 'fixtures/minimal.pt')
+ self.assertEqual(config.pkg, tests)
+
+ def test_call_with_renderer_dict(self):
+ import tests
+
+ decorator = self._makeOne(renderer={'a': 1})
+ venusian = DummyVenusian()
+ decorator.venusian = venusian
+
+ def foo(): # pragma: no cover
+ pass
+
+ wrapped = decorator(foo)
+ self.assertTrue(wrapped is foo)
+ config = call_venusian(venusian)
+ settings = config.settings
+ self.assertEqual(len(settings), 1)
+ self.assertEqual(settings[0]['renderer'], {'a': 1})
+ self.assertEqual(config.pkg, tests)
+
+ def test_call_with_renderer_IRendererInfo(self):
+ import tests
+ from pyramid.interfaces import IRendererInfo
+
+ @implementer(IRendererInfo)
+ class DummyRendererHelper(object):
+ pass
+
+ renderer_helper = DummyRendererHelper()
+ decorator = self._makeOne(renderer=renderer_helper)
+ venusian = DummyVenusian()
+ decorator.venusian = venusian
+
+ def foo(): # pragma: no cover
+ pass
+
+ wrapped = decorator(foo)
+ self.assertTrue(wrapped is foo)
+ context = DummyVenusianContext()
+ config = call_venusian(venusian, context)
+ settings = config.settings
+ self.assertEqual(len(settings), 1)
+ renderer = settings[0]['renderer']
+ self.assertTrue(renderer is renderer_helper)
+ self.assertEqual(config.pkg, tests)
+
+ def test_call_withdepth(self):
+ decorator = self._makeOne(_depth=1)
+ venusian = DummyVenusian()
+ decorator.venusian = venusian
+
+ def foo(): # pragma: no cover
+ pass
+
+ decorator(foo)
+ attachments = venusian.attachments
+ depth = attachments[0][3]
+ self.assertEqual(depth, 2)
+
+ def test_call_withoutcategory(self):
+ decorator = self._makeOne()
+ venusian = DummyVenusian()
+ decorator.venusian = venusian
+
+ def foo(): # pragma: no cover
+ pass
+
+ decorator(foo)
+ attachments = venusian.attachments
+ category = attachments[0][2]
+ self.assertEqual(category, 'pyramid')
+
+ def test_call_withcategory(self):
+ decorator = self._makeOne(_category='not_pyramid')
+ venusian = DummyVenusian()
+ decorator.venusian = venusian
+
+ def foo(): # pragma: no cover
+ pass
+
+ decorator(foo)
+ attachments = venusian.attachments
+ category = attachments[0][2]
+ self.assertEqual(category, 'not_pyramid')
+
+
+class Test_append_slash_notfound_view(BaseTest, unittest.TestCase):
+ def _callFUT(self, context, request):
+ from pyramid.view import append_slash_notfound_view
+
+ return append_slash_notfound_view(context, request)
+
+ def _registerMapper(self, reg, match=True):
+ from pyramid.interfaces import IRoutesMapper
+
+ class DummyRoute(object):
+ def __init__(self, val):
+ self.val = val
+
+ def match(self, path):
+ return self.val
+
+ class DummyMapper(object):
+ def __init__(self):
+ self.routelist = [DummyRoute(match)]
+
+ def get_routes(self):
+ return self.routelist
+
+ mapper = DummyMapper()
+ reg.registerUtility(mapper, IRoutesMapper)
+ return mapper
+
+ def test_context_is_not_exception(self):
+ request = self._makeRequest(PATH_INFO='/abc')
+ request.exception = ExceptionResponse()
+ context = DummyContext()
+ response = self._callFUT(context, request)
+ self.assertEqual(response.status, '404 Not Found')
+ self.assertEqual(response.app_iter, ['Not Found'])
+
+ def test_no_mapper(self):
+ request = self._makeRequest(PATH_INFO='/abc')
+ context = ExceptionResponse()
+ response = self._callFUT(context, request)
+ self.assertEqual(response.status, '404 Not Found')
+
+ def test_no_path(self):
+ request = self._makeRequest()
+ context = ExceptionResponse()
+ self._registerMapper(request.registry, True)
+ response = self._callFUT(context, request)
+ self.assertEqual(response.status, '404 Not Found')
+
+ def test_mapper_path_already_slash_ending(self):
+ request = self._makeRequest(PATH_INFO='/abc/')
+ context = ExceptionResponse()
+ self._registerMapper(request.registry, True)
+ response = self._callFUT(context, request)
+ self.assertEqual(response.status, '404 Not Found')
+
+ def test_no_route_matches(self):
+ request = self._makeRequest(PATH_INFO='/abc')
+ context = ExceptionResponse()
+ mapper = self._registerMapper(request.registry, True)
+ mapper.routelist[0].val = None
+ response = self._callFUT(context, request)
+ self.assertEqual(response.status, '404 Not Found')
+
+ def test_matches(self):
+ request = self._makeRequest(PATH_INFO='/abc')
+ context = ExceptionResponse()
+ self._registerMapper(request.registry, True)
+ response = self._callFUT(context, request)
+ self.assertEqual(response.status, '307 Temporary Redirect')
+ self.assertEqual(response.location, '/abc/')
+
+ def test_matches_with_script_name(self):
+ request = self._makeRequest(PATH_INFO='/abc', SCRIPT_NAME='/foo')
+ context = ExceptionResponse()
+ self._registerMapper(request.registry, True)
+ response = self._callFUT(context, request)
+ self.assertEqual(response.status, '307 Temporary Redirect')
+ self.assertEqual(response.location, '/foo/abc/')
+
+ def test_with_query_string(self):
+ request = self._makeRequest(PATH_INFO='/abc', QUERY_STRING='a=1&b=2')
+ context = ExceptionResponse()
+ self._registerMapper(request.registry, True)
+ response = self._callFUT(context, request)
+ self.assertEqual(response.status, '307 Temporary Redirect')
+ self.assertEqual(response.location, '/abc/?a=1&b=2')
+
+
+class TestAppendSlashNotFoundViewFactory(BaseTest, unittest.TestCase):
+ def _makeOne(self, notfound_view):
+ from pyramid.view import AppendSlashNotFoundViewFactory
+
+ return AppendSlashNotFoundViewFactory(notfound_view)
+
+ def test_custom_notfound_view(self):
+ request = self._makeRequest(PATH_INFO='/abc')
+ context = ExceptionResponse()
+
+ def custom_notfound(context, request):
+ return 'OK'
+
+ view = self._makeOne(custom_notfound)
+ response = view(context, request)
+ self.assertEqual(response, 'OK')
+
+
+class Test_default_exceptionresponse_view(unittest.TestCase):
+ def _callFUT(self, context, request):
+ from pyramid.view import default_exceptionresponse_view
+
+ return default_exceptionresponse_view(context, request)
+
+ def test_is_exception(self):
+ context = Exception()
+ result = self._callFUT(context, None)
+ self.assertTrue(result is context)
+
+ def test_is_not_exception_context_is_false_still_chose(self):
+ request = DummyRequest()
+ request.exception = 0
+ result = self._callFUT(None, request)
+ self.assertTrue(result is None)
+
+ def test_is_not_exception_no_request_exception(self):
+ context = object()
+ request = DummyRequest()
+ request.exception = None
+ result = self._callFUT(context, request)
+ self.assertTrue(result is context)
+
+ def test_is_not_exception_request_exception(self):
+ context = object()
+ request = DummyRequest()
+ request.exception = 'abc'
+ result = self._callFUT(context, request)
+ self.assertEqual(result, 'abc')
+
+
+class Test_view_defaults(unittest.TestCase):
+ def test_it(self):
+ from pyramid.view import view_defaults
+
+ @view_defaults(route_name='abc', renderer='def')
+ class Foo(object):
+ pass
+
+ self.assertEqual(Foo.__view_defaults__['route_name'], 'abc')
+ self.assertEqual(Foo.__view_defaults__['renderer'], 'def')
+
+ def test_it_inheritance_not_overridden(self):
+ from pyramid.view import view_defaults
+
+ @view_defaults(route_name='abc', renderer='def')
+ class Foo(object):
+ pass
+
+ class Bar(Foo):
+ pass
+
+ self.assertEqual(Bar.__view_defaults__['route_name'], 'abc')
+ self.assertEqual(Bar.__view_defaults__['renderer'], 'def')
+
+ def test_it_inheritance_overriden(self):
+ from pyramid.view import view_defaults
+
+ @view_defaults(route_name='abc', renderer='def')
+ class Foo(object):
+ pass
+
+ @view_defaults(route_name='ghi')
+ class Bar(Foo):
+ pass
+
+ self.assertEqual(Bar.__view_defaults__['route_name'], 'ghi')
+ self.assertFalse('renderer' in Bar.__view_defaults__)
+
+ def test_it_inheritance_overriden_empty(self):
+ from pyramid.view import view_defaults
+
+ @view_defaults(route_name='abc', renderer='def')
+ class Foo(object):
+ pass
+
+ @view_defaults()
+ class Bar(Foo):
+ pass
+
+ self.assertEqual(Bar.__view_defaults__, {})
+
+
+class TestViewMethodsMixin(unittest.TestCase):
+ def setUp(self):
+ self.config = testing.setUp()
+
+ def tearDown(self):
+ testing.tearDown()
+
+ def _makeOne(self, environ=None):
+ from pyramid.decorator import reify
+ from pyramid.view import ViewMethodsMixin
+
+ if environ is None:
+ environ = {}
+
+ class Request(ViewMethodsMixin):
+ def __init__(self, environ):
+ self.environ = environ
+
+ @reify
+ def response(self):
+ return DummyResponse()
+
+ request = Request(environ)
+ request.registry = self.config.registry
+ return request
+
+ def test_it(self):
+ def exc_view(exc, request):
+ self.assertTrue(exc is dummy_exc)
+ self.assertTrue(request.exception is dummy_exc)
+ return DummyResponse(b'foo')
+
+ self.config.add_view(exc_view, context=RuntimeError)
+ request = self._makeOne()
+ dummy_exc = RuntimeError()
+ try:
+ raise dummy_exc
+ except RuntimeError:
+ response = request.invoke_exception_view()
+ self.assertEqual(response.app_iter, [b'foo'])
+ else: # pragma: no cover
+ self.fail()
+
+ def test_it_hides_attrs(self):
+ def exc_view(exc, request):
+ self.assertTrue(exc is not orig_exc)
+ self.assertTrue(request.exception is not orig_exc)
+ self.assertTrue(request.exc_info is not orig_exc_info)
+ self.assertTrue(request.response is not orig_response)
+ request.response.app_iter = [b'bar']
+ return request.response
+
+ self.config.add_view(exc_view, context=RuntimeError)
+ request = self._makeOne()
+ orig_exc = request.exception = DummyContext()
+ orig_exc_info = request.exc_info = DummyContext()
+ orig_response = request.response = DummyResponse(b'foo')
+ try:
+ raise RuntimeError
+ except RuntimeError as ex:
+ response = request.invoke_exception_view()
+ self.assertEqual(response.app_iter, [b'bar'])
+ self.assertTrue(request.exception is ex)
+ self.assertTrue(request.exc_info[1] is ex)
+ self.assertTrue(request.response is orig_response)
+ else: # pragma: no cover
+ self.fail()
+
+ def test_it_supports_alternate_requests(self):
+ def exc_view(exc, request):
+ self.assertTrue(request is other_req)
+ from pyramid.threadlocal import get_current_request
+
+ self.assertTrue(get_current_request() is other_req)
+ return DummyResponse(b'foo')
+
+ self.config.add_view(exc_view, context=RuntimeError)
+ request = self._makeOne()
+ other_req = self._makeOne()
+ try:
+ raise RuntimeError
+ except RuntimeError:
+ response = request.invoke_exception_view(request=other_req)
+ self.assertEqual(response.app_iter, [b'foo'])
+ else: # pragma: no cover
+ self.fail()
+
+ def test_it_supports_threadlocal_registry(self):
+ def exc_view(exc, request):
+ return DummyResponse(b'foo')
+
+ self.config.add_view(exc_view, context=RuntimeError)
+ request = self._makeOne()
+ del request.registry
+ try:
+ raise RuntimeError
+ except RuntimeError:
+ response = request.invoke_exception_view()
+ self.assertEqual(response.app_iter, [b'foo'])
+ else: # pragma: no cover
+ self.fail()
+
+ def test_it_raises_if_no_registry(self):
+ request = self._makeOne()
+ del request.registry
+ from pyramid.threadlocal import manager
+
+ manager.push({'registry': None, 'request': request})
+ try:
+ raise RuntimeError
+ except RuntimeError:
+ try:
+ request.invoke_exception_view()
+ except RuntimeError as e:
+ self.assertEqual(e.args[0], "Unable to retrieve registry")
+ else: # pragma: no cover
+ self.fail()
+ finally:
+ manager.pop()
+
+ def test_it_supports_alternate_exc_info(self):
+ def exc_view(exc, request):
+ self.assertTrue(request.exc_info is exc_info)
+ return DummyResponse(b'foo')
+
+ self.config.add_view(exc_view, context=RuntimeError)
+ request = self._makeOne()
+ try:
+ raise RuntimeError
+ except RuntimeError:
+ exc_info = sys.exc_info()
+ response = request.invoke_exception_view(exc_info=exc_info)
+ self.assertEqual(response.app_iter, [b'foo'])
+
+ def test_it_rejects_secured_view(self):
+ from pyramid.exceptions import Forbidden
+
+ def exc_view(exc, request): # pragma: no cover
+ pass
+
+ self.config.testing_securitypolicy(permissive=False)
+ self.config.add_view(exc_view, context=RuntimeError, permission='view')
+ request = self._makeOne()
+ try:
+ raise RuntimeError
+ except RuntimeError:
+ self.assertRaises(Forbidden, request.invoke_exception_view)
+ else: # pragma: no cover
+ self.fail()
+
+ def test_it_allows_secured_view(self):
+ def exc_view(exc, request):
+ return DummyResponse(b'foo')
+
+ self.config.testing_securitypolicy(permissive=False)
+ self.config.add_view(exc_view, context=RuntimeError, permission='view')
+ request = self._makeOne()
+ try:
+ raise RuntimeError
+ except RuntimeError:
+ response = request.invoke_exception_view(secure=False)
+ self.assertEqual(response.app_iter, [b'foo'])
+ else: # pragma: no cover
+ self.fail()
+
+ def test_it_raises_if_not_found(self):
+ from pyramid.httpexceptions import HTTPNotFound
+
+ request = self._makeOne()
+ dummy_exc = RuntimeError()
+ try:
+ raise dummy_exc
+ except RuntimeError:
+ self.assertRaises(HTTPNotFound, request.invoke_exception_view)
+ else: # pragma: no cover
+ self.fail()
+
+ def test_it_reraises_if_not_found(self):
+ request = self._makeOne()
+ dummy_exc = RuntimeError()
+ try:
+ raise dummy_exc
+ except RuntimeError:
+ self.assertRaises(
+ RuntimeError,
+ lambda: request.invoke_exception_view(reraise=True),
+ )
+ else: # pragma: no cover
+ self.fail()
+
+ def test_it_raises_predicate_mismatch(self):
+ from pyramid.exceptions import PredicateMismatch
+
+ def exc_view(exc, request): # pragma: no cover
+ pass
+
+ self.config.add_view(
+ exc_view, context=Exception, request_method='POST'
+ )
+ request = self._makeOne()
+ request.method = 'GET'
+ dummy_exc = RuntimeError()
+ try:
+ raise dummy_exc
+ except RuntimeError:
+ self.assertRaises(PredicateMismatch, request.invoke_exception_view)
+ else: # pragma: no cover
+ self.fail()
+
+ def test_it_reraises_after_predicate_mismatch(self):
+ def exc_view(exc, request): # pragma: no cover
+ pass
+
+ self.config.add_view(
+ exc_view, context=Exception, request_method='POST'
+ )
+ request = self._makeOne()
+ request.method = 'GET'
+ dummy_exc = RuntimeError()
+ try:
+ raise dummy_exc
+ except RuntimeError:
+ self.assertRaises(
+ RuntimeError,
+ lambda: request.invoke_exception_view(reraise=True),
+ )
+ else: # pragma: no cover
+ self.fail()
+
+
+class ExceptionResponse(Exception):
+ status = '404 Not Found'
+ app_iter = ['Not Found']
+ headerlist = []
+
+
+class DummyContext:
+ pass
+
+
+def make_view(response):
+ def view(context, request):
+ return response
+
+ return view
+
+
+class DummyRequest:
+ exception = None
+ request_iface = IRequest
+
+ def __init__(self, environ=None):
+ if environ is None:
+ environ = {}
+ self.environ = environ
+
+
+@implementer(IResponse)
+class DummyResponse(object):
+ headerlist = ()
+ app_iter = ()
+ status = '200 OK'
+ environ = None
+
+ def __init__(self, body=None):
+ if body is None:
+ self.app_iter = ()
+ else:
+ self.app_iter = [body]
+
+
+class IContext(Interface):
+ pass
+
+
+class DummyVenusianInfo(object):
+ scope = 'notaclass'
+ module = sys.modules['tests']
+ codeinfo = 'codeinfo'
+
+
+class DummyVenusian(object):
+ def __init__(self, info=None):
+ if info is None:
+ info = DummyVenusianInfo()
+ self.info = info
+ self.attachments = []
+
+ def attach(self, wrapped, callback, category=None, depth=1):
+ self.attachments.append((wrapped, callback, category, depth))
+ return self.info
+
+
+class DummyRegistry(object):
+ pass
+
+
+class DummyConfig(object):
+ def __init__(self):
+ self.settings = []
+ self.registry = DummyRegistry()
+
+ def add_view(self, **kw):
+ self.settings.append(kw)
+
+ add_notfound_view = add_forbidden_view = add_exception_view = add_view
+
+ def with_package(self, pkg):
+ self.pkg = pkg
+ return self
+
+
+class DummyVenusianContext(object):
+ def __init__(self):
+ self.config = DummyConfig()
+
+
+def call_venusian(venusian, context=None):
+ if context is None:
+ context = DummyVenusianContext()
+ for wrapped, callback, category, depth in venusian.attachments:
+ callback(context, None, None)
+ return context.config
diff --git a/tests/test_viewderivers.py b/tests/test_viewderivers.py
new file mode 100644
index 000000000..f01cb490e
--- /dev/null
+++ b/tests/test_viewderivers.py
@@ -0,0 +1,2158 @@
+import unittest
+from zope.interface import implementer
+
+from pyramid import testing
+from pyramid.exceptions import ConfigurationError
+from pyramid.interfaces import IResponse, IRequest
+
+
+class TestDeriveView(unittest.TestCase):
+ def setUp(self):
+ self.config = testing.setUp()
+ self.config.set_default_csrf_options(require_csrf=False)
+
+ def tearDown(self):
+ self.config = None
+ testing.tearDown()
+
+ def _makeRequest(self):
+ request = DummyRequest()
+ request.registry = self.config.registry
+ return request
+
+ def _registerLogger(self):
+ from pyramid.interfaces import IDebugLogger
+
+ logger = DummyLogger()
+ self.config.registry.registerUtility(logger, IDebugLogger)
+ return logger
+
+ def _registerSecurityPolicy(self, permissive):
+ from pyramid.interfaces import IAuthenticationPolicy
+ from pyramid.interfaces import IAuthorizationPolicy
+
+ policy = DummySecurityPolicy(permissive)
+ self.config.registry.registerUtility(policy, IAuthenticationPolicy)
+ self.config.registry.registerUtility(policy, IAuthorizationPolicy)
+
+ def test_function_returns_non_adaptable(self):
+ def view(request):
+ return None
+
+ result = self.config.derive_view(view)
+ self.assertFalse(result is view)
+ try:
+ result(None, None)
+ except ValueError as e:
+ self.assertEqual(
+ e.args[0],
+ 'Could not convert return value of the view callable function '
+ 'tests.test_viewderivers.view into a response '
+ 'object. The value returned was None. You may have forgotten '
+ 'to return a value from the view callable.',
+ )
+ else: # pragma: no cover
+ raise AssertionError
+
+ def test_function_returns_non_adaptable_dict(self):
+ def view(request):
+ return {'a': 1}
+
+ result = self.config.derive_view(view)
+ self.assertFalse(result is view)
+ try:
+ result(None, None)
+ except ValueError as e:
+ self.assertEqual(
+ e.args[0],
+ "Could not convert return value of the view callable function "
+ "tests.test_viewderivers.view into a response "
+ "object. The value returned was {'a': 1}. You may have "
+ "forgotten to define a renderer in the view configuration.",
+ )
+ else: # pragma: no cover
+ raise AssertionError
+
+ def test_instance_returns_non_adaptable(self):
+ class AView(object):
+ def __call__(self, request):
+ return None
+
+ view = AView()
+ result = self.config.derive_view(view)
+ self.assertFalse(result is view)
+ try:
+ result(None, None)
+ except ValueError as e:
+ msg = e.args[0]
+ self.assertTrue(
+ msg.startswith(
+ 'Could not convert return value of the view callable '
+ 'object <tests.test_viewderivers.'
+ )
+ )
+ self.assertTrue(
+ msg.endswith(
+ '> into a response object. The value returned was None. '
+ 'You may have forgotten to return a value from the view '
+ 'callable.'
+ )
+ )
+ else: # pragma: no cover
+ raise AssertionError
+
+ def test_function_returns_true_Response_no_renderer(self):
+ from pyramid.response import Response
+
+ r = Response('Hello')
+
+ def view(request):
+ return r
+
+ result = self.config.derive_view(view)
+ self.assertFalse(result is view)
+ response = result(None, None)
+ self.assertEqual(response, r)
+
+ def test_function_returns_true_Response_with_renderer(self):
+ from pyramid.response import Response
+
+ r = Response('Hello')
+
+ def view(request):
+ return r
+
+ result = self.config.derive_view(view)
+ self.assertFalse(result is view)
+ response = result(None, None)
+ self.assertEqual(response, r)
+
+ def test_requestonly_default_method_returns_non_adaptable(self):
+ request = DummyRequest()
+
+ class AView(object):
+ def __init__(self, request):
+ pass
+
+ def __call__(self):
+ return None
+
+ result = self.config.derive_view(AView)
+ self.assertFalse(result is AView)
+ try:
+ result(None, request)
+ except ValueError as e:
+ self.assertEqual(
+ e.args[0],
+ 'Could not convert return value of the view callable '
+ 'method __call__ of '
+ 'class tests.test_viewderivers.AView into a '
+ 'response object. The value returned was None. You may have '
+ 'forgotten to return a value from the view callable.',
+ )
+ else: # pragma: no cover
+ raise AssertionError
+
+ def test_requestonly_nondefault_method_returns_non_adaptable(self):
+ request = DummyRequest()
+
+ class AView(object):
+ def __init__(self, request):
+ pass
+
+ def theviewmethod(self):
+ return None
+
+ result = self.config.derive_view(AView, attr='theviewmethod')
+ self.assertFalse(result is AView)
+ try:
+ result(None, request)
+ except ValueError as e:
+ self.assertEqual(
+ e.args[0],
+ 'Could not convert return value of the view callable '
+ 'method theviewmethod of '
+ 'class tests.test_viewderivers.AView into a '
+ 'response object. The value returned was None. You may have '
+ 'forgotten to return a value from the view callable.',
+ )
+ else: # pragma: no cover
+ raise AssertionError
+
+ def test_requestonly_function(self):
+ response = DummyResponse()
+
+ def view(request):
+ return response
+
+ result = self.config.derive_view(view)
+ self.assertFalse(result is view)
+ self.assertEqual(result(None, None), response)
+
+ def test_requestonly_function_with_renderer(self):
+ response = DummyResponse()
+
+ class moo(object):
+ def render_view(inself, req, resp, view_inst, ctx):
+ self.assertEqual(req, request)
+ self.assertEqual(resp, 'OK')
+ self.assertEqual(view_inst, view)
+ self.assertEqual(ctx, context)
+ return response
+
+ def clone(self):
+ return self
+
+ def view(request):
+ return 'OK'
+
+ result = self.config.derive_view(view, renderer=moo())
+ self.assertFalse(result.__wraps__ is view)
+ request = self._makeRequest()
+ context = testing.DummyResource()
+ self.assertEqual(result(context, request), response)
+
+ def test_requestonly_function_with_renderer_request_override(self):
+ def moo(info):
+ def inner(value, system):
+ self.assertEqual(value, 'OK')
+ self.assertEqual(system['request'], request)
+ self.assertEqual(system['context'], context)
+ return b'moo'
+
+ return inner
+
+ def view(request):
+ return 'OK'
+
+ self.config.add_renderer('moo', moo)
+ result = self.config.derive_view(view, renderer='string')
+ self.assertFalse(result is view)
+ request = self._makeRequest()
+ request.override_renderer = 'moo'
+ context = testing.DummyResource()
+ self.assertEqual(result(context, request).body, b'moo')
+
+ def test_requestonly_function_with_renderer_request_has_view(self):
+ response = DummyResponse()
+
+ class moo(object):
+ def render_view(inself, req, resp, view_inst, ctx):
+ self.assertEqual(req, request)
+ self.assertEqual(resp, 'OK')
+ self.assertEqual(view_inst, 'view')
+ self.assertEqual(ctx, context)
+ return response
+
+ def clone(self):
+ return self
+
+ def view(request):
+ return 'OK'
+
+ result = self.config.derive_view(view, renderer=moo())
+ self.assertFalse(result.__wraps__ is view)
+ request = self._makeRequest()
+ request.__view__ = 'view'
+ context = testing.DummyResource()
+ r = result(context, request)
+ self.assertEqual(r, response)
+ self.assertFalse(hasattr(request, '__view__'))
+
+ def test_class_without_attr(self):
+ response = DummyResponse()
+
+ class View(object):
+ def __init__(self, request):
+ pass
+
+ def __call__(self):
+ return response
+
+ result = self.config.derive_view(View)
+ request = self._makeRequest()
+ self.assertEqual(result(None, request), response)
+ self.assertEqual(request.__view__.__class__, View)
+
+ def test_class_with_attr(self):
+ response = DummyResponse()
+
+ class View(object):
+ def __init__(self, request):
+ pass
+
+ def another(self):
+ return response
+
+ result = self.config.derive_view(View, attr='another')
+ request = self._makeRequest()
+ self.assertEqual(result(None, request), response)
+ self.assertEqual(request.__view__.__class__, View)
+
+ def test_as_function_context_and_request(self):
+ def view(context, request):
+ return 'OK'
+
+ result = self.config.derive_view(view)
+ self.assertTrue(result.__wraps__ is view)
+ self.assertFalse(hasattr(result, '__call_permissive__'))
+ self.assertEqual(view(None, None), 'OK')
+
+ def test_as_function_requestonly(self):
+ response = DummyResponse()
+
+ def view(request):
+ return response
+
+ result = self.config.derive_view(view)
+ self.assertFalse(result is view)
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.assertEqual(view.__name__, result.__name__)
+ self.assertFalse(hasattr(result, '__call_permissive__'))
+ self.assertEqual(result(None, None), response)
+
+ def test_as_newstyle_class_context_and_request(self):
+ response = DummyResponse()
+
+ class view(object):
+ def __init__(self, context, request):
+ pass
+
+ def __call__(self):
+ return response
+
+ result = self.config.derive_view(view)
+ self.assertFalse(result is view)
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.assertEqual(view.__name__, result.__name__)
+ self.assertFalse(hasattr(result, '__call_permissive__'))
+ request = self._makeRequest()
+ self.assertEqual(result(None, request), response)
+ self.assertEqual(request.__view__.__class__, view)
+
+ def test_as_newstyle_class_requestonly(self):
+ response = DummyResponse()
+
+ class view(object):
+ def __init__(self, context, request):
+ pass
+
+ def __call__(self):
+ return response
+
+ result = self.config.derive_view(view)
+ self.assertFalse(result is view)
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.assertEqual(view.__name__, result.__name__)
+ self.assertFalse(hasattr(result, '__call_permissive__'))
+ request = self._makeRequest()
+ self.assertEqual(result(None, request), response)
+ self.assertEqual(request.__view__.__class__, view)
+
+ def test_as_oldstyle_class_context_and_request(self):
+ response = DummyResponse()
+
+ class view:
+ def __init__(self, context, request):
+ pass
+
+ def __call__(self):
+ return response
+
+ result = self.config.derive_view(view)
+ self.assertFalse(result is view)
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.assertEqual(view.__name__, result.__name__)
+ self.assertFalse(hasattr(result, '__call_permissive__'))
+ request = self._makeRequest()
+ self.assertEqual(result(None, request), response)
+ self.assertEqual(request.__view__.__class__, view)
+
+ def test_as_oldstyle_class_requestonly(self):
+ response = DummyResponse()
+
+ class view:
+ def __init__(self, context, request):
+ pass
+
+ def __call__(self):
+ return response
+
+ result = self.config.derive_view(view)
+ self.assertFalse(result is view)
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.assertEqual(view.__name__, result.__name__)
+ self.assertFalse(hasattr(result, '__call_permissive__'))
+ request = self._makeRequest()
+ self.assertEqual(result(None, request), response)
+ self.assertEqual(request.__view__.__class__, view)
+
+ def test_as_instance_context_and_request(self):
+ response = DummyResponse()
+
+ class View:
+ def __call__(self, context, request):
+ return response
+
+ view = View()
+ result = self.config.derive_view(view)
+ self.assertTrue(result.__wraps__ is view)
+ self.assertFalse(hasattr(result, '__call_permissive__'))
+ self.assertEqual(result(None, None), response)
+
+ def test_as_instance_requestonly(self):
+ response = DummyResponse()
+
+ class View:
+ def __call__(self, request):
+ return response
+
+ view = View()
+ result = self.config.derive_view(view)
+ self.assertFalse(result is view)
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.assertTrue('test_viewderivers' in result.__name__)
+ self.assertFalse(hasattr(result, '__call_permissive__'))
+ self.assertEqual(result(None, None), response)
+
+ def test_with_debug_authorization_no_authpol(self):
+ response = DummyResponse()
+ view = lambda *arg: response
+ self.config.registry.settings = dict(
+ debug_authorization=True, reload_templates=True
+ )
+ logger = self._registerLogger()
+ result = self.config._derive_view(view, permission='view')
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.assertEqual(view.__name__, result.__name__)
+ self.assertFalse(hasattr(result, '__call_permissive__'))
+ request = self._makeRequest()
+ request.view_name = 'view_name'
+ request.url = 'url'
+ self.assertEqual(result(None, request), response)
+ self.assertEqual(len(logger.messages), 1)
+ self.assertEqual(
+ logger.messages[0],
+ "debug_authorization of url url (view name "
+ "'view_name' against context None): Allowed "
+ "(no authorization policy in use)",
+ )
+
+ def test_with_debug_authorization_authn_policy_no_authz_policy(self):
+ response = DummyResponse()
+ view = lambda *arg: response
+ self.config.registry.settings = dict(debug_authorization=True)
+ from pyramid.interfaces import IAuthenticationPolicy
+
+ policy = DummySecurityPolicy(False)
+ self.config.registry.registerUtility(policy, IAuthenticationPolicy)
+ logger = self._registerLogger()
+ result = self.config._derive_view(view, permission='view')
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.assertEqual(view.__name__, result.__name__)
+ self.assertFalse(hasattr(result, '__call_permissive__'))
+ request = self._makeRequest()
+ request.view_name = 'view_name'
+ request.url = 'url'
+ self.assertEqual(result(None, request), response)
+ self.assertEqual(len(logger.messages), 1)
+ self.assertEqual(
+ logger.messages[0],
+ "debug_authorization of url url (view name "
+ "'view_name' against context None): Allowed "
+ "(no authorization policy in use)",
+ )
+
+ def test_with_debug_authorization_authz_policy_no_authn_policy(self):
+ response = DummyResponse()
+ view = lambda *arg: response
+ self.config.registry.settings = dict(debug_authorization=True)
+ from pyramid.interfaces import IAuthorizationPolicy
+
+ policy = DummySecurityPolicy(False)
+ self.config.registry.registerUtility(policy, IAuthorizationPolicy)
+ logger = self._registerLogger()
+ result = self.config._derive_view(view, permission='view')
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.assertEqual(view.__name__, result.__name__)
+ self.assertFalse(hasattr(result, '__call_permissive__'))
+ request = self._makeRequest()
+ request.view_name = 'view_name'
+ request.url = 'url'
+ self.assertEqual(result(None, request), response)
+ self.assertEqual(len(logger.messages), 1)
+ self.assertEqual(
+ logger.messages[0],
+ "debug_authorization of url url (view name "
+ "'view_name' against context None): Allowed "
+ "(no authorization policy in use)",
+ )
+
+ def test_with_debug_authorization_no_permission(self):
+ response = DummyResponse()
+ view = lambda *arg: response
+ self.config.registry.settings = dict(
+ debug_authorization=True, reload_templates=True
+ )
+ self._registerSecurityPolicy(True)
+ logger = self._registerLogger()
+ result = self.config._derive_view(view)
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.assertEqual(view.__name__, result.__name__)
+ self.assertFalse(hasattr(result, '__call_permissive__'))
+ request = self._makeRequest()
+ request.view_name = 'view_name'
+ request.url = 'url'
+ self.assertEqual(result(None, request), response)
+ self.assertEqual(len(logger.messages), 1)
+ self.assertEqual(
+ logger.messages[0],
+ "debug_authorization of url url (view name "
+ "'view_name' against context None): Allowed ("
+ "no permission registered)",
+ )
+
+ def test_debug_auth_permission_authpol_permitted(self):
+ response = DummyResponse()
+ view = lambda *arg: response
+ self.config.registry.settings = dict(
+ debug_authorization=True, reload_templates=True
+ )
+ logger = self._registerLogger()
+ self._registerSecurityPolicy(True)
+ result = self.config._derive_view(view, permission='view')
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.assertEqual(view.__name__, result.__name__)
+ self.assertEqual(result.__call_permissive__.__wraps__, view)
+ request = self._makeRequest()
+ request.view_name = 'view_name'
+ request.url = 'url'
+ self.assertEqual(result(None, request), response)
+ self.assertEqual(len(logger.messages), 1)
+ self.assertEqual(
+ logger.messages[0],
+ "debug_authorization of url url (view name "
+ "'view_name' against context None): True",
+ )
+
+ def test_debug_auth_permission_authpol_permitted_no_request(self):
+ response = DummyResponse()
+ view = lambda *arg: response
+ self.config.registry.settings = dict(
+ debug_authorization=True, reload_templates=True
+ )
+ logger = self._registerLogger()
+ self._registerSecurityPolicy(True)
+ result = self.config._derive_view(view, permission='view')
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.assertEqual(view.__name__, result.__name__)
+ self.assertEqual(result.__call_permissive__.__wraps__, view)
+ self.assertEqual(result(None, None), response)
+ self.assertEqual(len(logger.messages), 1)
+ self.assertEqual(
+ logger.messages[0],
+ "debug_authorization of url None (view name "
+ "None against context None): True",
+ )
+
+ def test_debug_auth_permission_authpol_denied(self):
+ from pyramid.httpexceptions import HTTPForbidden
+
+ response = DummyResponse()
+ view = lambda *arg: response
+ self.config.registry.settings = dict(
+ debug_authorization=True, reload_templates=True
+ )
+ logger = self._registerLogger()
+ self._registerSecurityPolicy(False)
+ result = self.config._derive_view(view, permission='view')
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.assertEqual(view.__name__, result.__name__)
+ self.assertEqual(result.__call_permissive__.__wraps__, view)
+ request = self._makeRequest()
+ request.view_name = 'view_name'
+ request.url = 'url'
+ self.assertRaises(HTTPForbidden, result, None, request)
+ self.assertEqual(len(logger.messages), 1)
+ self.assertEqual(
+ logger.messages[0],
+ "debug_authorization of url url (view name "
+ "'view_name' against context None): False",
+ )
+
+ def test_debug_auth_permission_authpol_denied2(self):
+ view = lambda *arg: 'OK'
+ self.config.registry.settings = dict(
+ debug_authorization=True, reload_templates=True
+ )
+ self._registerLogger()
+ self._registerSecurityPolicy(False)
+ result = self.config._derive_view(view, permission='view')
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.assertEqual(view.__name__, result.__name__)
+ request = self._makeRequest()
+ request.view_name = 'view_name'
+ request.url = 'url'
+ permitted = result.__permitted__(None, None)
+ self.assertEqual(permitted, False)
+
+ def test_debug_auth_permission_authpol_overridden(self):
+ from pyramid.security import NO_PERMISSION_REQUIRED
+
+ response = DummyResponse()
+ view = lambda *arg: response
+ self.config.registry.settings = dict(
+ debug_authorization=True, reload_templates=True
+ )
+ logger = self._registerLogger()
+ self._registerSecurityPolicy(False)
+ result = self.config._derive_view(
+ view, permission=NO_PERMISSION_REQUIRED
+ )
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.assertEqual(view.__name__, result.__name__)
+ self.assertFalse(hasattr(result, '__call_permissive__'))
+ request = self._makeRequest()
+ request.view_name = 'view_name'
+ request.url = 'url'
+ self.assertEqual(result(None, request), response)
+ self.assertEqual(len(logger.messages), 1)
+ self.assertEqual(
+ logger.messages[0],
+ "debug_authorization of url url (view name "
+ "'view_name' against context None): "
+ "Allowed (NO_PERMISSION_REQUIRED)",
+ )
+
+ def test_debug_auth_permission_authpol_permitted_excview(self):
+ response = DummyResponse()
+ view = lambda *arg: response
+ self.config.registry.settings = dict(
+ debug_authorization=True, reload_templates=True
+ )
+ logger = self._registerLogger()
+ self._registerSecurityPolicy(True)
+ result = self.config._derive_view(
+ view, context=Exception, permission='view'
+ )
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.assertEqual(view.__name__, result.__name__)
+ self.assertEqual(result.__call_permissive__.__wraps__, view)
+ request = self._makeRequest()
+ request.view_name = 'view_name'
+ request.url = 'url'
+ self.assertEqual(result(Exception(), request), response)
+ self.assertEqual(len(logger.messages), 1)
+ self.assertEqual(
+ logger.messages[0],
+ "debug_authorization of url url (view name "
+ "'view_name' against context Exception()): True",
+ )
+
+ def test_secured_view_authn_policy_no_authz_policy(self):
+ response = DummyResponse()
+ view = lambda *arg: response
+ self.config.registry.settings = {}
+ from pyramid.interfaces import IAuthenticationPolicy
+
+ policy = DummySecurityPolicy(False)
+ self.config.registry.registerUtility(policy, IAuthenticationPolicy)
+ result = self.config._derive_view(view, permission='view')
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.assertEqual(view.__name__, result.__name__)
+ self.assertFalse(hasattr(result, '__call_permissive__'))
+ request = self._makeRequest()
+ request.view_name = 'view_name'
+ request.url = 'url'
+ self.assertEqual(result(None, request), response)
+
+ def test_secured_view_authz_policy_no_authn_policy(self):
+ response = DummyResponse()
+ view = lambda *arg: response
+ self.config.registry.settings = {}
+ from pyramid.interfaces import IAuthorizationPolicy
+
+ policy = DummySecurityPolicy(False)
+ self.config.registry.registerUtility(policy, IAuthorizationPolicy)
+ result = self.config._derive_view(view, permission='view')
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.assertEqual(view.__name__, result.__name__)
+ self.assertFalse(hasattr(result, '__call_permissive__'))
+ request = self._makeRequest()
+ request.view_name = 'view_name'
+ request.url = 'url'
+ self.assertEqual(result(None, request), response)
+
+ def test_secured_view_raises_forbidden_no_name(self):
+ from pyramid.interfaces import IAuthenticationPolicy
+ from pyramid.interfaces import IAuthorizationPolicy
+ from pyramid.httpexceptions import HTTPForbidden
+
+ response = DummyResponse()
+ view = lambda *arg: response
+ self.config.registry.settings = {}
+ policy = DummySecurityPolicy(False)
+ self.config.registry.registerUtility(policy, IAuthenticationPolicy)
+ self.config.registry.registerUtility(policy, IAuthorizationPolicy)
+ result = self.config._derive_view(view, permission='view')
+ request = self._makeRequest()
+ request.view_name = 'view_name'
+ request.url = 'url'
+ try:
+ result(None, request)
+ except HTTPForbidden as e:
+ self.assertEqual(
+ e.message, 'Unauthorized: <lambda> failed permission check'
+ )
+ else: # pragma: no cover
+ raise AssertionError
+
+ def test_secured_view_raises_forbidden_with_name(self):
+ from pyramid.interfaces import IAuthenticationPolicy
+ from pyramid.interfaces import IAuthorizationPolicy
+ from pyramid.httpexceptions import HTTPForbidden
+
+ def myview(request): # pragma: no cover
+ pass
+
+ self.config.registry.settings = {}
+ policy = DummySecurityPolicy(False)
+ self.config.registry.registerUtility(policy, IAuthenticationPolicy)
+ self.config.registry.registerUtility(policy, IAuthorizationPolicy)
+ result = self.config._derive_view(myview, permission='view')
+ request = self._makeRequest()
+ request.view_name = 'view_name'
+ request.url = 'url'
+ try:
+ result(None, request)
+ except HTTPForbidden as e:
+ self.assertEqual(
+ e.message, 'Unauthorized: myview failed permission check'
+ )
+ else: # pragma: no cover
+ raise AssertionError
+
+ def test_secured_view_skipped_by_default_on_exception_view(self):
+ from pyramid.request import Request
+ from pyramid.security import NO_PERMISSION_REQUIRED
+
+ def view(request):
+ raise ValueError
+
+ def excview(request):
+ return 'hello'
+
+ self._registerSecurityPolicy(False)
+ self.config.add_settings({'debug_authorization': True})
+ self.config.set_default_permission('view')
+ self.config.add_view(
+ view, name='foo', permission=NO_PERMISSION_REQUIRED
+ )
+ self.config.add_view(excview, context=ValueError, renderer='string')
+ app = self.config.make_wsgi_app()
+ request = Request.blank('/foo', base_url='http://example.com')
+ request.method = 'POST'
+ response = request.get_response(app)
+ self.assertTrue(b'hello' in response.body)
+
+ def test_secured_view_failed_on_explicit_exception_view(self):
+ from pyramid.httpexceptions import HTTPForbidden
+ from pyramid.request import Request
+ from pyramid.security import NO_PERMISSION_REQUIRED
+
+ def view(request):
+ raise ValueError
+
+ def excview(request): # pragma: no cover
+ pass
+
+ self._registerSecurityPolicy(False)
+ self.config.add_view(
+ view, name='foo', permission=NO_PERMISSION_REQUIRED
+ )
+ self.config.add_view(
+ excview, context=ValueError, renderer='string', permission='view'
+ )
+ app = self.config.make_wsgi_app()
+ request = Request.blank('/foo', base_url='http://example.com')
+ request.method = 'POST'
+ try:
+ request.get_response(app)
+ except HTTPForbidden:
+ pass
+ else: # pragma: no cover
+ raise AssertionError
+
+ def test_secured_view_passed_on_explicit_exception_view(self):
+ from pyramid.request import Request
+ from pyramid.security import NO_PERMISSION_REQUIRED
+
+ def view(request):
+ raise ValueError
+
+ def excview(request):
+ return 'hello'
+
+ self._registerSecurityPolicy(True)
+ self.config.add_view(
+ view, name='foo', permission=NO_PERMISSION_REQUIRED
+ )
+ self.config.add_view(
+ excview, context=ValueError, renderer='string', permission='view'
+ )
+ app = self.config.make_wsgi_app()
+ request = Request.blank('/foo', base_url='http://example.com')
+ request.method = 'POST'
+ request.headers['X-CSRF-Token'] = 'foo'
+ response = request.get_response(app)
+ self.assertTrue(b'hello' in response.body)
+
+ def test_predicate_mismatch_view_has_no_name(self):
+ from pyramid.exceptions import PredicateMismatch
+
+ response = DummyResponse()
+ view = lambda *arg: response
+
+ def predicate1(context, request):
+ return False
+
+ predicate1.text = lambda *arg: 'text'
+ result = self.config._derive_view(view, predicates=[predicate1])
+ request = self._makeRequest()
+ request.method = 'POST'
+ try:
+ result(None, None)
+ except PredicateMismatch as e:
+ self.assertEqual(
+ e.detail, 'predicate mismatch for view <lambda> (text)'
+ )
+ else: # pragma: no cover
+ raise AssertionError
+
+ def test_predicate_mismatch_view_has_name(self):
+ from pyramid.exceptions import PredicateMismatch
+
+ def myview(request): # pragma: no cover
+ pass
+
+ def predicate1(context, request):
+ return False
+
+ predicate1.text = lambda *arg: 'text'
+ result = self.config._derive_view(myview, predicates=[predicate1])
+ request = self._makeRequest()
+ request.method = 'POST'
+ try:
+ result(None, None)
+ except PredicateMismatch as e:
+ self.assertEqual(
+ e.detail, 'predicate mismatch for view myview (text)'
+ )
+ else: # pragma: no cover
+ raise AssertionError
+
+ def test_predicate_mismatch_exception_has_text_in_detail(self):
+ from pyramid.exceptions import PredicateMismatch
+
+ def myview(request): # pragma: no cover
+ pass
+
+ def predicate1(context, request):
+ return True
+
+ predicate1.text = lambda *arg: 'pred1'
+
+ def predicate2(context, request):
+ return False
+
+ predicate2.text = lambda *arg: 'pred2'
+ result = self.config._derive_view(
+ myview, predicates=[predicate1, predicate2]
+ )
+ request = self._makeRequest()
+ request.method = 'POST'
+ try:
+ result(None, None)
+ except PredicateMismatch as e:
+ self.assertEqual(
+ e.detail, 'predicate mismatch for view myview (pred2)'
+ )
+ else: # pragma: no cover
+ raise AssertionError
+
+ def test_with_predicates_all(self):
+ response = DummyResponse()
+ view = lambda *arg: response
+ predicates = []
+
+ def predicate1(context, request):
+ predicates.append(True)
+ return True
+
+ def predicate2(context, request):
+ predicates.append(True)
+ return True
+
+ result = self.config._derive_view(
+ view, predicates=[predicate1, predicate2]
+ )
+ request = self._makeRequest()
+ request.method = 'POST'
+ next = result(None, None)
+ self.assertEqual(next, response)
+ self.assertEqual(predicates, [True, True])
+
+ def test_with_predicates_checker(self):
+ view = lambda *arg: 'OK'
+ predicates = []
+
+ def predicate1(context, request):
+ predicates.append(True)
+ return True
+
+ def predicate2(context, request):
+ predicates.append(True)
+ return True
+
+ result = self.config._derive_view(
+ view, predicates=[predicate1, predicate2]
+ )
+ request = self._makeRequest()
+ request.method = 'POST'
+ next = result.__predicated__(None, None)
+ self.assertEqual(next, True)
+ self.assertEqual(predicates, [True, True])
+
+ def test_with_predicates_notall(self):
+ from pyramid.httpexceptions import HTTPNotFound
+
+ view = lambda *arg: 'OK'
+ predicates = []
+
+ def predicate1(context, request):
+ predicates.append(True)
+ return True
+
+ predicate1.text = lambda *arg: 'text'
+
+ def predicate2(context, request):
+ predicates.append(True)
+ return False
+
+ predicate2.text = lambda *arg: 'text'
+ result = self.config._derive_view(
+ view, predicates=[predicate1, predicate2]
+ )
+ request = self._makeRequest()
+ request.method = 'POST'
+ self.assertRaises(HTTPNotFound, result, None, None)
+ self.assertEqual(predicates, [True, True])
+
+ def test_with_wrapper_viewname(self):
+ from pyramid.response import Response
+ from pyramid.interfaces import IView
+ from pyramid.interfaces import IViewClassifier
+
+ inner_response = Response('OK')
+
+ def inner_view(context, request):
+ return inner_response
+
+ def outer_view(context, request):
+ self.assertEqual(request.wrapped_response, inner_response)
+ self.assertEqual(request.wrapped_body, inner_response.body)
+ self.assertEqual(
+ request.wrapped_view.__original_view__, inner_view
+ )
+ return Response(b'outer ' + request.wrapped_body)
+
+ self.config.registry.registerAdapter(
+ outer_view, (IViewClassifier, None, None), IView, 'owrap'
+ )
+ result = self.config._derive_view(
+ inner_view, viewname='inner', wrapper_viewname='owrap'
+ )
+ self.assertFalse(result is inner_view)
+ self.assertEqual(inner_view.__module__, result.__module__)
+ self.assertEqual(inner_view.__doc__, result.__doc__)
+ request = self._makeRequest()
+ response = result(None, request)
+ self.assertEqual(response.body, b'outer OK')
+
+ def test_with_wrapper_viewname_notfound(self):
+ from pyramid.response import Response
+
+ inner_response = Response('OK')
+
+ def inner_view(context, request):
+ return inner_response
+
+ wrapped = self.config._derive_view(
+ inner_view, viewname='inner', wrapper_viewname='owrap'
+ )
+ request = self._makeRequest()
+ self.assertRaises(ValueError, wrapped, None, request)
+
+ def test_as_newstyle_class_context_and_request_attr_and_renderer(self):
+ response = DummyResponse()
+
+ class renderer(object):
+ def render_view(inself, req, resp, view_inst, ctx):
+ self.assertEqual(req, request)
+ self.assertEqual(resp, {'a': '1'})
+ self.assertEqual(view_inst.__class__, View)
+ self.assertEqual(ctx, context)
+ return response
+
+ def clone(self):
+ return self
+
+ class View(object):
+ def __init__(self, context, request):
+ pass
+
+ def index(self):
+ return {'a': '1'}
+
+ result = self.config._derive_view(
+ View, renderer=renderer(), attr='index'
+ )
+ self.assertFalse(result is View)
+ self.assertEqual(result.__module__, View.__module__)
+ self.assertEqual(result.__doc__, View.__doc__)
+ self.assertEqual(result.__name__, View.__name__)
+ request = self._makeRequest()
+ context = testing.DummyResource()
+ self.assertEqual(result(context, request), response)
+
+ def test_as_newstyle_class_requestonly_attr_and_renderer(self):
+ response = DummyResponse()
+
+ class renderer(object):
+ def render_view(inself, req, resp, view_inst, ctx):
+ self.assertEqual(req, request)
+ self.assertEqual(resp, {'a': '1'})
+ self.assertEqual(view_inst.__class__, View)
+ self.assertEqual(ctx, context)
+ return response
+
+ def clone(self):
+ return self
+
+ class View(object):
+ def __init__(self, request):
+ pass
+
+ def index(self):
+ return {'a': '1'}
+
+ result = self.config.derive_view(
+ View, renderer=renderer(), attr='index'
+ )
+ self.assertFalse(result is View)
+ self.assertEqual(result.__module__, View.__module__)
+ self.assertEqual(result.__doc__, View.__doc__)
+ self.assertEqual(result.__name__, View.__name__)
+ request = self._makeRequest()
+ context = testing.DummyResource()
+ self.assertEqual(result(context, request), response)
+
+ def test_as_oldstyle_cls_context_request_attr_and_renderer(self):
+ response = DummyResponse()
+
+ class renderer(object):
+ def render_view(inself, req, resp, view_inst, ctx):
+ self.assertEqual(req, request)
+ self.assertEqual(resp, {'a': '1'})
+ self.assertEqual(view_inst.__class__, View)
+ self.assertEqual(ctx, context)
+ return response
+
+ def clone(self):
+ return self
+
+ class View:
+ def __init__(self, context, request):
+ pass
+
+ def index(self):
+ return {'a': '1'}
+
+ result = self.config.derive_view(
+ View, renderer=renderer(), attr='index'
+ )
+ self.assertFalse(result is View)
+ self.assertEqual(result.__module__, View.__module__)
+ self.assertEqual(result.__doc__, View.__doc__)
+ self.assertEqual(result.__name__, View.__name__)
+ request = self._makeRequest()
+ context = testing.DummyResource()
+ self.assertEqual(result(context, request), response)
+
+ def test_as_oldstyle_cls_requestonly_attr_and_renderer(self):
+ response = DummyResponse()
+
+ class renderer(object):
+ def render_view(inself, req, resp, view_inst, ctx):
+ self.assertEqual(req, request)
+ self.assertEqual(resp, {'a': '1'})
+ self.assertEqual(view_inst.__class__, View)
+ self.assertEqual(ctx, context)
+ return response
+
+ def clone(self):
+ return self
+
+ class View:
+ def __init__(self, request):
+ pass
+
+ def index(self):
+ return {'a': '1'}
+
+ result = self.config.derive_view(
+ View, renderer=renderer(), attr='index'
+ )
+ self.assertFalse(result is View)
+ self.assertEqual(result.__module__, View.__module__)
+ self.assertEqual(result.__doc__, View.__doc__)
+ self.assertEqual(result.__name__, View.__name__)
+ request = self._makeRequest()
+ context = testing.DummyResource()
+ self.assertEqual(result(context, request), response)
+
+ def test_as_instance_context_and_request_attr_and_renderer(self):
+ response = DummyResponse()
+
+ class renderer(object):
+ def render_view(inself, req, resp, view_inst, ctx):
+ self.assertEqual(req, request)
+ self.assertEqual(resp, {'a': '1'})
+ self.assertEqual(view_inst, view)
+ self.assertEqual(ctx, context)
+ return response
+
+ def clone(self):
+ return self
+
+ class View:
+ def index(self, context, request):
+ return {'a': '1'}
+
+ view = View()
+ result = self.config.derive_view(
+ view, renderer=renderer(), attr='index'
+ )
+ self.assertFalse(result is view)
+ self.assertEqual(result.__module__, view.__module__)
+ self.assertEqual(result.__doc__, view.__doc__)
+ request = self._makeRequest()
+ context = testing.DummyResource()
+ self.assertEqual(result(context, request), response)
+
+ def test_as_instance_requestonly_attr_and_renderer(self):
+ response = DummyResponse()
+
+ class renderer(object):
+ def render_view(inself, req, resp, view_inst, ctx):
+ self.assertEqual(req, request)
+ self.assertEqual(resp, {'a': '1'})
+ self.assertEqual(view_inst, view)
+ self.assertEqual(ctx, context)
+ return response
+
+ def clone(self):
+ return self
+
+ class View:
+ def index(self, request):
+ return {'a': '1'}
+
+ view = View()
+ result = self.config.derive_view(
+ view, renderer=renderer(), attr='index'
+ )
+ self.assertFalse(result is view)
+ self.assertEqual(result.__module__, view.__module__)
+ self.assertEqual(result.__doc__, view.__doc__)
+ request = self._makeRequest()
+ context = testing.DummyResource()
+ self.assertEqual(result(context, request), response)
+
+ def test_with_view_mapper_config_specified(self):
+ response = DummyResponse()
+
+ class mapper(object):
+ def __init__(self, **kw):
+ self.kw = kw
+
+ def __call__(self, view):
+ def wrapped(context, request):
+ return response
+
+ return wrapped
+
+ def view(context, request): # pragma: no cover
+ return 'NOTOK'
+
+ result = self.config._derive_view(view, mapper=mapper)
+ self.assertFalse(result.__wraps__ is view)
+ self.assertEqual(result(None, None), response)
+
+ def test_with_view_mapper_view_specified(self):
+ from pyramid.response import Response
+
+ response = Response()
+
+ def mapper(**kw):
+ def inner(view):
+ def superinner(context, request):
+ self.assertEqual(request, None)
+ return response
+
+ return superinner
+
+ return inner
+
+ def view(context, request): # pragma: no cover
+ return 'NOTOK'
+
+ view.__view_mapper__ = mapper
+ result = self.config.derive_view(view)
+ self.assertFalse(result.__wraps__ is view)
+ self.assertEqual(result(None, None), response)
+
+ def test_with_view_mapper_default_mapper_specified(self):
+ from pyramid.response import Response
+
+ response = Response()
+
+ def mapper(**kw):
+ def inner(view):
+ def superinner(context, request):
+ self.assertEqual(request, None)
+ return response
+
+ return superinner
+
+ return inner
+
+ self.config.set_view_mapper(mapper)
+
+ def view(context, request): # pragma: no cover
+ return 'NOTOK'
+
+ result = self.config.derive_view(view)
+ self.assertFalse(result.__wraps__ is view)
+ self.assertEqual(result(None, None), response)
+
+ def test_attr_wrapped_view_branching_default_phash(self):
+ from pyramid.config.predicates import DEFAULT_PHASH
+
+ def view(context, request): # pragma: no cover
+ pass
+
+ result = self.config._derive_view(view, phash=DEFAULT_PHASH)
+ self.assertEqual(result.__wraps__, view)
+
+ def test_attr_wrapped_view_branching_nondefault_phash(self):
+ def view(context, request): # pragma: no cover
+ pass
+
+ result = self.config._derive_view(view, phash='nondefault')
+ self.assertNotEqual(result, view)
+
+ def test_http_cached_view_integer(self):
+ import datetime
+ from pyramid.response import Response
+
+ response = Response('OK')
+
+ def inner_view(context, request):
+ return response
+
+ result = self.config._derive_view(inner_view, http_cache=3600)
+ self.assertFalse(result is inner_view)
+ self.assertEqual(inner_view.__module__, result.__module__)
+ self.assertEqual(inner_view.__doc__, result.__doc__)
+ request = self._makeRequest()
+ when = datetime.datetime.utcnow() + datetime.timedelta(hours=1)
+ result = result(None, request)
+ self.assertEqual(result, response)
+ headers = dict(result.headerlist)
+ expires = parse_httpdate(headers['Expires'])
+ assert_similar_datetime(expires, when)
+ self.assertEqual(headers['Cache-Control'], 'max-age=3600')
+
+ def test_http_cached_view_timedelta(self):
+ import datetime
+ from pyramid.response import Response
+
+ response = Response('OK')
+
+ def inner_view(context, request):
+ return response
+
+ result = self.config._derive_view(
+ inner_view, http_cache=datetime.timedelta(hours=1)
+ )
+ self.assertFalse(result is inner_view)
+ self.assertEqual(inner_view.__module__, result.__module__)
+ self.assertEqual(inner_view.__doc__, result.__doc__)
+ request = self._makeRequest()
+ when = datetime.datetime.utcnow() + datetime.timedelta(hours=1)
+ result = result(None, request)
+ self.assertEqual(result, response)
+ headers = dict(result.headerlist)
+ expires = parse_httpdate(headers['Expires'])
+ assert_similar_datetime(expires, when)
+ self.assertEqual(headers['Cache-Control'], 'max-age=3600')
+
+ def test_http_cached_view_tuple(self):
+ import datetime
+ from pyramid.response import Response
+
+ response = Response('OK')
+
+ def inner_view(context, request):
+ return response
+
+ result = self.config._derive_view(
+ inner_view, http_cache=(3600, {'public': True})
+ )
+ self.assertFalse(result is inner_view)
+ self.assertEqual(inner_view.__module__, result.__module__)
+ self.assertEqual(inner_view.__doc__, result.__doc__)
+ request = self._makeRequest()
+ when = datetime.datetime.utcnow() + datetime.timedelta(hours=1)
+ result = result(None, request)
+ self.assertEqual(result, response)
+ headers = dict(result.headerlist)
+ expires = parse_httpdate(headers['Expires'])
+ assert_similar_datetime(expires, when)
+ self.assertEqual(headers['Cache-Control'], 'max-age=3600, public')
+
+ def test_http_cached_view_tuple_seconds_None(self):
+ from pyramid.response import Response
+
+ response = Response('OK')
+
+ def inner_view(context, request):
+ return response
+
+ result = self.config._derive_view(
+ inner_view, http_cache=(None, {'public': True})
+ )
+ self.assertFalse(result is inner_view)
+ self.assertEqual(inner_view.__module__, result.__module__)
+ self.assertEqual(inner_view.__doc__, result.__doc__)
+ request = self._makeRequest()
+ result = result(None, request)
+ self.assertEqual(result, response)
+ headers = dict(result.headerlist)
+ self.assertFalse('Expires' in headers)
+ self.assertEqual(headers['Cache-Control'], 'public')
+
+ def test_http_cached_view_prevent_auto_set(self):
+ from pyramid.response import Response
+
+ response = Response()
+ response.cache_control.prevent_auto = True
+
+ def inner_view(context, request):
+ return response
+
+ result = self.config._derive_view(inner_view, http_cache=3600)
+ request = self._makeRequest()
+ result = result(None, request)
+ self.assertEqual(result, response) # doesn't blow up
+ headers = dict(result.headerlist)
+ self.assertFalse('Expires' in headers)
+ self.assertFalse('Cache-Control' in headers)
+
+ def test_http_cached_prevent_http_cache_in_settings(self):
+ self.config.registry.settings['prevent_http_cache'] = True
+ from pyramid.response import Response
+
+ response = Response()
+
+ def inner_view(context, request):
+ return response
+
+ result = self.config._derive_view(inner_view, http_cache=3600)
+ request = self._makeRequest()
+ result = result(None, request)
+ self.assertEqual(result, response)
+ headers = dict(result.headerlist)
+ self.assertFalse('Expires' in headers)
+ self.assertFalse('Cache-Control' in headers)
+
+ def test_http_cached_view_bad_tuple(self):
+ def view(request): # pragma: no cover
+ pass
+
+ self.assertRaises(
+ ConfigurationError,
+ self.config._derive_view,
+ view,
+ http_cache=(None,),
+ )
+
+ def test_csrf_view_ignores_GET(self):
+ response = DummyResponse()
+
+ def inner_view(request):
+ return response
+
+ request = self._makeRequest()
+ request.method = 'GET'
+ view = self.config._derive_view(inner_view, require_csrf=True)
+ result = view(None, request)
+ self.assertTrue(result is response)
+
+ def test_csrf_view_fails_with_bad_POST_header(self):
+ from pyramid.exceptions import BadCSRFToken
+
+ def inner_view(request): # pragma: no cover
+ pass
+
+ request = self._makeRequest()
+ request.scheme = "http"
+ request.method = 'POST'
+ request.session = DummySession({'csrf_token': 'foo'})
+ request.headers = {'X-CSRF-Token': 'bar'}
+ view = self.config._derive_view(inner_view, require_csrf=True)
+ self.assertRaises(BadCSRFToken, lambda: view(None, request))
+
+ def test_csrf_view_passes_with_good_POST_header(self):
+ response = DummyResponse()
+
+ def inner_view(request):
+ return response
+
+ request = self._makeRequest()
+ request.scheme = "http"
+ request.method = 'POST'
+ request.session = DummySession({'csrf_token': 'foo'})
+ request.headers = {'X-CSRF-Token': 'foo'}
+ view = self.config._derive_view(inner_view, require_csrf=True)
+ result = view(None, request)
+ self.assertTrue(result is response)
+
+ def test_csrf_view_fails_with_bad_POST_token(self):
+ from pyramid.exceptions import BadCSRFToken
+
+ def inner_view(request): # pragma: no cover
+ pass
+
+ request = self._makeRequest()
+ request.scheme = "http"
+ request.method = 'POST'
+ request.session = DummySession({'csrf_token': 'foo'})
+ request.POST = {'csrf_token': 'bar'}
+ view = self.config._derive_view(inner_view, require_csrf=True)
+ self.assertRaises(BadCSRFToken, lambda: view(None, request))
+
+ def test_csrf_view_passes_with_good_POST_token(self):
+ response = DummyResponse()
+
+ def inner_view(request):
+ return response
+
+ request = self._makeRequest()
+ request.scheme = "http"
+ request.method = 'POST'
+ request.session = DummySession({'csrf_token': 'foo'})
+ request.POST = {'csrf_token': 'foo'}
+ view = self.config._derive_view(inner_view, require_csrf=True)
+ result = view(None, request)
+ self.assertTrue(result is response)
+
+ def test_csrf_view_https_domain(self):
+ response = DummyResponse()
+
+ def inner_view(request):
+ return response
+
+ request = self._makeRequest()
+ request.scheme = "https"
+ request.domain = "example.com"
+ request.host_port = "443"
+ request.referrer = "https://example.com/login/"
+ request.method = 'POST'
+ request.session = DummySession({'csrf_token': 'foo'})
+ request.POST = {'csrf_token': 'foo'}
+ view = self.config._derive_view(inner_view, require_csrf=True)
+ result = view(None, request)
+ self.assertTrue(result is response)
+
+ def test_csrf_view_fails_on_bad_PUT_header(self):
+ from pyramid.exceptions import BadCSRFToken
+
+ def inner_view(request): # pragma: no cover
+ pass
+
+ request = self._makeRequest()
+ request.scheme = "http"
+ request.method = 'PUT'
+ request.session = DummySession({'csrf_token': 'foo'})
+ request.headers = {'X-CSRF-Token': 'bar'}
+ view = self.config._derive_view(inner_view, require_csrf=True)
+ self.assertRaises(BadCSRFToken, lambda: view(None, request))
+
+ def test_csrf_view_fails_on_bad_referrer(self):
+ from pyramid.exceptions import BadCSRFOrigin
+
+ def inner_view(request): # pragma: no cover
+ pass
+
+ request = self._makeRequest()
+ request.method = "POST"
+ request.scheme = "https"
+ request.host_port = "443"
+ request.domain = "example.com"
+ request.referrer = "https://not-example.com/evil/"
+ request.registry.settings = {}
+ view = self.config._derive_view(inner_view, require_csrf=True)
+ self.assertRaises(BadCSRFOrigin, lambda: view(None, request))
+
+ def test_csrf_view_fails_on_bad_origin(self):
+ from pyramid.exceptions import BadCSRFOrigin
+
+ def inner_view(request): # pragma: no cover
+ pass
+
+ request = self._makeRequest()
+ request.method = "POST"
+ request.scheme = "https"
+ request.host_port = "443"
+ request.domain = "example.com"
+ request.headers = {"Origin": "https://not-example.com/evil/"}
+ request.registry.settings = {}
+ view = self.config._derive_view(inner_view, require_csrf=True)
+ self.assertRaises(BadCSRFOrigin, lambda: view(None, request))
+
+ def test_csrf_view_enabled_by_default(self):
+ from pyramid.exceptions import BadCSRFToken
+
+ def inner_view(request): # pragma: no cover
+ pass
+
+ request = self._makeRequest()
+ request.scheme = "http"
+ request.method = 'POST'
+ request.session = DummySession({'csrf_token': 'foo'})
+ self.config.set_default_csrf_options(require_csrf=True)
+ view = self.config._derive_view(inner_view)
+ self.assertRaises(BadCSRFToken, lambda: view(None, request))
+
+ def test_csrf_view_enabled_via_callback(self):
+ def callback(request):
+ return True
+
+ from pyramid.exceptions import BadCSRFToken
+
+ def inner_view(request): # pragma: no cover
+ pass
+
+ request = self._makeRequest()
+ request.scheme = "http"
+ request.method = 'POST'
+ request.session = DummySession({'csrf_token': 'foo'})
+ self.config.set_default_csrf_options(
+ require_csrf=True, callback=callback
+ )
+ view = self.config._derive_view(inner_view)
+ self.assertRaises(BadCSRFToken, lambda: view(None, request))
+
+ def test_csrf_view_disabled_via_callback(self):
+ def callback(request):
+ return False
+
+ response = DummyResponse()
+
+ def inner_view(request):
+ return response
+
+ request = self._makeRequest()
+ request.scheme = "http"
+ request.method = 'POST'
+ request.session = DummySession({'csrf_token': 'foo'})
+ self.config.set_default_csrf_options(
+ require_csrf=True, callback=callback
+ )
+ view = self.config._derive_view(inner_view)
+ result = view(None, request)
+ self.assertTrue(result is response)
+
+ def test_csrf_view_uses_custom_csrf_token(self):
+ response = DummyResponse()
+
+ def inner_view(request):
+ return response
+
+ request = self._makeRequest()
+ request.scheme = "http"
+ request.method = 'POST'
+ request.session = DummySession({'csrf_token': 'foo'})
+ request.POST = {'DUMMY': 'foo'}
+ self.config.set_default_csrf_options(require_csrf=True, token='DUMMY')
+ view = self.config._derive_view(inner_view)
+ result = view(None, request)
+ self.assertTrue(result is response)
+
+ def test_csrf_view_uses_custom_csrf_header(self):
+ response = DummyResponse()
+
+ def inner_view(request):
+ return response
+
+ request = self._makeRequest()
+ request.scheme = "http"
+ request.method = 'POST'
+ request.session = DummySession({'csrf_token': 'foo'})
+ request.headers = {'DUMMY': 'foo'}
+ self.config.set_default_csrf_options(require_csrf=True, header='DUMMY')
+ view = self.config._derive_view(inner_view)
+ result = view(None, request)
+ self.assertTrue(result is response)
+
+ def test_csrf_view_uses_custom_methods(self):
+ response = DummyResponse()
+
+ def inner_view(request):
+ return response
+
+ request = self._makeRequest()
+ request.scheme = "http"
+ request.method = 'PUT'
+ request.session = DummySession({'csrf_token': 'foo'})
+ self.config.set_default_csrf_options(
+ require_csrf=True, safe_methods=['PUT']
+ )
+ view = self.config._derive_view(inner_view)
+ result = view(None, request)
+ self.assertTrue(result is response)
+
+ def test_csrf_view_uses_view_option_override(self):
+ response = DummyResponse()
+
+ def inner_view(request):
+ return response
+
+ request = self._makeRequest()
+ request.scheme = "http"
+ request.method = 'POST'
+ request.session = DummySession({'csrf_token': 'foo'})
+ request.POST = {'csrf_token': 'bar'}
+ self.config.set_default_csrf_options(require_csrf=True)
+ view = self.config._derive_view(inner_view, require_csrf=False)
+ result = view(None, request)
+ self.assertTrue(result is response)
+
+ def test_csrf_view_skipped_by_default_on_exception_view(self):
+ from pyramid.request import Request
+
+ def view(request):
+ raise ValueError
+
+ def excview(request):
+ return 'hello'
+
+ self.config.set_default_csrf_options(require_csrf=True)
+ self.config.set_session_factory(
+ lambda request: DummySession({'csrf_token': 'foo'})
+ )
+ self.config.add_view(view, name='foo', require_csrf=False)
+ self.config.add_view(excview, context=ValueError, renderer='string')
+ app = self.config.make_wsgi_app()
+ request = Request.blank('/foo', base_url='http://example.com')
+ request.method = 'POST'
+ response = request.get_response(app)
+ self.assertTrue(b'hello' in response.body)
+
+ def test_csrf_view_failed_on_explicit_exception_view(self):
+ from pyramid.exceptions import BadCSRFToken
+ from pyramid.request import Request
+
+ def view(request):
+ raise ValueError
+
+ def excview(request): # pragma: no cover
+ pass
+
+ self.config.set_default_csrf_options(require_csrf=True)
+ self.config.set_session_factory(
+ lambda request: DummySession({'csrf_token': 'foo'})
+ )
+ self.config.add_view(view, name='foo', require_csrf=False)
+ self.config.add_view(
+ excview, context=ValueError, renderer='string', require_csrf=True
+ )
+ app = self.config.make_wsgi_app()
+ request = Request.blank('/foo', base_url='http://example.com')
+ request.method = 'POST'
+ try:
+ request.get_response(app)
+ except BadCSRFToken:
+ pass
+ else: # pragma: no cover
+ raise AssertionError
+
+ def test_csrf_view_passed_on_explicit_exception_view(self):
+ from pyramid.request import Request
+
+ def view(request):
+ raise ValueError
+
+ def excview(request):
+ return 'hello'
+
+ self.config.set_default_csrf_options(require_csrf=True)
+ self.config.set_session_factory(
+ lambda request: DummySession({'csrf_token': 'foo'})
+ )
+ self.config.add_view(view, name='foo', require_csrf=False)
+ self.config.add_view(
+ excview, context=ValueError, renderer='string', require_csrf=True
+ )
+ app = self.config.make_wsgi_app()
+ request = Request.blank('/foo', base_url='http://example.com')
+ request.method = 'POST'
+ request.headers['X-CSRF-Token'] = 'foo'
+ response = request.get_response(app)
+ self.assertTrue(b'hello' in response.body)
+
+
+class TestDerivationOrder(unittest.TestCase):
+ def setUp(self):
+ self.config = testing.setUp()
+
+ def tearDown(self):
+ self.config = None
+ testing.tearDown()
+
+ def test_right_order_user_sorted(self):
+ from pyramid.interfaces import IViewDerivers
+
+ self.config.add_view_deriver(None, 'deriv1')
+ self.config.add_view_deriver(
+ None, 'deriv2', 'decorated_view', 'deriv1'
+ )
+ self.config.add_view_deriver(None, 'deriv3', 'deriv2', 'deriv1')
+
+ derivers = self.config.registry.getUtility(IViewDerivers)
+ derivers_sorted = derivers.sorted()
+ dlist = [d for (d, _) in derivers_sorted]
+ self.assertEqual(
+ [
+ 'secured_view',
+ 'csrf_view',
+ 'owrapped_view',
+ 'http_cached_view',
+ 'decorated_view',
+ 'deriv2',
+ 'deriv3',
+ 'deriv1',
+ 'rendered_view',
+ 'mapped_view',
+ ],
+ dlist,
+ )
+
+ def test_right_order_implicit(self):
+ from pyramid.interfaces import IViewDerivers
+
+ self.config.add_view_deriver(None, 'deriv1')
+ self.config.add_view_deriver(None, 'deriv2')
+ self.config.add_view_deriver(None, 'deriv3')
+
+ derivers = self.config.registry.getUtility(IViewDerivers)
+ derivers_sorted = derivers.sorted()
+ dlist = [d for (d, _) in derivers_sorted]
+ self.assertEqual(
+ [
+ 'secured_view',
+ 'csrf_view',
+ 'owrapped_view',
+ 'http_cached_view',
+ 'decorated_view',
+ 'deriv3',
+ 'deriv2',
+ 'deriv1',
+ 'rendered_view',
+ 'mapped_view',
+ ],
+ dlist,
+ )
+
+ def test_right_order_under_rendered_view(self):
+ from pyramid.interfaces import IViewDerivers
+
+ self.config.add_view_deriver(
+ None, 'deriv1', 'rendered_view', 'mapped_view'
+ )
+
+ derivers = self.config.registry.getUtility(IViewDerivers)
+ derivers_sorted = derivers.sorted()
+ dlist = [d for (d, _) in derivers_sorted]
+ self.assertEqual(
+ [
+ 'secured_view',
+ 'csrf_view',
+ 'owrapped_view',
+ 'http_cached_view',
+ 'decorated_view',
+ 'rendered_view',
+ 'deriv1',
+ 'mapped_view',
+ ],
+ dlist,
+ )
+
+ def test_right_order_under_rendered_view_others(self):
+ from pyramid.interfaces import IViewDerivers
+
+ self.config.add_view_deriver(
+ None, 'deriv1', 'rendered_view', 'mapped_view'
+ )
+ self.config.add_view_deriver(None, 'deriv2')
+ self.config.add_view_deriver(None, 'deriv3')
+
+ derivers = self.config.registry.getUtility(IViewDerivers)
+ derivers_sorted = derivers.sorted()
+ dlist = [d for (d, _) in derivers_sorted]
+ self.assertEqual(
+ [
+ 'secured_view',
+ 'csrf_view',
+ 'owrapped_view',
+ 'http_cached_view',
+ 'decorated_view',
+ 'deriv3',
+ 'deriv2',
+ 'rendered_view',
+ 'deriv1',
+ 'mapped_view',
+ ],
+ dlist,
+ )
+
+
+class TestAddDeriver(unittest.TestCase):
+ def setUp(self):
+ self.config = testing.setUp()
+
+ def tearDown(self):
+ self.config = None
+ testing.tearDown()
+
+ def test_add_single_deriver(self):
+ response = DummyResponse()
+ response.deriv = False
+ view = lambda *arg: response
+
+ def deriv(view, info):
+ self.assertFalse(response.deriv)
+ response.deriv = True
+ return view
+
+ result = self.config._derive_view(view)
+ self.assertFalse(response.deriv)
+ self.config.add_view_deriver(deriv, 'test_deriv')
+
+ result = self.config._derive_view(view) # noqa: F841
+ self.assertTrue(response.deriv)
+
+ def test_override_deriver(self):
+ flags = {}
+
+ class AView:
+ def __init__(self):
+ self.response = DummyResponse()
+
+ def deriv1(view, info):
+ flags['deriv1'] = True
+ return view
+
+ def deriv2(view, info):
+ flags['deriv2'] = True
+ return view
+
+ view1 = AView()
+ self.config.add_view_deriver(deriv1, 'test_deriv')
+ result = self.config._derive_view(view1)
+ self.assertTrue(flags.get('deriv1'))
+ self.assertFalse(flags.get('deriv2'))
+
+ flags.clear()
+ view2 = AView()
+ self.config.add_view_deriver(deriv2, 'test_deriv')
+ result = self.config._derive_view(view2) # noqa: F841
+ self.assertFalse(flags.get('deriv1'))
+ self.assertTrue(flags.get('deriv2'))
+
+ def test_override_mapped_view(self):
+ from pyramid.viewderivers import VIEW
+
+ response = DummyResponse()
+ view = lambda *arg: response
+ flags = {}
+
+ def deriv1(view, info):
+ flags['deriv1'] = True
+ return view
+
+ result = self.config._derive_view(view)
+ self.assertFalse(flags.get('deriv1'))
+
+ flags.clear()
+ self.config.add_view_deriver(
+ deriv1, name='mapped_view', under='rendered_view', over=VIEW
+ )
+ result = self.config._derive_view(view) # noqa: F841
+ self.assertTrue(flags.get('deriv1'))
+
+ def test_add_multi_derivers_ordered(self):
+ from pyramid.viewderivers import INGRESS
+
+ response = DummyResponse()
+ view = lambda *arg: response
+ response.deriv = []
+
+ def deriv1(view, info):
+ response.deriv.append('deriv1')
+ return view
+
+ def deriv2(view, info):
+ response.deriv.append('deriv2')
+ return view
+
+ def deriv3(view, info):
+ response.deriv.append('deriv3')
+ return view
+
+ self.config.add_view_deriver(deriv1, 'deriv1')
+ self.config.add_view_deriver(deriv2, 'deriv2', INGRESS, 'deriv1')
+ self.config.add_view_deriver(deriv3, 'deriv3', 'deriv2', 'deriv1')
+ result = self.config._derive_view(view) # noqa: F841
+ self.assertEqual(response.deriv, ['deriv1', 'deriv3', 'deriv2'])
+
+ def test_add_deriver_without_name(self):
+ from pyramid.interfaces import IViewDerivers
+
+ def deriv1(view, info): # pragma: no cover
+ pass
+
+ self.config.add_view_deriver(deriv1)
+ derivers = self.config.registry.getUtility(IViewDerivers)
+ self.assertTrue('deriv1' in derivers.names)
+
+ def test_add_deriver_reserves_ingress(self):
+ from pyramid.exceptions import ConfigurationError
+ from pyramid.viewderivers import INGRESS
+
+ def deriv1(view, info): # pragma: no cover
+ pass
+
+ self.assertRaises(
+ ConfigurationError, self.config.add_view_deriver, deriv1, INGRESS
+ )
+
+ def test_add_deriver_enforces_ingress_is_first(self):
+ from pyramid.exceptions import ConfigurationError
+ from pyramid.viewderivers import INGRESS
+
+ def deriv1(view, info): # pragma: no cover
+ pass
+
+ try:
+ self.config.add_view_deriver(deriv1, over=INGRESS)
+ except ConfigurationError as ex:
+ self.assertTrue('cannot be over INGRESS' in ex.args[0])
+ else: # pragma: no cover
+ raise AssertionError
+
+ def test_add_deriver_enforces_view_is_last(self):
+ from pyramid.exceptions import ConfigurationError
+ from pyramid.viewderivers import VIEW
+
+ def deriv1(view, info): # pragma: no cover
+ pass
+
+ try:
+ self.config.add_view_deriver(deriv1, under=VIEW)
+ except ConfigurationError as ex:
+ self.assertTrue('cannot be under VIEW' in ex.args[0])
+ else: # pragma: no cover
+ raise AssertionError
+
+ def test_add_deriver_enforces_mapped_view_is_last(self):
+ from pyramid.exceptions import ConfigurationError
+
+ def deriv1(view, info): # pragma: no cover
+ pass
+
+ try:
+ self.config.add_view_deriver(deriv1, 'deriv1', under='mapped_view')
+ except ConfigurationError as ex:
+ self.assertTrue('cannot be under "mapped_view"' in ex.args[0])
+ else: # pragma: no cover
+ raise AssertionError
+
+
+class TestDeriverIntegration(unittest.TestCase):
+ def setUp(self):
+ self.config = testing.setUp()
+
+ def tearDown(self):
+ self.config = None
+ testing.tearDown()
+
+ def _getViewCallable(
+ self, config, ctx_iface=None, request_iface=None, name=''
+ ):
+ from zope.interface import Interface
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IView
+ from pyramid.interfaces import IViewClassifier
+
+ classifier = IViewClassifier
+ if ctx_iface is None:
+ ctx_iface = Interface
+ if request_iface is None:
+ request_iface = IRequest
+ return config.registry.adapters.lookup(
+ (classifier, request_iface, ctx_iface),
+ IView,
+ name=name,
+ default=None,
+ )
+
+ def _makeRequest(self, config):
+ request = DummyRequest()
+ request.registry = config.registry
+ return request
+
+ def test_view_options(self):
+ response = DummyResponse()
+ view = lambda *arg: response
+ response.deriv = []
+
+ def deriv1(view, info):
+ response.deriv.append(info.options['deriv1'])
+ return view
+
+ deriv1.options = ('deriv1',)
+
+ def deriv2(view, info):
+ response.deriv.append(info.options['deriv2'])
+ return view
+
+ deriv2.options = ('deriv2',)
+
+ self.config.add_view_deriver(deriv1, 'deriv1')
+ self.config.add_view_deriver(deriv2, 'deriv2')
+ self.config.add_view(view, deriv1='test1', deriv2='test2')
+
+ wrapper = self._getViewCallable(self.config)
+ request = self._makeRequest(self.config)
+ request.method = 'GET'
+ self.assertEqual(wrapper(None, request), response)
+ self.assertEqual(['test1', 'test2'], response.deriv)
+
+ def test_unexpected_view_options(self):
+ from pyramid.exceptions import ConfigurationError
+
+ def deriv1(view, info): # pragma: no cover
+ pass
+
+ self.config.add_view_deriver(deriv1, 'deriv1')
+ self.assertRaises(
+ ConfigurationError,
+ lambda: self.config.add_view(lambda r: {}, deriv1='test1'),
+ )
+
+
+@implementer(IResponse)
+class DummyResponse(object):
+ content_type = None
+ default_content_type = None
+ body = None
+
+
+class DummyRequest:
+ subpath = ()
+ matchdict = None
+ request_iface = IRequest
+
+ def __init__(self, environ=None):
+ if environ is None:
+ environ = {}
+ self.environ = environ
+ self.params = {}
+ self.POST = {}
+ self.cookies = {}
+ self.headers = {}
+ self.response = DummyResponse()
+
+
+class DummyLogger:
+ def __init__(self):
+ self.messages = []
+
+ def info(self, msg):
+ self.messages.append(msg)
+
+ warn = info
+ debug = info
+
+
+class DummySecurityPolicy:
+ def __init__(self, permitted=True):
+ self.permitted = permitted
+
+ def effective_principals(self, request):
+ return []
+
+ def permits(self, context, principals, permission):
+ return self.permitted
+
+
+class DummySession(dict):
+ def get_csrf_token(self):
+ return self['csrf_token']
+
+
+def parse_httpdate(s):
+ import datetime
+
+ # cannot use %Z, must use literal GMT; Jython honors timezone
+ # but CPython does not
+ return datetime.datetime.strptime(s, "%a, %d %b %Y %H:%M:%S GMT")
+
+
+def assert_similar_datetime(one, two):
+ for attr in ('year', 'month', 'day', 'hour', 'minute'):
+ one_attr = getattr(one, attr)
+ two_attr = getattr(two, attr)
+ if not one_attr == two_attr: # pragma: no cover
+ raise AssertionError('%r != %r in %s' % (one_attr, two_attr, attr))
diff --git a/tests/test_wsgi.py b/tests/test_wsgi.py
new file mode 100644
index 000000000..a5a955621
--- /dev/null
+++ b/tests/test_wsgi.py
@@ -0,0 +1,139 @@
+import unittest
+
+
+class WSGIAppTests(unittest.TestCase):
+ def _callFUT(self, app):
+ from pyramid.wsgi import wsgiapp
+
+ return wsgiapp(app)
+
+ def test_wsgiapp_none(self):
+ self.assertRaises(ValueError, self._callFUT, None)
+
+ def test_decorator(self):
+ context = DummyContext()
+ request = DummyRequest()
+ decorator = self._callFUT(dummyapp)
+ response = decorator(context, request)
+ self.assertEqual(response, dummyapp)
+
+ def test_decorator_object_instance(self):
+ context = DummyContext()
+ request = DummyRequest()
+ app = DummyApp()
+ decorator = self._callFUT(app)
+ response = decorator(context, request)
+ self.assertEqual(response, app)
+
+
+class WSGIApp2Tests(unittest.TestCase):
+ def _callFUT(self, app):
+ from pyramid.wsgi import wsgiapp2
+
+ return wsgiapp2(app)
+
+ def test_wsgiapp2_none(self):
+ self.assertRaises(ValueError, self._callFUT, None)
+
+ def test_decorator_with_subpath_and_view_name(self):
+ context = DummyContext()
+ request = DummyRequest()
+ request.subpath = ('subpath',)
+ request.environ = {
+ 'SCRIPT_NAME': '/foo',
+ 'PATH_INFO': '/b/view_name/subpath',
+ }
+ decorator = self._callFUT(dummyapp)
+ response = decorator(context, request)
+ self.assertEqual(response, dummyapp)
+ self.assertEqual(request.environ['PATH_INFO'], '/subpath')
+ self.assertEqual(request.environ['SCRIPT_NAME'], '/foo/b/view_name')
+
+ def test_decorator_with_subpath_no_view_name(self):
+ context = DummyContext()
+ request = DummyRequest()
+ request.subpath = ('subpath',)
+ request.environ = {'SCRIPT_NAME': '/foo', 'PATH_INFO': '/b/subpath'}
+ decorator = self._callFUT(dummyapp)
+ response = decorator(context, request)
+ self.assertEqual(response, dummyapp)
+ self.assertEqual(request.environ['PATH_INFO'], '/subpath')
+ self.assertEqual(request.environ['SCRIPT_NAME'], '/foo/b')
+
+ def test_decorator_no_subpath_with_view_name(self):
+ context = DummyContext()
+ request = DummyRequest()
+ request.subpath = ()
+ request.environ = {'SCRIPT_NAME': '/foo', 'PATH_INFO': '/b/view_name'}
+ decorator = self._callFUT(dummyapp)
+ response = decorator(context, request)
+ self.assertEqual(response, dummyapp)
+ self.assertEqual(request.environ['PATH_INFO'], '/')
+ self.assertEqual(request.environ['SCRIPT_NAME'], '/foo/b/view_name')
+
+ def test_decorator_traversed_empty_with_view_name(self):
+ context = DummyContext()
+ request = DummyRequest()
+ request.subpath = ()
+ request.environ = {'SCRIPT_NAME': '/foo', 'PATH_INFO': '/view_name'}
+ decorator = self._callFUT(dummyapp)
+ response = decorator(context, request)
+ self.assertEqual(response, dummyapp)
+ self.assertEqual(request.environ['PATH_INFO'], '/')
+ self.assertEqual(request.environ['SCRIPT_NAME'], '/foo/view_name')
+
+ def test_decorator_traversed_empty_no_view_name(self):
+ context = DummyContext()
+ request = DummyRequest()
+ request.subpath = ()
+ request.environ = {'SCRIPT_NAME': '/foo', 'PATH_INFO': '/'}
+ decorator = self._callFUT(dummyapp)
+ response = decorator(context, request)
+ self.assertEqual(response, dummyapp)
+ self.assertEqual(request.environ['PATH_INFO'], '/')
+ self.assertEqual(request.environ['SCRIPT_NAME'], '/foo')
+
+ def test_decorator_traversed_empty_no_view_name_no_script_name(self):
+ context = DummyContext()
+ request = DummyRequest()
+ request.subpath = ()
+ request.environ = {'SCRIPT_NAME': '', 'PATH_INFO': '/'}
+ decorator = self._callFUT(dummyapp)
+ response = decorator(context, request)
+ self.assertEqual(response, dummyapp)
+ self.assertEqual(request.environ['PATH_INFO'], '/')
+ self.assertEqual(request.environ['SCRIPT_NAME'], '')
+
+ def test_decorator_on_callable_object_instance(self):
+ context = DummyContext()
+ request = DummyRequest()
+ request.subpath = ()
+ request.environ = {'SCRIPT_NAME': '/foo', 'PATH_INFO': '/'}
+ app = DummyApp()
+ decorator = self._callFUT(app)
+ response = decorator(context, request)
+ self.assertEqual(response, app)
+ self.assertEqual(request.environ['PATH_INFO'], '/')
+ self.assertEqual(request.environ['SCRIPT_NAME'], '/foo')
+
+
+def dummyapp(environ, start_response):
+ """ """
+
+
+class DummyApp(object):
+ def __call__(self, environ, start_response):
+ """ """
+
+
+class DummyContext:
+ pass
+
+
+class DummyRequest:
+ def get_response(self, application):
+ return application
+
+ def copy(self):
+ self.copied = True
+ return self