summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorMichael Merickel <michael@merickel.org>2021-01-15 13:31:48 -0600
committerGitHub <noreply@github.com>2021-01-15 13:31:48 -0600
commit074f4f3eeec94b133293c0d1d0fa81d681b08e37 (patch)
tree2c0b41982a2298592a180887a924b67fa16d65e0 /docs
parent837358ee6be552fd2f990d1ed8d6ea9e1c98d583 (diff)
parentb0dd658429367dd5e3cd99973bcc9a6763dcc5e7 (diff)
downloadpyramid-074f4f3eeec94b133293c0d1d0fa81d681b08e37.tar.gz
pyramid-074f4f3eeec94b133293c0d1d0fa81d681b08e37.tar.bz2
pyramid-074f4f3eeec94b133293c0d1d0fa81d681b08e37.zip
Merge pull request #3648 from Pylons/prep-2.0-docs
More 2.0 docs prep
Diffstat (limited to 'docs')
-rw-r--r--docs/narr/myproject/.gitignore2
-rw-r--r--docs/narr/myproject/README.txt7
-rw-r--r--docs/narr/myproject/pytest.ini2
-rw-r--r--docs/narr/myproject/tests/conftest.py33
-rw-r--r--docs/narr/project.rst12
-rw-r--r--docs/quick_tour.rst29
-rw-r--r--docs/quick_tour/logging/tests/conftest.py76
-rw-r--r--docs/quick_tour/logging/tests/test_functional.py7
-rw-r--r--docs/quick_tour/logging/tests/test_it.py39
-rw-r--r--docs/quick_tour/logging/tests/test_views.py13
-rw-r--r--docs/quick_tour/package/tests/conftest.py76
-rw-r--r--docs/quick_tour/package/tests/test_functional.py7
-rw-r--r--docs/quick_tour/package/tests/test_it.py39
-rw-r--r--docs/quick_tour/package/tests/test_views.py13
-rw-r--r--docs/quick_tour/sessions/tests/conftest.py76
-rw-r--r--docs/quick_tour/sessions/tests/test_functional.py7
-rw-r--r--docs/quick_tour/sessions/tests/test_it.py39
-rw-r--r--docs/quick_tour/sessions/tests/test_views.py13
-rw-r--r--docs/quick_tour/sqla_demo/.gitignore3
-rw-r--r--docs/quick_tour/sqla_demo/README.txt7
-rw-r--r--docs/quick_tour/sqla_demo/pytest.ini2
-rw-r--r--docs/quick_tour/sqla_demo/sqla_demo/__init__.py2
-rw-r--r--docs/quick_tour/sqla_demo/sqla_demo/models/__init__.py22
-rw-r--r--docs/quick_tour/sqla_demo/sqla_demo/views/default.py7
-rw-r--r--docs/quick_tour/sqla_demo/testing.ini79
-rw-r--r--docs/quick_tour/sqla_demo/tests/conftest.py132
-rw-r--r--docs/quick_tour/sqla_demo/tests/test_functional.py13
-rw-r--r--docs/quick_tour/sqla_demo/tests/test_it.py66
-rw-r--r--docs/quick_tour/sqla_demo/tests/test_views.py23
-rw-r--r--docs/quick_tutorial/cookiecutters/.gitignore3
-rw-r--r--docs/quick_tutorial/cookiecutters/README.txt7
-rw-r--r--docs/quick_tutorial/cookiecutters/pytest.ini2
-rw-r--r--docs/quick_tutorial/cookiecutters/tests/conftest.py76
-rw-r--r--docs/quick_tutorial/cookiecutters/tests/test_functional.py7
-rw-r--r--docs/quick_tutorial/cookiecutters/tests/test_it.py39
-rw-r--r--docs/quick_tutorial/cookiecutters/tests/test_views.py13
-rw-r--r--docs/tutorials/wiki/authorization.rst17
-rw-r--r--docs/tutorials/wiki/installation.rst19
-rw-r--r--docs/tutorials/wiki/src/authorization/README.txt7
-rw-r--r--docs/tutorials/wiki/src/authorization/pytest.ini2
-rw-r--r--docs/tutorials/wiki/src/authorization/setup.py2
-rw-r--r--docs/tutorials/wiki/src/authorization/tests/conftest.py34
-rw-r--r--docs/tutorials/wiki/src/basiclayout/README.txt7
-rw-r--r--docs/tutorials/wiki/src/basiclayout/pytest.ini2
-rw-r--r--docs/tutorials/wiki/src/basiclayout/setup.py2
-rw-r--r--docs/tutorials/wiki/src/basiclayout/tests/conftest.py34
-rw-r--r--docs/tutorials/wiki/src/installation/README.txt7
-rw-r--r--docs/tutorials/wiki/src/installation/pytest.ini2
-rw-r--r--docs/tutorials/wiki/src/installation/setup.py2
-rw-r--r--docs/tutorials/wiki/src/installation/tests/conftest.py34
-rw-r--r--docs/tutorials/wiki/src/models/README.txt7
-rw-r--r--docs/tutorials/wiki/src/models/pytest.ini2
-rw-r--r--docs/tutorials/wiki/src/models/setup.py2
-rw-r--r--docs/tutorials/wiki/src/models/tests/conftest.py34
-rw-r--r--docs/tutorials/wiki/src/tests/README.txt7
-rw-r--r--docs/tutorials/wiki/src/tests/pytest.ini2
-rw-r--r--docs/tutorials/wiki/src/tests/setup.py2
-rw-r--r--docs/tutorials/wiki/src/views/README.txt7
-rw-r--r--docs/tutorials/wiki/src/views/pytest.ini2
-rw-r--r--docs/tutorials/wiki/src/views/setup.py2
-rw-r--r--docs/tutorials/wiki/src/views/tests/conftest.py34
-rw-r--r--docs/tutorials/wiki2/authentication.rst2
-rw-r--r--docs/tutorials/wiki2/installation.rst16
63 files changed, 870 insertions, 413 deletions
diff --git a/docs/narr/myproject/.gitignore b/docs/narr/myproject/.gitignore
index c612e59f2..e9336274d 100644
--- a/docs/narr/myproject/.gitignore
+++ b/docs/narr/myproject/.gitignore
@@ -11,7 +11,7 @@ dist/
nosetests.xml
env*/
tmp/
-Data.fs*
+Data*.fs*
*.sublime-project
*.sublime-workspace
.*.sw?
diff --git a/docs/narr/myproject/README.txt b/docs/narr/myproject/README.txt
index 6c5a0fee0..0a71384dc 100644
--- a/docs/narr/myproject/README.txt
+++ b/docs/narr/myproject/README.txt
@@ -4,15 +4,16 @@ myproject
Getting Started
---------------
-- Change directory into your newly created project.
+- Change directory into your newly created project if not already there. Your
+ current directory should be the same as this README.txt file and setup.py.
cd myproject
-- Create a Python virtual environment.
+- Create a Python virtual environment, if not already created.
python3 -m venv env
-- Upgrade packaging tools.
+- Upgrade packaging tools, if necessary.
env/bin/pip install --upgrade pip setuptools
diff --git a/docs/narr/myproject/pytest.ini b/docs/narr/myproject/pytest.ini
index 5c8c59068..074237039 100644
--- a/docs/narr/myproject/pytest.ini
+++ b/docs/narr/myproject/pytest.ini
@@ -1,5 +1,5 @@
[pytest]
-addopts = --strict
+addopts = --strict-markers
testpaths =
myproject
diff --git a/docs/narr/myproject/tests/conftest.py b/docs/narr/myproject/tests/conftest.py
index 296205927..ec09cdb2d 100644
--- a/docs/narr/myproject/tests/conftest.py
+++ b/docs/narr/myproject/tests/conftest.py
@@ -1,7 +1,7 @@
import os
from pyramid.paster import get_appsettings
from pyramid.scripting import prepare
-from pyramid.testing import DummyRequest
+from pyramid.testing import DummyRequest, testConfig
import pytest
import webtest
@@ -41,29 +41,36 @@ def app_request(app):
drawbacks in tests as it's harder to mock data and is heavier.
"""
- env = prepare(registry=app.registry)
- request = env['request']
- request.host = 'example.com'
-
- yield request
- env['closer']()
+ with prepare(registry=app.registry) as env:
+ request = env['request']
+ request.host = 'example.com'
+ yield request
@pytest.fixture
-def dummy_request(app):
+def dummy_request():
"""
A lightweight dummy request.
- This request is ultra-lightweight and should be used only when the
- request itself is not a large focus in the call-stack.
-
- It is way easier to mock and control side-effects using this object.
+ This request is ultra-lightweight and should be used only when the request
+ itself is not a large focus in the call-stack. It is much easier to mock
+ and control side-effects using this object, however:
- It does not have request extensions applied.
- Threadlocals are not properly pushed.
"""
request = DummyRequest()
- request.registry = app.registry
request.host = 'example.com'
return request
+
+@pytest.fixture
+def dummy_config(dummy_request):
+ """
+ A dummy :class:`pyramid.config.Configurator` object. This allows for
+ mock configuration, including configuration for ``dummy_request``, as well
+ as pushing the appropriate threadlocals.
+
+ """
+ with testConfig(request=dummy_request) as config:
+ yield config
diff --git a/docs/narr/project.rst b/docs/narr/project.rst
index ee75587e9..31dce9265 100644
--- a/docs/narr/project.rst
+++ b/docs/narr/project.rst
@@ -208,12 +208,7 @@ Elided output from a run of this command on Unix is shown below:
.. code-block:: bash
Running setup.py develop for myproject
- Successfully installed Jinja2-2.10.3 Mako-1.1.0 MarkupSafe-1.1.1 \
- PasteDeploy-2.0.1 Pygments-2.5.2 hupper-1.9.1 myproject plaster-1.0 \
- plaster-pastedeploy-0.7 pyramid-1.10.4 pyramid-debugtoolbar-4.5.2 \
- pyramid-jinja2-2.8 pyramid-mako-1.1.0 repoze.lru-0.7 \
- translationstring-1.3 venusian-3.0.0 waitress-1.4.2 webob-1.8.5 \
- zope.deprecation-4.4.0 zope.interface-4.7.1
+ Successfully installed Jinja2-2.11.2 Mako-1.1.3 MarkupSafe-1.1.1 PasteDeploy-2.1.1 Pygments-2.7.3 hupper-1.10.2 myproject plaster-1.0 plaster-pastedeploy-0.7 pyramid-1.10.5 pyramid-debugtoolbar-4.9 pyramid-jinja2-2.8 pyramid-mako-1.1.0 repoze.lru-0.7 translationstring-1.4 venusian-3.0.0 waitress-1.4.4 webob-1.8.6 zope.deprecation-4.4.0 zope.interface-5.2.0
This will install a :term:`distribution` representing your project into the
virtual environment interpreter's library set so it can be found by ``import``
@@ -555,6 +550,7 @@ The ``myproject`` project we've generated has the following directory structure:
│   └── notfound.py
├── production.ini
├── pytest.ini
+ ├── setup.py
├── testing.ini
└── tests
├── __init__.py
@@ -566,8 +562,8 @@ The ``myproject`` project we've generated has the following directory structure:
.. index::
single: tests
-``test_it.py``
-~~~~~~~~~~~~~~
+``tests`` package
+~~~~~~~~~~~~~~~~~
The ``conftest.py``, ``test_functional.py``, and ``test_views.py`` modules in the ``tests`` package includes tests for your application.
diff --git a/docs/quick_tour.rst b/docs/quick_tour.rst
index c4ab0b3e8..be53a3344 100644
--- a/docs/quick_tour.rst
+++ b/docs/quick_tour.rst
@@ -682,7 +682,7 @@ Yikes! We got this far and we haven't yet discussed tests. This is particularly
egregious, as Pyramid has had a deep commitment to full test coverage since
before its release.
-Our ``pyramid-cookiecutter-starter`` cookiecutter generated a ``test_it.py`` module inside the ``tests`` package with two unit tests and two functional tests in it.
+Our ``pyramid-cookiecutter-starter`` cookiecutter generated ``conftest.py``, ``test_functional.py``, and ``test_views.py`` modules inside the ``tests`` package with two unit tests and two functional tests in it.
It also configured ``setup.py`` with test requirements:
``pytest`` as the test runner, ``WebTest`` for running view tests, and the
``pytest-cov`` tool which yells at us for code that isn't tested:
@@ -708,29 +708,34 @@ This yields the following output.
.. code-block:: text
=========================== test session starts ===========================
- platform darwin -- Python 3.7.3, pytest-5.3.2, py-1.8.1, pluggy-0.13.1
- rootdir: /<somepath>/hello_world, inifile: pytest.ini, testpaths: hello_world, tests
- plugins: cov-2.8.1
+ platform darwin -- Python 3.9.0, pytest-6.2.1, py-1.10.0, pluggy-0.13.1
+ rootdir: /<somepath>/hello_world, configfile: pytest.ini, testpaths: hello_world, tests
+ plugins: cov-2.10.1
collected 4 items
- tests/test_it.py .... [100%]
+ tests/test_functional.py .. [ 50%]
+ tests/test_views.py .. [100%]
- ---------- coverage: platform darwin, python 3.7.3-final-0 -----------
+ ---------- coverage: platform darwin, python 3.9.0-final-0 -----------
Name Stmts Miss Cover Missing
-------------------------------------------------------------
hello_world/__init__.py 7 0 100%
hello_world/routes.py 3 0 100%
hello_world/views/__init__.py 0 0 100%
- hello_world/views/default.py 3 0 100%
- hello_world/views/notfound.py 4 0 100%
+ hello_world/views/default.py 4 0 100%
+ hello_world/views/notfound.py 5 0 100%
-------------------------------------------------------------
- TOTAL 17 0 100%
+ TOTAL 19 0 100%
======================== 4 passed in 0.65 seconds =========================
-Our tests passed, and its coverage is complete. What did our test look like?
+Our tests passed, and its coverage is complete. What did our tests look like?
-.. literalinclude:: quick_tour/package/tests/test_it.py
+.. literalinclude:: quick_tour/package/tests/test_functional.py
+ :language: python
+ :linenos:
+
+.. literalinclude:: quick_tour/package/tests/test_views.py
:language: python
:linenos:
@@ -755,7 +760,7 @@ logging for you to some reasonable defaults. You then see messages sent by
Pyramid (for example, when a new request comes in).
Maybe you would like to log messages in your code? In your Python module,
-import and set up the logging in your ``views.py``:
+import and set up the logging in your ``views/default.py``:
.. literalinclude:: quick_tour/logging/hello_world/views/default.py
:language: python
diff --git a/docs/quick_tour/logging/tests/conftest.py b/docs/quick_tour/logging/tests/conftest.py
new file mode 100644
index 000000000..adc1e0f3f
--- /dev/null
+++ b/docs/quick_tour/logging/tests/conftest.py
@@ -0,0 +1,76 @@
+import os
+from pyramid.paster import get_appsettings
+from pyramid.scripting import prepare
+from pyramid.testing import DummyRequest, testConfig
+import pytest
+import webtest
+
+from hello_world import main
+
+
+def pytest_addoption(parser):
+ parser.addoption('--ini', action='store', metavar='INI_FILE')
+
+@pytest.fixture(scope='session')
+def ini_file(request):
+ # potentially grab this path from a pytest option
+ return os.path.abspath(request.config.option.ini or 'testing.ini')
+
+@pytest.fixture(scope='session')
+def app_settings(ini_file):
+ return get_appsettings(ini_file)
+
+@pytest.fixture(scope='session')
+def app(app_settings):
+ return main({}, **app_settings)
+
+@pytest.fixture
+def testapp(app):
+ testapp = webtest.TestApp(app, extra_environ={
+ 'HTTP_HOST': 'example.com',
+ })
+
+ return testapp
+
+@pytest.fixture
+def app_request(app):
+ """
+ A real request.
+
+ This request is almost identical to a real request but it has some
+ drawbacks in tests as it's harder to mock data and is heavier.
+
+ """
+ with prepare(registry=app.registry) as env:
+ request = env['request']
+ request.host = 'example.com'
+ yield request
+
+@pytest.fixture
+def dummy_request():
+ """
+ A lightweight dummy request.
+
+ This request is ultra-lightweight and should be used only when the request
+ itself is not a large focus in the call-stack. It is much easier to mock
+ and control side-effects using this object, however:
+
+ - It does not have request extensions applied.
+ - Threadlocals are not properly pushed.
+
+ """
+ request = DummyRequest()
+ request.host = 'example.com'
+
+ return request
+
+@pytest.fixture
+def dummy_config(dummy_request):
+ """
+ A dummy :class:`pyramid.config.Configurator` object. This allows for
+ mock configuration, including configuration for ``dummy_request``, as well
+ as pushing the appropriate threadlocals.
+
+ """
+ with testConfig(request=dummy_request) as config:
+ yield config
diff --git a/docs/quick_tour/logging/tests/test_functional.py b/docs/quick_tour/logging/tests/test_functional.py
new file mode 100644
index 000000000..bac5d63f4
--- /dev/null
+++ b/docs/quick_tour/logging/tests/test_functional.py
@@ -0,0 +1,7 @@
+def test_root(testapp):
+ res = testapp.get('/', status=200)
+ assert b'Pyramid' in res.body
+
+def test_notfound(testapp):
+ res = testapp.get('/badurl', status=404)
+ assert res.status_code == 404
diff --git a/docs/quick_tour/logging/tests/test_it.py b/docs/quick_tour/logging/tests/test_it.py
deleted file mode 100644
index 90c6302fe..000000000
--- a/docs/quick_tour/logging/tests/test_it.py
+++ /dev/null
@@ -1,39 +0,0 @@
-import unittest
-
-from pyramid import testing
-
-
-class ViewTests(unittest.TestCase):
- def setUp(self):
- self.config = testing.setUp()
-
- def tearDown(self):
- testing.tearDown()
-
- def test_my_view(self):
- from hello_world.views.default import my_view
- request = testing.DummyRequest()
- info = my_view(request)
- self.assertEqual(info['project'], 'hello_world')
-
- def test_notfound_view(self):
- from hello_world.views.notfound import notfound_view
- request = testing.DummyRequest()
- info = notfound_view(request)
- self.assertEqual(info, {})
-
-
-class FunctionalTests(unittest.TestCase):
- def setUp(self):
- from hello_world import main
- app = main({})
- from webtest import TestApp
- self.testapp = TestApp(app)
-
- def test_root(self):
- res = self.testapp.get('/', status=200)
- self.assertTrue(b'Pyramid' in res.body)
-
- def test_notfound(self):
- res = self.testapp.get('/badurl', status=404)
- self.assertTrue(res.status_code == 404)
diff --git a/docs/quick_tour/logging/tests/test_views.py b/docs/quick_tour/logging/tests/test_views.py
new file mode 100644
index 000000000..0b019fe82
--- /dev/null
+++ b/docs/quick_tour/logging/tests/test_views.py
@@ -0,0 +1,13 @@
+from hello_world.views.default import my_view
+from hello_world.views.notfound import notfound_view
+
+
+def test_my_view(app_request):
+ info = my_view(app_request)
+ assert app_request.response.status_int == 200
+ assert info['project'] == 'hello_world'
+
+def test_notfound_view(app_request):
+ info = notfound_view(app_request)
+ assert app_request.response.status_int == 404
+ assert info == {}
diff --git a/docs/quick_tour/package/tests/conftest.py b/docs/quick_tour/package/tests/conftest.py
new file mode 100644
index 000000000..adc1e0f3f
--- /dev/null
+++ b/docs/quick_tour/package/tests/conftest.py
@@ -0,0 +1,76 @@
+import os
+from pyramid.paster import get_appsettings
+from pyramid.scripting import prepare
+from pyramid.testing import DummyRequest, testConfig
+import pytest
+import webtest
+
+from hello_world import main
+
+
+def pytest_addoption(parser):
+ parser.addoption('--ini', action='store', metavar='INI_FILE')
+
+@pytest.fixture(scope='session')
+def ini_file(request):
+ # potentially grab this path from a pytest option
+ return os.path.abspath(request.config.option.ini or 'testing.ini')
+
+@pytest.fixture(scope='session')
+def app_settings(ini_file):
+ return get_appsettings(ini_file)
+
+@pytest.fixture(scope='session')
+def app(app_settings):
+ return main({}, **app_settings)
+
+@pytest.fixture
+def testapp(app):
+ testapp = webtest.TestApp(app, extra_environ={
+ 'HTTP_HOST': 'example.com',
+ })
+
+ return testapp
+
+@pytest.fixture
+def app_request(app):
+ """
+ A real request.
+
+ This request is almost identical to a real request but it has some
+ drawbacks in tests as it's harder to mock data and is heavier.
+
+ """
+ with prepare(registry=app.registry) as env:
+ request = env['request']
+ request.host = 'example.com'
+ yield request
+
+@pytest.fixture
+def dummy_request():
+ """
+ A lightweight dummy request.
+
+ This request is ultra-lightweight and should be used only when the request
+ itself is not a large focus in the call-stack. It is much easier to mock
+ and control side-effects using this object, however:
+
+ - It does not have request extensions applied.
+ - Threadlocals are not properly pushed.
+
+ """
+ request = DummyRequest()
+ request.host = 'example.com'
+
+ return request
+
+@pytest.fixture
+def dummy_config(dummy_request):
+ """
+ A dummy :class:`pyramid.config.Configurator` object. This allows for
+ mock configuration, including configuration for ``dummy_request``, as well
+ as pushing the appropriate threadlocals.
+
+ """
+ with testConfig(request=dummy_request) as config:
+ yield config
diff --git a/docs/quick_tour/package/tests/test_functional.py b/docs/quick_tour/package/tests/test_functional.py
new file mode 100644
index 000000000..bac5d63f4
--- /dev/null
+++ b/docs/quick_tour/package/tests/test_functional.py
@@ -0,0 +1,7 @@
+def test_root(testapp):
+ res = testapp.get('/', status=200)
+ assert b'Pyramid' in res.body
+
+def test_notfound(testapp):
+ res = testapp.get('/badurl', status=404)
+ assert res.status_code == 404
diff --git a/docs/quick_tour/package/tests/test_it.py b/docs/quick_tour/package/tests/test_it.py
deleted file mode 100644
index 90c6302fe..000000000
--- a/docs/quick_tour/package/tests/test_it.py
+++ /dev/null
@@ -1,39 +0,0 @@
-import unittest
-
-from pyramid import testing
-
-
-class ViewTests(unittest.TestCase):
- def setUp(self):
- self.config = testing.setUp()
-
- def tearDown(self):
- testing.tearDown()
-
- def test_my_view(self):
- from hello_world.views.default import my_view
- request = testing.DummyRequest()
- info = my_view(request)
- self.assertEqual(info['project'], 'hello_world')
-
- def test_notfound_view(self):
- from hello_world.views.notfound import notfound_view
- request = testing.DummyRequest()
- info = notfound_view(request)
- self.assertEqual(info, {})
-
-
-class FunctionalTests(unittest.TestCase):
- def setUp(self):
- from hello_world import main
- app = main({})
- from webtest import TestApp
- self.testapp = TestApp(app)
-
- def test_root(self):
- res = self.testapp.get('/', status=200)
- self.assertTrue(b'Pyramid' in res.body)
-
- def test_notfound(self):
- res = self.testapp.get('/badurl', status=404)
- self.assertTrue(res.status_code == 404)
diff --git a/docs/quick_tour/package/tests/test_views.py b/docs/quick_tour/package/tests/test_views.py
new file mode 100644
index 000000000..0b019fe82
--- /dev/null
+++ b/docs/quick_tour/package/tests/test_views.py
@@ -0,0 +1,13 @@
+from hello_world.views.default import my_view
+from hello_world.views.notfound import notfound_view
+
+
+def test_my_view(app_request):
+ info = my_view(app_request)
+ assert app_request.response.status_int == 200
+ assert info['project'] == 'hello_world'
+
+def test_notfound_view(app_request):
+ info = notfound_view(app_request)
+ assert app_request.response.status_int == 404
+ assert info == {}
diff --git a/docs/quick_tour/sessions/tests/conftest.py b/docs/quick_tour/sessions/tests/conftest.py
new file mode 100644
index 000000000..adc1e0f3f
--- /dev/null
+++ b/docs/quick_tour/sessions/tests/conftest.py
@@ -0,0 +1,76 @@
+import os
+from pyramid.paster import get_appsettings
+from pyramid.scripting import prepare
+from pyramid.testing import DummyRequest, testConfig
+import pytest
+import webtest
+
+from hello_world import main
+
+
+def pytest_addoption(parser):
+ parser.addoption('--ini', action='store', metavar='INI_FILE')
+
+@pytest.fixture(scope='session')
+def ini_file(request):
+ # potentially grab this path from a pytest option
+ return os.path.abspath(request.config.option.ini or 'testing.ini')
+
+@pytest.fixture(scope='session')
+def app_settings(ini_file):
+ return get_appsettings(ini_file)
+
+@pytest.fixture(scope='session')
+def app(app_settings):
+ return main({}, **app_settings)
+
+@pytest.fixture
+def testapp(app):
+ testapp = webtest.TestApp(app, extra_environ={
+ 'HTTP_HOST': 'example.com',
+ })
+
+ return testapp
+
+@pytest.fixture
+def app_request(app):
+ """
+ A real request.
+
+ This request is almost identical to a real request but it has some
+ drawbacks in tests as it's harder to mock data and is heavier.
+
+ """
+ with prepare(registry=app.registry) as env:
+ request = env['request']
+ request.host = 'example.com'
+ yield request
+
+@pytest.fixture
+def dummy_request():
+ """
+ A lightweight dummy request.
+
+ This request is ultra-lightweight and should be used only when the request
+ itself is not a large focus in the call-stack. It is much easier to mock
+ and control side-effects using this object, however:
+
+ - It does not have request extensions applied.
+ - Threadlocals are not properly pushed.
+
+ """
+ request = DummyRequest()
+ request.host = 'example.com'
+
+ return request
+
+@pytest.fixture
+def dummy_config(dummy_request):
+ """
+ A dummy :class:`pyramid.config.Configurator` object. This allows for
+ mock configuration, including configuration for ``dummy_request``, as well
+ as pushing the appropriate threadlocals.
+
+ """
+ with testConfig(request=dummy_request) as config:
+ yield config
diff --git a/docs/quick_tour/sessions/tests/test_functional.py b/docs/quick_tour/sessions/tests/test_functional.py
new file mode 100644
index 000000000..bac5d63f4
--- /dev/null
+++ b/docs/quick_tour/sessions/tests/test_functional.py
@@ -0,0 +1,7 @@
+def test_root(testapp):
+ res = testapp.get('/', status=200)
+ assert b'Pyramid' in res.body
+
+def test_notfound(testapp):
+ res = testapp.get('/badurl', status=404)
+ assert res.status_code == 404
diff --git a/docs/quick_tour/sessions/tests/test_it.py b/docs/quick_tour/sessions/tests/test_it.py
deleted file mode 100644
index 90c6302fe..000000000
--- a/docs/quick_tour/sessions/tests/test_it.py
+++ /dev/null
@@ -1,39 +0,0 @@
-import unittest
-
-from pyramid import testing
-
-
-class ViewTests(unittest.TestCase):
- def setUp(self):
- self.config = testing.setUp()
-
- def tearDown(self):
- testing.tearDown()
-
- def test_my_view(self):
- from hello_world.views.default import my_view
- request = testing.DummyRequest()
- info = my_view(request)
- self.assertEqual(info['project'], 'hello_world')
-
- def test_notfound_view(self):
- from hello_world.views.notfound import notfound_view
- request = testing.DummyRequest()
- info = notfound_view(request)
- self.assertEqual(info, {})
-
-
-class FunctionalTests(unittest.TestCase):
- def setUp(self):
- from hello_world import main
- app = main({})
- from webtest import TestApp
- self.testapp = TestApp(app)
-
- def test_root(self):
- res = self.testapp.get('/', status=200)
- self.assertTrue(b'Pyramid' in res.body)
-
- def test_notfound(self):
- res = self.testapp.get('/badurl', status=404)
- self.assertTrue(res.status_code == 404)
diff --git a/docs/quick_tour/sessions/tests/test_views.py b/docs/quick_tour/sessions/tests/test_views.py
new file mode 100644
index 000000000..0b019fe82
--- /dev/null
+++ b/docs/quick_tour/sessions/tests/test_views.py
@@ -0,0 +1,13 @@
+from hello_world.views.default import my_view
+from hello_world.views.notfound import notfound_view
+
+
+def test_my_view(app_request):
+ info = my_view(app_request)
+ assert app_request.response.status_int == 200
+ assert info['project'] == 'hello_world'
+
+def test_notfound_view(app_request):
+ info = notfound_view(app_request)
+ assert app_request.response.status_int == 404
+ assert info == {}
diff --git a/docs/quick_tour/sqla_demo/.gitignore b/docs/quick_tour/sqla_demo/.gitignore
index 1853d983c..e9336274d 100644
--- a/docs/quick_tour/sqla_demo/.gitignore
+++ b/docs/quick_tour/sqla_demo/.gitignore
@@ -11,7 +11,7 @@ dist/
nosetests.xml
env*/
tmp/
-Data.fs*
+Data*.fs*
*.sublime-project
*.sublime-workspace
.*.sw?
@@ -19,3 +19,4 @@ Data.fs*
.DS_Store
coverage
test
+*.sqlite
diff --git a/docs/quick_tour/sqla_demo/README.txt b/docs/quick_tour/sqla_demo/README.txt
index d00790492..3c3d7293e 100644
--- a/docs/quick_tour/sqla_demo/README.txt
+++ b/docs/quick_tour/sqla_demo/README.txt
@@ -4,15 +4,16 @@ sqla_demo
Getting Started
---------------
-- Change directory into your newly created project.
+- Change directory into your newly created project if not already there. Your
+ current directory should be the same as this README.txt file and setup.py.
cd sqla_demo
-- Create a Python virtual environment.
+- Create a Python virtual environment, if not already created.
python3 -m venv env
-- Upgrade packaging tools.
+- Upgrade packaging tools, if necessary.
env/bin/pip install --upgrade pip setuptools
diff --git a/docs/quick_tour/sqla_demo/pytest.ini b/docs/quick_tour/sqla_demo/pytest.ini
index e7fd17682..2c35d84ef 100644
--- a/docs/quick_tour/sqla_demo/pytest.ini
+++ b/docs/quick_tour/sqla_demo/pytest.ini
@@ -1,5 +1,5 @@
[pytest]
-addopts = --strict
+addopts = --strict-markers
testpaths =
sqla_demo
diff --git a/docs/quick_tour/sqla_demo/sqla_demo/__init__.py b/docs/quick_tour/sqla_demo/sqla_demo/__init__.py
index 5c2ba5cc0..7edc0957d 100644
--- a/docs/quick_tour/sqla_demo/sqla_demo/__init__.py
+++ b/docs/quick_tour/sqla_demo/sqla_demo/__init__.py
@@ -5,8 +5,8 @@ def main(global_config, **settings):
""" This function returns a Pyramid WSGI application.
"""
with Configurator(settings=settings) as config:
- config.include('.models')
config.include('pyramid_jinja2')
config.include('.routes')
+ config.include('.models')
config.scan()
return config.make_wsgi_app()
diff --git a/docs/quick_tour/sqla_demo/sqla_demo/models/__init__.py b/docs/quick_tour/sqla_demo/sqla_demo/models/__init__.py
index 31aab9d26..71f9f36b5 100644
--- a/docs/quick_tour/sqla_demo/sqla_demo/models/__init__.py
+++ b/docs/quick_tour/sqla_demo/sqla_demo/models/__init__.py
@@ -65,13 +65,21 @@ def includeme(config):
# use pyramid_retry to retry a request when transient exceptions occur
config.include('pyramid_retry')
- session_factory = get_session_factory(get_engine(settings))
+ # hook to share the dbengine fixture in testing
+ dbengine = settings.get('dbengine')
+ if not dbengine:
+ dbengine = get_engine(settings)
+
+ session_factory = get_session_factory(dbengine)
config.registry['dbsession_factory'] = session_factory
# make request.dbsession available for use in Pyramid
- config.add_request_method(
- # r.tm is the transaction manager used by pyramid_tm
- lambda r: get_tm_session(session_factory, r.tm),
- 'dbsession',
- reify=True
- )
+ def dbsession(request):
+ # hook to share the dbsession fixture in testing
+ dbsession = request.environ.get('app.dbsession')
+ if dbsession is None:
+ # request.tm is the transaction manager used by pyramid_tm
+ dbsession = get_tm_session(session_factory, request.tm)
+ return dbsession
+
+ config.add_request_method(dbsession, reify=True)
diff --git a/docs/quick_tour/sqla_demo/sqla_demo/views/default.py b/docs/quick_tour/sqla_demo/sqla_demo/views/default.py
index 3aadb905f..5476a9c7f 100644
--- a/docs/quick_tour/sqla_demo/sqla_demo/views/default.py
+++ b/docs/quick_tour/sqla_demo/sqla_demo/views/default.py
@@ -1,7 +1,6 @@
from pyramid.view import view_config
from pyramid.response import Response
-
-from sqlalchemy.exc import DBAPIError
+from sqlalchemy.exc import SQLAlchemyError
from .. import models
@@ -10,8 +9,8 @@ from .. import models
def my_view(request):
try:
query = request.dbsession.query(models.MyModel)
- one = query.filter(models.MyModel.name == 'one').first()
- except DBAPIError:
+ one = query.filter(models.MyModel.name == 'one').one()
+ except SQLAlchemyError:
return Response(db_err_msg, content_type='text/plain', status=500)
return {'one': one, 'project': 'sqla_demo'}
diff --git a/docs/quick_tour/sqla_demo/testing.ini b/docs/quick_tour/sqla_demo/testing.ini
new file mode 100644
index 000000000..bccd51895
--- /dev/null
+++ b/docs/quick_tour/sqla_demo/testing.ini
@@ -0,0 +1,79 @@
+###
+# app configuration
+# https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html
+###
+
+[app:main]
+use = egg:sqla_demo
+
+pyramid.reload_templates = false
+pyramid.debug_authorization = false
+pyramid.debug_notfound = false
+pyramid.debug_routematch = false
+pyramid.default_locale_name = en
+
+sqlalchemy.url = sqlite:///%(here)s/testing.sqlite
+
+retry.attempts = 3
+
+[pshell]
+setup = sqla_demo.pshell.setup
+
+###
+# wsgi server configuration
+###
+
+[alembic]
+# path to migration scripts
+script_location = sqla_demo/alembic
+file_template = %%(year)d%%(month).2d%%(day).2d_%%(rev)s
+# file_template = %%(rev)s_%%(slug)s
+
+[server:main]
+use = egg:waitress#main
+listen = localhost:6543
+
+###
+# logging configuration
+# https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html
+###
+
+[loggers]
+keys = root, sqla_demo, sqlalchemy, alembic
+
+[handlers]
+keys = console
+
+[formatters]
+keys = generic
+
+[logger_root]
+level = INFO
+handlers = console
+
+[logger_sqla_demo]
+level = DEBUG
+handlers =
+qualname = sqla_demo
+
+[logger_sqlalchemy]
+level = WARN
+handlers =
+qualname = sqlalchemy.engine
+# "level = INFO" logs SQL queries.
+# "level = DEBUG" logs SQL queries and results.
+# "level = WARN" logs neither. (Recommended for production systems.)
+
+[logger_alembic]
+level = WARN
+handlers =
+qualname = alembic
+
+[handler_console]
+class = StreamHandler
+args = (sys.stderr,)
+level = NOTSET
+formatter = generic
+
+[formatter_generic]
+format = %(asctime)s %(levelname)-5.5s [%(name)s:%(lineno)s][%(threadName)s] %(message)s
diff --git a/docs/quick_tour/sqla_demo/tests/conftest.py b/docs/quick_tour/sqla_demo/tests/conftest.py
new file mode 100644
index 000000000..641527ca1
--- /dev/null
+++ b/docs/quick_tour/sqla_demo/tests/conftest.py
@@ -0,0 +1,132 @@
+import alembic
+import alembic.config
+import alembic.command
+import os
+from pyramid.paster import get_appsettings
+from pyramid.scripting import prepare
+from pyramid.testing import DummyRequest, testConfig
+import pytest
+import transaction
+import webtest
+
+from sqla_demo import main
+from sqla_demo import models
+from sqla_demo.models.meta import Base
+
+
+def pytest_addoption(parser):
+ parser.addoption('--ini', action='store', metavar='INI_FILE')
+
+@pytest.fixture(scope='session')
+def ini_file(request):
+ # potentially grab this path from a pytest option
+ return os.path.abspath(request.config.option.ini or 'testing.ini')
+
+@pytest.fixture(scope='session')
+def app_settings(ini_file):
+ return get_appsettings(ini_file)
+
+@pytest.fixture(scope='session')
+def dbengine(app_settings, ini_file):
+ engine = models.get_engine(app_settings)
+
+ alembic_cfg = alembic.config.Config(ini_file)
+ Base.metadata.drop_all(bind=engine)
+ alembic.command.stamp(alembic_cfg, None, purge=True)
+
+ # run migrations to initialize the database
+ # depending on how we want to initialize the database from scratch
+ # we could alternatively call:
+ # Base.metadata.create_all(bind=engine)
+ # alembic.command.stamp(alembic_cfg, "head")
+ alembic.command.upgrade(alembic_cfg, "head")
+
+ yield engine
+
+ Base.metadata.drop_all(bind=engine)
+ alembic.command.stamp(alembic_cfg, None, purge=True)
+
+@pytest.fixture(scope='session')
+def app(app_settings, dbengine):
+ return main({}, dbengine=dbengine, **app_settings)
+
+@pytest.fixture
+def tm():
+ tm = transaction.TransactionManager(explicit=True)
+ tm.begin()
+ tm.doom()
+
+ yield tm
+
+ tm.abort()
+
+@pytest.fixture
+def dbsession(app, tm):
+ session_factory = app.registry['dbsession_factory']
+ return models.get_tm_session(session_factory, tm)
+
+@pytest.fixture
+def testapp(app, tm, dbsession):
+ # override request.dbsession and request.tm with our own
+ # externally-controlled values that are shared across requests but aborted
+ # at the end
+ testapp = webtest.TestApp(app, extra_environ={
+ 'HTTP_HOST': 'example.com',
+ 'tm.active': True,
+ 'tm.manager': tm,
+ 'app.dbsession': dbsession,
+ })
+
+ return testapp
+
+@pytest.fixture
+def app_request(app, tm, dbsession):
+ """
+ A real request.
+
+ This request is almost identical to a real request but it has some
+ drawbacks in tests as it's harder to mock data and is heavier.
+
+ """
+ with prepare(registry=app.registry) as env:
+ request = env['request']
+ request.host = 'example.com'
+
+ # without this, request.dbsession will be joined to the same transaction
+ # manager but it will be using a different sqlalchemy.orm.Session using
+ # a separate database transaction
+ request.dbsession = dbsession
+ request.tm = tm
+
+ yield request
+
+@pytest.fixture
+def dummy_request(tm, dbsession):
+ """
+ A lightweight dummy request.
+
+ This request is ultra-lightweight and should be used only when the request
+ itself is not a large focus in the call-stack. It is much easier to mock
+ and control side-effects using this object, however:
+
+ - It does not have request extensions applied.
+ - Threadlocals are not properly pushed.
+
+ """
+ request = DummyRequest()
+ request.host = 'example.com'
+ request.dbsession = dbsession
+ request.tm = tm
+
+ return request
+
+@pytest.fixture
+def dummy_config(dummy_request):
+ """
+ A dummy :class:`pyramid.config.Configurator` object. This allows for
+ mock configuration, including configuration for ``dummy_request``, as well
+ as pushing the appropriate threadlocals.
+
+ """
+ with testConfig(request=dummy_request) as config:
+ yield config
diff --git a/docs/quick_tour/sqla_demo/tests/test_functional.py b/docs/quick_tour/sqla_demo/tests/test_functional.py
new file mode 100644
index 000000000..4045871da
--- /dev/null
+++ b/docs/quick_tour/sqla_demo/tests/test_functional.py
@@ -0,0 +1,13 @@
+from sqla_demo import models
+
+def test_my_view_success(testapp, dbsession):
+ model = models.MyModel(name='one', value=55)
+ dbsession.add(model)
+ dbsession.flush()
+
+ res = testapp.get('/', status=200)
+ assert res.body
+
+def test_notfound(testapp):
+ res = testapp.get('/badurl', status=404)
+ assert res.status_code == 404
diff --git a/docs/quick_tour/sqla_demo/tests/test_it.py b/docs/quick_tour/sqla_demo/tests/test_it.py
deleted file mode 100644
index f0848564b..000000000
--- a/docs/quick_tour/sqla_demo/tests/test_it.py
+++ /dev/null
@@ -1,66 +0,0 @@
-import unittest
-
-from pyramid import testing
-
-import transaction
-
-
-def dummy_request(dbsession):
- return testing.DummyRequest(dbsession=dbsession)
-
-
-class BaseTest(unittest.TestCase):
- def setUp(self):
- self.config = testing.setUp(settings={
- 'sqlalchemy.url': 'sqlite:///:memory:'
- })
- self.config.include('sqla_demo.models')
- settings = self.config.get_settings()
-
- from sqla_demo.models import (
- get_engine,
- get_session_factory,
- get_tm_session,
- )
-
- self.engine = get_engine(settings)
- session_factory = get_session_factory(self.engine)
-
- self.session = get_tm_session(session_factory, transaction.manager)
-
- def init_database(self):
- from sqla_demo.models.meta import Base
- Base.metadata.create_all(self.engine)
-
- def tearDown(self):
- from sqla_demo.models.meta import Base
-
- testing.tearDown()
- transaction.abort()
- Base.metadata.drop_all(self.engine)
-
-
-class TestMyViewSuccessCondition(BaseTest):
-
- def setUp(self):
- super().setUp()
- self.init_database()
-
- from sqla_demo.models import MyModel
-
- model = MyModel(name='one', value=55)
- self.session.add(model)
-
- def test_passing_view(self):
- from sqla_demo.views.default import my_view
- info = my_view(dummy_request(self.session))
- self.assertEqual(info['one'].name, 'one')
- self.assertEqual(info['project'], 'sqla_demo')
-
-
-class TestMyViewFailureCondition(BaseTest):
-
- def test_failing_view(self):
- from sqla_demo.views.default import my_view
- info = my_view(dummy_request(self.session))
- self.assertEqual(info.status_int, 500)
diff --git a/docs/quick_tour/sqla_demo/tests/test_views.py b/docs/quick_tour/sqla_demo/tests/test_views.py
new file mode 100644
index 000000000..b98d9af61
--- /dev/null
+++ b/docs/quick_tour/sqla_demo/tests/test_views.py
@@ -0,0 +1,23 @@
+from sqla_demo import models
+from sqla_demo.views.default import my_view
+from sqla_demo.views.notfound import notfound_view
+
+
+def test_my_view_failure(app_request):
+ info = my_view(app_request)
+ assert info.status_int == 500
+
+def test_my_view_success(app_request, dbsession):
+ model = models.MyModel(name='one', value=55)
+ dbsession.add(model)
+ dbsession.flush()
+
+ info = my_view(app_request)
+ assert app_request.response.status_int == 200
+ assert info['one'].name == 'one'
+ assert info['project'] == 'sqla_demo'
+
+def test_notfound_view(app_request):
+ info = notfound_view(app_request)
+ assert app_request.response.status_int == 404
+ assert info == {}
diff --git a/docs/quick_tutorial/cookiecutters/.gitignore b/docs/quick_tutorial/cookiecutters/.gitignore
index 1853d983c..e9336274d 100644
--- a/docs/quick_tutorial/cookiecutters/.gitignore
+++ b/docs/quick_tutorial/cookiecutters/.gitignore
@@ -11,7 +11,7 @@ dist/
nosetests.xml
env*/
tmp/
-Data.fs*
+Data*.fs*
*.sublime-project
*.sublime-workspace
.*.sw?
@@ -19,3 +19,4 @@ Data.fs*
.DS_Store
coverage
test
+*.sqlite
diff --git a/docs/quick_tutorial/cookiecutters/README.txt b/docs/quick_tutorial/cookiecutters/README.txt
index 55c5dcec6..74a86520c 100644
--- a/docs/quick_tutorial/cookiecutters/README.txt
+++ b/docs/quick_tutorial/cookiecutters/README.txt
@@ -4,15 +4,16 @@ cc_starter
Getting Started
---------------
-- Change directory into your newly created project.
+- Change directory into your newly created project if not already there. Your
+ current directory should be the same as this README.txt file and setup.py.
cd cc_starter
-- Create a Python virtual environment.
+- Create a Python virtual environment, if not already created.
python3 -m venv env
-- Upgrade packaging tools.
+- Upgrade packaging tools, if necessary.
env/bin/pip install --upgrade pip setuptools
diff --git a/docs/quick_tutorial/cookiecutters/pytest.ini b/docs/quick_tutorial/cookiecutters/pytest.ini
index 515cc3cf0..b678eef00 100644
--- a/docs/quick_tutorial/cookiecutters/pytest.ini
+++ b/docs/quick_tutorial/cookiecutters/pytest.ini
@@ -1,5 +1,5 @@
[pytest]
-addopts = --strict
+addopts = --strict-markers
testpaths =
cc_starter
diff --git a/docs/quick_tutorial/cookiecutters/tests/conftest.py b/docs/quick_tutorial/cookiecutters/tests/conftest.py
new file mode 100644
index 000000000..ec09cdb2d
--- /dev/null
+++ b/docs/quick_tutorial/cookiecutters/tests/conftest.py
@@ -0,0 +1,76 @@
+import os
+from pyramid.paster import get_appsettings
+from pyramid.scripting import prepare
+from pyramid.testing import DummyRequest, testConfig
+import pytest
+import webtest
+
+from myproject import main
+
+
+def pytest_addoption(parser):
+ parser.addoption('--ini', action='store', metavar='INI_FILE')
+
+@pytest.fixture(scope='session')
+def ini_file(request):
+ # potentially grab this path from a pytest option
+ return os.path.abspath(request.config.option.ini or 'testing.ini')
+
+@pytest.fixture(scope='session')
+def app_settings(ini_file):
+ return get_appsettings(ini_file)
+
+@pytest.fixture(scope='session')
+def app(app_settings):
+ return main({}, **app_settings)
+
+@pytest.fixture
+def testapp(app):
+ testapp = webtest.TestApp(app, extra_environ={
+ 'HTTP_HOST': 'example.com',
+ })
+
+ return testapp
+
+@pytest.fixture
+def app_request(app):
+ """
+ A real request.
+
+ This request is almost identical to a real request but it has some
+ drawbacks in tests as it's harder to mock data and is heavier.
+
+ """
+ with prepare(registry=app.registry) as env:
+ request = env['request']
+ request.host = 'example.com'
+ yield request
+
+@pytest.fixture
+def dummy_request():
+ """
+ A lightweight dummy request.
+
+ This request is ultra-lightweight and should be used only when the request
+ itself is not a large focus in the call-stack. It is much easier to mock
+ and control side-effects using this object, however:
+
+ - It does not have request extensions applied.
+ - Threadlocals are not properly pushed.
+
+ """
+ request = DummyRequest()
+ request.host = 'example.com'
+
+ return request
+
+@pytest.fixture
+def dummy_config(dummy_request):
+ """
+ A dummy :class:`pyramid.config.Configurator` object. This allows for
+ mock configuration, including configuration for ``dummy_request``, as well
+ as pushing the appropriate threadlocals.
+
+ """
+ with testConfig(request=dummy_request) as config:
+ yield config
diff --git a/docs/quick_tutorial/cookiecutters/tests/test_functional.py b/docs/quick_tutorial/cookiecutters/tests/test_functional.py
new file mode 100644
index 000000000..bac5d63f4
--- /dev/null
+++ b/docs/quick_tutorial/cookiecutters/tests/test_functional.py
@@ -0,0 +1,7 @@
+def test_root(testapp):
+ res = testapp.get('/', status=200)
+ assert b'Pyramid' in res.body
+
+def test_notfound(testapp):
+ res = testapp.get('/badurl', status=404)
+ assert res.status_code == 404
diff --git a/docs/quick_tutorial/cookiecutters/tests/test_it.py b/docs/quick_tutorial/cookiecutters/tests/test_it.py
deleted file mode 100644
index 634abfdf2..000000000
--- a/docs/quick_tutorial/cookiecutters/tests/test_it.py
+++ /dev/null
@@ -1,39 +0,0 @@
-import unittest
-
-from pyramid import testing
-
-
-class ViewTests(unittest.TestCase):
- def setUp(self):
- self.config = testing.setUp()
-
- def tearDown(self):
- testing.tearDown()
-
- def test_my_view(self):
- from cc_starter.views.default import my_view
- request = testing.DummyRequest()
- info = my_view(request)
- self.assertEqual(info['project'], 'cc_starter')
-
- def test_notfound_view(self):
- from cc_starter.views.notfound import notfound_view
- request = testing.DummyRequest()
- info = notfound_view(request)
- self.assertEqual(info, {})
-
-
-class FunctionalTests(unittest.TestCase):
- def setUp(self):
- from cc_starter import main
- app = main({})
- from webtest import TestApp
- self.testapp = TestApp(app)
-
- def test_root(self):
- res = self.testapp.get('/', status=200)
- self.assertTrue(b'Pyramid' in res.body)
-
- def test_notfound(self):
- res = self.testapp.get('/badurl', status=404)
- self.assertTrue(res.status_code == 404)
diff --git a/docs/quick_tutorial/cookiecutters/tests/test_views.py b/docs/quick_tutorial/cookiecutters/tests/test_views.py
new file mode 100644
index 000000000..1fd9db8ab
--- /dev/null
+++ b/docs/quick_tutorial/cookiecutters/tests/test_views.py
@@ -0,0 +1,13 @@
+from myproject.views.default import my_view
+from myproject.views.notfound import notfound_view
+
+
+def test_my_view(app_request):
+ info = my_view(app_request)
+ assert app_request.response.status_int == 200
+ assert info['project'] == 'myproject'
+
+def test_notfound_view(app_request):
+ info = notfound_view(app_request)
+ assert app_request.response.status_int == 404
+ assert info == {}
diff --git a/docs/tutorials/wiki/authorization.rst b/docs/tutorials/wiki/authorization.rst
index 9c685639d..2b700ee5b 100644
--- a/docs/tutorials/wiki/authorization.rst
+++ b/docs/tutorials/wiki/authorization.rst
@@ -164,7 +164,7 @@ Add an ACL
Open ``tutorial/models/__init__.py`` and add the following import statement near the top:
.. literalinclude:: src/authorization/tutorial/models/__init__.py
- :lines: 4-7
+ :lines: 3-6
:lineno-match:
:language: python
@@ -315,6 +315,14 @@ Launch a browser and visit each of the following URLs, checking that the result
This always redirects to the ``view_page`` view of the ``FrontPage`` Page resource.
It is executable by any user.
+- http://localhost:6543/login invokes the ``login`` view, and a login form will be displayed.
+ On every page, there is a "Login" link in the upper right corner while the user is not authenticated, else it is a "Logout" link when the user is authenticated.
+
+ Supplying the credentials with either the username ``editor`` and password ``editor`` will authenticate the user and grant access for that group.
+
+ After logging in (as a result of hitting an edit or add page and submitting valid credentials), we will see a "Logout" link in the upper right hand corner.
+ When we click it, we are logged out, redirected back to the front page, and a "Login" link is shown in the upper right hand corner.
+
- http://localhost:6543/FrontPage invokes the ``view_page`` view of the ``FrontPage`` Page resource.
This is because it is the :term:`default view` (a view without a ``name``) for ``Page`` resources.
It is executable by any user.
@@ -322,14 +330,11 @@ Launch a browser and visit each of the following URLs, checking that the result
- http://localhost:6543/FrontPage/edit_page invokes the edit view for the FrontPage object.
It is executable by only the ``editor`` user.
If a different user (or the anonymous user) invokes it, then a login form will be displayed.
- Supplying the credentials with the username ``editor`` and password ``editor`` will display the edit page form.
+ The ``editor`` user will see the edit page form.
- http://localhost:6543/add_page/SomePageName invokes the add view for a page.
It is executable by only the ``editor`` user.
If a different user (or the anonymous user) invokes it, a login form will be displayed.
- Supplying the credentials with the username ``editor``, password ``editor`` will display the edit page form.
-
-- After logging in (as a result of hitting an edit or add page and submitting the login form with the ``editor`` credentials), we will see a Logout link in the upper right hand corner.
- When we click it, we are logged out, and redirected back to the front page.
+ The ``editor`` user will see the edit page form.
- To generate a not found error, visit http://localhost:6543/wakawaka which will invoke the ``notfound_view`` view provided by the cookiecutter.
diff --git a/docs/tutorials/wiki/installation.rst b/docs/tutorials/wiki/installation.rst
index 4de9b4b9c..7113c4bc2 100644
--- a/docs/tutorials/wiki/installation.rst
+++ b/docs/tutorials/wiki/installation.rst
@@ -185,20 +185,7 @@ The console will show ``pip`` checking for packages and installing missing packa
.. code-block:: bash
- Successfully installed BTrees-4.6.1 Chameleon-3.6.2 Mako-1.1.0 \
- MarkupSafe-1.1.1 PasteDeploy-2.0.1 Pygments-2.5.2 WebTest-2.0.33 \
- ZConfig-3.5.0 ZEO-5.2.1 ZODB-5.5.1 ZODB3-3.11.0 attrs-19.3.0 \
- beautifulsoup4-4.8.2 cffi-1.13.2 coverage-5.0.3 hupper-1.9.1 \
- importlib-metadata-1.4.0 more-itertools-8.1.0 packaging-20.0 \
- persistent-4.5.1 plaster-1.0 plaster-pastedeploy-0.7 pluggy-0.13.1 \
- py-1.8.1 pycparser-2.19 pyparsing-2.4.6 pyramid-1.10.4 \
- pyramid-chameleon-0.3 pyramid-debugtoolbar-4.5.2 pyramid-mako-1.1.0 \
- pyramid-retry-2.1 pyramid-tm-2.4 pyramid-zodbconn-0.8.1 pytest-5.3.2 \
- pytest-cov-2.8.1 repoze.lru-0.7 six-1.13.0 soupsieve-1.9.5 \
- transaction-3.0.0 translationstring-1.3 tutorial venusian-3.0.0 \
- waitress-1.4.2 wcwidth-0.1.8 webob-1.8.5 zc.lockfile-2.0 zdaemon-4.3 \
- zipp-0.6.0 zodbpickle-2.0.0 zodburi-2.4.0 zope.deprecation-4.4.0 \
- zope.interface-4.7.1
+ Successfully installed BTrees-4.7.2 Chameleon-3.8.1 Mako-1.1.3 MarkupSafe-1.1.1 PasteDeploy-2.1.1 Pygments-2.7.3 WebTest-2.0.35 ZConfig-3.5.0 ZEO-5.2.2 ZODB-5.6.0 attrs-20.3.0 beautifulsoup4-4.9.3 cffi-1.14.4 coverage-5.3.1 hupper-1.10.2 iniconfig-1.1.1 packaging-20.8 persistent-4.6.4 plaster-1.0 plaster-pastedeploy-0.7 pluggy-0.13.1 py-1.10.0 pycparser-2.20 pyparsing-2.4.7 pyramid-1.10.5 pyramid-chameleon-0.3 pyramid-debugtoolbar-4.9 pyramid-mako-1.1.0 pyramid-retry-2.1.1 pyramid-tm-2.4 pyramid-zodbconn-0.8.1 pytest-6.2.1 pytest-cov-2.10.1 repoze.lru-0.7 six-1.15.0 soupsieve-2.1 toml-0.10.2 transaction-3.0.1 translationstring-1.4 tutorial venusian-3.0.0 waitress-1.4.4 webob-1.8.6 zc.lockfile-2.0 zdaemon-4.3 zodbpickle-2.0.0 zodburi-2.4.0 zope.deprecation-4.4.0 zope.interface-5.2.0
Testing requirements are defined in our project's ``setup.py`` file, in the ``tests_require`` and ``extras_require`` stanzas.
@@ -276,9 +263,9 @@ If successful, you will see output something like this:
.. code-block:: bash
======================== test session starts =========================
- platform darwin -- Python 3.7.3, pytest-5.3.2, py-1.8.1, pluggy-0.13.1
+ platform darwin -- Python 3.9.0, pytest-6.2.1, py-1.10.0, pluggy-0.13.1
rootdir: /filepath/tutorial, inifile: pytest.ini, testpaths: tutorial
- plugins: cov-2.8.1
+ plugins: cov-2.10.1
collected 4 items
tests/test_functional.py .. [ 50%]
diff --git a/docs/tutorials/wiki/src/authorization/README.txt b/docs/tutorials/wiki/src/authorization/README.txt
index 8a56d14af..b4a924cc4 100644
--- a/docs/tutorials/wiki/src/authorization/README.txt
+++ b/docs/tutorials/wiki/src/authorization/README.txt
@@ -4,15 +4,16 @@ myproj
Getting Started
---------------
-- Change directory into your newly created project.
+- Change directory into your newly created project if not already there. Your
+ current directory should be the same as this README.txt file and setup.py.
cd tutorial
-- Create a Python virtual environment.
+- Create a Python virtual environment, if not already created.
python3 -m venv env
-- Upgrade packaging tools.
+- Upgrade packaging tools, if necessary.
env/bin/pip install --upgrade pip setuptools
diff --git a/docs/tutorials/wiki/src/authorization/pytest.ini b/docs/tutorials/wiki/src/authorization/pytest.ini
index 42c3259f9..3df78fe9d 100644
--- a/docs/tutorials/wiki/src/authorization/pytest.ini
+++ b/docs/tutorials/wiki/src/authorization/pytest.ini
@@ -1,5 +1,5 @@
[pytest]
-addopts = --strict
+addopts = --strict-markers
testpaths =
tutorial
diff --git a/docs/tutorials/wiki/src/authorization/setup.py b/docs/tutorials/wiki/src/authorization/setup.py
index cdfa18e09..f619a9915 100644
--- a/docs/tutorials/wiki/src/authorization/setup.py
+++ b/docs/tutorials/wiki/src/authorization/setup.py
@@ -20,7 +20,7 @@ requires = [
'pyramid_tm',
'pyramid_zodbconn',
'transaction',
- 'ZODB3',
+ 'ZODB',
]
tests_require = [
diff --git a/docs/tutorials/wiki/src/authorization/tests/conftest.py b/docs/tutorials/wiki/src/authorization/tests/conftest.py
index 6a702ae12..86793408d 100644
--- a/docs/tutorials/wiki/src/authorization/tests/conftest.py
+++ b/docs/tutorials/wiki/src/authorization/tests/conftest.py
@@ -1,7 +1,7 @@
import os
from pyramid.paster import get_appsettings
from pyramid.scripting import prepare
-from pyramid.testing import DummyRequest
+from pyramid.testing import DummyRequest, testConfig
import pytest
import transaction
import webtest
@@ -54,31 +54,37 @@ def app_request(app, tm):
drawbacks in tests as it's harder to mock data and is heavier.
"""
- env = prepare(registry=app.registry)
- request = env['request']
- request.host = 'example.com'
- request.tm = tm
-
- yield request
- env['closer']()
+ with prepare(registry=app.registry) as env:
+ request = env['request']
+ request.host = 'example.com'
+ yield request
@pytest.fixture
-def dummy_request(app, tm):
+def dummy_request(tm):
"""
A lightweight dummy request.
- This request is ultra-lightweight and should be used only when the
- request itself is not a large focus in the call-stack.
-
- It is way easier to mock and control side-effects using this object.
+ This request is ultra-lightweight and should be used only when the request
+ itself is not a large focus in the call-stack. It is much easier to mock
+ and control side-effects using this object, however:
- It does not have request extensions applied.
- Threadlocals are not properly pushed.
"""
request = DummyRequest()
- request.registry = app.registry
request.host = 'example.com'
request.tm = tm
return request
+
+@pytest.fixture
+def dummy_config(dummy_request):
+ """
+ A dummy :class:`pyramid.config.Configurator` object. This allows for
+ mock configuration, including configuration for ``dummy_request``, as well
+ as pushing the appropriate threadlocals.
+
+ """
+ with testConfig(request=dummy_request) as config:
+ yield config
diff --git a/docs/tutorials/wiki/src/basiclayout/README.txt b/docs/tutorials/wiki/src/basiclayout/README.txt
index 8a56d14af..b4a924cc4 100644
--- a/docs/tutorials/wiki/src/basiclayout/README.txt
+++ b/docs/tutorials/wiki/src/basiclayout/README.txt
@@ -4,15 +4,16 @@ myproj
Getting Started
---------------
-- Change directory into your newly created project.
+- Change directory into your newly created project if not already there. Your
+ current directory should be the same as this README.txt file and setup.py.
cd tutorial
-- Create a Python virtual environment.
+- Create a Python virtual environment, if not already created.
python3 -m venv env
-- Upgrade packaging tools.
+- Upgrade packaging tools, if necessary.
env/bin/pip install --upgrade pip setuptools
diff --git a/docs/tutorials/wiki/src/basiclayout/pytest.ini b/docs/tutorials/wiki/src/basiclayout/pytest.ini
index 42c3259f9..3df78fe9d 100644
--- a/docs/tutorials/wiki/src/basiclayout/pytest.ini
+++ b/docs/tutorials/wiki/src/basiclayout/pytest.ini
@@ -1,5 +1,5 @@
[pytest]
-addopts = --strict
+addopts = --strict-markers
testpaths =
tutorial
diff --git a/docs/tutorials/wiki/src/basiclayout/setup.py b/docs/tutorials/wiki/src/basiclayout/setup.py
index f85780010..d70df0959 100644
--- a/docs/tutorials/wiki/src/basiclayout/setup.py
+++ b/docs/tutorials/wiki/src/basiclayout/setup.py
@@ -18,7 +18,7 @@ requires = [
'pyramid_tm',
'pyramid_zodbconn',
'transaction',
- 'ZODB3',
+ 'ZODB',
]
tests_require = [
diff --git a/docs/tutorials/wiki/src/basiclayout/tests/conftest.py b/docs/tutorials/wiki/src/basiclayout/tests/conftest.py
index 6a702ae12..86793408d 100644
--- a/docs/tutorials/wiki/src/basiclayout/tests/conftest.py
+++ b/docs/tutorials/wiki/src/basiclayout/tests/conftest.py
@@ -1,7 +1,7 @@
import os
from pyramid.paster import get_appsettings
from pyramid.scripting import prepare
-from pyramid.testing import DummyRequest
+from pyramid.testing import DummyRequest, testConfig
import pytest
import transaction
import webtest
@@ -54,31 +54,37 @@ def app_request(app, tm):
drawbacks in tests as it's harder to mock data and is heavier.
"""
- env = prepare(registry=app.registry)
- request = env['request']
- request.host = 'example.com'
- request.tm = tm
-
- yield request
- env['closer']()
+ with prepare(registry=app.registry) as env:
+ request = env['request']
+ request.host = 'example.com'
+ yield request
@pytest.fixture
-def dummy_request(app, tm):
+def dummy_request(tm):
"""
A lightweight dummy request.
- This request is ultra-lightweight and should be used only when the
- request itself is not a large focus in the call-stack.
-
- It is way easier to mock and control side-effects using this object.
+ This request is ultra-lightweight and should be used only when the request
+ itself is not a large focus in the call-stack. It is much easier to mock
+ and control side-effects using this object, however:
- It does not have request extensions applied.
- Threadlocals are not properly pushed.
"""
request = DummyRequest()
- request.registry = app.registry
request.host = 'example.com'
request.tm = tm
return request
+
+@pytest.fixture
+def dummy_config(dummy_request):
+ """
+ A dummy :class:`pyramid.config.Configurator` object. This allows for
+ mock configuration, including configuration for ``dummy_request``, as well
+ as pushing the appropriate threadlocals.
+
+ """
+ with testConfig(request=dummy_request) as config:
+ yield config
diff --git a/docs/tutorials/wiki/src/installation/README.txt b/docs/tutorials/wiki/src/installation/README.txt
index 8a56d14af..b4a924cc4 100644
--- a/docs/tutorials/wiki/src/installation/README.txt
+++ b/docs/tutorials/wiki/src/installation/README.txt
@@ -4,15 +4,16 @@ myproj
Getting Started
---------------
-- Change directory into your newly created project.
+- Change directory into your newly created project if not already there. Your
+ current directory should be the same as this README.txt file and setup.py.
cd tutorial
-- Create a Python virtual environment.
+- Create a Python virtual environment, if not already created.
python3 -m venv env
-- Upgrade packaging tools.
+- Upgrade packaging tools, if necessary.
env/bin/pip install --upgrade pip setuptools
diff --git a/docs/tutorials/wiki/src/installation/pytest.ini b/docs/tutorials/wiki/src/installation/pytest.ini
index 42c3259f9..3df78fe9d 100644
--- a/docs/tutorials/wiki/src/installation/pytest.ini
+++ b/docs/tutorials/wiki/src/installation/pytest.ini
@@ -1,5 +1,5 @@
[pytest]
-addopts = --strict
+addopts = --strict-markers
testpaths =
tutorial
diff --git a/docs/tutorials/wiki/src/installation/setup.py b/docs/tutorials/wiki/src/installation/setup.py
index f85780010..d70df0959 100644
--- a/docs/tutorials/wiki/src/installation/setup.py
+++ b/docs/tutorials/wiki/src/installation/setup.py
@@ -18,7 +18,7 @@ requires = [
'pyramid_tm',
'pyramid_zodbconn',
'transaction',
- 'ZODB3',
+ 'ZODB',
]
tests_require = [
diff --git a/docs/tutorials/wiki/src/installation/tests/conftest.py b/docs/tutorials/wiki/src/installation/tests/conftest.py
index 6a702ae12..86793408d 100644
--- a/docs/tutorials/wiki/src/installation/tests/conftest.py
+++ b/docs/tutorials/wiki/src/installation/tests/conftest.py
@@ -1,7 +1,7 @@
import os
from pyramid.paster import get_appsettings
from pyramid.scripting import prepare
-from pyramid.testing import DummyRequest
+from pyramid.testing import DummyRequest, testConfig
import pytest
import transaction
import webtest
@@ -54,31 +54,37 @@ def app_request(app, tm):
drawbacks in tests as it's harder to mock data and is heavier.
"""
- env = prepare(registry=app.registry)
- request = env['request']
- request.host = 'example.com'
- request.tm = tm
-
- yield request
- env['closer']()
+ with prepare(registry=app.registry) as env:
+ request = env['request']
+ request.host = 'example.com'
+ yield request
@pytest.fixture
-def dummy_request(app, tm):
+def dummy_request(tm):
"""
A lightweight dummy request.
- This request is ultra-lightweight and should be used only when the
- request itself is not a large focus in the call-stack.
-
- It is way easier to mock and control side-effects using this object.
+ This request is ultra-lightweight and should be used only when the request
+ itself is not a large focus in the call-stack. It is much easier to mock
+ and control side-effects using this object, however:
- It does not have request extensions applied.
- Threadlocals are not properly pushed.
"""
request = DummyRequest()
- request.registry = app.registry
request.host = 'example.com'
request.tm = tm
return request
+
+@pytest.fixture
+def dummy_config(dummy_request):
+ """
+ A dummy :class:`pyramid.config.Configurator` object. This allows for
+ mock configuration, including configuration for ``dummy_request``, as well
+ as pushing the appropriate threadlocals.
+
+ """
+ with testConfig(request=dummy_request) as config:
+ yield config
diff --git a/docs/tutorials/wiki/src/models/README.txt b/docs/tutorials/wiki/src/models/README.txt
index 8a56d14af..b4a924cc4 100644
--- a/docs/tutorials/wiki/src/models/README.txt
+++ b/docs/tutorials/wiki/src/models/README.txt
@@ -4,15 +4,16 @@ myproj
Getting Started
---------------
-- Change directory into your newly created project.
+- Change directory into your newly created project if not already there. Your
+ current directory should be the same as this README.txt file and setup.py.
cd tutorial
-- Create a Python virtual environment.
+- Create a Python virtual environment, if not already created.
python3 -m venv env
-- Upgrade packaging tools.
+- Upgrade packaging tools, if necessary.
env/bin/pip install --upgrade pip setuptools
diff --git a/docs/tutorials/wiki/src/models/pytest.ini b/docs/tutorials/wiki/src/models/pytest.ini
index 42c3259f9..3df78fe9d 100644
--- a/docs/tutorials/wiki/src/models/pytest.ini
+++ b/docs/tutorials/wiki/src/models/pytest.ini
@@ -1,5 +1,5 @@
[pytest]
-addopts = --strict
+addopts = --strict-markers
testpaths =
tutorial
diff --git a/docs/tutorials/wiki/src/models/setup.py b/docs/tutorials/wiki/src/models/setup.py
index f85780010..d70df0959 100644
--- a/docs/tutorials/wiki/src/models/setup.py
+++ b/docs/tutorials/wiki/src/models/setup.py
@@ -18,7 +18,7 @@ requires = [
'pyramid_tm',
'pyramid_zodbconn',
'transaction',
- 'ZODB3',
+ 'ZODB',
]
tests_require = [
diff --git a/docs/tutorials/wiki/src/models/tests/conftest.py b/docs/tutorials/wiki/src/models/tests/conftest.py
index 6a702ae12..86793408d 100644
--- a/docs/tutorials/wiki/src/models/tests/conftest.py
+++ b/docs/tutorials/wiki/src/models/tests/conftest.py
@@ -1,7 +1,7 @@
import os
from pyramid.paster import get_appsettings
from pyramid.scripting import prepare
-from pyramid.testing import DummyRequest
+from pyramid.testing import DummyRequest, testConfig
import pytest
import transaction
import webtest
@@ -54,31 +54,37 @@ def app_request(app, tm):
drawbacks in tests as it's harder to mock data and is heavier.
"""
- env = prepare(registry=app.registry)
- request = env['request']
- request.host = 'example.com'
- request.tm = tm
-
- yield request
- env['closer']()
+ with prepare(registry=app.registry) as env:
+ request = env['request']
+ request.host = 'example.com'
+ yield request
@pytest.fixture
-def dummy_request(app, tm):
+def dummy_request(tm):
"""
A lightweight dummy request.
- This request is ultra-lightweight and should be used only when the
- request itself is not a large focus in the call-stack.
-
- It is way easier to mock and control side-effects using this object.
+ This request is ultra-lightweight and should be used only when the request
+ itself is not a large focus in the call-stack. It is much easier to mock
+ and control side-effects using this object, however:
- It does not have request extensions applied.
- Threadlocals are not properly pushed.
"""
request = DummyRequest()
- request.registry = app.registry
request.host = 'example.com'
request.tm = tm
return request
+
+@pytest.fixture
+def dummy_config(dummy_request):
+ """
+ A dummy :class:`pyramid.config.Configurator` object. This allows for
+ mock configuration, including configuration for ``dummy_request``, as well
+ as pushing the appropriate threadlocals.
+
+ """
+ with testConfig(request=dummy_request) as config:
+ yield config
diff --git a/docs/tutorials/wiki/src/tests/README.txt b/docs/tutorials/wiki/src/tests/README.txt
index 8a56d14af..b4a924cc4 100644
--- a/docs/tutorials/wiki/src/tests/README.txt
+++ b/docs/tutorials/wiki/src/tests/README.txt
@@ -4,15 +4,16 @@ myproj
Getting Started
---------------
-- Change directory into your newly created project.
+- Change directory into your newly created project if not already there. Your
+ current directory should be the same as this README.txt file and setup.py.
cd tutorial
-- Create a Python virtual environment.
+- Create a Python virtual environment, if not already created.
python3 -m venv env
-- Upgrade packaging tools.
+- Upgrade packaging tools, if necessary.
env/bin/pip install --upgrade pip setuptools
diff --git a/docs/tutorials/wiki/src/tests/pytest.ini b/docs/tutorials/wiki/src/tests/pytest.ini
index 42c3259f9..3df78fe9d 100644
--- a/docs/tutorials/wiki/src/tests/pytest.ini
+++ b/docs/tutorials/wiki/src/tests/pytest.ini
@@ -1,5 +1,5 @@
[pytest]
-addopts = --strict
+addopts = --strict-markers
testpaths =
tutorial
diff --git a/docs/tutorials/wiki/src/tests/setup.py b/docs/tutorials/wiki/src/tests/setup.py
index cdfa18e09..f619a9915 100644
--- a/docs/tutorials/wiki/src/tests/setup.py
+++ b/docs/tutorials/wiki/src/tests/setup.py
@@ -20,7 +20,7 @@ requires = [
'pyramid_tm',
'pyramid_zodbconn',
'transaction',
- 'ZODB3',
+ 'ZODB',
]
tests_require = [
diff --git a/docs/tutorials/wiki/src/views/README.txt b/docs/tutorials/wiki/src/views/README.txt
index 8a56d14af..b4a924cc4 100644
--- a/docs/tutorials/wiki/src/views/README.txt
+++ b/docs/tutorials/wiki/src/views/README.txt
@@ -4,15 +4,16 @@ myproj
Getting Started
---------------
-- Change directory into your newly created project.
+- Change directory into your newly created project if not already there. Your
+ current directory should be the same as this README.txt file and setup.py.
cd tutorial
-- Create a Python virtual environment.
+- Create a Python virtual environment, if not already created.
python3 -m venv env
-- Upgrade packaging tools.
+- Upgrade packaging tools, if necessary.
env/bin/pip install --upgrade pip setuptools
diff --git a/docs/tutorials/wiki/src/views/pytest.ini b/docs/tutorials/wiki/src/views/pytest.ini
index 42c3259f9..3df78fe9d 100644
--- a/docs/tutorials/wiki/src/views/pytest.ini
+++ b/docs/tutorials/wiki/src/views/pytest.ini
@@ -1,5 +1,5 @@
[pytest]
-addopts = --strict
+addopts = --strict-markers
testpaths =
tutorial
diff --git a/docs/tutorials/wiki/src/views/setup.py b/docs/tutorials/wiki/src/views/setup.py
index 86c778bf2..786691e21 100644
--- a/docs/tutorials/wiki/src/views/setup.py
+++ b/docs/tutorials/wiki/src/views/setup.py
@@ -19,7 +19,7 @@ requires = [
'pyramid_tm',
'pyramid_zodbconn',
'transaction',
- 'ZODB3',
+ 'ZODB',
]
tests_require = [
diff --git a/docs/tutorials/wiki/src/views/tests/conftest.py b/docs/tutorials/wiki/src/views/tests/conftest.py
index 6a702ae12..86793408d 100644
--- a/docs/tutorials/wiki/src/views/tests/conftest.py
+++ b/docs/tutorials/wiki/src/views/tests/conftest.py
@@ -1,7 +1,7 @@
import os
from pyramid.paster import get_appsettings
from pyramid.scripting import prepare
-from pyramid.testing import DummyRequest
+from pyramid.testing import DummyRequest, testConfig
import pytest
import transaction
import webtest
@@ -54,31 +54,37 @@ def app_request(app, tm):
drawbacks in tests as it's harder to mock data and is heavier.
"""
- env = prepare(registry=app.registry)
- request = env['request']
- request.host = 'example.com'
- request.tm = tm
-
- yield request
- env['closer']()
+ with prepare(registry=app.registry) as env:
+ request = env['request']
+ request.host = 'example.com'
+ yield request
@pytest.fixture
-def dummy_request(app, tm):
+def dummy_request(tm):
"""
A lightweight dummy request.
- This request is ultra-lightweight and should be used only when the
- request itself is not a large focus in the call-stack.
-
- It is way easier to mock and control side-effects using this object.
+ This request is ultra-lightweight and should be used only when the request
+ itself is not a large focus in the call-stack. It is much easier to mock
+ and control side-effects using this object, however:
- It does not have request extensions applied.
- Threadlocals are not properly pushed.
"""
request = DummyRequest()
- request.registry = app.registry
request.host = 'example.com'
request.tm = tm
return request
+
+@pytest.fixture
+def dummy_config(dummy_request):
+ """
+ A dummy :class:`pyramid.config.Configurator` object. This allows for
+ mock configuration, including configuration for ``dummy_request``, as well
+ as pushing the appropriate threadlocals.
+
+ """
+ with testConfig(request=dummy_request) as config:
+ yield config
diff --git a/docs/tutorials/wiki2/authentication.rst b/docs/tutorials/wiki2/authentication.rst
index a798e7748..e8a770491 100644
--- a/docs/tutorials/wiki2/authentication.rst
+++ b/docs/tutorials/wiki2/authentication.rst
@@ -40,7 +40,7 @@ Update ``tutorial/security.py`` with the following content:
:linenos:
:language: python
-Here we've defined a new security policy named ``MySecurityPolicy``, which is implementing most of the :class:`pyramid.interfaces.ISecurityPolicy` interface by tracking a :term:`identity` using a signed cookie implemented by :class:`pyramid.authentication.AuthTktCookieHelper` (lines 8-34).
+Here we've defined a new security policy named ``MySecurityPolicy``, which is implementing most of the :class:`pyramid.interfaces.ISecurityPolicy` interface by tracking an :term:`identity` using a signed cookie implemented by :class:`pyramid.authentication.AuthTktCookieHelper` (lines 8-34).
The security policy outputs the authenticated ``tutorial.models.User`` object for the logged-in user as the :term:`identity`, which is available as ``request.identity``.
Our new :term:`security policy` defines how our application will remember, forget, and identify users.
diff --git a/docs/tutorials/wiki2/installation.rst b/docs/tutorials/wiki2/installation.rst
index 004f6ed31..c961d490b 100644
--- a/docs/tutorials/wiki2/installation.rst
+++ b/docs/tutorials/wiki2/installation.rst
@@ -338,15 +338,15 @@ If successful, you will see output something like this:
.. code-block:: bash
======================== test session starts ========================
- platform -- Python 3.7.3, pytest-5.3.2, py-1.8.1, pluggy-0.13.1
+ platform darwin -- Python 3.9.0, pytest-6.2.1, py-1.10.0, pluggy-0.13.1
rootdir: <somepath>/tutorial, inifile: pytest.ini, testpaths: tutorial, tests
- plugins: cov-2.8.1
+ plugins: cov-2.10.1
collected 5 items
- tests/test_functional.py ..
- tests/test_views.py ...
+ tests/test_functional.py .. [ 40%]
+ tests/test_views.py ... [100%]
- ---------- coverage: platform darwin, python 3.7.4-final-0 -----------
+ ---------- coverage: platform darwin, python 3.9.0-final-0 -----------
Name Stmts Miss Cover Missing
----------------------------------------------------------------------------------
tutorial/__init__.py 8 0 100%
@@ -360,10 +360,10 @@ If successful, you will see output something like this:
tutorial/scripts/__init__.py 0 0 100%
tutorial/scripts/initialize_db.py 22 14 36% 15-16, 20-25, 29-38
tutorial/views/__init__.py 0 0 100%
- tutorial/views/default.py 12 0 100%
- tutorial/views/notfound.py 4 0 100%
+ tutorial/views/default.py 13 0 100%
+ tutorial/views/notfound.py 5 0 100%
----------------------------------------------------------------------------------
- TOTAL 136 27 80%
+ TOTAL 138 27 80%
===================== 5 passed in 0.77 seconds ======================