From d9c20d0a5002052df675b8a06b2e8711dc1cb586 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Sat, 16 Apr 2016 15:49:18 -0500 Subject: flip master to 1.8 --- CHANGES.txt | 126 +----------------------------------------------------- HISTORY.txt | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 142 insertions(+), 124 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index d316594bc..c0681053d 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -4,136 +4,14 @@ unreleased Backward Incompatibilities -------------------------- -- Following the Pyramid deprecation period (1.4 -> 1.6), - AuthTktAuthenticationPolicy's default hashing algorithm is changing from md5 - to sha512. If you are using the authentication policy and need to continue - using md5, please explicitly set hashalg to 'md5'. - - This change does mean that any existing auth tickets (and associated cookies) - will no longer be valid, and users will no longer be logged in, and have to - login to their accounts again. - - See https://github.com/Pylons/pyramid/pull/2496 - -- The ``check_csrf_token`` function no longer validates a csrf token in the - query string of a request. Only headers and request bodies are supported. - See https://github.com/Pylons/pyramid/pull/2500 - Features -------- -- Added a new setting, ``pyramid.require_default_csrf`` which may be used - to turn on CSRF checks globally for every POST request in the application. - This should be considered a good default for websites built on Pyramid. - It is possible to opt-out of CSRF checks on a per-view basis by setting - ``require_csrf=False`` on those views. - See https://github.com/Pylons/pyramid/pull/2413 - -- Added a ``require_csrf`` view option which will enforce CSRF checks on any - request with an unsafe method as defined by RFC2616. If the CSRF check fails - a ``BadCSRFToken`` exception will be raised and may be caught by exception - views (the default response is a ``400 Bad Request``). This option should be - used in place of the deprecated ``check_csrf`` view predicate which would - normally result in unexpected ``404 Not Found`` response to the client - instead of a catchable exception. See - https://github.com/Pylons/pyramid/pull/2413 and - https://github.com/Pylons/pyramid/pull/2500 - -- Added an additional CSRF validation that checks the origin/referrer of a - request and makes sure it matches the current ``request.domain``. This - particular check is only active when accessing a site over HTTPS as otherwise - browsers don't always send the required information. If this additional CSRF - validation fails a ``BadCSRFOrigin`` exception will be raised and may be - caught by exception views (the default response is ``400 Bad Request``). - Additional allowed origins may be configured by setting - ``pyramid.csrf_trusted_origins`` to a list of domain names (with ports if on - a non standard port) to allow. Subdomains are not allowed unless the domain - name has been prefixed with a ``.``. See - https://github.com/Pylons/pyramid/pull/2501 - -- Added a new ``pyramid.session.check_csrf_origin`` API for validating the - origin or referrer headers against the request's domain. - See https://github.com/Pylons/pyramid/pull/2501 - -- Pyramid HTTPExceptions will now take into account the best match for the - clients Accept header, and depending on what is requested will return - text/html, application/json or text/plain. The default for */* is still - text/html, but if application/json is explicitly mentioned it will now - receive a valid JSON response. See - https://github.com/Pylons/pyramid/pull/2489 - -- A new event and interface (BeforeTraversal) has been introduced that will - notify listeners before traversal starts in the router. See - https://github.com/Pylons/pyramid/pull/2469 and - https://github.com/Pylons/pyramid/pull/1876 - -- Add a new "view deriver" concept to Pyramid to allow framework authors to - inject elements into the standard Pyramid view pipeline and affect all - views in an application. This is similar to a decorator except that it - has access to options passed to ``config.add_view`` and can affect other - stages of the pipeline such as the raw response from a view or prior to - security checks. See https://github.com/Pylons/pyramid/pull/2021 - -- Allow a leading ``=`` on the key of the request param predicate. - For example, '=abc=1' is equivalent down to - ``request.params['=abc'] == '1'``. - See https://github.com/Pylons/pyramid/pull/1370 - -- A new ``request.invoke_exception_view(...)`` method which can be used to - invoke an exception view and get back a response. This is useful for - rendering an exception view outside of the context of the excview tween - where you may need more control over the request. - See https://github.com/Pylons/pyramid/pull/2393 - -- Allow using variable substitutions like ``%(LOGGING_LOGGER_ROOT_LEVEL)s`` - for logging sections of the .ini file and populate these variables from - the ``pserve`` command line -- e.g.: - ``pserve development.ini LOGGING_LOGGER_ROOT_LEVEL=DEBUG`` - See https://github.com/Pylons/pyramid/pull/2399 - -Documentation Changes ---------------------- - -- A complete overhaul of the docs: - - - Use pip instead of easy_install. - - Become opinionated by preferring Python 3.4 or greater to simplify - installation of Python and its required packaging tools. - - Use venv for the tool, and virtual environment for the thing created, - instead of virtualenv. - - Use py.test and pytest-cov instead of nose and coverage. - - Further updates to the scaffolds as well as tutorials and their src files. - - See https://github.com/Pylons/pyramid/pull/2468 - -- A complete overhaul of the ``alchemy`` scaffold as well as the - Wiki2 SQLAlchemy + URLDispatch tutorial to introduce more modern features - into the usage of SQLAlchemy with Pyramid and provide a better starting - point for new projects. - See https://github.com/Pylons/pyramid/pull/2024 - Bug Fixes --------- -- Fix ``pserve --browser`` to use the ``--server-name`` instead of the - app name when selecting a section to use. This was only working for people - who had server and app sections with the same name, for example - ``[app:main]`` and ``[server:main]``. - See https://github.com/Pylons/pyramid/pull/2292 - Deprecations ------------ -- The ``check_csrf`` view predicate has been deprecated. Use the - new ``require_csrf`` option or the ``pyramid.require_default_csrf`` setting - to ensure that the ``BadCSRFToken`` exception is raised. - See https://github.com/Pylons/pyramid/pull/2413 - -- Support for Python 3.3 will be removed in Pyramid 1.8. - https://github.com/Pylons/pyramid/issues/2477 - -- Python 2.6 is no longer supported by Pyramid. See - https://github.com/Pylons/pyramid/issues/2368 - -- Dropped Python 3.2 support. - See https://github.com/Pylons/pyramid/pull/2256 +Documentation Changes +--------------------- diff --git a/HISTORY.txt b/HISTORY.txt index b7f30ff86..53a17a4d3 100644 --- a/HISTORY.txt +++ b/HISTORY.txt @@ -1,3 +1,143 @@ +1.7a1 (2016-04-16) +================== + +Backward Incompatibilities +-------------------------- + +- Following the Pyramid deprecation period (1.4 -> 1.6), + AuthTktAuthenticationPolicy's default hashing algorithm is changing from md5 + to sha512. If you are using the authentication policy and need to continue + using md5, please explicitly set hashalg to 'md5'. + + This change does mean that any existing auth tickets (and associated cookies) + will no longer be valid, and users will no longer be logged in, and have to + login to their accounts again. + + See https://github.com/Pylons/pyramid/pull/2496 + +- The ``check_csrf_token`` function no longer validates a csrf token in the + query string of a request. Only headers and request bodies are supported. + See https://github.com/Pylons/pyramid/pull/2500 + +Features +-------- + +- Added a new setting, ``pyramid.require_default_csrf`` which may be used + to turn on CSRF checks globally for every POST request in the application. + This should be considered a good default for websites built on Pyramid. + It is possible to opt-out of CSRF checks on a per-view basis by setting + ``require_csrf=False`` on those views. + See https://github.com/Pylons/pyramid/pull/2413 + +- Added a ``require_csrf`` view option which will enforce CSRF checks on any + request with an unsafe method as defined by RFC2616. If the CSRF check fails + a ``BadCSRFToken`` exception will be raised and may be caught by exception + views (the default response is a ``400 Bad Request``). This option should be + used in place of the deprecated ``check_csrf`` view predicate which would + normally result in unexpected ``404 Not Found`` response to the client + instead of a catchable exception. See + https://github.com/Pylons/pyramid/pull/2413 and + https://github.com/Pylons/pyramid/pull/2500 + +- Added an additional CSRF validation that checks the origin/referrer of a + request and makes sure it matches the current ``request.domain``. This + particular check is only active when accessing a site over HTTPS as otherwise + browsers don't always send the required information. If this additional CSRF + validation fails a ``BadCSRFOrigin`` exception will be raised and may be + caught by exception views (the default response is ``400 Bad Request``). + Additional allowed origins may be configured by setting + ``pyramid.csrf_trusted_origins`` to a list of domain names (with ports if on + a non standard port) to allow. Subdomains are not allowed unless the domain + name has been prefixed with a ``.``. See + https://github.com/Pylons/pyramid/pull/2501 + +- Added a new ``pyramid.session.check_csrf_origin`` API for validating the + origin or referrer headers against the request's domain. + See https://github.com/Pylons/pyramid/pull/2501 + +- Pyramid HTTPExceptions will now take into account the best match for the + clients Accept header, and depending on what is requested will return + text/html, application/json or text/plain. The default for */* is still + text/html, but if application/json is explicitly mentioned it will now + receive a valid JSON response. See + https://github.com/Pylons/pyramid/pull/2489 + +- A new event and interface (BeforeTraversal) has been introduced that will + notify listeners before traversal starts in the router. See + https://github.com/Pylons/pyramid/pull/2469 and + https://github.com/Pylons/pyramid/pull/1876 + +- Add a new "view deriver" concept to Pyramid to allow framework authors to + inject elements into the standard Pyramid view pipeline and affect all + views in an application. This is similar to a decorator except that it + has access to options passed to ``config.add_view`` and can affect other + stages of the pipeline such as the raw response from a view or prior to + security checks. See https://github.com/Pylons/pyramid/pull/2021 + +- Allow a leading ``=`` on the key of the request param predicate. + For example, '=abc=1' is equivalent down to + ``request.params['=abc'] == '1'``. + See https://github.com/Pylons/pyramid/pull/1370 + +- A new ``request.invoke_exception_view(...)`` method which can be used to + invoke an exception view and get back a response. This is useful for + rendering an exception view outside of the context of the excview tween + where you may need more control over the request. + See https://github.com/Pylons/pyramid/pull/2393 + +- Allow using variable substitutions like ``%(LOGGING_LOGGER_ROOT_LEVEL)s`` + for logging sections of the .ini file and populate these variables from + the ``pserve`` command line -- e.g.: + ``pserve development.ini LOGGING_LOGGER_ROOT_LEVEL=DEBUG`` + See https://github.com/Pylons/pyramid/pull/2399 + +Documentation Changes +--------------------- + +- A complete overhaul of the docs: + + - Use pip instead of easy_install. + - Become opinionated by preferring Python 3.4 or greater to simplify + installation of Python and its required packaging tools. + - Use venv for the tool, and virtual environment for the thing created, + instead of virtualenv. + - Use py.test and pytest-cov instead of nose and coverage. + - Further updates to the scaffolds as well as tutorials and their src files. + + See https://github.com/Pylons/pyramid/pull/2468 + +- A complete overhaul of the ``alchemy`` scaffold as well as the + Wiki2 SQLAlchemy + URLDispatch tutorial to introduce more modern features + into the usage of SQLAlchemy with Pyramid and provide a better starting + point for new projects. + See https://github.com/Pylons/pyramid/pull/2024 + +Bug Fixes +--------- + +- Fix ``pserve --browser`` to use the ``--server-name`` instead of the + app name when selecting a section to use. This was only working for people + who had server and app sections with the same name, for example + ``[app:main]`` and ``[server:main]``. + See https://github.com/Pylons/pyramid/pull/2292 + +Deprecations +------------ + +- The ``check_csrf`` view predicate has been deprecated. Use the + new ``require_csrf`` option or the ``pyramid.require_default_csrf`` setting + to ensure that the ``BadCSRFToken`` exception is raised. + See https://github.com/Pylons/pyramid/pull/2413 + +- Support for Python 3.3 will be removed in Pyramid 1.8. + https://github.com/Pylons/pyramid/issues/2477 + +- Python 2.6 is no longer supported by Pyramid. See + https://github.com/Pylons/pyramid/issues/2368 + +- Dropped Python 3.2 support. + See https://github.com/Pylons/pyramid/pull/2256 + 1.6 (2016-01-03) ================ -- cgit v1.2.3 From a575d1f9d77195d53f55fa8b409bd7c21f3f64de Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 17 Apr 2016 15:38:26 -0700 Subject: update RELEASING.txt to better account for master and previous branches - add term "final" release - explicitify the implicit - --- RELEASING.txt | 69 ++++++++++++++++++++++++++++++++++++++++++++++++--------- contributing.md | 2 ++ docs/conf.py | 1 + 3 files changed, 61 insertions(+), 11 deletions(-) diff --git a/RELEASING.txt b/RELEASING.txt index 866fff305..8b3d908e6 100644 --- a/RELEASING.txt +++ b/RELEASING.txt @@ -6,12 +6,19 @@ Releasing Pyramid - Alpha, beta, dev and similar statuses do not qualify whether a release is major or minor. The term "pre-release" means alpha, beta, or dev. + - A release is final when it is no longer pre-release. + - A *major* release is where the first number either before or after the first dot increases. Examples: 1.6 to 1.7a1, or 1.8 to 2.0. - A *minor* or *bug fix* release is where the number after the second dot increases. Example: 1.6 to 1.6.1. +Prepare new release branch +-------------------------- + +- Create a new release branch, incrementing the version number. + - Do any necessary branch merges (e.g., master to branch, branch to master). - On release branch: @@ -34,6 +41,8 @@ Releasing Pyramid - Ensure all features of the release are documented (audit CHANGES.txt or communicate with contributors). +- Change CHANGES.txt heading to reflect the new version number. + - Copy relevant changes (delta bug fixes) from CHANGES.txt to docs/whatsnew-X.X (if it's a major release). Minor releases should include a link under "Bug Fix Releases" to the minor feature @@ -52,10 +61,7 @@ Releasing Pyramid branch, and previously released branch. Also in the previously released branch only, uncomment the sections to enable pylons_sphinx_latesturl. -- Change setup.py version to the new version number on both master and the new - branch. - -- Change CHANGES.txt heading to reflect the new version number. +- Change setup.py version to the release version number. - Make sure PyPI long description renders (requires ``collective.dist`` installed into your Python):: @@ -70,6 +76,37 @@ Releasing Pyramid $ python setup.py sdist bdist_wheel $ twine upload dist/pyramid-X.X-* +- Configure RTD to publish the new release version of the docs. + +Prepare master for further development (major releases only) +------------------------------------------------------------ + +- Checkout master. + +- In CHANGES.txt, preserve headings but clear out content. + +- From the release branch, forward port the changes in CHANGES.txt to + HISTORY.txt. + +- In contributing.md, forward port branch descriptions from release branch. + +- In docs/conf.py, add a commented line under + pylons_sphinx_latesturl_pagename_overrides for the release. + +- Change setup.py version to the next version number. + +Update previous version (final releases only) +--------------------------------------------- + +- In docs/conf.py, update values under html_theme_options for in_progress and + outdated. Uncomment the sections to enable pylons_sphinx_latesturl. + +- Configure RTD to point the "latest" alias to the new release version of the + docs. + +Marketing and communications +---------------------------- + - Edit Pylons/pylonshq/templates/home/home.mako. - Edit Pylons/pylonshq/templates/home/inside.rst for major releases only. @@ -82,15 +119,24 @@ Releasing Pyramid - Edit `http://wiki.python.org/moin/WebFrameworks `_. -- Publish new version of docs. +- Announce to Twitter. -- Announce to maillist. +``` +Pyramid 1.x released. -- Announce to Twitter. +PyPI +https://pypi.python.org/pypi/pyramid/1.x + +What's New +http://docs.pylonsproject.org/projects/pyramid/1.X/whatsnew-1.X.html -Announcement template ----------------------- +Issues +https://github.com/Pylons/pyramid/issues +``` + +- Announce to maillist. +``` Pyramid 1.X.X has been released. Here are the changes: @@ -106,11 +152,12 @@ at http://docs.pylonsproject.org/projects/pyramid/1.X/ . You can install it via PyPI: - easy_install Pyramid==1.X + pip install Pyramid==1.X Enjoy, and please report any issues you find to the issue tracker at https://github.com/Pylons/pyramid/issues Thanks! -- C +- Pyramid core developers +``` diff --git a/contributing.md b/contributing.md index af19ed093..1393a2507 100644 --- a/contributing.md +++ b/contributing.md @@ -26,6 +26,8 @@ listed below. * [master](https://github.com/Pylons/pyramid/) - The branch on which further development takes place. The default branch on GitHub. +* [1.7-branch](https://github.com/Pylons/pyramid/tree/1.7-branch) - The branch +classified as alpha. Actively maintained. * [1.6-branch](https://github.com/Pylons/pyramid/tree/1.6-branch) - The branch classified as "stable" or "latest". Actively maintained. * [1.5-branch](https://github.com/Pylons/pyramid/tree/1.5-branch) - The oldest diff --git a/docs/conf.py b/docs/conf.py index 786ff3abf..518f7e784 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -138,6 +138,7 @@ if book: # 'whatsnew-1.4': 'index', # 'whatsnew-1.5': 'index', # 'whatsnew-1.6': 'index', +# 'whatsnew-1.7': 'index', # 'tutorials/gae/index': 'index', # 'api/chameleon_text': 'api', # 'api/chameleon_zpt': 'api', -- cgit v1.2.3 From b5237a573acb1dedebc236e852f4437c66fd26be Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 17 Apr 2016 15:54:06 -0700 Subject: update RELEASING.txt with "unreleased" heading --- RELEASING.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/RELEASING.txt b/RELEASING.txt index 8b3d908e6..e50adb52b 100644 --- a/RELEASING.txt +++ b/RELEASING.txt @@ -83,7 +83,8 @@ Prepare master for further development (major releases only) - Checkout master. -- In CHANGES.txt, preserve headings but clear out content. +- In CHANGES.txt, preserve headings but clear out content. Add heading + "unreleased" for the version number. - From the release branch, forward port the changes in CHANGES.txt to HISTORY.txt. -- cgit v1.2.3 From b4ea370131a9b28cd02db3c674d1b4fcdd7ce6d5 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Sun, 17 Apr 2016 19:50:25 -0500 Subject: fix csrf setting error message --- pyramid/tests/test_viewderivers.py | 2 +- pyramid/viewderivers.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyramid/tests/test_viewderivers.py b/pyramid/tests/test_viewderivers.py index 6bfe353e5..ae02e0152 100644 --- a/pyramid/tests/test_viewderivers.py +++ b/pyramid/tests/test_viewderivers.py @@ -1108,7 +1108,7 @@ class TestDeriveView(unittest.TestCase): self.config._derive_view(view) except ConfigurationError as ex: self.assertEqual( - 'Config setting "pyramid.require_csrf_default" must be a ' + 'Config setting "pyramid.require_default_csrf" must be a ' 'string or boolean value', ex.args[0]) else: # pragma: no cover diff --git a/pyramid/viewderivers.py b/pyramid/viewderivers.py index d5a5c480a..d9d9c2904 100644 --- a/pyramid/viewderivers.py +++ b/pyramid/viewderivers.py @@ -482,7 +482,7 @@ SAFE_REQUEST_METHODS = frozenset(["GET", "HEAD", "OPTIONS", "TRACE"]) def csrf_view(view, info): default_val = _parse_csrf_setting( info.settings.get('pyramid.require_default_csrf'), - 'Config setting "pyramid.require_csrf_default"') + 'Config setting "pyramid.require_default_csrf"') val = _parse_csrf_setting( info.options.get('require_csrf'), 'View option "require_csrf"') -- cgit v1.2.3 From 8840437df934a3a29a19be4bfee96cbcf5d537ff Mon Sep 17 00:00:00 2001 From: Donald Stufft Date: Sun, 17 Apr 2016 12:09:58 -0400 Subject: request.host_port is a str not an int --- pyramid/session.py | 2 +- pyramid/tests/test_session.py | 14 +++++++------- pyramid/tests/test_viewderivers.py | 6 +++--- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/pyramid/session.py b/pyramid/session.py index 36ebc2f00..811c81fb4 100644 --- a/pyramid/session.py +++ b/pyramid/session.py @@ -182,7 +182,7 @@ def check_csrf_origin(request, trusted_origins=None, raises=True): "pyramid.csrf_trusted_origins", []) ) - if request.host_port not in set([80, 443]): + if request.host_port not in set(["80", "443"]): trusted_origins.append("{0.domain}:{0.host_port}".format(request)) else: trusted_origins.append(request.domain) diff --git a/pyramid/tests/test_session.py b/pyramid/tests/test_session.py index e08f9a919..3a308d08b 100644 --- a/pyramid/tests/test_session.py +++ b/pyramid/tests/test_session.py @@ -721,7 +721,7 @@ class Test_check_csrf_origin(unittest.TestCase): request = testing.DummyRequest() request.scheme = "https" request.host = "example.com" - request.host_port = 443 + request.host_port = "443" request.referrer = "https://example.com/login/" request.registry.settings = {} self.assertTrue(self._callFUT(request)) @@ -730,7 +730,7 @@ class Test_check_csrf_origin(unittest.TestCase): request = testing.DummyRequest() request.scheme = "https" request.host = "example.com" - request.host_port = 443 + request.host_port = "443" request.headers = {"Origin": "https://example.com/"} request.referrer = "https://not-example.com/" request.registry.settings = {} @@ -740,7 +740,7 @@ class Test_check_csrf_origin(unittest.TestCase): request = testing.DummyRequest() request.scheme = "https" request.host = "example.com" - request.host_port = 443 + request.host_port = "443" request.referrer = "https://not-example.com/login/" request.registry.settings = { "pyramid.csrf_trusted_origins": ["not-example.com"], @@ -751,7 +751,7 @@ class Test_check_csrf_origin(unittest.TestCase): request = testing.DummyRequest() request.scheme = "https" request.host = "example.com:8080" - request.host_port = 8080 + request.host_port = "8080" request.referrer = "https://example.com:8080/login/" request.registry.settings = {} self.assertTrue(self._callFUT(request)) @@ -761,7 +761,7 @@ class Test_check_csrf_origin(unittest.TestCase): request = testing.DummyRequest() request.scheme = "https" request.host = "example.com" - request.host_port = 443 + request.host_port = "443" request.referrer = "https://not-example.com/login/" request.registry.settings = {} self.assertRaises(BadCSRFOrigin, self._callFUT, request) @@ -780,7 +780,7 @@ class Test_check_csrf_origin(unittest.TestCase): request = testing.DummyRequest() request.scheme = "https" request.host = "example.com" - request.host_port = 443 + request.host_port = "443" request.referrer = "http://example.com/evil/" request.registry.settings = {} self.assertRaises(BadCSRFOrigin, self._callFUT, request) @@ -791,7 +791,7 @@ class Test_check_csrf_origin(unittest.TestCase): request = testing.DummyRequest() request.scheme = "https" request.host = "example.com:8080" - request.host_port = 8080 + request.host_port = "8080" request.referrer = "https://example.com/login/" request.registry.settings = {} self.assertRaises(BadCSRFOrigin, self._callFUT, request) diff --git a/pyramid/tests/test_viewderivers.py b/pyramid/tests/test_viewderivers.py index ae02e0152..4767da580 100644 --- a/pyramid/tests/test_viewderivers.py +++ b/pyramid/tests/test_viewderivers.py @@ -1148,7 +1148,7 @@ class TestDeriveView(unittest.TestCase): request = self._makeRequest() request.scheme = "https" request.domain = "example.com" - request.host_port = 443 + request.host_port = "443" request.referrer = "https://example.com/login/" request.method = 'POST' request.session = DummySession({'csrf_token': 'foo'}) @@ -1208,7 +1208,7 @@ class TestDeriveView(unittest.TestCase): request = self._makeRequest() request.method = "POST" request.scheme = "https" - request.host_port = 443 + request.host_port = "443" request.domain = "example.com" request.referrer = "https://not-example.com/evil/" request.registry.settings = {} @@ -1221,7 +1221,7 @@ class TestDeriveView(unittest.TestCase): request = self._makeRequest() request.method = "POST" request.scheme = "https" - request.host_port = 443 + request.host_port = "443" request.domain = "example.com" request.headers = {"Origin": "https://not-example.com/evil/"} request.registry.settings = {} -- cgit v1.2.3 From 6f524a94157b0caa471222b0d9768a48173c1c7e Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Sun, 17 Apr 2016 22:59:50 -0500 Subject: disable csrf checking on all exception views unless explicitly turned on --- pyramid/tests/test_viewderivers.py | 59 +++++++++++++++++++++++++++++++++++++- pyramid/viewderivers.py | 24 ++++++++++------ 2 files changed, 74 insertions(+), 9 deletions(-) diff --git a/pyramid/tests/test_viewderivers.py b/pyramid/tests/test_viewderivers.py index 4767da580..4a7a04197 100644 --- a/pyramid/tests/test_viewderivers.py +++ b/pyramid/tests/test_viewderivers.py @@ -1297,6 +1297,64 @@ class TestDeriveView(unittest.TestCase): 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.add_settings({'pyramid.require_default_csrf': 'yes'}) + 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): pass + self.config.add_settings({'pyramid.require_default_csrf': 'yes'}) + 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.add_settings({'pyramid.require_default_csrf': 'yes'}) + 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): @@ -1554,7 +1612,6 @@ class TestDeriverIntegration(unittest.TestCase): from pyramid.interfaces import IRequest from pyramid.interfaces import IView from pyramid.interfaces import IViewClassifier - from pyramid.interfaces import IExceptionViewClassifier classifier = IViewClassifier if ctx_iface is None: ctx_iface = Interface diff --git a/pyramid/viewderivers.py b/pyramid/viewderivers.py index d9d9c2904..fbe7cd660 100644 --- a/pyramid/viewderivers.py +++ b/pyramid/viewderivers.py @@ -483,21 +483,29 @@ def csrf_view(view, info): default_val = _parse_csrf_setting( info.settings.get('pyramid.require_default_csrf'), 'Config setting "pyramid.require_default_csrf"') - val = _parse_csrf_setting( + explicit_val = _parse_csrf_setting( info.options.get('require_csrf'), 'View option "require_csrf"') - if (val is True and default_val) or val is None: - val = default_val - if val is True: - val = 'csrf_token' + resolved_val = explicit_val + if (explicit_val is True and default_val) or explicit_val is None: + resolved_val = default_val + if resolved_val is True: + resolved_val = 'csrf_token' wrapped_view = view - if val: + if resolved_val: def csrf_view(context, request): # Assume that anything not defined as 'safe' by RFC2616 needs # protection - if request.method not in SAFE_REQUEST_METHODS: + if ( + request.method not in SAFE_REQUEST_METHODS and + ( + # skip exception views unless value is explicitly defined + getattr(request, 'exception', None) is None or + explicit_val is not None + ) + ): check_csrf_origin(request, raises=True) - check_csrf_token(request, val, raises=True) + check_csrf_token(request, resolved_val, raises=True) return view(context, request) wrapped_view = csrf_view return wrapped_view -- cgit v1.2.3 From de3d0c784198796285ddc4c80e45b8082ecab9e2 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Mon, 18 Apr 2016 10:15:32 -0500 Subject: replace pyramid.require_default_csrf setting with config.set_default_csrf_options --- docs/api/config.rst | 2 + docs/narr/extconfig.rst | 1 + docs/narr/introspector.rst | 25 +++++ docs/narr/sessions.rst | 76 ++++++++------- pyramid/config/security.py | 57 ++++++++++- pyramid/config/views.py | 37 ++++--- pyramid/interfaces.py | 10 ++ pyramid/session.py | 7 +- pyramid/tests/test_config/test_security.py | 21 ++++ pyramid/tests/test_viewderivers.py | 152 ++++++++++++----------------- pyramid/viewderivers.py | 58 +++++------ 11 files changed, 266 insertions(+), 180 deletions(-) diff --git a/docs/api/config.rst b/docs/api/config.rst index e083dbc68..ab3ff0fe1 100644 --- a/docs/api/config.rst +++ b/docs/api/config.rst @@ -35,6 +35,7 @@ .. automethod:: set_authentication_policy .. automethod:: set_authorization_policy + .. automethod:: set_default_csrf_options .. automethod:: set_default_permission .. automethod:: add_permission @@ -65,6 +66,7 @@ .. automethod:: add_traverser .. automethod:: add_tween .. automethod:: add_route_predicate + .. automethod:: add_subscriber_predicate .. automethod:: add_view_predicate .. automethod:: add_view_deriver .. automethod:: set_request_factory diff --git a/docs/narr/extconfig.rst b/docs/narr/extconfig.rst index af7d0a349..babfa0a98 100644 --- a/docs/narr/extconfig.rst +++ b/docs/narr/extconfig.rst @@ -261,6 +261,7 @@ Pre-defined Phases - :meth:`pyramid.config.Configurator.add_view_predicate` - :meth:`pyramid.config.Configurator.add_view_deriver` - :meth:`pyramid.config.Configurator.set_authorization_policy` +- :meth:`pyramid.config.Configurator.set_default_csrf_options` - :meth:`pyramid.config.Configurator.set_default_permission` - :meth:`pyramid.config.Configurator.set_view_mapper` diff --git a/docs/narr/introspector.rst b/docs/narr/introspector.rst index 98315ac9f..c9fecd4f4 100644 --- a/docs/narr/introspector.rst +++ b/docs/narr/introspector.rst @@ -337,6 +337,31 @@ introspectables in categories not described here. The permission name passed to ``set_default_permission``. +``default csrf options`` + + There will be one and only one introspectable in the ``default csrf options`` + category. It represents a call to the + :meth:`pyramid.config.Configurator.set_default_csrf_options` method. It + will have the following data. + + ``require_csrf`` + + The default value for ``require_csrf`` if left unspecified on calls to + :meth:`pyramid.config.Configurator.add_view`. + + ``token`` + + The name of the token searched in ``request.POST`` to find a valid CSRF + token. + + ``header`` + + The name of the request header searched to find a valid CSRF token. + + ``safe_methods`` + + The list of HTTP methods considered safe and exempt from CSRF checks. + ``views`` Each introspectable in the ``views`` category represents a call to diff --git a/docs/narr/sessions.rst b/docs/narr/sessions.rst index 7cf96ac7d..bfc908396 100644 --- a/docs/narr/sessions.rst +++ b/docs/narr/sessions.rst @@ -396,13 +396,13 @@ named ``X-CSRF-Token``. .. code-block:: python - from pyramid.session import check_csrf_token + from pyramid.session import check_csrf_token - def myview(request): - # Require CSRF Token - check_csrf_token(request) + def myview(request): + # Require CSRF Token + check_csrf_token(request) - # ... + # ... .. _auto_csrf_checking: @@ -414,41 +414,45 @@ Checking CSRF Tokens Automatically :app:`Pyramid` supports automatically checking CSRF tokens on requests with an unsafe method as defined by RFC2616. Any other request may be checked manually. This feature can be turned on globally for an application using the -``pyramid.require_default_csrf`` setting. - -If the ``pyramid.required_default_csrf`` setting is a :term:`truthy string` or -``True`` then the default CSRF token parameter will be ``csrf_token``. If a -different token is desired, it may be passed as the value. Finally, a -:term:`falsey string` or ``False`` will turn off automatic CSRF checking -globally on every request. - -No matter what, CSRF checking may be explicitly enabled or disabled on a -per-view basis using the ``require_csrf`` view option. This option is of the -same format as the ``pyramid.require_default_csrf`` setting, accepting strings -or boolean values. - -If ``require_csrf`` is ``True`` but does not explicitly define a token to -check, then the token name is pulled from whatever was set in the -``pyramid.require_default_csrf`` setting. Finally, if that setting does not -explicitly define a token, then ``csrf_token`` is the token required. This token -name will be required in ``request.POST`` which is the submitted form body. - -It is always possible to pass the token in the ``X-CSRF-Token`` header as well. -There is currently no way to define an alternate name for this header without -performing CSRF checking manually. - -In addition to token based CSRF checks, the automatic CSRF checking will also -check the referrer of the request to ensure that it matches one of the trusted -origins. By default the only trusted origin is the current host, however -additional origins may be configured by setting +:meth:`pyramid.config.Configurator.set_default_csrf_options` directive. +For example: + +.. code-block:: python + + from pyramid.config import Configurator + + config = Configurator() + config.set_default_csrf_options(require_csrf=True) + +CSRF checking may be explicitly enabled or disabled on a per-view basis using +the ``require_csrf`` view option. A value of ``True`` or ``False`` will +override the default set by ``set_default_csrf_options``. For example: + +.. code-block:: python + + @view_config(route_name='hello', require_csrf=False) + def myview(request): + # ... + +When CSRF checking is active, the token and header used to find the +supplied CSRF token will be ``csrf_token`` and ``X-CSRF-Token``, respectively, +unless otherwise overridden by ``set_default_csrf_options``. The token is +checked against the value in ``request.POST`` which is the submitted form body. +If this value is not present, then the header will be checked. + +In addition to token based CSRF checks, if the request is using HTTPS then the +automatic CSRF checking will also check the referrer of the request to ensure +that it matches one of the trusted origins. By default the only trusted origin +is the current host, however additional origins may be configured by setting ``pyramid.csrf_trusted_origins`` to a list of domain names (and ports if they are non standard). If a host in the list of domains starts with a ``.`` then that will allow all subdomains as well as the domain without the ``.``. -If CSRF checks fail then a :class:`pyramid.exceptions.BadCSRFToken` exception -will be raised. This exception may be caught and handled by an -:term:`exception view` but, by default, will result in a ``400 Bad Request`` -response being sent to the client. +If CSRF checks fail then a :class:`pyramid.exceptions.BadCSRFToken` or +:class:`pyramid.exceptions.BadCSRFOrigin` exception will be raised. This +exception may be caught and handled by an :term:`exception view` but, by +default, will result in a ``400 Bad Request`` response being sent to the +client. Checking CSRF Tokens with a View Predicate ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/pyramid/config/security.py b/pyramid/config/security.py index 81549cbfc..e387eade9 100644 --- a/pyramid/config/security.py +++ b/pyramid/config/security.py @@ -1,11 +1,15 @@ +from zope.interface import implementer + from pyramid.interfaces import ( IAuthorizationPolicy, IAuthenticationPolicy, + IDefaultCSRFOptions, IDefaultPermission, PHASE1_CONFIG, PHASE2_CONFIG, ) +from pyramid.config.util import as_sorted_tuple from pyramid.exceptions import ConfigurationError from pyramid.util import action_method @@ -138,7 +142,6 @@ class SecurityConfiguratorMixin(object): self.action(IDefaultPermission, register, order=PHASE1_CONFIG, introspectables=(intr, perm_intr,)) - def add_permission(self, permission_name): """ A configurator directive which registers a free-standing @@ -159,3 +162,55 @@ class SecurityConfiguratorMixin(object): intr['value'] = permission_name self.action(None, introspectables=(intr,)) + @action_method + def set_default_csrf_options( + self, + require_csrf=True, + token='csrf_token', + header='X-CSRF-Token', + safe_methods=('GET', 'HEAD', 'OPTIONS', 'TRACE'), + ): + """ + Set the default CSRF options used by subsequent view registrations. + + ``require_csrf`` controls whether CSRF checks will be automatically + enabled on each view in the application. This value is used as the + fallback when ``require_csrf`` is left at the default of ``None`` on + :meth:`pyramid.config.Configurator.add_view`. + + ``token`` is the name of the CSRF token used in the body of the + request, accessed via ``request.POST[token]``. Default: ``csrf_token``. + + ``header`` is the name of the header containing the CSRF token, + accessed via ``request.headers[header]``. Default: ``X-CSRF-Token``. + + If ``token`` or ``header`` are set to ``None`` they will not be used + for checking CSRF tokens. + + ``safe_methods`` is an iterable of HTTP methods which are expected to + not contain side-effects as defined by RFC2616. Safe methods will + never be automatically checked for CSRF tokens. + Default: ``('GET', 'HEAD', 'OPTIONS', TRACE')``. + + """ + options = DefaultCSRFOptions(require_csrf, token, header, safe_methods) + def register(): + self.registry.registerUtility(options, IDefaultCSRFOptions) + intr = self.introspectable('default csrf view options', + None, + options, + 'default csrf view options') + intr['require_csrf'] = require_csrf + intr['token'] = token + intr['header'] = header + intr['safe_methods'] = as_sorted_tuple(safe_methods) + self.action(IDefaultCSRFOptions, register, order=PHASE1_CONFIG, + introspectables=(intr,)) + +@implementer(IDefaultCSRFOptions) +class DefaultCSRFOptions(object): + def __init__(self, require_csrf, token, header, safe_methods): + self.require_csrf = require_csrf + self.token = token + self.header = header + self.safe_methods = frozenset(safe_methods) diff --git a/pyramid/config/views.py b/pyramid/config/views.py index 6fe31fd4a..34f289fcc 100644 --- a/pyramid/config/views.py +++ b/pyramid/config/views.py @@ -371,24 +371,24 @@ class ViewsConfiguratorMixin(object): .. versionadded:: 1.7 - CSRF checks only affect POST requests. Any other request methods - will pass untouched. This option is used in combination with the - ``pyramid.require_default_csrf`` setting to control which - request parameters are checked for CSRF tokens. - - This feature requires a configured :term:`session factory`. + A boolean option or ``None``. Default: ``None``. If this option is set to ``True`` then CSRF checks will be enabled - for POST requests to this view. The required token will be whatever - was specified by the ``pyramid.require_default_csrf`` setting, or - will fallback to ``csrf_token``. + for requests to this view. The required token or header default to + ``csrf_token`` and ``X-CSRF-Token``, respectively. - If this option is set to a string then CSRF checks will be enabled - and it will be used as the required token regardless of the - ``pyramid.require_default_csrf`` setting. + CSRF checks only affect "unsafe" methods as defined by RFC2616. By + default, these methods are anything except + ``GET``, ``HEAD``, ``OPTIONS``, and ``TRACE``. + + The defaults here may be overridden by + :meth:`pyramid.config.Configurator.set_default_csrf_options`. + + This feature requires a configured :term:`session factory`. If this option is set to ``False`` then CSRF checks will be disabled - regardless of the ``pyramid.require_default_csrf`` setting. + regardless of the default ``require_csrf`` setting passed + to ``set_default_csrf_options``. See :ref:`auto_csrf_checking` for more information. @@ -1229,7 +1229,6 @@ class ViewsConfiguratorMixin(object): d = pyramid.viewderivers derivers = [ ('secured_view', d.secured_view), - ('csrf_view', d.csrf_view), ('owrapped_view', d.owrapped_view), ('http_cached_view', d.http_cached_view), ('decorated_view', d.decorated_view), @@ -1246,6 +1245,16 @@ class ViewsConfiguratorMixin(object): ) last = name + # leave the csrf_view loosely coupled to the rest of the pipeline + # by ensuring nothing in the default pipeline depends on the order + # of the csrf_view + self.add_view_deriver( + d.csrf_view, + 'csrf_view', + under='secured_view', + over='owrapped_view', + ) + def derive_view(self, view, attr=None, renderer=None): """ Create a :term:`view callable` using the function, instance, diff --git a/pyramid/interfaces.py b/pyramid/interfaces.py index 2b00752cf..c03afbd39 100644 --- a/pyramid/interfaces.py +++ b/pyramid/interfaces.py @@ -916,6 +916,16 @@ class IDefaultPermission(Interface): for all view configurations which do not explicitly declare their own.""" +class IDefaultCSRFOptions(Interface): + """ An object representing the default CSRF settings to be used for + all view configurations which do not explicitly declare their own.""" + require_csrf = Attribute( + 'Boolean attribute. If ``True``, then CSRF checks will be enabled by ' + 'default for the view unless overridden.') + token = Attribute('The key to be matched in the body of the request.') + header = Attribute('The header to be matched with the CSRF token.') + safe_methods = Attribute('A set of safe methods that skip CSRF checks.') + class ISessionFactory(Interface): """ An interface representing a factory which accepts a request object and returns an ISession object """ diff --git a/pyramid/session.py b/pyramid/session.py index 811c81fb4..a3cbe5172 100644 --- a/pyramid/session.py +++ b/pyramid/session.py @@ -109,7 +109,6 @@ def signed_deserialize(serialized, secret, hmac=hmac): return pickle.loads(pickled) - def check_csrf_origin(request, trusted_origins=None, raises=True): """ Check the Origin of the request to see if it is a cross site request or @@ -233,16 +232,18 @@ def check_csrf_token(request, considered valid. It must be passed in either the request body or a header. """ + supplied_token = "" # If this is a POST/PUT/etc request, then we'll check the body to see if it # has a token. We explicitly use request.POST here because CSRF tokens # should never appear in an URL as doing so is a security issue. We also # explicitly check for request.POST here as we do not support sending form # encoded data over anything but a request.POST. - supplied_token = request.POST.get(token, "") + if token is not None: + supplied_token = request.POST.get(token, "") # If we were unable to locate a CSRF token in a request body, then we'll # check to see if there are any headers that have a value for us. - if supplied_token == "": + if supplied_token == "" and header is not None: supplied_token = request.headers.get(header, "") expected_token = request.session.get_csrf_token() diff --git a/pyramid/tests/test_config/test_security.py b/pyramid/tests/test_config/test_security.py index 817f6ce02..e461bfd4a 100644 --- a/pyramid/tests/test_config/test_security.py +++ b/pyramid/tests/test_config/test_security.py @@ -98,3 +98,24 @@ class ConfiguratorSecurityMethodsTests(unittest.TestCase): 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']) + + def test_changing_set_default_csrf_options(self): + from pyramid.interfaces import IDefaultCSRFOptions + config = self._makeOne(autocommit=True) + config.set_default_csrf_options( + require_csrf=False, token='DUMMY', header=None, safe_methods=('PUT',)) + 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']) diff --git a/pyramid/tests/test_viewderivers.py b/pyramid/tests/test_viewderivers.py index 4a7a04197..e84863d69 100644 --- a/pyramid/tests/test_viewderivers.py +++ b/pyramid/tests/test_viewderivers.py @@ -1090,45 +1090,52 @@ class TestDeriveView(unittest.TestCase): self.assertRaises(ConfigurationError, self.config._derive_view, view, http_cache=(None,)) - def test_csrf_view_requires_bool_or_str_in_require_csrf(self): - def view(request): pass - try: - self.config._derive_view(view, require_csrf=object()) - except ConfigurationError as ex: - self.assertEqual( - 'View option "require_csrf" must be a string or boolean value', - ex.args[0]) - else: # pragma: no cover - raise AssertionError + 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_requires_bool_or_str_in_config_setting(self): - def view(request): pass - self.config.add_settings({'pyramid.require_default_csrf': object()}) - try: - self.config._derive_view(view) - except ConfigurationError as ex: - self.assertEqual( - 'Config setting "pyramid.require_default_csrf" must be a ' - 'string or boolean value', - ex.args[0]) - else: # pragma: no cover - raise AssertionError + def test_csrf_view_fails_with_bad_POST_header(self): + from pyramid.exceptions import BadCSRFToken + def inner_view(request): 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_requires_header(self): + 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.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_requires_param(self): + def test_csrf_view_fails_with_bad_POST_token(self): + from pyramid.exceptions import BadCSRFToken + def inner_view(request): 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 @@ -1136,8 +1143,8 @@ class TestDeriveView(unittest.TestCase): request.scheme = "http" request.method = 'POST' request.session = DummySession({'csrf_token': 'foo'}) - request.POST = {'DUMMY': 'foo'} - view = self.config._derive_view(inner_view, require_csrf='DUMMY') + request.POST = {'csrf_token': 'foo'} + view = self.config._derive_view(inner_view, require_csrf=True) result = view(None, request) self.assertTrue(result is response) @@ -1152,54 +1159,20 @@ class TestDeriveView(unittest.TestCase): request.referrer = "https://example.com/login/" request.method = 'POST' request.session = DummySession({'csrf_token': 'foo'}) - request.POST = {'DUMMY': 'foo'} - view = self.config._derive_view(inner_view, require_csrf='DUMMY') - result = view(None, request) - self.assertTrue(result is response) - - def test_csrf_view_ignores_GET(self): - response = DummyResponse() - def inner_view(request): - return response - request = self._makeRequest() - request.method = 'GET' + 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_POST_param(self): - from pyramid.exceptions import BadCSRFToken - def inner_view(request): pass - request = self._makeRequest() - request.scheme = "http" - request.method = 'POST' - request.session = DummySession({'csrf_token': 'foo'}) - request.POST = {'DUMMY': 'bar'} - view = self.config._derive_view(inner_view, require_csrf='DUMMY') - self.assertRaises(BadCSRFToken, lambda: view(None, request)) - - def test_csrf_view_fails_on_bad_POST_header(self): - from pyramid.exceptions import BadCSRFToken - def inner_view(request): pass - request = self._makeRequest() - request.scheme = "http" - request.method = 'POST' - request.POST = {} - request.session = DummySession({'csrf_token': 'foo'}) - request.headers = {'X-CSRF-Token': 'bar'} - view = self.config._derive_view(inner_view, require_csrf='DUMMY') - self.assertRaises(BadCSRFToken, lambda: view(None, request)) - def test_csrf_view_fails_on_bad_PUT_header(self): from pyramid.exceptions import BadCSRFToken def inner_view(request): pass request = self._makeRequest() request.scheme = "http" request.method = 'PUT' - request.POST = {} request.session = DummySession({'csrf_token': 'foo'}) request.headers = {'X-CSRF-Token': 'bar'} - view = self.config._derive_view(inner_view, require_csrf='DUMMY') + 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): @@ -1212,7 +1185,7 @@ class TestDeriveView(unittest.TestCase): request.domain = "example.com" request.referrer = "https://not-example.com/evil/" request.registry.settings = {} - view = self.config._derive_view(inner_view, require_csrf='DUMMY') + 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): @@ -1225,24 +1198,21 @@ class TestDeriveView(unittest.TestCase): request.domain = "example.com" request.headers = {"Origin": "https://not-example.com/evil/"} request.registry.settings = {} - view = self.config._derive_view(inner_view, require_csrf='DUMMY') + view = self.config._derive_view(inner_view, require_csrf=True) self.assertRaises(BadCSRFOrigin, lambda: view(None, request)) - def test_csrf_view_uses_config_setting_truthy(self): - response = DummyResponse() - def inner_view(request): - return response + def test_csrf_view_enabled_by_default(self): + from pyramid.exceptions import BadCSRFToken + def inner_view(request): pass request = self._makeRequest() request.scheme = "http" request.method = 'POST' request.session = DummySession({'csrf_token': 'foo'}) - request.POST = {'csrf_token': 'foo'} - self.config.add_settings({'pyramid.require_default_csrf': 'yes'}) + self.config.set_default_csrf_options(require_csrf=True) view = self.config._derive_view(inner_view) - result = view(None, request) - self.assertTrue(result is response) + self.assertRaises(BadCSRFToken, lambda: view(None, request)) - def test_csrf_view_uses_config_setting_with_custom_token(self): + def test_csrf_view_uses_custom_csrf_token(self): response = DummyResponse() def inner_view(request): return response @@ -1251,39 +1221,40 @@ class TestDeriveView(unittest.TestCase): request.method = 'POST' request.session = DummySession({'csrf_token': 'foo'}) request.POST = {'DUMMY': 'foo'} - self.config.add_settings({'pyramid.require_default_csrf': 'DUMMY'}) + 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_config_setting_falsey(self): + 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.params['csrf_token'] = 'foo' - self.config.add_settings({'pyramid.require_default_csrf': 'no'}) + 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_view_option_override(self): + def test_csrf_view_uses_custom_methods(self): response = DummyResponse() def inner_view(request): return response request = self._makeRequest() request.scheme = "http" - request.method = 'POST' + request.method = 'PUT' request.session = DummySession({'csrf_token': 'foo'}) - request.POST = {'DUMMY': 'foo'} - self.config.add_settings({'pyramid.require_default_csrf': 'yes'}) - view = self.config._derive_view(inner_view, require_csrf='DUMMY') + 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_config_setting_when_view_option_is_true(self): + def test_csrf_view_uses_view_option_override(self): response = DummyResponse() def inner_view(request): return response @@ -1291,9 +1262,9 @@ class TestDeriveView(unittest.TestCase): request.scheme = "http" request.method = 'POST' request.session = DummySession({'csrf_token': 'foo'}) - request.POST = {'DUMMY': 'foo'} - self.config.add_settings({'pyramid.require_default_csrf': 'DUMMY'}) - view = self.config._derive_view(inner_view, require_csrf=True) + 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) @@ -1303,7 +1274,7 @@ class TestDeriveView(unittest.TestCase): raise ValueError def excview(request): return 'hello' - self.config.add_settings({'pyramid.require_default_csrf': 'yes'}) + 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) @@ -1320,7 +1291,7 @@ class TestDeriveView(unittest.TestCase): def view(request): raise ValueError def excview(request): pass - self.config.add_settings({'pyramid.require_default_csrf': 'yes'}) + 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) @@ -1342,7 +1313,7 @@ class TestDeriveView(unittest.TestCase): raise ValueError def excview(request): return 'hello' - self.config.add_settings({'pyramid.require_default_csrf': 'yes'}) + 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) @@ -1675,6 +1646,7 @@ class DummyRequest: environ = {} self.environ = environ self.params = {} + self.POST = {} self.cookies = {} self.headers = {} self.response = DummyResponse() diff --git a/pyramid/viewderivers.py b/pyramid/viewderivers.py index fbe7cd660..1b922b89e 100644 --- a/pyramid/viewderivers.py +++ b/pyramid/viewderivers.py @@ -15,6 +15,7 @@ from pyramid.response import Response from pyramid.interfaces import ( IAuthenticationPolicy, IAuthorizationPolicy, + IDefaultCSRFOptions, IDebugLogger, IResponse, IViewMapper, @@ -22,7 +23,6 @@ from pyramid.interfaces import ( ) from pyramid.compat import ( - string_types, is_bound_method, is_unbound_method, ) @@ -38,10 +38,6 @@ from pyramid.exceptions import ( PredicateMismatch, ) from pyramid.httpexceptions import HTTPForbidden -from pyramid.settings import ( - falsey, - truthy, -) from pyramid.util import object_description from pyramid.view import render_view_to_response from pyramid import renderers @@ -464,40 +460,30 @@ def decorated_view(view, info): decorated_view.options = ('decorator',) -def _parse_csrf_setting(val, error_source): - if val: - if isinstance(val, string_types): - if val.lower() in truthy: - val = True - elif val.lower() in falsey: - val = False - elif not isinstance(val, bool): - raise ConfigurationError( - '{0} must be a string or boolean value' - .format(error_source)) - return val - -SAFE_REQUEST_METHODS = frozenset(["GET", "HEAD", "OPTIONS", "TRACE"]) - def csrf_view(view, info): - default_val = _parse_csrf_setting( - info.settings.get('pyramid.require_default_csrf'), - 'Config setting "pyramid.require_default_csrf"') - explicit_val = _parse_csrf_setting( - info.options.get('require_csrf'), - 'View option "require_csrf"') - resolved_val = explicit_val - if (explicit_val is True and default_val) or explicit_val is None: - resolved_val = default_val - if resolved_val is True: - resolved_val = 'csrf_token' + explicit_val = info.options.get('require_csrf') + defaults = info.registry.queryUtility(IDefaultCSRFOptions) + if defaults is None: + default_val = False + token = 'csrf_token' + header = 'X-CSRF-Token' + safe_methods = frozenset(["GET", "HEAD", "OPTIONS", "TRACE"]) + else: + default_val = defaults.require_csrf + token = defaults.token + header = defaults.header + safe_methods = defaults.safe_methods + enabled = ( + explicit_val is True or + (explicit_val is not False and default_val) + ) + # disable if both header and token are disabled + enabled = enabled and (token or header) wrapped_view = view - if resolved_val: + if enabled: def csrf_view(context, request): - # Assume that anything not defined as 'safe' by RFC2616 needs - # protection if ( - request.method not in SAFE_REQUEST_METHODS and + request.method not in safe_methods and ( # skip exception views unless value is explicitly defined getattr(request, 'exception', None) is None or @@ -505,7 +491,7 @@ def csrf_view(view, info): ) ): check_csrf_origin(request, raises=True) - check_csrf_token(request, resolved_val, raises=True) + check_csrf_token(request, token, header, raises=True) return view(context, request) wrapped_view = csrf_view return wrapped_view -- cgit v1.2.3 From 4e6f989169bff51348718fa398af10cdad83cd68 Mon Sep 17 00:00:00 2001 From: Christoph Zwerschke Date: Tue, 19 Apr 2016 21:45:48 +0200 Subject: Make tests pass under Windows --- pyramid/tests/test_config/test_views.py | 2 +- pyramid/tests/test_scripts/test_proutes.py | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/pyramid/tests/test_config/test_views.py b/pyramid/tests/test_config/test_views.py index 21ed24f44..878574e88 100644 --- a/pyramid/tests/test_config/test_views.py +++ b/pyramid/tests/test_config/test_views.py @@ -3093,7 +3093,7 @@ class TestStaticURLInfo(unittest.TestCase): inst = self._makeOne() cb = DummyCacheBuster('foo') inst.add_cache_buster(config, here, cb) - self.assertEqual(inst.cache_busters, [(here + '/', cb, False)]) + self.assertEqual(inst.cache_busters, [(here + os.sep, cb, False)]) def test_add_cachebuster_overwrite(self): config = DummyConfig() diff --git a/pyramid/tests/test_scripts/test_proutes.py b/pyramid/tests/test_scripts/test_proutes.py index e426eee73..876572b01 100644 --- a/pyramid/tests/test_scripts/test_proutes.py +++ b/pyramid/tests/test_scripts/test_proutes.py @@ -1,3 +1,4 @@ +import os import unittest from pyramid.tests.test_scripts import dummy @@ -396,7 +397,8 @@ class TestPRoutesCommand(unittest.TestCase): from pyramid.renderers import null_renderer as nr config = self._makeConfig(autocommit=True) config.add_static_view('static', 'static', cache_max_age=3600) - config.add_static_view(name='static2', path='/var/www/static') + 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' @@ -413,7 +415,7 @@ class TestPRoutesCommand(unittest.TestCase): expected = [ ['__static/', '/static/*subpath', 'pyramid.tests.test_scripts:static/', '*'], - ['__static2/', '/static2/*subpath', '/var/www/static/', '*'], + ['__static2/', '/static2/*subpath', path2 + os.sep, '*'], ['__pyramid_scaffold/', '/pyramid_scaffold/*subpath', 'pyramid:scaffolds/starter/+package+/static/', '*'], ] -- cgit v1.2.3 From 947aca9cf28477c4ebb45e319ee2eaa638d4e0d9 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Tue, 19 Apr 2016 20:20:17 -0500 Subject: remove vestiges of pyramid.require_default_csrf --- pyramid/config/settings.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pyramid/config/settings.py b/pyramid/config/settings.py index 9e5c3b62d..f9dbd752e 100644 --- a/pyramid/config/settings.py +++ b/pyramid/config/settings.py @@ -122,8 +122,6 @@ class Settings(dict): config_prevent_cachebust) eff_prevent_cachebust = asbool(eget('PYRAMID_PREVENT_CACHEBUST', config_prevent_cachebust)) - require_default_csrf = self.get('pyramid.require_default_csrf') - eff_require_default_csrf = require_default_csrf csrf_trusted_origins = self.get("pyramid.csrf_trusted_origins", []) eff_csrf_trusted_origins = csrf_trusted_origins @@ -138,7 +136,6 @@ class Settings(dict): 'default_locale_name':eff_locale_name, 'prevent_http_cache':eff_prevent_http_cache, 'prevent_cachebust':eff_prevent_cachebust, - 'require_default_csrf':eff_require_default_csrf, 'csrf_trusted_origins':eff_csrf_trusted_origins, 'pyramid.debug_authorization': eff_debug_all or eff_debug_auth, @@ -151,7 +148,6 @@ class Settings(dict): 'pyramid.default_locale_name':eff_locale_name, 'pyramid.prevent_http_cache':eff_prevent_http_cache, 'pyramid.prevent_cachebust':eff_prevent_cachebust, - 'pyramid.require_default_csrf':eff_require_default_csrf, 'pyramid.csrf_trusted_origins':eff_csrf_trusted_origins, } -- cgit v1.2.3 From 564c396522113ba31cf1c0c81c4497aa6ba5d704 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Tue, 19 Apr 2016 20:49:17 -0500 Subject: test appveyor.yml --- appveyor.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 appveyor.yml diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 000000000..1350507b2 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,12 @@ +environment: + matrix: + - PYTHON: "C:\\Python35" + TOXENV: "py35" + +install: + - "%PYTHON%\\python.exe -m pip install tox" + +build: off + +test_script: + - "%PYTHON%\\Scripts\\tox.exe" -- cgit v1.2.3 From 0b09a81bf50029c3b1a4cc61f6fd88ba65b9afc6 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Tue, 19 Apr 2016 22:01:16 -0500 Subject: drop unsupported test endpoints --- scaffoldtests.sh | 2 +- tox.ini | 14 +------------- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/scaffoldtests.sh b/scaffoldtests.sh index 34c303797..84fd8e072 100755 --- a/scaffoldtests.sh +++ b/scaffoldtests.sh @@ -1,3 +1,3 @@ #!/bin/bash -tox -e{py26,py27,py32,py33,py34,pypy,pypy3}-scaffolds, +tox -e{py27,py33,py34,pypy}-scaffolds, diff --git a/tox.ini b/tox.ini index d29f41662..258b2892c 100644 --- a/tox.ini +++ b/tox.ini @@ -27,14 +27,8 @@ commands = python pyramid/scaffolds/tests.py deps = virtualenv -[testenv:py32-scaffolds] -basepython = python3.2 -commands = - python pyramid/scaffolds/tests.py -deps = virtualenv - [testenv:py33-scaffolds] -basepython = python3.4 +basepython = python3.3 commands = python pyramid/scaffolds/tests.py deps = virtualenv @@ -51,12 +45,6 @@ commands = python pyramid/scaffolds/tests.py deps = virtualenv -[testenv:pypy3-scaffolds] -basepython = pypy3 -commands = - python pyramid/scaffolds/tests.py -deps = virtualenv - [testenv:pep8] basepython = python3.5 commands = -- cgit v1.2.3 From 13522a677e2700c84a10709fd758f379110780f8 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 19 Apr 2016 23:42:18 -0700 Subject: Fix what's new links in templates with "-branch" in RELEASING.txt --- RELEASING.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/RELEASING.txt b/RELEASING.txt index e50adb52b..78fd98f52 100644 --- a/RELEASING.txt +++ b/RELEASING.txt @@ -129,7 +129,7 @@ PyPI https://pypi.python.org/pypi/pyramid/1.x What's New -http://docs.pylonsproject.org/projects/pyramid/1.X/whatsnew-1.X.html +http://docs.pylonsproject.org/projects/pyramid/1.X-branch/whatsnew-1.X.html Issues https://github.com/Pylons/pyramid/issues @@ -145,11 +145,11 @@ Here are the changes: <> A "What's New In Pyramid 1.X" document exists at -http://docs.pylonsproject.org/projects/pyramid/1.X/whatsnew-1.X.html . +http://docs.pylonsproject.org/projects/pyramid/1.X-branch/whatsnew-1.X.html . You will be able to see the 1.X release documentation (across all alphas and betas, as well as when it eventually gets to final release) -at http://docs.pylonsproject.org/projects/pyramid/1.X/ . +at http://docs.pylonsproject.org/projects/pyramid/1.X-branch/ . You can install it via PyPI: -- cgit v1.2.3 From fc47a49587f1af6ea0db0804be2d984042486cd2 Mon Sep 17 00:00:00 2001 From: int3l Date: Sat, 23 Apr 2016 03:24:29 +0300 Subject: import/docstring adjustments in decorator module --- pyramid/decorator.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/pyramid/decorator.py b/pyramid/decorator.py index df30c5e10..890bd3461 100644 --- a/pyramid/decorator.py +++ b/pyramid/decorator.py @@ -1,4 +1,4 @@ -import functools +from functools import update_wrapper class reify(object): @@ -19,17 +19,22 @@ class reify(object): And usage of Foo: >>> f = Foo() - >>> v = f.jammy + >>> print(f.jammy) 'jammy called' - >>> print(v) 1 - >>> f.jammy + >>> print(f.jammy) 1 >>> # jammy func not called the second time; it replaced itself with 1 + + Note: reassignment is possible + + >>> f.jammy = 2 + >>> f.jammy + 2 """ def __init__(self, wrapped): self.wrapped = wrapped - functools.update_wrapper(self, wrapped) + update_wrapper(self, wrapped) def __get__(self, inst, objtype=None): if inst is None: -- cgit v1.2.3 From 4509b306114d8de13e1b90d46829286f7dbb30f3 Mon Sep 17 00:00:00 2001 From: int3l Date: Sat, 23 Apr 2016 11:57:21 +0300 Subject: adjustment and update docstring to be consistant --- pyramid/decorator.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/pyramid/decorator.py b/pyramid/decorator.py index 890bd3461..72c8b3800 100644 --- a/pyramid/decorator.py +++ b/pyramid/decorator.py @@ -19,15 +19,14 @@ class reify(object): And usage of Foo: >>> f = Foo() - >>> print(f.jammy) + >>> v = f.jammy 'jammy called' + >>> print(v) 1 - >>> print(f.jammy) + >>> f.jammy 1 >>> # jammy func not called the second time; it replaced itself with 1 - - Note: reassignment is possible - + >>> # Note: reassignment is possible >>> f.jammy = 2 >>> f.jammy 2 -- cgit v1.2.3 From 1cb30e690a7ba97db212e7ec9002fd83f950b0bd Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 23 Apr 2016 02:45:04 -0700 Subject: Fix all the stinky linkie rot via `make linkcheck SPHINXBUILD=$VENV/bin/sphinx-build`, but don't bother with HISTORY.txt or whatsnew-xx --- docs/conventions.rst | 2 +- docs/copyright.rst | 8 +-- docs/designdefense.rst | 43 ++++++++------- docs/glossary.rst | 98 +++++++++++++++++------------------ docs/index.rst | 12 +++-- docs/narr/firstapp.rst | 2 +- docs/narr/i18n.rst | 4 +- docs/narr/install.rst | 4 +- docs/narr/introduction.rst | 12 ++--- docs/narr/logging.rst | 3 +- docs/narr/muchadoabouttraversal.rst | 4 +- docs/narr/project.rst | 40 +++++++------- docs/narr/renderers.rst | 2 +- docs/narr/templates.rst | 2 +- docs/narr/upgrading.rst | 8 +-- docs/narr/urldispatch.rst | 7 +-- docs/narr/webob.rst | 6 +-- docs/tutorials/modwsgi/index.rst | 15 +++--- docs/tutorials/wiki/distributing.rst | 4 +- docs/tutorials/wiki2/distributing.rst | 6 +-- pyramid/renderers.py | 2 +- 21 files changed, 144 insertions(+), 140 deletions(-) diff --git a/docs/conventions.rst b/docs/conventions.rst index 4469d0c73..0f5daf106 100644 --- a/docs/conventions.rst +++ b/docs/conventions.rst @@ -35,7 +35,7 @@ References to glossary terms are presented using the following style: URLs are presented using the following style: - `Pylons `_ + `Pylons `_ References to sections and chapters are presented using the following style: diff --git a/docs/copyright.rst b/docs/copyright.rst index 3beaee7f7..9532c15b7 100644 --- a/docs/copyright.rst +++ b/docs/copyright.rst @@ -63,7 +63,7 @@ Contributors: GitHub. Cover Designer: - Hugues Laflamme of `Kemeneur `_. + Hugues Laflamme of Kemeneur. Used with permission: @@ -80,8 +80,8 @@ Print Production ---------------- The print version of this book was produced using the `Sphinx -`_ documentation generation system and the -`LaTeX `_ typesetting system. +`_ documentation generation system and +the `LaTeX `_ typesetting system. Contacting The Publisher ------------------------ @@ -90,7 +90,7 @@ Please send documentation licensing inquiries, translation inquiries, and other business communications to `Agendaless Consulting `_. Please send software and other technical queries to the `Pylons-devel mailing list -`_. +`_. HTML Version and Source Code ---------------------------- diff --git a/docs/designdefense.rst b/docs/designdefense.rst index 5f3295305..3c1046b82 100644 --- a/docs/designdefense.rst +++ b/docs/designdefense.rst @@ -131,7 +131,7 @@ obvious. First, what's a "utility"? Well, for the purposes of this discussion, and for the purpose of the code above, it's just not very important. If you really want to know, you can read `this -`_. However, still, readers +`_. However, still, readers of such code need to understand the concept in order to parse it. This is problem number one. @@ -665,7 +665,7 @@ desktop GUI platforms by using similar terminology, and to provide some frame of reference for how various components in the common web framework might hang together. But in the opinion of the author, "MVC" doesn't match the web very well in general. Quoting from the `Model-View-Controller Wikipedia entry -`_: +`_: Though MVC comes in different flavors, control flow is generally as follows: @@ -847,9 +847,9 @@ Challenge +++++++++ :app:`Pyramid` performs automatic authorization checks only at :term:`view` -execution time. Zope 3 wraps context objects with a `security proxy -`_, which causes Zope 3 also -to do security checks during attribute access. I like this, because it means: +execution time. Zope 3 wraps context objects with a security proxy, which +causes Zope 3 also to do security checks during attribute access. I like this, +because it means: #) When I use the security proxy machinery, I can have a view that conditionally displays certain HTML elements (like form fields) or @@ -1006,16 +1006,18 @@ the following: Microframeworks have smaller Hello World programs ------------------------------------------------- -Self-described "microframeworks" exist. `Bottle `_ and -`Flask `_ are two that are becoming popular. `Bobo -`_ doesn't describe itself as a microframework, but -its intended user base is much the same. Many others exist. We've even (only as -a teaching tool, not as any sort of official project) `created one using -Pyramid `_. The videos use BFG, -a precursor to Pyramid, but the resulting code is `available for Pyramid too -`_). Microframeworks are small frameworks -with one common feature: each allows its users to create a fully functional -application that lives in a single Python file. +Self-described "microframeworks" exist. `Bottle +`_ and `Flask +`_ are two that are becoming popular. `Bobo +`_ doesn't describe itself as a +microframework, but its intended user base is much the same. Many others exist. +We've even (only as a teaching tool, not as any sort of official project) +`created one using Pyramid `_. +The videos use BFG, a precursor to Pyramid, but the resulting code is +`available for Pyramid too `_). +Microframeworks are small frameworks with one common feature: each allows its +users to create a fully functional application that lives in a single Python +file. Some developers and microframework authors point out that Pyramid's "hello world" single-file program is longer (by about five lines) than the equivalent @@ -1430,9 +1432,9 @@ object which *is not logically global*: # this is executed if the request method was GET or the # credentials were invalid -The `Pylons 1.X `_ web framework uses a similar -strategy. It calls these things "Stacked Object Proxies", so, for purposes -of this discussion, I'll do so as well. +The `Pylons 1.X `_ +web framework uses a similar strategy. It calls these things "Stacked Object +Proxies", so, for purposes of this discussion, I'll do so as well. Import statements in Python (``import foo``, ``from bar import baz``) are most frequently performed to obtain a reference to an object defined globally @@ -1701,5 +1703,6 @@ Other Challenges ---------------- Other challenges are encouraged to be sent to the `Pylons-devel -`_ maillist. We'll try to address -them by considering a design change, or at very least via exposition here. +`_ maillist. We'll try +to address them by considering a design change, or at very least via exposition +here. diff --git a/docs/glossary.rst b/docs/glossary.rst index 1d97bffe8..9b41b4359 100644 --- a/docs/glossary.rst +++ b/docs/glossary.rst @@ -36,7 +36,7 @@ Glossary Repoze "Repoze" is essentially a "brand" of software developed by `Agendaless - Consulting `_ and a set of contributors. The + Consulting `_ and a set of contributors. The term has no special intrinsic meaning. The project's `website `_ has more information. The software developed "under the brand" is available in a `Subversion repository @@ -51,7 +51,7 @@ Glossary You can use :term:`distribute` under Python 3 instead. distribute - `Distribute `_ is a fork of + `Distribute `_ is a fork of :term:`setuptools` which runs on both Python 2 and Python 3. pkg_resources @@ -321,18 +321,18 @@ Glossary :term:`principal` (or principals) associated with a request. WSGI - `Web Server Gateway Interface `_. This is a - Python standard for connecting web applications to web servers, - similar to the concept of Java Servlets. :app:`Pyramid` requires - that your application be served as a WSGI application. + `Web Server Gateway Interface `_. + This is a Python standard for connecting web applications to web servers, + similar to the concept of Java Servlets. :app:`Pyramid` requires that + your application be served as a WSGI application. middleware *Middleware* is a :term:`WSGI` concept. It is a WSGI component that acts both as a server and an application. Interesting uses for middleware exist, such as caching, content-transport - encoding, and other functions. See `WSGI.org `_ - or `PyPI `_ to find middleware for your - application. + encoding, and other functions. See `WSGI.org + `_ or `PyPI + `_ to find middleware for your application. pipeline The :term:`PasteDeploy` term for a single configuration of a WSGI @@ -346,15 +346,15 @@ Glossary `A web framework based on Zope 3 `_. Django - `A full-featured Python web framework `_. + `A full-featured Python web framework `_. Pylons `A lightweight Python web framework `_ and a predecessor of Pyramid. ZODB - `Zope Object Database `_, a - persistent Python object store. + `Zope Object Database `_, a persistent + Python object store. WebOb `WebOb `_ is a WSGI request/response @@ -376,28 +376,27 @@ Glossary the box in ZPT and text flavors. ZPT - The `Zope Page Template `_ + The `Zope Page Template `_ templating language. METAL - `Macro Expansion for TAL `_, a - part of :term:`ZPT` which makes it possible to share common look - and feel between templates. + `Macro Expansion for TAL + `_, a + part of :term:`ZPT` which makes it possible to share common look and feel + between templates. Genshi - An `XML templating language `_ + An `XML templating language `_ by Christopher Lenz. Jinja2 - A `text templating language `_ by Armin - Ronacher. + A `text templating language `_ by Armin Ronacher. Routes - A `system by Ben Bangert `_ which - parses URLs and compares them against a number of user defined - mappings. The URL pattern matching syntax in :app:`Pyramid` is - inspired by the Routes syntax (which was inspired by Ruby On - Rails pattern syntax). + A `system by Ben Bangert `_ + which parses URLs and compares them against a number of user defined + mappings. The URL pattern matching syntax in :app:`Pyramid` is inspired by + the Routes syntax (which was inspired by Ruby On Rails pattern syntax). route A single pattern matched by the :term:`url dispatch` subsystem, @@ -416,7 +415,7 @@ Glossary Zope Component Architecture The `Zope Component Architecture - `_ (aka ZCA) is a system + `_ (aka ZCA) is a system which allows for application pluggability and complex dispatching based on objects which implement an :term:`interface`. :app:`Pyramid` uses the ZCA "under the hood" to perform view @@ -442,7 +441,7 @@ Glossary subpath. See :ref:`star_subpath` for more information. interface - A `Zope interface `_ + A `Zope interface `_ object. In :app:`Pyramid`, an interface may be attached to a :term:`resource` object or a :term:`request` object in order to identify that the object is "of a type". Interfaces are used @@ -488,13 +487,13 @@ Glossary repoze.catalog An indexing and search facility (fielded and full-text) based on - `zope.index `_. See `the + `zope.index `_. See `the documentation `_ for more information. repoze.who - `Authentication middleware `_ for - :term:`WSGI` applications. It can be used by :app:`Pyramid` to + `Authentication middleware `_ + for :term:`WSGI` applications. It can be used by :app:`Pyramid` to provide authentication information. repoze.workflow @@ -555,7 +554,7 @@ Glossary serialization format. jQuery - A popular `Javascript library `_. + A popular `Javascript library `_. renderer A serializer which converts non-:term:`Response` return values from a @@ -569,10 +568,10 @@ Glossary :ref:`adding_and_overriding_renderers` for more information. mod_wsgi - `mod_wsgi `_ is an Apache - module developed by Graham Dumpleton. It allows :term:`WSGI` - applications (such as applications developed using - :app:`Pyramid`) to be served using the Apache web server. + `mod_wsgi `_ is an Apache + module developed by Graham Dumpleton. It allows :term:`WSGI` applications + (such as applications developed using :app:`Pyramid`) to be served using + the Apache web server. view predicate An argument to a :term:`view configuration` which evaluates to @@ -609,7 +608,7 @@ Glossary .. seealso:: - See also `PEP 318 `_. + See also `PEP 318 `_. configuration declaration An individual method call made to a :term:`configuration directive`, @@ -683,7 +682,7 @@ Glossary thread local A thread-local variable is one which is essentially a global variable in terms of how it is accessed and treated, however, each `thread - `_ used by the + `_ used by the application may have a different value for this same "global" variable. :app:`Pyramid` uses a small number of thread local variables, as described in :ref:`threadlocals_chapter`. @@ -700,8 +699,8 @@ Glossary :ref:`multidict_narr` and :class:`pyramid.interfaces.IMultiDict`. PyPI - `The Python Package Index `_, a - collection of software available for Python. + `The Python Package Index `_, a collection + of software available for Python. Agendaless Consulting A consulting organization formed by Paul Everitt, Tres Seaver, @@ -709,14 +708,14 @@ Glossary .. seealso:: - See also `Agendaless Consulting `_. + See also `Agendaless Consulting `_. Jython A `Python implementation `_ written for the Java Virtual Machine. Python - The `programming language `_ in which + The `programming language `_ in which :app:`Pyramid` is written. CPython @@ -736,7 +735,7 @@ Glossary subsystems used by :app:`Pyramid`. Google App Engine - `Google App Engine `_ (aka + `Google App Engine `_ (aka "GAE") is a Python application hosting service offered by Google. :app:`Pyramid` runs on GAE. @@ -913,7 +912,7 @@ Glossary can be used as global application values. WebTest - `WebTest `_ is a package which can help + `WebTest `_ is a package which can help you write functional tests for your WSGI application. view mapper @@ -936,20 +935,19 @@ Glossary ZCML `Zope Configuration Markup Language - `_, an XML dialect + `_, an XML dialect used by Zope and :term:`pyramid_zcml` for configuration tasks. pyramid_handlers An add-on package which allows :app:`Pyramid` users to create classes that are analogues of Pylons 1 "controllers". See - http://docs.pylonsproject.org/projects/pyramid_handlers/dev/ . + http://docs.pylonsproject.org/projects/pyramid_handlers/en/latest/. pyramid_jinja2 :term:`Jinja2` templating system bindings for Pyramid, documented at - http://docs.pylonsproject.org/projects/pyramid_jinja2/dev/ . This - package also includes a scaffold named - ``pyramid_jinja2_starter``, which creates an application package based - on the Jinja2 templating system. + http://docs.pylonsproject.org/projects/pyramid_jinja2/en/latest/. This + package also includes a scaffold named ``pyramid_jinja2_starter``, which + creates an application package based on the Jinja2 templating system. Akhet `Akhet `_ is a @@ -965,7 +963,7 @@ Glossary distutils The standard system for packaging and distributing Python packages. See - http://docs.python.org/distutils/index.html for more information. + https://docs.python.org/2/distutils/index.html for more information. :term:`setuptools` is actually an *extension* of the Distutils. exception response @@ -1008,7 +1006,7 @@ Glossary used in production applications, because the logger can be configured to log to a file, to UNIX syslog, to the Windows Event Log, or even to email. See its `documentation - `_. + `_. console script A script written to the ``bin`` (on UNIX, or ``Scripts`` on Windows) diff --git a/docs/index.rst b/docs/index.rst index aecc26d2e..ad667684c 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -5,7 +5,7 @@ The Pyramid Web Framework ========================= :app:`Pyramid` is a small, fast, down-to-earth Python web framework. It is -developed as part of the `Pylons Project `_. +developed as part of the `Pylons Project `_. It is licensed under a `BSD-like license `_. Here is one of the simplest :app:`Pyramid` applications you can make: @@ -70,15 +70,17 @@ platforms. Support and Development ======================= -The `Pylons Project web site `_ is the main online -source of :app:`Pyramid` support and development information. +The `Pylons Project web site `_ is the main +online source of :app:`Pyramid` support and development information. To report bugs, use the `issue tracker `_. If you've got questions that aren't answered by this documentation, contact the -`Pylons-discuss maillist `_ or -join the `#pyramid IRC channel `_. +`Pylons-discuss maillist +`_ or join the +`#pyramid IRC channel +`_. Browse and check out tagged and trunk versions of :app:`Pyramid` via the `Pyramid GitHub repository `_. To check out diff --git a/docs/narr/firstapp.rst b/docs/narr/firstapp.rst index 6a952dec9..a8491eabd 100644 --- a/docs/narr/firstapp.rst +++ b/docs/narr/firstapp.rst @@ -197,7 +197,7 @@ method returns a :term:`WSGI` application object that can be used by any WSGI server to present an application to a requestor. :term:`WSGI` is a protocol that allows servers to talk to Python applications. We don't discuss :term:`WSGI` in any depth within this book, but you can learn more about it by -visiting `wsgi.org `_. +reading its `documentation `_. The :app:`Pyramid` application object, in particular, is an instance of a class representing a :app:`Pyramid` :term:`router`. It has a reference to the diff --git a/docs/narr/i18n.rst b/docs/narr/i18n.rst index 014f314ad..131832aae 100644 --- a/docs/narr/i18n.rst +++ b/docs/narr/i18n.rst @@ -343,7 +343,7 @@ This will create a new message catalog ``.po`` file in ``myapplication/locale/es/LC_MESSAGES/myapplication.po``. Once the file is there, it can be worked on by a human translator. One tool -which may help with this is `Poedit `_. +which may help with this is `Poedit `_. Note that :app:`Pyramid` itself ignores the existence of all ``.po`` files. For a running application to have translations available, a ``.mo`` file must @@ -647,7 +647,7 @@ before being rendered: The features represented by attributes of the ``i18n`` namespace of Chameleon will also consult the :app:`Pyramid` translations. See -http://chameleon.readthedocs.org/en/latest/reference.html#id50. +http://chameleon.readthedocs.org/en/latest/reference.html#translation-i18n. .. note:: diff --git a/docs/narr/install.rst b/docs/narr/install.rst index 3e5523262..7d96f4074 100644 --- a/docs/narr/install.rst +++ b/docs/narr/install.rst @@ -90,7 +90,7 @@ If You Don't Yet Have a Python Interpreter (Windows) If your Windows system doesn't have a Python interpreter, you'll need to install it by downloading a Python 3.x-series interpreter executable from -`python.org's download section `_ (the files +`python.org's download section `_ (the files labeled "Windows Installer"). Once you've downloaded it, double click on the executable and accept the defaults during the installation process. You may also need to download and install the Python for Windows extensions. @@ -99,7 +99,7 @@ also need to download and install the Python for Windows extensions. Windows ` for full details. .. seealso:: Download and install the `Python for Windows extensions - `_. Carefully read + `_. Carefully read the README.txt file at the end of the list of builds, and follow its directions. Make sure you get the proper 32- or 64-bit build and Python version. diff --git a/docs/narr/introduction.rst b/docs/narr/introduction.rst index 24c9f6b93..d92916503 100644 --- a/docs/narr/introduction.rst +++ b/docs/narr/introduction.rst @@ -221,7 +221,7 @@ send email, let you use the Jinja2 templating system, let you use XML-RPC or JSON-RPC, let you integrate with jQuery Mobile, etc. Examples: -http://docs.pylonsproject.org/en/latest/docs/pyramid.html#pyramid-add-on-documentation +http://docs.pylonsproject.org/en/latest/docs/pyramid.html#pyramid-add-ons Class-based and function-based views ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -881,7 +881,7 @@ new-user-friendly. Example: Visit irc\://freenode.net#pyramid (the ``#pyramid`` channel on irc.freenode.net in an IRC client) or the pylons-discuss maillist at -http://groups.google.com/group/pylons-discuss/. +https://groups.google.com/forum/#!forum/pylons-discuss. Documentation ~~~~~~~~~~~~~ @@ -903,7 +903,7 @@ What Is The Pylons Project? :app:`Pyramid` is a member of the collection of software published under the Pylons Project. Pylons software is written by a loose-knit community of -contributors. The `Pylons Project website `_ +contributors. The `Pylons Project website `_ includes details about how :app:`Pyramid` relates to the Pylons Project. .. index:: @@ -967,9 +967,9 @@ nor discouraging the decision. Other Python web frameworks advertise themselves as members of a class of web frameworks named `model-view-controller -`_ frameworks. Insofar as -this term has been claimed to represent a class of web frameworks, -:app:`Pyramid` also generally fits into this class. +`_ +frameworks. Insofar as this term has been claimed to represent a class of web +frameworks, :app:`Pyramid` also generally fits into this class. .. sidebar:: You Say :app:`Pyramid` is MVC, but Where's the Controller? diff --git a/docs/narr/logging.rst b/docs/narr/logging.rst index 9c6e8a319..c7b4b9d6f 100644 --- a/docs/narr/logging.rst +++ b/docs/narr/logging.rst @@ -292,7 +292,8 @@ Logging Exceptions To log or email exceptions generated by your :app:`Pyramid` application, use the :term:`pyramid_exclog` package. Details about its configuration are in its -`documentation `_. +`documentation +`_. .. index:: single: TransLogger diff --git a/docs/narr/muchadoabouttraversal.rst b/docs/narr/muchadoabouttraversal.rst index 3e00a295a..02cd8ee3a 100644 --- a/docs/narr/muchadoabouttraversal.rst +++ b/docs/narr/muchadoabouttraversal.rst @@ -8,9 +8,7 @@ Much Ado About Traversal .. note:: - This chapter was adapted, with permission, from a blog post by `Rob Miller - `_, originally published at - http://blog.nonsequitarian.org/2010/much-ado-about-traversal/. + This chapter was adapted, with permission, from a blog post by Rob Miller. Traversal is an alternative to :term:`URL dispatch` which allows :app:`Pyramid` applications to map URLs to code. diff --git a/docs/narr/project.rst b/docs/narr/project.rst index 81fc9acf4..56247ee33 100644 --- a/docs/narr/project.rst +++ b/docs/narr/project.rst @@ -584,7 +584,7 @@ only (``127.0.0.1``). The sections after ``# logging configuration`` represent Python's standard library :mod:`logging` module configuration for your application. These sections are passed to the `logging module's config file configuration engine -`_ when the +`_ when the ``pserve`` or ``pshell`` commands are executed. The default configuration sends application logging output to the standard error output of your terminal. For more information about logging configuration, see :ref:`logging_chapter`. @@ -628,8 +628,8 @@ setup.py sdist``. Due to the information contained in the default ``MANIFEST.in``, an sdist of your Pyramid project will include ``.txt`` files, ``.ini`` files, ``.rst`` files, graphics files, and template files, as well as ``.py`` files. See -http://docs.python.org/distutils/sourcedist.html#the-manifest-in-template for -more information about the syntax and usage of ``MANIFEST.in``. +https://docs.python.org/2/distutils/sourcedist.html#the-manifest-in-template +for more information about the syntax and usage of ``MANIFEST.in``. Without the presence of a ``MANIFEST.in`` file or without checking your source code into a version control repository, ``setup.py sdist`` places only *Python @@ -647,8 +647,8 @@ files with extensions other than the files named in the project's ``MANIFEST.in`` and you don't make use of a setuptools-compatible version control system, you'll need to edit the ``MANIFEST.in`` file and include the statements necessary to include your new files. See -http://docs.python.org/distutils/sourcedist.html#principle for more information -about how to do this. +https://docs.python.org/2/distutils/sourcedist.html#principle for more +information about how to do this. You can also delete ``MANIFEST.in`` from your project and rely on a setuptools feature which simply causes all files checked into a version control system to @@ -697,21 +697,21 @@ Your application's name can be any string; it is specified in the ``name`` field. The version number is specified in the ``version`` value. A short description is provided in the ``description`` field. The ``long_description`` is conventionally the content of the ``README`` and ``CHANGES`` files appended -together. The ``classifiers`` field is a list of `Trove -`_ classifiers -describing your application. ``author`` and ``author_email`` are text fields -which probably don't need any description. ``url`` is a field that should -point at your application project's URL (if any). ``packages=find_packages()`` -causes all packages within the project to be found when packaging the -application. ``include_package_data`` will include non-Python files when the -application is packaged if those files are checked into version control. -``zip_safe=False`` indicates that this package is not safe to use as a zipped -egg; instead it will always unpack as a directory, which is more convenient. -``install_requires`` indicate that this package depends on the ``pyramid`` -package. ``extras_require`` is a Python dictionary that defines what is -required to be installed for running tests. We examined ``entry_points`` in our -discussion of the ``development.ini`` file; this file defines the ``main`` -entry point that represents our project's application. +together. The ``classifiers`` field is a list of `Trove classifiers +`_ describing your +application. ``author`` and ``author_email`` are text fields which probably +don't need any description. ``url`` is a field that should point at your +application project's URL (if any). ``packages=find_packages()`` causes all +packages within the project to be found when packaging the application. +``include_package_data`` will include non-Python files when the application is +packaged if those files are checked into version control. ``zip_safe=False`` +indicates that this package is not safe to use as a zipped egg; instead it will +always unpack as a directory, which is more convenient. ``install_requires`` +indicates that this package depends on the ``pyramid`` package. +``extras_require`` is a Python dictionary that defines what is required to be +installed for running tests. We examined ``entry_points`` in our discussion of +the ``development.ini`` file; this file defines the ``main`` entry point that +represents our project's application. Usually you only need to think about the contents of the ``setup.py`` file when distributing your application to other people, when adding Python package diff --git a/docs/narr/renderers.rst b/docs/narr/renderers.rst index 50e85813a..e06c78028 100644 --- a/docs/narr/renderers.rst +++ b/docs/narr/renderers.rst @@ -317,7 +317,7 @@ JSONP Renderer .. versionadded:: 1.1 :class:`pyramid.renderers.JSONP` is a `JSONP -`_ renderer factory helper which implements +`_ renderer factory helper which implements a hybrid JSON/JSONP renderer. JSONP is useful for making cross-domain AJAX requests. diff --git a/docs/narr/templates.rst b/docs/narr/templates.rst index 9e3a31845..6b3b5fcce 100644 --- a/docs/narr/templates.rst +++ b/docs/narr/templates.rst @@ -448,7 +448,7 @@ templating languages including the following: .. _pyramid_chameleon: http://docs.pylonsproject.org/projects/pyramid-chameleon/en/latest/ -.. _Jinja2: http://jinja.pocoo.org/docs/ +.. _Jinja2: http://jinja.pocoo.org/docs/dev/ .. _pyramid_jinja2: http://docs.pylonsproject.org/projects/pyramid-jinja2/en/latest/ diff --git a/docs/narr/upgrading.rst b/docs/narr/upgrading.rst index fcdce4f8d..21b696775 100644 --- a/docs/narr/upgrading.rst +++ b/docs/narr/upgrading.rst @@ -128,7 +128,8 @@ you can see DeprecationWarnings printed to the console when the tests run. The ``-Wd`` argument tells Python to print deprecation warnings to the console. See `the Python -W flag documentation -`_ for more information. +`_ for more +information. As your tests run, deprecation warnings will be printed to the console explaining the deprecation and providing instructions about how to prevent the @@ -215,9 +216,10 @@ around in your application interactively to try to generate them, and remediate as explained in :ref:`testing_under_new_release`. See `the PYTHONWARNINGS environment variable documentation -`_ or `the +`_ or `the Python -W flag documentation -`_ for more information. +`_ for more +information. Upgrading to the very latest Pyramid release -------------------------------------------- diff --git a/docs/narr/urldispatch.rst b/docs/narr/urldispatch.rst index c13558008..2472ace31 100644 --- a/docs/narr/urldispatch.rst +++ b/docs/narr/urldispatch.rst @@ -271,8 +271,9 @@ pattern like this: But this will either cause an error at startup time or it won't match properly. You'll want to use a Unicode value as the pattern instead rather than raw bytestring escapes. You can use a high-order Unicode value as the pattern by -using `Python source file encoding `_ -plus the "real" character in the Unicode pattern in the source, like so: +using `Python source file encoding +`_ plus the "real" character in the +Unicode pattern in the source, like so: .. code-block:: text @@ -1194,7 +1195,7 @@ If a predicate is a class, just add ``__text__`` property in a standard manner. __text__ = 'my custom class predicate' If a predicate is a method, you'll need to assign it after method declaration -(see `PEP 232 `_). +(see `PEP 232 `_). .. code-block:: python :linenos: diff --git a/docs/narr/webob.rst b/docs/narr/webob.rst index cfcf532bc..ce1586834 100644 --- a/docs/narr/webob.rst +++ b/docs/narr/webob.rst @@ -27,8 +27,8 @@ functionality to the standard WebOb request, which is documented in the :ref:`request_module` API documentation. WebOb provides objects for HTTP requests and responses. Specifically it does -this by wrapping the `WSGI `_ request environment and response -status, header list, and app_iter (body) values. +this by wrapping the `WSGI `_ request +environment and response status, header list, and app_iter (body) values. WebOb request and response objects provide many conveniences for parsing WSGI requests and forming WSGI responses. WebOb is a nice way to represent "raw" @@ -46,7 +46,7 @@ Request ~~~~~~~ The request object is a wrapper around the `WSGI environ dictionary -`_. This +`_. This dictionary contains keys for each header, keys that describe the request (including the path and query string), a file-like object for the request body, and a variety of custom keys. You can always access the environ with diff --git a/docs/tutorials/modwsgi/index.rst b/docs/tutorials/modwsgi/index.rst index 3cc182d13..7f5aac0a0 100644 --- a/docs/tutorials/modwsgi/index.rst +++ b/docs/tutorials/modwsgi/index.rst @@ -18,7 +18,7 @@ specific path information for commands and files. ``mod_wsgi``. If you have experience with :app:`Pyramid` and ``mod_wsgi`` on Windows systems, please help us document this experience by submitting documentation to the `Pylons-devel maillist - `_. + `_. #. The tutorial assumes you have Apache already installed on your system. If you do not, install Apache 2.X for your platform in @@ -29,7 +29,7 @@ specific path information for commands and files. #. Once you have Apache installed, install ``mod_wsgi``. Use the (excellent) `installation instructions - `_ + `_ for your platform into your system's Apache installation. #. Create a :term:`virtual environment` which we'll use to install our @@ -119,9 +119,8 @@ specific path information for commands and files. #. Visit ``http://localhost/myapp`` in a browser. You should see the sample application rendered in your browser. -:term:`mod_wsgi` has many knobs and a great variety of deployment -modes. This is just one representation of how you might use it to -serve up a :app:`Pyramid` application. See the `mod_wsgi -configuration documentation -`_ for -more in-depth configuration information. +:term:`mod_wsgi` has many knobs and a great variety of deployment modes. This +is just one representation of how you might use it to serve up a :app:`Pyramid` +application. See the `mod_wsgi configuration documentation +`_ +for more in-depth configuration information. diff --git a/docs/tutorials/wiki/distributing.rst b/docs/tutorials/wiki/distributing.rst index c3037f396..386b880e6 100644 --- a/docs/tutorials/wiki/distributing.rst +++ b/docs/tutorials/wiki/distributing.rst @@ -36,6 +36,6 @@ Note that this command creates a tarball in the "dist" subdirectory named ``tutorial-0.0.tar.gz``. You can send this file to your friends to show them your cool new application. They should be able to install it by pointing the ``pip install .`` command directly at it. Or you can upload it to `PyPI -`_ and share it with the rest of the world, where it -can be downloaded via ``pip install`` remotely like any other package people +`_ and share it with the rest of the world, where +it can be downloaded via ``pip install`` remotely like any other package people download from PyPI. diff --git a/docs/tutorials/wiki2/distributing.rst b/docs/tutorials/wiki2/distributing.rst index f264448b0..f38a733f4 100644 --- a/docs/tutorials/wiki2/distributing.rst +++ b/docs/tutorials/wiki2/distributing.rst @@ -35,6 +35,6 @@ Note that this command creates a tarball in the "dist" subdirectory named ``tutorial-0.0.tar.gz``. You can send this file to your friends to show them your cool new application. They should be able to install it by pointing the ``easy_install`` command directly at it. Or you can upload it to `PyPI -`_ and share it with the rest of the world, where it -can be downloaded via ``easy_install`` remotely like any other package people -download from PyPI. +`_ and share it with the rest of the world, where +it can be downloaded via ``easy_install`` remotely like any other package +people download from PyPI. diff --git a/pyramid/renderers.py b/pyramid/renderers.py index bcbcbb0aa..9b3f19510 100644 --- a/pyramid/renderers.py +++ b/pyramid/renderers.py @@ -294,7 +294,7 @@ json_renderer_factory = JSON() # bw compat JSONP_VALID_CALLBACK = re.compile(r"^[$a-z_][$0-9a-z_\.\[\]]+[^.]$", re.I) class JSONP(JSON): - """ `JSONP `_ renderer factory helper + """ `JSONP `_ renderer factory helper which implements a hybrid json/jsonp renderer. JSONP is useful for making cross-domain AJAX requests. -- cgit v1.2.3 From ac4d2ca3f47260c8029b51b23ed78908415b4a22 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 24 Apr 2016 02:52:09 -0700 Subject: Use parsed-literal for installing versions of Pyramid. This should future proof docs. --- docs/tutorials/modwsgi/index.rst | 6 +++--- docs/tutorials/wiki/installation.rst | 9 +++++---- docs/tutorials/wiki2/installation.rst | 8 ++++---- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/docs/tutorials/modwsgi/index.rst b/docs/tutorials/modwsgi/index.rst index 7f5aac0a0..c66786b11 100644 --- a/docs/tutorials/modwsgi/index.rst +++ b/docs/tutorials/modwsgi/index.rst @@ -44,11 +44,11 @@ specific path information for commands and files. #. Install :app:`Pyramid` into the newly created virtual environment: - .. code-block:: text + .. parsed-literal:: $ cd ~/modwsgi/env - $ $VENV/bin/pip install pyramid - + $ $VENV/bin/pip install "pyramid==\ |release|\ " + #. Create and install your :app:`Pyramid` application. For the purposes of this tutorial, we'll just be using the ``pyramid_starter`` application as a baseline application. Substitute your existing :app:`Pyramid` diff --git a/docs/tutorials/wiki/installation.rst b/docs/tutorials/wiki/installation.rst index dbf995595..d9c3bec1e 100644 --- a/docs/tutorials/wiki/installation.rst +++ b/docs/tutorials/wiki/installation.rst @@ -97,16 +97,17 @@ Install Pyramid into the virtual Python environment On UNIX ^^^^^^^ -.. code-block:: bash +.. parsed-literal:: - $ $VENV/bin/pip install pyramid + $ $VENV/bin/pip install "pyramid==\ |release|\ " On Windows ^^^^^^^^^^ -.. code-block:: doscon +.. parsed-literal:: + + c:\\> %VENV%\\Scripts\\pip install "pyramid==\ |release|\ " - c:\> %VENV%\Scripts\pip install pyramid Change directory to your virtual Python environment --------------------------------------------------- diff --git a/docs/tutorials/wiki2/installation.rst b/docs/tutorials/wiki2/installation.rst index f4676345e..e45b13315 100644 --- a/docs/tutorials/wiki2/installation.rst +++ b/docs/tutorials/wiki2/installation.rst @@ -97,16 +97,16 @@ Install Pyramid into the virtual Python environment On UNIX ^^^^^^^ -.. code-block:: bash +.. parsed-literal:: - $ $VENV/bin/pip install pyramid + $ $VENV/bin/pip install "pyramid==\ |release|\ " On Windows ^^^^^^^^^^ -.. code-block:: doscon +.. parsed-literal:: - c:\> %VENV%\Scripts\pip install pyramid + c:\\> %VENV%\\Scripts\\pip install "pyramid==\ |release|\ " Install SQLite3 and its development packages -- cgit v1.2.3 From 7461299e7489458ed9e9996fde33b095eb7e729a Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 24 Apr 2016 13:23:05 -0700 Subject: update bad link --- docs/narr/sessions.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/narr/sessions.rst b/docs/narr/sessions.rst index bfc908396..7e961f5e8 100644 --- a/docs/narr/sessions.rst +++ b/docs/narr/sessions.rst @@ -305,7 +305,7 @@ Preventing Cross-Site Request Forgery Attacks --------------------------------------------- `Cross-site request forgery -`_ attacks are a +`_ attacks are a phenomenon whereby a user who is logged in to your website might inadvertantly load a URL because it is linked from, or embedded in, an attacker's website. If the URL is one that may modify or delete data, the consequences can be dire. -- cgit v1.2.3 From b5fcc452c364284648aae4c0ce061b3bac711cd0 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 24 Apr 2016 15:42:34 -0700 Subject: Allow Sphinx doctests to run and pass with `make doctest SPHINXBUILD=$VENV/bin/sphinx-build`. - TODO: two tests in `docs/narr/hooks.rst` --- abc.py | 18 ++++++++++++++++++ docs/Makefile | 22 +++++++++++++++------- docs/narr/sessions.rst | 45 ++++++++++++++++++++++++++++----------------- pyramid/decorator.py | 40 ++++++++++++++++++++++------------------ 4 files changed, 83 insertions(+), 42 deletions(-) create mode 100644 abc.py diff --git a/abc.py b/abc.py new file mode 100644 index 000000000..c200d64c5 --- /dev/null +++ b/abc.py @@ -0,0 +1,18 @@ +from pyramid import testing +from pyramid.config import Configurator + + +def total(request, *args): + return sum(args) + + +def prop(request): + print("getting the property") + return "the property" + + +config = Configurator() +config.add_request_method(total) +config.add_request_method(prop, reify=True) + +request = testing.DummyRequest() diff --git a/docs/Makefile b/docs/Makefile index 546deb30a..411ff35df 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -12,16 +12,20 @@ PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . -.PHONY: help clean html web pickle htmlhelp latex changes linkcheck +.PHONY: help clean html text web pickle htmlhelp latex latexpdf changes linkcheck epub doctest help: @echo "Please use \`make ' where is one of" - @echo " html to make standalone HTML files" - @echo " pickle to make pickle files (usable by e.g. sphinx-web)" - @echo " htmlhelp to make HTML files and a HTML help project" - @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" - @echo " changes to make an overview over all changed/added/deprecated items" - @echo " linkcheck to check all external links for integrity" + @echo " html to make standalone HTML files" + @echo " text to make text files" + @echo " pickle to make pickle files (usable by e.g. sphinx-web)" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " changes to make an overview over all changed/added/deprecated items" + @echo " linkcheck to check all external links for integrity" + @echo " epub to make an epub" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: -rm -rf $(BUILDDIR)/* @@ -90,3 +94,7 @@ epub: @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." diff --git a/docs/narr/sessions.rst b/docs/narr/sessions.rst index 7e961f5e8..a1319e45f 100644 --- a/docs/narr/sessions.rst +++ b/docs/narr/sessions.rst @@ -260,19 +260,28 @@ added to the flash queue, and empties the queue. .. method:: pop_flash(queue='') ->>> request.session.flash('info message') ->>> request.session.pop_flash() -['info message'] +.. testsetup:: + + from pyramid import testing + request = testing.DummyRequest() + +.. doctest:: + + >>> request.session.flash('info message') + >>> request.session.pop_flash() + ['info message'] Calling ``session.pop_flash()`` again like above without a corresponding call to ``session.flash()`` will return an empty list, because the queue has already been popped. ->>> request.session.flash('info message') ->>> request.session.pop_flash() -['info message'] ->>> request.session.pop_flash() -[] +.. doctest:: + + >>> request.session.flash('info message') + >>> request.session.pop_flash() + ['info message'] + >>> request.session.pop_flash() + [] .. index:: single: session.peek_flash @@ -287,15 +296,17 @@ flash storage. .. method:: peek_flash(queue='') ->>> request.session.flash('info message') ->>> request.session.peek_flash() -['info message'] ->>> request.session.peek_flash() -['info message'] ->>> request.session.pop_flash() -['info message'] ->>> request.session.peek_flash() -[] +.. doctest:: + + >>> request.session.flash('info message') + >>> request.session.peek_flash() + ['info message'] + >>> request.session.peek_flash() + ['info message'] + >>> request.session.pop_flash() + ['info message'] + >>> request.session.peek_flash() + [] .. index:: single: preventing cross-site request forgery attacks diff --git a/pyramid/decorator.py b/pyramid/decorator.py index 72c8b3800..ea518bfcb 100644 --- a/pyramid/decorator.py +++ b/pyramid/decorator.py @@ -8,28 +8,32 @@ class reify(object): replacing the function it decorates with an instance variable. It is, in Python parlance, a non-data descriptor. An example: - .. code-block:: python + .. testsetup:: - class Foo(object): - @reify - def jammy(self): - print('jammy called') - return 1 + from pyramid.decorator import reify + + class Foo(object): + @reify + def jammy(self): + print('jammy called') + return 1 And usage of Foo: - >>> f = Foo() - >>> v = f.jammy - 'jammy called' - >>> print(v) - 1 - >>> f.jammy - 1 - >>> # jammy func not called the second time; it replaced itself with 1 - >>> # Note: reassignment is possible - >>> f.jammy = 2 - >>> f.jammy - 2 + .. doctest:: + + >>> f = Foo() + >>> v = f.jammy + jammy called + >>> print(v) + 1 + >>> f.jammy + 1 + >>> # jammy func not called the second time; it replaced itself with 1 + >>> # Note: reassignment is possible + >>> f.jammy = 2 + >>> f.jammy + 2 """ def __init__(self, wrapped): self.wrapped = wrapped -- cgit v1.2.3 From 8f556a5568faa5f2df17d6cafc0900074bb0acfe Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 24 Apr 2016 15:43:31 -0700 Subject: remove file for testing --- abc.py | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 abc.py diff --git a/abc.py b/abc.py deleted file mode 100644 index c200d64c5..000000000 --- a/abc.py +++ /dev/null @@ -1,18 +0,0 @@ -from pyramid import testing -from pyramid.config import Configurator - - -def total(request, *args): - return sum(args) - - -def prop(request): - print("getting the property") - return "the property" - - -config = Configurator() -config.add_request_method(total) -config.add_request_method(prop, reify=True) - -request = testing.DummyRequest() -- cgit v1.2.3 From a470ff601182fed93446b8bfe4bc8707a8455949 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 24 Apr 2016 20:39:37 -0700 Subject: add sphinx doctests for hooks.rst --- docs/narr/hooks.rst | 62 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 58 insertions(+), 4 deletions(-) diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index b776f99e8..150eca944 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -300,13 +300,38 @@ added as a property and its result is cached per-request by setting ``reify=True``. This way, we eliminate the overhead of running the function multiple times. +.. testsetup:: group1 + + from pyramid.config import Configurator + + + def total(request, *args): + return sum(args) + + + def prop(request): + print("getting the property") + return "the property" + + + + config = Configurator() + config.add_request_method(total) + config.add_request_method(prop, reify=True) + config.commit() + + from pyramid.scripting import prepare + request = prepare(registry=config.registry)["request"] + +.. doctest:: group1 + >>> request.total(1, 2, 3) 6 >>> request.prop getting the property - the property + 'the property' >>> request.prop - the property + 'the property' To not cache the result of ``request.prop``, set ``property=True`` instead of ``reify=True``. @@ -338,13 +363,42 @@ Here is an example of passing a class to ``Configurator.add_request_method``: We attach and cache an object named ``extra`` to the ``request`` object. +.. testsetup:: group2 + + from pyramid.config import Configurator + from pyramid.decorator import reify + + class ExtraStuff(object): + + def __init__(self, request): + self.request = request + + def total(self, *args): + return sum(args) + + # use @property if you don't want to cache the result + @reify + def prop(self): + print("getting the property") + return "the property" + + config = Configurator() + config.add_request_method(ExtraStuff, 'extra', reify=True) + config.commit() + + from pyramid.scripting import prepare + request = prepare(registry=config.registry)["request"] + +.. doctest:: group2 + >>> request.extra.total(1, 2, 3) 6 >>> request.extra.prop getting the property - the property + 'the property' >>> request.extra.prop - the property + 'the property' + .. index:: single: response factory -- cgit v1.2.3 From e600d60408526fe510ace0f2c625793fea8e94b8 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 24 Apr 2016 20:54:16 -0700 Subject: add doctest to tox.ini [docs] environment --- tox.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/tox.ini b/tox.ini index 258b2892c..3c0d25493 100644 --- a/tox.ini +++ b/tox.ini @@ -58,6 +58,7 @@ whitelist_externals = make commands = pip install pyramid[docs] make -C docs html epub BUILDDIR={envdir} "SPHINXOPTS=-W -E" + sphinx-build -b doctest -d docs/_build/doctrees docs docs/_build/doctest # we separate coverage into its own testenv because a) "last run wins" wrt # cobertura jenkins reporting and b) pypy and jython can't handle any -- cgit v1.2.3 From 0fec6d3d000425314f5a50f98d6409277b89512c Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 25 Apr 2016 00:19:35 -0700 Subject: put doctest into make command --- tox.ini | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tox.ini b/tox.ini index 3c0d25493..fc47faf17 100644 --- a/tox.ini +++ b/tox.ini @@ -57,8 +57,7 @@ basepython = python3.5 whitelist_externals = make commands = pip install pyramid[docs] - make -C docs html epub BUILDDIR={envdir} "SPHINXOPTS=-W -E" - sphinx-build -b doctest -d docs/_build/doctrees docs docs/_build/doctest + make -C docs doctest html epub BUILDDIR={envdir} "SPHINXOPTS=-W -E" # we separate coverage into its own testenv because a) "last run wins" wrt # cobertura jenkins reporting and b) pypy and jython can't handle any -- cgit v1.2.3 From f2bc0e39cabb2f234ea622b2ebdd0b8eac5cea32 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Mon, 25 Apr 2016 21:12:32 -0500 Subject: fix explanation of require_csrf --- docs/narr/hooks.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 150eca944..49ef29d3f 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -1647,8 +1647,9 @@ the user-defined :term:`view callable`: ``csrf_view`` Used to check the CSRF token provided in the request. This element is a - no-op if both the ``require_csrf`` view option and the - ``pyramid.require_default_csrf`` setting are disabled. + no-op if ``require_csrf`` view option is not ``True``. Note there will + always be a ``require_csrf`` option if a default value was assigned via + :meth:`pyramid.config.Configurator.set_default_csrf_options`. ``owrapped_view`` -- cgit v1.2.3 From 2160ce9152944393caf34113e49982481385e27a Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Tue, 26 Apr 2016 17:49:23 -0500 Subject: do not enforce default permissions on exception views - this normalizes the behavior to work similar to require_csrf - if an explicit permission= is set on the view it will still be enforced, this just affects a default permission via config.set_default_permission - permission=NO_PERMISSION_REQUIRED was already forced on for notfound and forbidden views, this just helps out with other exception views --- pyramid/config/views.py | 18 ++++++------ pyramid/interfaces.py | 4 +-- pyramid/tests/test_viewderivers.py | 57 ++++++++++++++++++++++++++++++++++++++ pyramid/viewderivers.py | 21 ++++++++++++-- 4 files changed, 88 insertions(+), 12 deletions(-) diff --git a/pyramid/config/views.py b/pyramid/config/views.py index 34f289fcc..9e46ba155 100644 --- a/pyramid/config/views.py +++ b/pyramid/config/views.py @@ -13,7 +13,6 @@ from zope.interface import ( from zope.interface.interfaces import IInterface from pyramid.interfaces import ( - IDefaultPermission, IException, IExceptionViewClassifier, IMultiView, @@ -878,11 +877,6 @@ class ViewsConfiguratorMixin(object): registry=self.registry ) - if permission is None: - # intent: will be None if no default permission is registered - # (reg'd in phase 1) - permission = self.registry.queryUtility(IDefaultPermission) - # added by discrim_func above during conflict resolving preds = view_intr['predicates'] order = view_intr['order'] @@ -1436,7 +1430,10 @@ class ViewsConfiguratorMixin(object): .. versionadded:: 1.3 """ - for arg in ('name', 'permission', 'context', 'for_', 'http_cache'): + for arg in ( + 'name', 'permission', 'context', 'for_', 'http_cache', + 'require_csrf', + ): if arg in view_options: raise ConfigurationError( '%s may not be used as an argument to add_forbidden_view' @@ -1464,6 +1461,7 @@ class ViewsConfiguratorMixin(object): match_param=match_param, route_name=route_name, permission=NO_PERMISSION_REQUIRED, + require_csrf=False, attr=attr, renderer=renderer, ) @@ -1548,7 +1546,10 @@ class ViewsConfiguratorMixin(object): .. versionchanged:: 1.6 .. versionadded:: 1.3 """ - for arg in ('name', 'permission', 'context', 'for_', 'http_cache'): + for arg in ( + 'name', 'permission', 'context', 'for_', 'http_cache', + 'require_csrf', + ): if arg in view_options: raise ConfigurationError( '%s may not be used as an argument to add_notfound_view' @@ -1576,6 +1577,7 @@ class ViewsConfiguratorMixin(object): match_param=match_param, route_name=route_name, permission=NO_PERMISSION_REQUIRED, + require_csrf=False, ) settings.update(view_options) if append_slash: diff --git a/pyramid/interfaces.py b/pyramid/interfaces.py index c03afbd39..b252d0f4a 100644 --- a/pyramid/interfaces.py +++ b/pyramid/interfaces.py @@ -1224,9 +1224,9 @@ class IViewDeriver(Interface): class IViewDeriverInfo(Interface): """ An object implementing this interface is passed to every :term:`view deriver` during configuration.""" - registry = Attribute('The "current" application registry when the ' + registry = Attribute('The "current" application registry where the ' 'view was created') - package = Attribute('The "current package" when the view ' + package = Attribute('The "current package" where the view ' 'configuration statement was found') settings = Attribute('The deployment settings dictionary related ' 'to the current application') diff --git a/pyramid/tests/test_viewderivers.py b/pyramid/tests/test_viewderivers.py index e84863d69..79fcd6e71 100644 --- a/pyramid/tests/test_viewderivers.py +++ b/pyramid/tests/test_viewderivers.py @@ -628,6 +628,63 @@ class TestDeriveView(unittest.TestCase): 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): 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() diff --git a/pyramid/viewderivers.py b/pyramid/viewderivers.py index 1b922b89e..5d138a02a 100644 --- a/pyramid/viewderivers.py +++ b/pyramid/viewderivers.py @@ -16,6 +16,7 @@ from pyramid.interfaces import ( IAuthenticationPolicy, IAuthorizationPolicy, IDefaultCSRFOptions, + IDefaultPermission, IDebugLogger, IResponse, IViewMapper, @@ -272,7 +273,9 @@ def secured_view(view, info): secured_view.options = ('permission',) def _secured_view(view, info): - permission = info.options.get('permission') + permission = explicit_val = info.options.get('permission') + if permission is None: + permission = info.registry.queryUtility(IDefaultPermission) if permission == NO_PERMISSION_REQUIRED: # allow views registered within configurations that have a # default permission to explicitly override the default @@ -288,6 +291,12 @@ def _secured_view(view, info): principals = authn_policy.effective_principals(request) return authz_policy.permits(context, principals, permission) def _secured_view(context, request): + if ( + getattr(request, 'exception', None) is not None and + explicit_val is None + ): + return view(context, request) + result = _permitted(context, request) if result: return view(context, request) @@ -306,12 +315,20 @@ def _secured_view(view, info): def _authdebug_view(view, info): wrapped_view = view settings = info.settings - permission = info.options.get('permission') + permission = explicit_val = info.options.get('permission') + if permission is None: + permission = info.registry.queryUtility(IDefaultPermission) authn_policy = info.registry.queryUtility(IAuthenticationPolicy) authz_policy = info.registry.queryUtility(IAuthorizationPolicy) logger = info.registry.queryUtility(IDebugLogger) if settings and settings.get('debug_authorization', False): def _authdebug_view(context, request): + if ( + getattr(request, 'exception', None) is not None and + explicit_val is None + ): + return view(context, request) + view_name = getattr(request, 'view_name', None) if authn_policy and authz_policy: -- cgit v1.2.3 From f7d515de86ad1ceab1b330cf1d95257b712b2659 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Wed, 27 Apr 2016 21:01:28 -0500 Subject: fix bugs in design defense code examples fixes #2287 --- docs/designdefense.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/designdefense.rst b/docs/designdefense.rst index 3c1046b82..70dbbe720 100644 --- a/docs/designdefense.rst +++ b/docs/designdefense.rst @@ -1297,12 +1297,12 @@ Consider the following simple `Groundhog from groundhog import Groundhog app = Groundhog('myapp', 'seekrit') - app.route('/admin') + @app.route('/admin') def admin(): return 'admin page' - app.route('/:action') - def action(): + @app.route('/:action') + def do_action(action): if action == 'add': return 'add' if action == 'delete': @@ -1322,15 +1322,15 @@ order of the function definitions in the file? from groundhog import Groundhog app = Groundhog('myapp', 'seekrit') - app.route('/:action') - def action(): + @app.route('/:action') + def do_action(action): if action == 'add': return 'add' if action == 'delete': return 'delete' return app.abort(404) - app.route('/admin') + @app.route('/admin') def admin(): return 'admin page' -- cgit v1.2.3 From 78f6ef077c7f67440f5ccfad9b20771fe68ecee1 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Wed, 27 Apr 2016 23:59:31 -0500 Subject: avoid executing the discriminator functions multiple times --- pyramid/registry.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pyramid/registry.py b/pyramid/registry.py index 1073134ff..df9a10822 100644 --- a/pyramid/registry.py +++ b/pyramid/registry.py @@ -255,9 +255,13 @@ class Deferred(object): def __init__(self, func): self.func = func - def resolve(self): + @reify + def value(self): return self.func() + def resolve(self): + return self.value + def undefer(v): """ Function which accepts an object and returns it unless it is a :class:`pyramid.registry.Deferred` instance. If it is an instance of -- cgit v1.2.3 From 649f5918f9205268f18cfade2775e503f8a19b1b Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 1 May 2016 01:54:12 -0700 Subject: remove pyramid_tm from development.ini - fixes #2538 --- pyramid/scaffolds/alchemy/development.ini_tmpl | 1 - 1 file changed, 1 deletion(-) diff --git a/pyramid/scaffolds/alchemy/development.ini_tmpl b/pyramid/scaffolds/alchemy/development.ini_tmpl index 07811f7c3..f8ee290be 100644 --- a/pyramid/scaffolds/alchemy/development.ini_tmpl +++ b/pyramid/scaffolds/alchemy/development.ini_tmpl @@ -13,7 +13,6 @@ pyramid.debug_routematch = false pyramid.default_locale_name = en pyramid.includes = pyramid_debugtoolbar - pyramid_tm sqlalchemy.url = sqlite:///%(here)s/{{project}}.sqlite -- cgit v1.2.3 From 478c6ef8c05bea4541844e40c9428d573266e9dc Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 2 May 2016 04:35:45 -0700 Subject: fix what's new link (cherry picked from commit 023b6ba) --- RELEASING.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASING.txt b/RELEASING.txt index 78fd98f52..a09b6d24a 100644 --- a/RELEASING.txt +++ b/RELEASING.txt @@ -129,7 +129,7 @@ PyPI https://pypi.python.org/pypi/pyramid/1.x What's New -http://docs.pylonsproject.org/projects/pyramid/1.X-branch/whatsnew-1.X.html +http://docs.pylonsproject.org/projects/pyramid/en/1.X-branch/whatsnew-1.X.html Issues https://github.com/Pylons/pyramid/issues -- cgit v1.2.3 From c1732b845348763cd514721126fc05e1531e44f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vincent=20F=C3=A9rotin?= Date: Fri, 6 May 2016 19:45:32 +0200 Subject: scaffolds: Allow `py.test` to be run on new project without specifying test module path. --- pyramid/scaffolds/alchemy/+dot+coveragerc_tmpl | 3 +++ pyramid/scaffolds/alchemy/pytest.ini_tmpl | 3 +++ pyramid/scaffolds/starter/+dot+coveragerc_tmpl | 3 +++ pyramid/scaffolds/starter/pytest.ini_tmpl | 3 +++ pyramid/scaffolds/zodb/+dot+coveragerc_tmpl | 3 +++ pyramid/scaffolds/zodb/pytest.ini_tmpl | 3 +++ 6 files changed, 18 insertions(+) create mode 100644 pyramid/scaffolds/alchemy/+dot+coveragerc_tmpl create mode 100644 pyramid/scaffolds/alchemy/pytest.ini_tmpl create mode 100644 pyramid/scaffolds/starter/+dot+coveragerc_tmpl create mode 100644 pyramid/scaffolds/starter/pytest.ini_tmpl create mode 100644 pyramid/scaffolds/zodb/+dot+coveragerc_tmpl create mode 100644 pyramid/scaffolds/zodb/pytest.ini_tmpl diff --git a/pyramid/scaffolds/alchemy/+dot+coveragerc_tmpl b/pyramid/scaffolds/alchemy/+dot+coveragerc_tmpl new file mode 100644 index 000000000..273a4a580 --- /dev/null +++ b/pyramid/scaffolds/alchemy/+dot+coveragerc_tmpl @@ -0,0 +1,3 @@ +[run] +source = {{package}} +omit = {{package}}/test* diff --git a/pyramid/scaffolds/alchemy/pytest.ini_tmpl b/pyramid/scaffolds/alchemy/pytest.ini_tmpl new file mode 100644 index 000000000..a30c8bcad --- /dev/null +++ b/pyramid/scaffolds/alchemy/pytest.ini_tmpl @@ -0,0 +1,3 @@ +[pytest] +testpaths = {{package}} +python_files = *.py diff --git a/pyramid/scaffolds/starter/+dot+coveragerc_tmpl b/pyramid/scaffolds/starter/+dot+coveragerc_tmpl new file mode 100644 index 000000000..273a4a580 --- /dev/null +++ b/pyramid/scaffolds/starter/+dot+coveragerc_tmpl @@ -0,0 +1,3 @@ +[run] +source = {{package}} +omit = {{package}}/test* diff --git a/pyramid/scaffolds/starter/pytest.ini_tmpl b/pyramid/scaffolds/starter/pytest.ini_tmpl new file mode 100644 index 000000000..a30c8bcad --- /dev/null +++ b/pyramid/scaffolds/starter/pytest.ini_tmpl @@ -0,0 +1,3 @@ +[pytest] +testpaths = {{package}} +python_files = *.py diff --git a/pyramid/scaffolds/zodb/+dot+coveragerc_tmpl b/pyramid/scaffolds/zodb/+dot+coveragerc_tmpl new file mode 100644 index 000000000..273a4a580 --- /dev/null +++ b/pyramid/scaffolds/zodb/+dot+coveragerc_tmpl @@ -0,0 +1,3 @@ +[run] +source = {{package}} +omit = {{package}}/test* diff --git a/pyramid/scaffolds/zodb/pytest.ini_tmpl b/pyramid/scaffolds/zodb/pytest.ini_tmpl new file mode 100644 index 000000000..a30c8bcad --- /dev/null +++ b/pyramid/scaffolds/zodb/pytest.ini_tmpl @@ -0,0 +1,3 @@ +[pytest] +testpaths = {{package}} +python_files = *.py -- cgit v1.2.3 From 68ba583735aedc6762131af2cf93cf0fdd470fef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vincent=20F=C3=A9rotin?= Date: Fri, 6 May 2016 19:45:32 +0200 Subject: doc: Update documentation for using ``py.test [--cov]`` for newly created project with scaffolds. --- docs/narr/project.rst | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/docs/narr/project.rst b/docs/narr/project.rst index 56247ee33..8849e9ee7 100644 --- a/docs/narr/project.rst +++ b/docs/narr/project.rst @@ -209,25 +209,29 @@ On UNIX: .. code-block:: bash - $ $VENV/bin/py.test myproject/tests.py -q + $ $VENV/bin/py.test -q On Windows: .. code-block:: doscon - > %VENV%\Scripts\py.test myproject\tests.py -q + > %VENV%\Scripts\py.test -q Here's sample output from a test run on UNIX: .. code-block:: bash - $ $VENV/bin/py.test myproject/tests.py -q + $ $VENV/bin/py.test -q .. 2 passed in 0.47 seconds The tests themselves are found in the ``tests.py`` module in your ``pcreate`` generated project. Within a project generated by the ``starter`` scaffold, -only two sample tests exist. +only two sample tests exist. Previous command is identical to: + +.. code-block:: bash + + $ $VENV/bin/py.test myproject/tests.py -q .. note:: @@ -235,6 +239,14 @@ only two sample tests exist. to a stream of dots. If you don't pass ``-q``, you'll see verbose test result output (which normally isn't very useful). +Alternatively, if you'd like to see test coverage, pass the ``--cov`` option +to ``py.test``: + +.. code-block:: bash + + $ $VENV/bin/py.test -q --cov + + .. index:: single: running an application single: pserve -- cgit v1.2.3 From 9591e95fd8c8d3e0359851f093eb060b7f9b56b7 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 6 May 2016 11:02:28 -0700 Subject: Update wiki tutorials with py.test remarks - better synch up wiki tutorials installation instructions - improve .rst syntax and add more .rst links --- docs/tutorials/wiki/installation.rst | 53 +++++++++++++++++++++++++++++------ docs/tutorials/wiki2/installation.rst | 31 +++++++++++--------- 2 files changed, 62 insertions(+), 22 deletions(-) diff --git a/docs/tutorials/wiki/installation.rst b/docs/tutorials/wiki/installation.rst index d9c3bec1e..251d79606 100644 --- a/docs/tutorials/wiki/installation.rst +++ b/docs/tutorials/wiki/installation.rst @@ -129,6 +129,7 @@ On Windows c:\> cd pyramidtut + .. _making_a_project: Making a project @@ -209,7 +210,7 @@ packages. Success executing this command will show a line like the following: zc.lockfile-1.1.0 zdaemon-4.1.0 zodbpickle-0.6.0 zodburi-2.0 -.. _install-testing-requirements_zodb: +.. _install-testing-requirements-zodb: Install testing requirements ---------------------------- @@ -252,7 +253,9 @@ Run the tests ------------- After you've installed the project in development mode as well as the testing -requirements, you may run the tests for the project. +requirements, you may run the tests for the project. The following commands +provide options to py.test that specify the module for which its tests shall be +run, and to run py.test in quiet mode. On UNIX ^^^^^^^ @@ -275,6 +278,16 @@ For a successful test run, you should see output that ends like this: . 1 passed in 0.24 seconds +.. note:: + py.test follows :ref:`conventions for Python test discovery + `. This explains why we cannot run just ``py.test`` + without specifying the module to test after generating a project from a + scaffold. + + py.test is a :ref:`mature full-featured Python testing tool + `. See py.test's documentation for :ref:`pytest:usage` or + invoke ``py.test -h`` to see its full set of options. + Expose test coverage information -------------------------------- @@ -358,9 +371,9 @@ If successful, you will see something like this on your console: .. code-block:: text - Starting subprocess with file monitor - Starting server in PID 95736. - serving on http://127.0.0.1:6543 + Starting subprocess with file monitor + Starting server in PID 82349. + serving on http://127.0.0.1:6543 This means the server is ready to accept requests. @@ -387,9 +400,31 @@ assumptions: - You are willing to use :term:`traversal` to map URLs to code. +- You want to use pyramid_zodbconn_, pyramid_tm_, and the transaction_ packages + to manage connections and transactions with :term:`ZODB`. + +- You want to use pyramid_chameleon_ to render your templates. Different + templating engines can be used, but we had to choose one to make this + tutorial. See :ref:`available_template_system_bindings` for some options. + .. note:: - :app:`Pyramid` supports any persistent storage mechanism (e.g., a SQL - database or filesystem files). It also supports an additional - mechanism to map URLs to code (:term:`URL dispatch`). However, for the - purposes of this tutorial, we'll only be using traversal and ZODB. + :app:`Pyramid` supports any persistent storage mechanism (e.g., an SQL + database or filesystem files). It also supports an additional mechanism to + map URLs to code (:term:`URL dispatch`). However, for the purposes of this + tutorial, we'll only be using :term:`traversal` and :term:`ZODB`. + +.. _pyramid_chameleon: + http://docs.pylonsproject.org/projects/pyramid-chameleon/en/latest/ + +.. _pyramid_tm: + http://docs.pylonsproject.org/projects/pyramid-tm/en/latest/ + +.. _pyramid_zodbconn: + http://docs.pylonsproject.org/projects/pyramid-zodbconn/en/latest/ + +.. _transaction: + http://zodb.readthedocs.org/en/latest/transactions.html + +.. _pyramid_chameleon: + http://docs.pylonsproject.org/projects/pyramid-chameleon/en/latest/ diff --git a/docs/tutorials/wiki2/installation.rst b/docs/tutorials/wiki2/installation.rst index e45b13315..4919c8fa5 100644 --- a/docs/tutorials/wiki2/installation.rst +++ b/docs/tutorials/wiki2/installation.rst @@ -270,7 +270,9 @@ Run the tests ------------- After you've installed the project in development mode as well as the testing -requirements, you may run the tests for the project. +requirements, you may run the tests for the project. The following commands +provide options to py.test that specify the module for which its tests shall be +run, and to run py.test in quiet mode. On UNIX ^^^^^^^ @@ -293,6 +295,16 @@ For a successful test run, you should see output that ends like this: .. 2 passed in 0.44 seconds +.. note:: + py.test follows :ref:`conventions for Python test discovery + `. This explains why we cannot run just ``py.test`` + without specifying the module to test after generating a project from a + scaffold. + + py.test is a :ref:`mature full-featured Python testing tool + `. See py.test's documentation for :ref:`pytest:usage` or + invoke ``py.test -h`` to see its full set of options. + Expose test coverage information -------------------------------- @@ -451,7 +463,9 @@ On Windows Your OS firewall, if any, may pop up a dialog asking for authorization to allow python to accept incoming network connections. -If successful, you will see something like this on your console:: +If successful, you will see something like this on your console: + +.. code-block:: text Starting subprocess with file monitor Starting server in PID 82349. @@ -463,7 +477,7 @@ This means the server is ready to accept requests. Visit the application in a browser ---------------------------------- -In a browser, visit http://localhost:6543/. You will see the generated +In a browser, visit http://localhost:6543/. You will see the generated application's default page. One thing you'll notice is the "debug toolbar" icon on right hand side of the @@ -494,7 +508,7 @@ assumptions: :app:`Pyramid` supports any persistent storage mechanism (e.g., object database or filesystem files). It also supports an additional mechanism to map URLs to code (:term:`traversal`). However, for the purposes of this - tutorial, we'll only be using URL dispatch and SQLAlchemy. + tutorial, we'll only be using :term:`URL dispatch` and :term:`SQLAlchemy`. .. _pyramid_jinja2: http://docs.pylonsproject.org/projects/pyramid-jinja2/en/latest/ @@ -510,12 +524,3 @@ assumptions: .. _pyramid_jinja2: http://docs.pylonsproject.org/projects/pyramid-jinja2/en/latest/ - -.. _pyramid_tm: - http://docs.pylonsproject.org/projects/pyramid-tm/en/latest/ - -.. _zope.sqlalchemy: - https://pypi.python.org/pypi/zope.sqlalchemy - -.. _transaction: - http://zodb.readthedocs.org/en/latest/transactions.html -- cgit v1.2.3 From f69beca1c0ea61d6d1d03b85a92aaecbe1ede837 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 6 May 2016 11:05:35 -0700 Subject: remove duplicate links --- docs/tutorials/wiki2/installation.rst | 3 --- 1 file changed, 3 deletions(-) diff --git a/docs/tutorials/wiki2/installation.rst b/docs/tutorials/wiki2/installation.rst index 4919c8fa5..6f46c5539 100644 --- a/docs/tutorials/wiki2/installation.rst +++ b/docs/tutorials/wiki2/installation.rst @@ -521,6 +521,3 @@ assumptions: .. _transaction: http://zodb.readthedocs.org/en/latest/transactions.html - -.. _pyramid_jinja2: - http://docs.pylonsproject.org/projects/pyramid-jinja2/en/latest/ -- cgit v1.2.3 From 02161cc32a1a2fe0c4fbae94e605610e63e0d545 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 6 May 2016 11:14:31 -0700 Subject: remove duplicate links --- docs/tutorials/wiki/installation.rst | 3 --- 1 file changed, 3 deletions(-) diff --git a/docs/tutorials/wiki/installation.rst b/docs/tutorials/wiki/installation.rst index 251d79606..ee87dcaf9 100644 --- a/docs/tutorials/wiki/installation.rst +++ b/docs/tutorials/wiki/installation.rst @@ -425,6 +425,3 @@ assumptions: .. _transaction: http://zodb.readthedocs.org/en/latest/transactions.html - -.. _pyramid_chameleon: - http://docs.pylonsproject.org/projects/pyramid-chameleon/en/latest/ -- cgit v1.2.3 From e09369f02f61f2443f393bcd29fa84e970268b53 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 7 May 2016 00:54:55 -0700 Subject: wordsmith py.test and coverage configuration --- docs/narr/project.rst | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/docs/narr/project.rst b/docs/narr/project.rst index 8849e9ee7..a25394151 100644 --- a/docs/narr/project.rst +++ b/docs/narr/project.rst @@ -227,11 +227,7 @@ Here's sample output from a test run on UNIX: The tests themselves are found in the ``tests.py`` module in your ``pcreate`` generated project. Within a project generated by the ``starter`` scaffold, -only two sample tests exist. Previous command is identical to: - -.. code-block:: bash - - $ $VENV/bin/py.test myproject/tests.py -q +only two sample tests exist. .. note:: @@ -244,7 +240,19 @@ to ``py.test``: .. code-block:: bash - $ $VENV/bin/py.test -q --cov + $ $VENV/bin/py.test --cov -q + +Scaffolds include configuration defaults for ``py.test`` and test coverage. +These configuration files are ``pytest.ini`` and ``.coveragerc``, located at +the root of your package. Without these defaults, we would need to specify the +path to the module on which we want to run tests and coverage. + +.. code-block:: bash + + $ $VENV/bin/py.test --cov=myproject myproject/tests.py -q + +.. seealso:: See py.test's documentation for :ref:`pytest:usage` or invoke + ``py.test -h`` to see its full set of options. .. index:: -- cgit v1.2.3 From 5e3eebda0ef61e46128fa7c6eed94c3b2d72c476 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 7 May 2016 01:32:09 -0700 Subject: update wiki2 with py.test and coverage defaults --- docs/tutorials/wiki2/installation.rst | 54 +++++++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 15 deletions(-) diff --git a/docs/tutorials/wiki2/installation.rst b/docs/tutorials/wiki2/installation.rst index 6f46c5539..815164138 100644 --- a/docs/tutorials/wiki2/installation.rst +++ b/docs/tutorials/wiki2/installation.rst @@ -279,14 +279,14 @@ On UNIX .. code-block:: bash - $ $VENV/bin/py.test tutorial/tests.py -q + $ $VENV/bin/py.test -q On Windows ^^^^^^^^^^ .. code-block:: doscon - c:\pyramidtut\tutorial> %VENV%\Scripts\py.test tutorial\tests.py -q + c:\pyramidtut\tutorial> %VENV%\Scripts\py.test -q For a successful test run, you should see output that ends like this: @@ -295,16 +295,6 @@ For a successful test run, you should see output that ends like this: .. 2 passed in 0.44 seconds -.. note:: - py.test follows :ref:`conventions for Python test discovery - `. This explains why we cannot run just ``py.test`` - without specifying the module to test after generating a project from a - scaffold. - - py.test is a :ref:`mature full-featured Python testing tool - `. See py.test's documentation for :ref:`pytest:usage` or - invoke ``py.test -h`` to see its full set of options. - Expose test coverage information -------------------------------- @@ -322,15 +312,15 @@ On UNIX .. code-block:: bash - $ $VENV/bin/py.test --cov=tutorial --cov-report=term-missing tutorial/tests.py + $ $VENV/bin/py.test --cov --cov-report=term-missing On Windows ^^^^^^^^^^ .. code-block:: doscon - c:\pyramidtut\tutorial> %VENV%\Scripts\py.test --cov=tutorial \ - --cov-report=term-missing tutorial\tests.py + c:\pyramidtut\tutorial> %VENV%\Scripts\py.test --cov \ + --cov-report=term-missing If successful, you will see output something like this: @@ -365,6 +355,40 @@ If successful, you will see output something like this: Our package doesn't quite have 100% test coverage. +.. _test_and_coverage_scaffold_defaults: + +Test and coverage scaffold defaults +----------------------------------- + +Scaffolds include configuration defaults for ``py.test`` and test coverage. +These configuration files are ``pytest.ini`` and ``.coveragerc``, located at +the root of your package. Without these defaults, we would need to specify the +path to the module on which we want to run tests and coverage. + +On UNIX +^^^^^^^ + +.. code-block:: bash + + $ $VENV/bin/py.test --cov=tutorial tutorial/tests.py -q + +On Windows +^^^^^^^^^^ + +.. code-block:: doscon + + c:\pyramidtut\tutorial> %VENV%\Scripts\py.test --cov=tutorial \ + --cov-report=term-missing tutorial\tests.py -q + +py.test follows :ref:`conventions for Python test discovery +`, and the configuration defaults from the scaffold +tell ``py.test`` where to find the module on which we want to run tests and +coverage. + +.. seealso:: See py.test's documentation for :ref:`pytest:usage` or invoke + ``py.test -h`` to see its full set of options. + + .. _initialize_db_wiki2: Initializing the database -- cgit v1.2.3 From 779b316ec36ad4920bbe2fd6c6e0aaa5c021e029 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 7 May 2016 01:34:37 -0700 Subject: update wiki1 with py.test and coverage defaults --- docs/tutorials/wiki/installation.rst | 54 +++++++++++++++++++++++++---------- docs/tutorials/wiki2/installation.rst | 2 +- 2 files changed, 40 insertions(+), 16 deletions(-) diff --git a/docs/tutorials/wiki/installation.rst b/docs/tutorials/wiki/installation.rst index ee87dcaf9..6172b122b 100644 --- a/docs/tutorials/wiki/installation.rst +++ b/docs/tutorials/wiki/installation.rst @@ -262,14 +262,14 @@ On UNIX .. code-block:: bash - $ $VENV/bin/py.test tutorial/tests.py -q + $ $VENV/bin/py.test -q On Windows ^^^^^^^^^^ .. code-block:: doscon - c:\pyramidtut\tutorial> %VENV%\Scripts\py.test tutorial\tests.py -q + c:\pyramidtut\tutorial> %VENV%\Scripts\py.test -q For a successful test run, you should see output that ends like this: @@ -278,16 +278,6 @@ For a successful test run, you should see output that ends like this: . 1 passed in 0.24 seconds -.. note:: - py.test follows :ref:`conventions for Python test discovery - `. This explains why we cannot run just ``py.test`` - without specifying the module to test after generating a project from a - scaffold. - - py.test is a :ref:`mature full-featured Python testing tool - `. See py.test's documentation for :ref:`pytest:usage` or - invoke ``py.test -h`` to see its full set of options. - Expose test coverage information -------------------------------- @@ -305,15 +295,15 @@ On UNIX .. code-block:: bash - $ $VENV/bin/py.test --cov=tutorial --cov-report=term-missing tutorial/tests.py + $ $VENV/bin/py.test --cov --cov-report=term-missing On Windows ^^^^^^^^^^ .. code-block:: doscon - c:\pyramidtut\tutorial> %VENV%\Scripts\py.test --cov=tutorial \ - --cov-report=term-missing tutorial\tests.py + c:\pyramidtut\tutorial> %VENV%\Scripts\py.test --cov \ + --cov-report=term-missing If successful, you will see output something like this: @@ -341,6 +331,40 @@ If successful, you will see output something like this: Our package doesn't quite have 100% test coverage. +.. _test_and_coverage_scaffold_defaults_zodb: + +Test and coverage scaffold defaults +----------------------------------- + +Scaffolds include configuration defaults for ``py.test`` and test coverage. +These configuration files are ``pytest.ini`` and ``.coveragerc``, located at +the root of your package. Without these defaults, we would need to specify the +path to the module on which we want to run tests and coverage. + +On UNIX +^^^^^^^ + +.. code-block:: bash + + $ $VENV/bin/py.test --cov=tutorial tutorial/tests.py -q + +On Windows +^^^^^^^^^^ + +.. code-block:: doscon + + c:\pyramidtut\tutorial> %VENV%\Scripts\py.test --cov=tutorial \ + --cov-report=term-missing tutorial\tests.py -q + +py.test follows :ref:`conventions for Python test discovery +`, and the configuration defaults from the scaffold +tell ``py.test`` where to find the module on which we want to run tests and +coverage. + +.. seealso:: See py.test's documentation for :ref:`pytest:usage` or invoke + ``py.test -h`` to see its full set of options. + + .. _wiki-start-the-application: Start the application diff --git a/docs/tutorials/wiki2/installation.rst b/docs/tutorials/wiki2/installation.rst index 815164138..2b8ce5dfa 100644 --- a/docs/tutorials/wiki2/installation.rst +++ b/docs/tutorials/wiki2/installation.rst @@ -355,7 +355,7 @@ If successful, you will see output something like this: Our package doesn't quite have 100% test coverage. -.. _test_and_coverage_scaffold_defaults: +.. _test_and_coverage_scaffold_defaults_sql: Test and coverage scaffold defaults ----------------------------------- -- cgit v1.2.3 From 683d7517f33329ef6bd0a0d1f8a5a9470c0e0bf1 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 7 May 2016 01:39:57 -0700 Subject: update quick tour with py.test and coverage defaults --- docs/quick_tour.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/quick_tour.rst b/docs/quick_tour.rst index 78af6fd40..b170e5d98 100644 --- a/docs/quick_tour.rst +++ b/docs/quick_tour.rst @@ -699,7 +699,7 @@ We changed ``setup.py`` which means we need to rerun ``$VENV/bin/pip install -e .. code-block:: bash - $ $VENV/bin/py.test --cov=hello_world --cov-report=term-missing hello_world/tests.py + $ $VENV/bin/py.test --cov --cov-report=term-missing This yields the following output. -- cgit v1.2.3 From ea252c3df9cab326a5a5e9a7bdcafae637bd0d47 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 7 May 2016 01:53:23 -0700 Subject: update narr/project.rst with py.test and coverage defaults --- docs/narr/project.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/narr/project.rst b/docs/narr/project.rst index a25394151..1ce12a938 100644 --- a/docs/narr/project.rst +++ b/docs/narr/project.rst @@ -929,10 +929,10 @@ The ``tests.py`` module includes unit tests for your application. :linenos: This sample ``tests.py`` file has one unit test and one functional test defined -within it. These tests are executed when you run ``py.test myproject/tests.py --q``. You may add more tests here as you build your application. You are not -required to write tests to use :app:`Pyramid`. This file is simply provided for -convenience and example. +within it. These tests are executed when you run ``py.test -q``. You may add +more tests here as you build your application. You are not required to write +tests to use :app:`Pyramid`. This file is simply provided for convenience and +example. See :ref:`testing_chapter` for more information about writing :app:`Pyramid` unit tests. -- cgit v1.2.3 From b0eb612ca540d5d69841902424cd09b92b80e13b Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 7 May 2016 01:53:43 -0700 Subject: update conventions.rst with py.test and coverage defaults --- docs/conventions.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/conventions.rst b/docs/conventions.rst index 0f5daf106..43853882c 100644 --- a/docs/conventions.rst +++ b/docs/conventions.rst @@ -55,7 +55,7 @@ character, e.g.: .. code-block:: bash - $ $VENV/bin/py.test tutorial/tests.py -q + $ $VENV/bin/py.test -q (See :term:`venv` for the meaning of ``$VENV``) @@ -64,7 +64,7 @@ drive letter and/or a directory name, e.g.: .. code-block:: doscon - c:\examples> %VENV%\Scripts\py.test tutorial\tests.py -q + c:\examples> %VENV%\Scripts\py.test -q (See :term:`venv` for the meaning of ``%VENV%``) @@ -73,7 +73,7 @@ example block commands are prefixed only with a ``>`` character, e.g.: .. code-block:: doscon - > %VENV%\Scripts\py.test tutorial\tests.py -q + > %VENV%\Scripts\py.test -q When a command that should be typed on one line is too long to fit on a page, the backslash ``\`` is used to indicate that the following printed line should -- cgit v1.2.3 From edab48b35d1175bf20416fa570ba32506605e662 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 7 May 2016 01:58:03 -0700 Subject: update tutorials/wiki/tests.rst with py.test and coverage defaults --- docs/tutorials/wiki/tests.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/tutorials/wiki/tests.rst b/docs/tutorials/wiki/tests.rst index 788ec595b..aa4cb3597 100644 --- a/docs/tutorials/wiki/tests.rst +++ b/docs/tutorials/wiki/tests.rst @@ -52,20 +52,21 @@ Running the tests ================= We can run these tests by using ``py.test`` similarly to how we did in -:ref:`running_tests`. Our testing dependencies have already been satisfied, -courtesy of the scaffold, so we can jump right to running tests. +:ref:`running_tests`. Courtest of the scaffold, our testing dependencies have +already been satisfied and ``py.test`` and coverage has already been +configured, so we can jump right to running tests. On UNIX: .. code-block:: text - $ $VENV/bin/py.test tutorial/tests.py -q + $ $VENV/bin/py.test -q On Windows: .. code-block:: text - c:\pyramidtut\tutorial> %VENV%\Scripts\py.test tutorial/tests.py -q + c:\pyramidtut\tutorial> %VENV%\Scripts\py.test -q The expected result should look like the following: -- cgit v1.2.3 From 1ce7fe71a238a2a735d49597232bc1fc240f5eeb Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 7 May 2016 02:03:38 -0700 Subject: fix typo --- docs/designdefense.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/designdefense.rst b/docs/designdefense.rst index 70dbbe720..51c3c5bd8 100644 --- a/docs/designdefense.rst +++ b/docs/designdefense.rst @@ -608,7 +608,7 @@ pyramid/scaffolds/ 133KB -pyramid/ (except for ``pyramd/tests`` and ``pyramid/scaffolds``) +pyramid/ (except for ``pyramid/tests`` and ``pyramid/scaffolds``) 812KB -- cgit v1.2.3 From 283ad4c8125061cc3166bf1af925a38920478c9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vincent=20F=C3=A9rotin?= Date: Sun, 8 May 2016 17:12:42 +0200 Subject: docs: Fix typos. --- docs/tutorials/wiki/tests.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/tutorials/wiki/tests.rst b/docs/tutorials/wiki/tests.rst index aa4cb3597..85a023cc9 100644 --- a/docs/tutorials/wiki/tests.rst +++ b/docs/tutorials/wiki/tests.rst @@ -52,8 +52,8 @@ Running the tests ================= We can run these tests by using ``py.test`` similarly to how we did in -:ref:`running_tests`. Courtest of the scaffold, our testing dependencies have -already been satisfied and ``py.test`` and coverage has already been +:ref:`running_tests`. Courtesy of the scaffold, our testing dependencies have +already been satisfied and ``py.test`` and coverage have already been configured, so we can jump right to running tests. On UNIX: -- cgit v1.2.3 From f06f2e8d39a186fbd8b46fdecd1e5bff42070407 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vincent=20F=C3=A9rotin?= Date: Sun, 8 May 2016 17:19:32 +0200 Subject: =?UTF-8?q?Add=20Vincent=20F=C3=A9rotin=20to=20contributors.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CONTRIBUTORS.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index 563a995a9..55fdf096b 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -266,3 +266,5 @@ Contributors - Marcin Raczyński, 2016/01/26 - Arian Maykon de A. Diógenes, 2016/04/13 + +- Vincent Férotin, 2016/05/08 -- cgit v1.2.3 From 2b50258d4f7771b4a52a0170733186b3fc4e9b7b Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 8 May 2016 12:27:24 -0700 Subject: pylons != pyramid --- docs/designdefense.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/designdefense.rst b/docs/designdefense.rst index 51c3c5bd8..e759c0e2a 100644 --- a/docs/designdefense.rst +++ b/docs/designdefense.rst @@ -1432,7 +1432,8 @@ object which *is not logically global*: # this is executed if the request method was GET or the # credentials were invalid -The `Pylons 1.X `_ +The `Pylons 1.X +`_ web framework uses a similar strategy. It calls these things "Stacked Object Proxies", so, for purposes of this discussion, I'll do so as well. -- cgit v1.2.3 From a1aa71ac60fbaac4fc0fbc3d4846fb9f33d2ad07 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 8 May 2016 12:35:16 -0700 Subject: - use cleaner URL for IRC --- docs/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.rst b/docs/index.rst index ad667684c..452666dc8 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -80,7 +80,7 @@ If you've got questions that aren't answered by this documentation, contact the `Pylons-discuss maillist `_ or join the `#pyramid IRC channel -`_. +`_. Browse and check out tagged and trunk versions of :app:`Pyramid` via the `Pyramid GitHub repository `_. To check out -- cgit v1.2.3 From 9d16a111299601df3a2d1c22b4a6ca6044efcd3f Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 9 May 2016 01:16:54 -0700 Subject: add alt tag for Travis CI Status --- README.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/README.rst b/README.rst index 2237d9950..1b3e01b04 100644 --- a/README.rst +++ b/README.rst @@ -3,6 +3,7 @@ Pyramid .. image:: https://travis-ci.org/Pylons/pyramid.png?branch=master :target: https://travis-ci.org/Pylons/pyramid + :alt: Master Travis CI Status .. image:: https://readthedocs.org/projects/pyramid/badge/?version=master :target: http://docs.pylonsproject.org/projects/pyramid/en/master/ -- cgit v1.2.3 From c6729daea00b438bcf01c15c0e98f4a8024bf3c7 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 8 May 2016 12:41:08 -0700 Subject: use new trypyramid.com page. whee! --- docs/narr/introduction.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/narr/introduction.rst b/docs/narr/introduction.rst index d92916503..de6ac408b 100644 --- a/docs/narr/introduction.rst +++ b/docs/narr/introduction.rst @@ -221,7 +221,7 @@ send email, let you use the Jinja2 templating system, let you use XML-RPC or JSON-RPC, let you integrate with jQuery Mobile, etc. Examples: -http://docs.pylonsproject.org/en/latest/docs/pyramid.html#pyramid-add-ons +https://trypyramid.com/resources-extending-pyramid.html Class-based and function-based views ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- cgit v1.2.3 From e045cfa4e1cae401273430ef0d49cd706f0e65b4 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Tue, 10 May 2016 00:06:21 -0500 Subject: ensure invoke_exception_view always returns a response --- pyramid/tests/test_view.py | 25 +++++++++++++++++++++++++ pyramid/view.py | 8 ++++++-- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/pyramid/tests/test_view.py b/pyramid/tests/test_view.py index 2be47e318..2de44d579 100644 --- a/pyramid/tests/test_view.py +++ b/pyramid/tests/test_view.py @@ -805,6 +805,31 @@ class TestViewMethodsMixin(unittest.TestCase): 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_raises_predicate_mismatch(self): + from pyramid.exceptions import PredicateMismatch + def exc_view(exc, request): 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() + class ExceptionResponse(Exception): status = '404 Not Found' app_iter = ['Not Found'] diff --git a/pyramid/view.py b/pyramid/view.py index 62ac5310e..88c6397af 100644 --- a/pyramid/view.py +++ b/pyramid/view.py @@ -21,6 +21,7 @@ from pyramid.exceptions import PredicateMismatch from pyramid.httpexceptions import ( HTTPFound, + HTTPNotFound, default_exceptionresponse_view, ) @@ -589,8 +590,9 @@ class ViewMethodsMixin(object): object that this method is attached to as the ``request``, and ``True`` for ``secure``. - This method returns a :term:`response` object or ``None`` if no - matching exception view can be found.""" + This method returns a :term:`response` object or raises + :class:`pyramid.httpexceptions.HTTPNotFound` if a matching view cannot + be found.""" if request is None: request = self @@ -623,4 +625,6 @@ class ViewMethodsMixin(object): secure=secure, request_iface=request_iface.combined, ) + if response is None: + raise HTTPNotFound return response -- cgit v1.2.3 From aa52c5f60dd329216b1ef459d53c2710bbaf5b50 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Tue, 10 May 2016 00:34:08 -0500 Subject: execute scaffolds using pip and py.test --- pyramid/scaffolds/tests.py | 11 +++++------ tox.ini | 6 ++++++ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/pyramid/scaffolds/tests.py b/pyramid/scaffolds/tests.py index 49358c1cf..44680a464 100644 --- a/pyramid/scaffolds/tests.py +++ b/pyramid/scaffolds/tests.py @@ -29,19 +29,18 @@ class TemplateTest(object): self.make_venv(self.directory) here = os.path.abspath(os.path.dirname(__file__)) os.chdir(os.path.dirname(os.path.dirname(here))) - subprocess.check_call( - [os.path.join(self.directory, 'bin', 'python'), - 'setup.py', 'develop']) + pip = os.path.join(self.directory, 'bin', 'pip') + subprocess.check_call([pip, 'install', '-e', '.']) os.chdir(self.directory) subprocess.check_call(['bin/pcreate', '-s', tmpl_name, 'Dingle']) os.chdir('Dingle') - py = os.path.join(self.directory, 'bin', 'python') - subprocess.check_call([py, 'setup.py', 'install']) + subprocess.check_call([pip, 'install', '.[testing]']) if tmpl_name == 'alchemy': populate = os.path.join(self.directory, 'bin', 'initialize_Dingle_db') subprocess.check_call([populate, 'development.ini']) - subprocess.check_call([py, 'setup.py', 'test']) + subprocess.check_call([ + os.path.join(self.directory, 'bin', 'py.test')]) pserve = os.path.join(self.directory, 'bin', 'pserve') for ininame, hastoolbar in (('development.ini', True), ('production.ini', False)): diff --git a/tox.ini b/tox.ini index fc47faf17..441b62223 100644 --- a/tox.ini +++ b/tox.ini @@ -39,6 +39,12 @@ commands = python pyramid/scaffolds/tests.py deps = virtualenv +[testenv:py35-scaffolds] +basepython = python3.5 +commands = + python pyramid/scaffolds/tests.py +deps = virtualenv + [testenv:pypy-scaffolds] basepython = pypy commands = -- cgit v1.2.3 From 1d7501afdda49cf5e7561e542988581c360f4ed2 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Tue, 10 May 2016 00:42:08 -0500 Subject: drop pypy3 from scaffold tests --- RELEASING.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/RELEASING.txt b/RELEASING.txt index a09b6d24a..4b4f40f99 100644 --- a/RELEASING.txt +++ b/RELEASING.txt @@ -33,8 +33,8 @@ Prepare new release branch - Run tests on Windows if feasible. -- Make sure all scaffold tests pass (Py 2.7, 3.3, 3.4, 3.5, pypy, and pypy3 on - UNIX; this doesn't work on Windows): +- Make sure all scaffold tests pass (Py 2.7, 3.3, 3.4, 3.5, and pypy on UNIX; + this doesn't work on Windows): $ ./scaffoldtests.sh -- cgit v1.2.3 From 66af391cb319c16a34acd0b1b087339e4a40271d Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Tue, 10 May 2016 00:44:47 -0500 Subject: drop pypy3 entirely until it supports py33+ --- tox.ini | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tox.ini b/tox.ini index 441b62223..55c723716 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] envlist = - py27,py33,py34,py35,pypy,pypy3, + py27,py33,py34,py35,pypy, docs,pep8, {py2,py3}-cover,coverage, @@ -13,7 +13,6 @@ basepython = py34: python3.4 py35: python3.5 pypy: pypy - pypy3: pypy3 py2: python2.7 py3: python3.5 -- cgit v1.2.3 From 1b3554b541618da9021cac26a49ea6976e66a655 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Tue, 10 May 2016 00:47:20 -0500 Subject: drop pypy3 from travis builds --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index e45f3df7d..fbdd88224 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,8 +14,6 @@ matrix: env: TOXENV=py35 - python: pypy env: TOXENV=pypy - - python: pypy3 - env: TOXENV=pypy3 - python: 3.5 env: TOXENV=py2-cover,py3-cover,coverage - python: 3.5 -- cgit v1.2.3 From e5561fcabb09173bdc12fbd47bf83aaa0407f09d Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Tue, 10 May 2016 01:53:19 -0500 Subject: fix excview tween to reraise the original exception if left unhandled by exception views fixes #2566 --- pyramid/tweens.py | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/pyramid/tweens.py b/pyramid/tweens.py index d6044dcdc..a842b1133 100644 --- a/pyramid/tweens.py +++ b/pyramid/tweens.py @@ -1,5 +1,7 @@ import sys +from pyramid.compat import reraise +from pyramid.exceptions import PredicateMismatch from pyramid.interfaces import ( IExceptionViewClassifier, IRequest, @@ -38,17 +40,26 @@ def excview_tween_factory(handler, registry): # https://github.com/Pylons/pyramid/issues/700 request_iface = attrs.get('request_iface', IRequest) provides = providedBy(exc) - response = _call_view( - registry, - request, - exc, - provides, - '', - view_classifier=IExceptionViewClassifier, - request_iface=request_iface.combined - ) + try: + response = _call_view( + registry, + request, + exc, + provides, + '', + view_classifier=IExceptionViewClassifier, + request_iface=request_iface.combined + ) + + # if views matched but did not pass predicates, squash the error + # and re-raise the original exception + except PredicateMismatch: + response = None + + # re-raise the original exception as no exception views were + # able to handle the error if response is None: - raise + reraise(*attrs['exc_info']) return response -- cgit v1.2.3 From 9b4eedc84c335b690f04fc155ccd38a615b9594b Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 10 May 2016 00:04:32 -0700 Subject: update twitter announcement --- RELEASING.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/RELEASING.txt b/RELEASING.txt index 4b4f40f99..d8572fa94 100644 --- a/RELEASING.txt +++ b/RELEASING.txt @@ -128,8 +128,12 @@ Pyramid 1.x released. PyPI https://pypi.python.org/pypi/pyramid/1.x +=== One time only for new version, first pre-release === What's New http://docs.pylonsproject.org/projects/pyramid/en/1.X-branch/whatsnew-1.X.html +=== For all subsequent pre-releases === +Changes +http://docs.pylonsproject.org/projects/pyramid/en/1.X-branch/changes.html#version-yyyy-mm-dd Issues https://github.com/Pylons/pyramid/issues -- cgit v1.2.3 From 5c89d4d4e95d0f95668d9b823159057bf5c7b289 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Tue, 10 May 2016 03:13:58 -0500 Subject: expose the IRequestFactory interface --- docs/api/interfaces.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/api/interfaces.rst b/docs/api/interfaces.rst index 272820a91..521d65d2b 100644 --- a/docs/api/interfaces.rst +++ b/docs/api/interfaces.rst @@ -59,6 +59,9 @@ Other Interfaces .. autointerface:: IRenderer :members: + .. autointerface:: IRequestFactory + :members: + .. autointerface:: IResponseFactory :members: -- cgit v1.2.3 From de61f454cdda890ffa1eebf29dc2df817398a34b Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Thu, 12 May 2016 01:51:13 -0500 Subject: add some tests for excview tween --- pyramid/tests/test_tweens.py | 73 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 pyramid/tests/test_tweens.py diff --git a/pyramid/tests/test_tweens.py b/pyramid/tests/test_tweens.py new file mode 100644 index 000000000..c8eada34c --- /dev/null +++ b/pyramid/tests/test_tweens.py @@ -0,0 +1,73 @@ +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) + + 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('/') + result = tween(request) + self.assertEqual(result.status, '404 Not Found') + + 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('/') + result = tween(request) + self.assertTrue(b'foo' in result.body) + + def test_it_reraises_on_mismatch(self): + from pyramid.request import Request + def excview(request): pass + self.config.add_view(excview, context=ValueError, request_method='GET') + def handler(request): + raise ValueError + tween = self._makeOne(handler) + request = Request.blank('/') + request.method = 'POST' + self.assertRaises(ValueError, lambda: tween(request)) + + 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('/') + self.assertRaises(ValueError, lambda: tween(request)) + +class DummyRequest: + pass + +class DummyResponse: + pass -- cgit v1.2.3 From 3a32502ee74b1a966e9e122b9d76551ec2cd7e80 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 14 May 2016 22:47:01 -0700 Subject: fix punctuation --- docs/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.rst b/docs/index.rst index 452666dc8..f337174b1 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -167,7 +167,7 @@ Comprehensive reference material for every public API exposed by ``p*`` Scripts Documentation ============================ -``p*`` scripts included with :app:`Pyramid`:. +``p*`` scripts included with :app:`Pyramid`. .. toctree:: :maxdepth: 1 -- cgit v1.2.3 From e998458448688c11c983e72e92a200056ee1739b Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 14 May 2016 23:56:32 -0700 Subject: make version perpetual --- docs/copyright.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/copyright.rst b/docs/copyright.rst index 9532c15b7..30ae40603 100644 --- a/docs/copyright.rst +++ b/docs/copyright.rst @@ -1,7 +1,7 @@ Copyright, Trademarks, and Attributions ======================================= -*The Pyramid Web Framework, Version 1.1* +"The Pyramid Web Framework, Version |version|" by Chris McDonough @@ -101,4 +101,3 @@ http://docs.pylonsproject.org/projects/pyramid/en/latest/ The source code for the examples used in this book are available within the :app:`Pyramid` software distribution, always available via https://github.com/Pylons/pyramid - -- cgit v1.2.3 From 8eb4e184c05ac1822a0ce1986bde1ad4410a9322 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 14 May 2016 23:58:11 -0700 Subject: fix IRC link and page count --- docs/designdefense.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/designdefense.rst b/docs/designdefense.rst index e759c0e2a..dbdb53b8d 100644 --- a/docs/designdefense.rst +++ b/docs/designdefense.rst @@ -1653,10 +1653,11 @@ If you can understand this hello world program, you can use Pyramid: server = make_server('0.0.0.0', 8080, app) server.serve_forever() -Pyramid has ~ 700 pages of documentation (printed), covering topics from the -very basic to the most advanced. *Nothing* is left undocumented, quite +Pyramid has about 800 pages of documentation (printed), covering topics from +the very basic to the most advanced. *Nothing* is left undocumented, quite literally. It also has an *awesome*, very helpful community. Visit the -#pyramid IRC channel on freenode.net (irc://freenode.net#pyramid) and see. +`#pyramid IRC channel on freenode.net +`_ and see. Hate Zope +++++++++ -- cgit v1.2.3 From da1c240b3c589340f28a20366d02239f1314f965 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 15 May 2016 03:00:43 -0700 Subject: revise latexindex.rst - add designdefense, quick_tour, quick_tutorial, p* scripts, change history --- docs/latexindex.rst | 59 ++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 45 insertions(+), 14 deletions(-) diff --git a/docs/latexindex.rst b/docs/latexindex.rst index c4afff212..05199d313 100644 --- a/docs/latexindex.rst +++ b/docs/latexindex.rst @@ -14,12 +14,27 @@ Front Matter .. toctree:: :maxdepth: 1 - copyright.rst - conventions.rst - authorintro.rst + copyright + conventions + authorintro + designdefense .. mainmatter:: +.. _tutorials: + +Tutorials +@@@@@@@@@ + +.. toctree:: + :maxdepth: 1 + + quick_tour + quick_tutorial/index + tutorials/wiki2/index + tutorials/wiki/index + tutorials/modwsgi/index + .. _narrative_documentation: Narrative Documentation @@ -68,31 +83,47 @@ Narrative Documentation narr/threadlocals narr/zca -.. _tutorials: - -Tutorials -@@@@@@@@@ +API Documentation +@@@@@@@@@@@@@@@@@ .. toctree:: :maxdepth: 1 + :glob: - tutorials/wiki2/index.rst - tutorials/wiki/index.rst - tutorials/modwsgi/index.rst + api/index + api/* -.. _api_documentation: -API Documentation -@@@@@@@@@@@@@@@@@ +``p*`` Scripts Documentation +@@@@@@@@@@@@@@@@@@@@@@@@@@@@ .. toctree:: :maxdepth: 1 :glob: - api/* + pscripts/index + pscripts/* + .. backmatter:: +Change History +@@@@@@@@@@@@@@ + +.. toctree:: + :maxdepth: 1 + + whatsnew-1.7 + whatsnew-1.6 + whatsnew-1.5 + whatsnew-1.4 + whatsnew-1.3 + whatsnew-1.2 + whatsnew-1.1 + whatsnew-1.0 + changes + + Glossary and Index @@@@@@@@@@@@@@@@@@ -- cgit v1.2.3 From b8dd44f39d4372abfff503904cda94f2030128d7 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 15 May 2016 03:01:16 -0700 Subject: fix page count --- docs/designdefense.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/designdefense.rst b/docs/designdefense.rst index dbdb53b8d..f42582e47 100644 --- a/docs/designdefense.rst +++ b/docs/designdefense.rst @@ -1653,7 +1653,7 @@ If you can understand this hello world program, you can use Pyramid: server = make_server('0.0.0.0', 8080, app) server.serve_forever() -Pyramid has about 800 pages of documentation (printed), covering topics from +Pyramid has over 1200 pages of documentation (printed), covering topics from the very basic to the most advanced. *Nothing* is left undocumented, quite literally. It also has an *awesome*, very helpful community. Visit the `#pyramid IRC channel on freenode.net -- cgit v1.2.3 From f3a884f2ef39f7768c82be5dfca759852f1e443a Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 15 May 2016 03:02:26 -0700 Subject: use characters that don't break the latexpdf builder. See #2572 --- docs/quick_tutorial/requirements.rst | 18 +++++++++--------- docs/quick_tutorial/tutorial_approach.rst | 16 ++++++++-------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/docs/quick_tutorial/requirements.rst b/docs/quick_tutorial/requirements.rst index 1f2b4da97..62dd570fc 100644 --- a/docs/quick_tutorial/requirements.rst +++ b/docs/quick_tutorial/requirements.rst @@ -79,15 +79,15 @@ will reside as we proceed through the tutorial: .. code-block:: text - └── ~ - └── projects - └── quick_tutorial - ├── env - └── step_one - ├── intro - │ ├── __init__.py - │ └── app.py - └── setup.py + `── ~ + `── projects + `── quick_tutorial + │── env + `── step_one + │── intro + │ │── __init__.py + │ `── app.py + `── setup.py For Linux, the commands to do so are as follows: diff --git a/docs/quick_tutorial/tutorial_approach.rst b/docs/quick_tutorial/tutorial_approach.rst index 6d534fe13..49a6bfd85 100644 --- a/docs/quick_tutorial/tutorial_approach.rst +++ b/docs/quick_tutorial/tutorial_approach.rst @@ -32,14 +32,14 @@ below: .. code-block:: text quick_tutorial - ├── env - └── request_response - ├── tutorial - │ ├── __init__.py - │ ├── tests.py - │ └── views.py - ├── development.ini - └── setup.py + │── env + `── request_response + `── tutorial + │ │── __init__.py + │ │── tests.py + │ `── views.py + │── development.ini + `── setup.py Each of the first-level directories (e.g., ``request_response``) is a *Python project* (except as noted for the ``hello_world`` step). The ``tutorial`` -- cgit v1.2.3 From d66e2080906ec41a84d63f19765c10bf018e256b Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 15 May 2016 03:03:07 -0700 Subject: reorganize authorintro sections to align with latexindex --- docs/authorintro.rst | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/docs/authorintro.rst b/docs/authorintro.rst index ebc6bcff8..6e96fad9a 100644 --- a/docs/authorintro.rst +++ b/docs/authorintro.rst @@ -54,7 +54,14 @@ technologies. Book Content ============ -This book is divided into three major parts: +This book is divided into four major parts: + +:ref:`tutorials` + + Each tutorial builds a sample application or implements a set of + concepts with a sample; it then describes the application or + concepts in terms of the sample. You should read the tutorials if + you want a guided tour of :app:`Pyramid`. :ref:`narrative_documentation` @@ -66,19 +73,16 @@ This book is divided into three major parts: out-of-order, or when you need only a reminder about a particular topic while you're developing an application. -:ref:`tutorials` - - Each tutorial builds a sample application or implements a set of - concepts with a sample; it then describes the application or - concepts in terms of the sample. You should read the tutorials if - you want a guided tour of :app:`Pyramid`. - :ref:`api_documentation` Comprehensive reference material for every public API exposed by :app:`Pyramid`. The API documentation is organized alphabetically by module name. +:ref:`pscripts_documentation` + + ``p*`` scripts included with :app:`Pyramid`. + .. index:: single: repoze.zope2 single: Zope 3 -- cgit v1.2.3 From 9337737a9ce2403c724cdd4d3ce8a7f0e5e85e47 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 15 May 2016 03:03:37 -0700 Subject: fix headings and suffices --- docs/api/index.rst | 2 +- docs/index.rst | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/api/index.rst b/docs/api/index.rst index cb38aa0b2..4b912e2bd 100644 --- a/docs/api/index.rst +++ b/docs/api/index.rst @@ -1,4 +1,4 @@ -.. _html_api_documentation: +.. _api_documentation: API Documentation ================= diff --git a/docs/index.rst b/docs/index.rst index f337174b1..cb63832c1 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -18,7 +18,7 @@ After you install :app:`Pyramid` and run this application, when you visit this application works. -.. _html_getting_started: +.. _getting_started: Getting Started =============== @@ -60,9 +60,9 @@ platforms. .. toctree:: :maxdepth: 1 - tutorials/wiki2/index.rst - tutorials/wiki/index.rst - tutorials/modwsgi/index.rst + tutorials/wiki2/index + tutorials/wiki/index + tutorials/modwsgi/index .. _support-and-development: -- cgit v1.2.3 From 5b73bd4fce3f00fef581940ca6ca972576c03094 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Sun, 15 May 2016 23:11:29 -0500 Subject: password_hash is unicode, needs to be encoded --- docs/tutorials/wiki2/src/authentication/tutorial/models/user.py | 2 +- docs/tutorials/wiki2/src/models/tutorial/models/user.py | 2 +- docs/tutorials/wiki2/src/tests/tutorial/models/user.py | 2 +- docs/tutorials/wiki2/src/views/tutorial/models/user.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/tutorials/wiki2/src/authentication/tutorial/models/user.py b/docs/tutorials/wiki2/src/authentication/tutorial/models/user.py index 6bd3315d6..6fb32a1b2 100644 --- a/docs/tutorials/wiki2/src/authentication/tutorial/models/user.py +++ b/docs/tutorials/wiki2/src/authentication/tutorial/models/user.py @@ -23,7 +23,7 @@ class User(Base): def check_password(self, pw): if self.password_hash is not None: - expected_hash = self.password_hash + expected_hash = self.password_hash.encode('utf8') actual_hash = bcrypt.hashpw(pw.encode('utf8'), expected_hash) return expected_hash == actual_hash return False diff --git a/docs/tutorials/wiki2/src/models/tutorial/models/user.py b/docs/tutorials/wiki2/src/models/tutorial/models/user.py index 6bd3315d6..6fb32a1b2 100644 --- a/docs/tutorials/wiki2/src/models/tutorial/models/user.py +++ b/docs/tutorials/wiki2/src/models/tutorial/models/user.py @@ -23,7 +23,7 @@ class User(Base): def check_password(self, pw): if self.password_hash is not None: - expected_hash = self.password_hash + expected_hash = self.password_hash.encode('utf8') actual_hash = bcrypt.hashpw(pw.encode('utf8'), expected_hash) return expected_hash == actual_hash return False diff --git a/docs/tutorials/wiki2/src/tests/tutorial/models/user.py b/docs/tutorials/wiki2/src/tests/tutorial/models/user.py index 6bd3315d6..6fb32a1b2 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/models/user.py +++ b/docs/tutorials/wiki2/src/tests/tutorial/models/user.py @@ -23,7 +23,7 @@ class User(Base): def check_password(self, pw): if self.password_hash is not None: - expected_hash = self.password_hash + expected_hash = self.password_hash.encode('utf8') actual_hash = bcrypt.hashpw(pw.encode('utf8'), expected_hash) return expected_hash == actual_hash return False diff --git a/docs/tutorials/wiki2/src/views/tutorial/models/user.py b/docs/tutorials/wiki2/src/views/tutorial/models/user.py index 6bd3315d6..6fb32a1b2 100644 --- a/docs/tutorials/wiki2/src/views/tutorial/models/user.py +++ b/docs/tutorials/wiki2/src/views/tutorial/models/user.py @@ -23,7 +23,7 @@ class User(Base): def check_password(self, pw): if self.password_hash is not None: - expected_hash = self.password_hash + expected_hash = self.password_hash.encode('utf8') actual_hash = bcrypt.hashpw(pw.encode('utf8'), expected_hash) return expected_hash == actual_hash return False -- cgit v1.2.3 From ab03198772afedf9a03dc3a0c689720de97f1acb Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 16 May 2016 00:32:00 -0700 Subject: remove reference to Twitter Bootstrap styling. Closes #2570. --- docs/quick_tutorial/forms.rst | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/docs/quick_tutorial/forms.rst b/docs/quick_tutorial/forms.rst index 6b29833bd..66e77491d 100644 --- a/docs/quick_tutorial/forms.rst +++ b/docs/quick_tutorial/forms.rst @@ -1,7 +1,7 @@ .. _qtut_forms: ==================================== -18: Forms and Validation With Deform +18: Forms and Validation with Deform ==================================== Schema-driven, autogenerated forms with validation. @@ -19,9 +19,6 @@ Instead there are a variety of form libraries that are easy to use in Pyramid. Deform for our forms. This also gives us :ref:`Colander ` for schemas and validation. -Deform uses styling from Twitter Bootstrap and advanced widgets from popular -JavaScript projects. - Objectives ========== -- cgit v1.2.3 From dcb5d6922b8939963ed1995bc04fe096b9b0d6ae Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 16 May 2016 00:53:00 -0700 Subject: Change link from pylonsproject.org to trypyramid.com --- docs/index.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index cb63832c1..d4476a952 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -70,8 +70,9 @@ platforms. Support and Development ======================= -The `Pylons Project web site `_ is the main -online source of :app:`Pyramid` support and development information. +The `Pyramid website `_ is the main +entry point to :app:`Pyramid` web framework resources for support and +development information. To report bugs, use the `issue tracker `_. -- cgit v1.2.3 From 88030f98e792c4f9723faba80de0a79784238725 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 16 May 2016 01:02:49 -0700 Subject: remove stray / --- docs/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.rst b/docs/index.rst index d4476a952..02c35866a 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -70,7 +70,7 @@ platforms. Support and Development ======================= -The `Pyramid website `_ is the main +The `Pyramid website `_ is the main entry point to :app:`Pyramid` web framework resources for support and development information. -- cgit v1.2.3 From 2e7c71a65bde37e59773298f01b751c0bee32ecc Mon Sep 17 00:00:00 2001 From: Berker Peksag Date: Mon, 16 May 2016 22:14:13 +0300 Subject: Simplify Windows detection code --- CONTRIBUTORS.txt | 2 ++ pyramid/compat.py | 5 +---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index 55fdf096b..762793d0b 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -268,3 +268,5 @@ Contributors - Arian Maykon de A. Diógenes, 2016/04/13 - Vincent Férotin, 2016/05/08 + +- Berker Peksag, 2016/05/16 diff --git a/pyramid/compat.py b/pyramid/compat.py index 2bfbabb8e..3f38b88a6 100644 --- a/pyramid/compat.py +++ b/pyramid/compat.py @@ -3,10 +3,7 @@ import platform import sys import types -if platform.system() == 'Windows': # pragma: no cover - WIN = True -else: # pragma: no cover - WIN = False +WIN = platform.system() == 'Windows' try: # pragma: no cover import __pypy__ -- cgit v1.2.3 From ea560a1b7df1690d60ccadcbe6cc25dee11ea0f0 Mon Sep 17 00:00:00 2001 From: Berker Peksag Date: Mon, 16 May 2016 22:21:11 +0300 Subject: Delete duplicate getargspec imports --- pyramid/compat.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/pyramid/compat.py b/pyramid/compat.py index 2bfbabb8e..0532e179f 100644 --- a/pyramid/compat.py +++ b/pyramid/compat.py @@ -215,11 +215,6 @@ if PY2: else: input_ = input -if PY2: - from inspect import getargspec -else: - from inspect import getfullargspec as getargspec - if PY2: from io import BytesIO as NativeIO else: -- cgit v1.2.3 From 6d42e2d4118cdc656bbb8301cf5a08adb4b855d5 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Thu, 19 May 2016 22:32:12 -0500 Subject: update contributing to reference 1.7 as stable --- contributing.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/contributing.md b/contributing.md index 1393a2507..ae201d370 100644 --- a/contributing.md +++ b/contributing.md @@ -25,13 +25,11 @@ Git branches and their purpose and status at the time of this writing are listed below. * [master](https://github.com/Pylons/pyramid/) - The branch on which further -development takes place. The default branch on GitHub. + development takes place. The default branch on GitHub. * [1.7-branch](https://github.com/Pylons/pyramid/tree/1.7-branch) - The branch -classified as alpha. Actively maintained. -* [1.6-branch](https://github.com/Pylons/pyramid/tree/1.6-branch) - The branch -classified as "stable" or "latest". Actively maintained. -* [1.5-branch](https://github.com/Pylons/pyramid/tree/1.5-branch) - The oldest -actively maintained and stable branch. + classified as "stable" or "latest". +* [1.6-branch](https://github.com/Pylons/pyramid/tree/1.6-branch) - The oldest + actively maintained and stable branch. Older branches are not actively maintained. In general, two stable branches and one or two development branches are actively maintained. -- cgit v1.2.3 From f038c7d477f98713d48eed9f74822f2b2d7028cd Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Thu, 19 May 2016 23:06:49 -0500 Subject: update master's history with the changelog from 1.7 --- HISTORY.txt | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++ docs/whatsnew-1.7.rst | 34 +++++++++++++---- 2 files changed, 127 insertions(+), 8 deletions(-) diff --git a/HISTORY.txt b/HISTORY.txt index 53a17a4d3..5de5b20bd 100644 --- a/HISTORY.txt +++ b/HISTORY.txt @@ -1,3 +1,104 @@ +1.7 (2016-05-19) +================ + +- Fix a bug in the wiki2 tutorial where bcrypt is always expecting byte + strings. See https://github.com/Pylons/pyramid/pull/2576 + +- Simplify windows detection code and remove some duplicated data. + See https://github.com/Pylons/pyramid/pull/2585 and + https://github.com/Pylons/pyramid/pull/2586 + +1.7b4 (2016-05-12) +================== + +- Fixed the exception view tween to re-raise the original exception if + no exception view could be found to handle the exception. This better + allows tweens further up the chain to handle exceptions that were + left unhandled. Previously they would be converted into a + ``PredicateMismatch`` exception if predicates failed to allow the view to + handle the exception. + See https://github.com/Pylons/pyramid/pull/2567 + +- Exposed the ``pyramid.interfaces.IRequestFactory`` interface to mirror + the public ``pyramid.interfaces.IResponseFactory`` interface. + +1.7b3 (2016-05-10) +================== + +- Fix ``request.invoke_exception_view`` to raise an ``HTTPNotFound`` + exception if no view is matched. Previously ``None`` would be returned + if no views were matched and a ``PredicateMismatch`` would be raised if + a view "almost" matched (a view was found matching the context). + See https://github.com/Pylons/pyramid/pull/2564 + +- Add defaults for py.test configuration and coverage to all three scaffolds, + and update documentation accordingly. + See https://github.com/Pylons/pyramid/pull/2550 + +- Add ``linkcheck`` to ``Makefile`` for Sphinx. To check the documentation for + broken links, use the command ``make linkcheck + SPHINXBUILD=$VENV/bin/sphinx-build``. Also removed and fixed dozens of broken + external links. + +- Fix the internal runner for scaffold tests to ensure they work with pip + and py.test. + See https://github.com/Pylons/pyramid/pull/2565 + +1.7b2 (2016-05-01) +================== + +- Removed inclusion of pyramid_tm in development.ini for alchemy scaffold + See https://github.com/Pylons/pyramid/issues/2538 + +- A default permission set via ``config.set_default_permission`` will no + longer be enforced on an exception view. This has been the case for a while + with the default exception views (``config.add_notfound_view`` and + ``config.add_forbidden_view``), however for any other exception view a + developer had to remember to set ``permission=NO_PERMISSION_REQUIRED`` or + be surprised when things didn't work. It is still possible to force a + permission check on an exception view by setting the ``permission`` argument + manually to ``config.add_view``. This behavior is consistent with the new + CSRF features added in the 1.7 series. + See https://github.com/Pylons/pyramid/pull/2534 + +1.7b1 (2016-04-25) +================== + +- This release announces the beta period for 1.7. + +- Fix an issue where some files were being included in the alchemy scafffold + which had been removed from the 1.7 series. + See https://github.com/Pylons/pyramid/issues/2525 + +1.7a2 (2016-04-19) +================== + +Features +-------- + +- Automatic CSRF checks are now disabled by default on exception views. They + can be turned back on by setting the appropriate `require_csrf` option on + the view. + See https://github.com/Pylons/pyramid/pull/2517 + +- The automatic CSRF API was reworked to use a config directive for + setting the options. The ``pyramid.require_default_csrf`` setting is + no longer supported. Instead, a new ``config.set_default_csrf_options`` + directive has been introduced that allows the developer to specify + the default value for ``require_csrf`` as well as change the CSRF token, + header and safe request methods. The ``pyramid.csrf_trusted_origins`` + setting is still supported. + See https://github.com/Pylons/pyramid/pull/2518 + +Bug fixes +--------- + +- CSRF origin checks had a bug causing the checks to always fail. + See https://github.com/Pylons/pyramid/pull/2512 + +- Fix the test suite to pass on windows. + See https://github.com/Pylons/pyramid/pull/2520 + 1.7a1 (2016-04-16) ================== diff --git a/docs/whatsnew-1.7.rst b/docs/whatsnew-1.7.rst index fd144a24a..398b12f01 100644 --- a/docs/whatsnew-1.7.rst +++ b/docs/whatsnew-1.7.rst @@ -32,6 +32,11 @@ Backwards Incompatibilities csrf token in the query string of a request. Only headers and request bodies are supported. See https://github.com/Pylons/pyramid/pull/2500 +- A global permission set via + :meth:`pyramid.config.Configurator.set_default_permission` will no longer + affect exception views. A permission must be set explicitly on the view for + it to be enforced. See https://github.com/Pylons/pyramid/pull/2534 + Feature Additions ----------------- @@ -42,14 +47,6 @@ Feature Additions other stages of the pipeline such as the raw response from a view or prior to security checks. See https://github.com/Pylons/pyramid/pull/2021 -- Added a new setting, ``pyramid.require_default_csrf`` which may be used - to turn on CSRF checks globally for every request in the application. - This should be considered a good default for websites built on Pyramid. - It is possible to opt-out of CSRF checks on a per-view basis by setting - ``require_csrf=False`` on those views. - See :ref:`auto_csrf_checking` and - https://github.com/Pylons/pyramid/pull/2413 - - Added a ``require_csrf`` view option which will enforce CSRF checks on requests with an unsafe method as defined by RFC2616. If the CSRF check fails a ``BadCSRFToken`` exception will be raised and may be caught by exception @@ -60,6 +57,17 @@ Feature Additions https://github.com/Pylons/pyramid/pull/2413 and https://github.com/Pylons/pyramid/pull/2500 +- Added a new method, + :meth:`pyramid.config.Configurator.set_csrf_default_options`, + for configuring CSRF checks used by the ``require_csrf=True`` view option. + This method can be used to turn on CSRF checks globally for every view + in the application. This should be considered a good default for websites + built on Pyramid. It is possible to opt-out of CSRF checks on a per-view + basis by setting ``require_csrf=False`` on those views. + See :ref:`auto_csrf_checking` and + https://github.com/Pylons/pyramid/pull/2413 and + https://github.com/Pylons/pyramid/pull/2518 + - Added an additional CSRF validation that checks the origin/referrer of a request and makes sure it matches the current ``request.domain``. This particular check is only active when accessing a site over HTTPS as otherwise @@ -96,6 +104,11 @@ Feature Additions ``EXCVIEW`` tween where you may need more control over the request. See https://github.com/Pylons/pyramid/pull/2393 +- A global permission set via + :meth:`pyramid.config.Configurator.set_default_permission` will no longer + affect exception views. A permission must be set explicitly on the view for + it to be enforced. See https://github.com/Pylons/pyramid/pull/2534 + - Allow a leading ``=`` on the key of the request param predicate. For example, ``'=abc=1'`` is equivalent down to ``request.params['=abc'] == '1'``. @@ -111,6 +124,11 @@ Feature Additions :func:`pyramid.paster.setup_logging`. See https://github.com/Pylons/pyramid/pull/2399 +- The :attr:`pyramid.tweens.EXCVIEW` tween will now re-raise the original + exception if no exception view could be found to handle it. This allows + the exception to be handled upstream by another tween or middelware. + See https://github.com/Pylons/pyramid/pull/2567 + Deprecations ------------ -- cgit v1.2.3 From 4918628b83319749f73e843ef01a0b9060f5956e Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Thu, 19 May 2016 23:37:38 -0500 Subject: oops, encode the password in the authorization tutorial as well --- docs/tutorials/wiki2/src/authorization/tutorial/models/user.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/models/user.py b/docs/tutorials/wiki2/src/authorization/tutorial/models/user.py index 6bd3315d6..6fb32a1b2 100644 --- a/docs/tutorials/wiki2/src/authorization/tutorial/models/user.py +++ b/docs/tutorials/wiki2/src/authorization/tutorial/models/user.py @@ -23,7 +23,7 @@ class User(Base): def check_password(self, pw): if self.password_hash is not None: - expected_hash = self.password_hash + expected_hash = self.password_hash.encode('utf8') actual_hash = bcrypt.hashpw(pw.encode('utf8'), expected_hash) return expected_hash == actual_hash return False -- cgit v1.2.3 From e8a994a75ddd46769c4d25d0cb64072a5bfaf53a Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 19 May 2016 21:49:44 -0700 Subject: update link to canonical location for support and documentation --- README.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 1b3e01b04..dec7e03d0 100644 --- a/README.rst +++ b/README.rst @@ -26,8 +26,9 @@ Pyramid is produced by the `Pylons Project `_. Support and Documentation ------------------------- -See the `Pylons Project website `_ to view -documentation, report bugs, and obtain support. +See `Pyramid Support and Development +`_ +for documentation, reporting bugs, and getting support. Developing and Contributing --------------------------- -- cgit v1.2.3 From a004ca4068b60fa79552b71da2d953e47463a536 Mon Sep 17 00:00:00 2001 From: viniciusban Date: Fri, 20 May 2016 15:32:26 -0300 Subject: Change column `Page.data` to `Text` --- docs/tutorials/wiki2/src/authentication/tutorial/models/page.py | 2 +- docs/tutorials/wiki2/src/authorization/tutorial/models/page.py | 2 +- docs/tutorials/wiki2/src/models/tutorial/models/page.py | 2 +- docs/tutorials/wiki2/src/tests/tutorial/models/page.py | 2 +- docs/tutorials/wiki2/src/views/tutorial/models/page.py | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/tutorials/wiki2/src/authentication/tutorial/models/page.py b/docs/tutorials/wiki2/src/authentication/tutorial/models/page.py index 4dd5b5721..74ff1faf8 100644 --- a/docs/tutorials/wiki2/src/authentication/tutorial/models/page.py +++ b/docs/tutorials/wiki2/src/authentication/tutorial/models/page.py @@ -14,7 +14,7 @@ class Page(Base): __tablename__ = 'pages' id = Column(Integer, primary_key=True) name = Column(Text, nullable=False, unique=True) - data = Column(Integer, nullable=False) + data = Column(Text, nullable=False) creator_id = Column(ForeignKey('users.id'), nullable=False) creator = relationship('User', backref='created_pages') diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/models/page.py b/docs/tutorials/wiki2/src/authorization/tutorial/models/page.py index 4dd5b5721..74ff1faf8 100644 --- a/docs/tutorials/wiki2/src/authorization/tutorial/models/page.py +++ b/docs/tutorials/wiki2/src/authorization/tutorial/models/page.py @@ -14,7 +14,7 @@ class Page(Base): __tablename__ = 'pages' id = Column(Integer, primary_key=True) name = Column(Text, nullable=False, unique=True) - data = Column(Integer, nullable=False) + data = Column(Text, nullable=False) creator_id = Column(ForeignKey('users.id'), nullable=False) creator = relationship('User', backref='created_pages') diff --git a/docs/tutorials/wiki2/src/models/tutorial/models/page.py b/docs/tutorials/wiki2/src/models/tutorial/models/page.py index 4dd5b5721..74ff1faf8 100644 --- a/docs/tutorials/wiki2/src/models/tutorial/models/page.py +++ b/docs/tutorials/wiki2/src/models/tutorial/models/page.py @@ -14,7 +14,7 @@ class Page(Base): __tablename__ = 'pages' id = Column(Integer, primary_key=True) name = Column(Text, nullable=False, unique=True) - data = Column(Integer, nullable=False) + data = Column(Text, nullable=False) creator_id = Column(ForeignKey('users.id'), nullable=False) creator = relationship('User', backref='created_pages') diff --git a/docs/tutorials/wiki2/src/tests/tutorial/models/page.py b/docs/tutorials/wiki2/src/tests/tutorial/models/page.py index 4dd5b5721..74ff1faf8 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/models/page.py +++ b/docs/tutorials/wiki2/src/tests/tutorial/models/page.py @@ -14,7 +14,7 @@ class Page(Base): __tablename__ = 'pages' id = Column(Integer, primary_key=True) name = Column(Text, nullable=False, unique=True) - data = Column(Integer, nullable=False) + data = Column(Text, nullable=False) creator_id = Column(ForeignKey('users.id'), nullable=False) creator = relationship('User', backref='created_pages') diff --git a/docs/tutorials/wiki2/src/views/tutorial/models/page.py b/docs/tutorials/wiki2/src/views/tutorial/models/page.py index 4dd5b5721..74ff1faf8 100644 --- a/docs/tutorials/wiki2/src/views/tutorial/models/page.py +++ b/docs/tutorials/wiki2/src/views/tutorial/models/page.py @@ -14,7 +14,7 @@ class Page(Base): __tablename__ = 'pages' id = Column(Integer, primary_key=True) name = Column(Text, nullable=False, unique=True) - data = Column(Integer, nullable=False) + data = Column(Text, nullable=False) creator_id = Column(ForeignKey('users.id'), nullable=False) creator = relationship('User', backref='created_pages') -- cgit v1.2.3 From 8a6f759f46da108b24283ed3fae099a0007c5a70 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 21 May 2016 11:05:57 -0700 Subject: Change type to Text from Integer. See #2591 --- pyramid/scaffolds/alchemy/+package+/models/mymodel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyramid/scaffolds/alchemy/+package+/models/mymodel.py b/pyramid/scaffolds/alchemy/+package+/models/mymodel.py index d65a01a42..1d2abaf25 100644 --- a/pyramid/scaffolds/alchemy/+package+/models/mymodel.py +++ b/pyramid/scaffolds/alchemy/+package+/models/mymodel.py @@ -12,7 +12,7 @@ class MyModel(Base): __tablename__ = 'models' id = Column(Integer, primary_key=True) name = Column(Text) - value = Column(Integer) + value = Column(Text) Index('my_index', MyModel.name, unique=True, mysql_length=255) -- cgit v1.2.3 From 224b9878a11046297d1a64092a240e80e8129f04 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 22 May 2016 03:51:35 -0700 Subject: Change type to Text from Integer. See #2591 --- docs/quick_tour/sqla_demo/sqla_demo/models/mymodel.py | 2 +- docs/tutorials/wiki2/src/basiclayout/tutorial/models/mymodel.py | 2 +- docs/tutorials/wiki2/src/installation/tutorial/models/mymodel.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/quick_tour/sqla_demo/sqla_demo/models/mymodel.py b/docs/quick_tour/sqla_demo/sqla_demo/models/mymodel.py index eb645bfe6..cdb748fc7 100644 --- a/docs/quick_tour/sqla_demo/sqla_demo/models/mymodel.py +++ b/docs/quick_tour/sqla_demo/sqla_demo/models/mymodel.py @@ -12,7 +12,7 @@ class MyModel(Base): __tablename__ = 'models' id = Column(Integer, primary_key=True) name = Column(Text) - value = Column(Integer) + value = Column(Text) # End Sphinx Include diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/models/mymodel.py b/docs/tutorials/wiki2/src/basiclayout/tutorial/models/mymodel.py index d65a01a42..1d2abaf25 100644 --- a/docs/tutorials/wiki2/src/basiclayout/tutorial/models/mymodel.py +++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/models/mymodel.py @@ -12,7 +12,7 @@ class MyModel(Base): __tablename__ = 'models' id = Column(Integer, primary_key=True) name = Column(Text) - value = Column(Integer) + value = Column(Text) Index('my_index', MyModel.name, unique=True, mysql_length=255) diff --git a/docs/tutorials/wiki2/src/installation/tutorial/models/mymodel.py b/docs/tutorials/wiki2/src/installation/tutorial/models/mymodel.py index d65a01a42..1d2abaf25 100644 --- a/docs/tutorials/wiki2/src/installation/tutorial/models/mymodel.py +++ b/docs/tutorials/wiki2/src/installation/tutorial/models/mymodel.py @@ -12,7 +12,7 @@ class MyModel(Base): __tablename__ = 'models' id = Column(Integer, primary_key=True) name = Column(Text) - value = Column(Integer) + value = Column(Text) Index('my_index', MyModel.name, unique=True, mysql_length=255) -- cgit v1.2.3 From 45835ac934fc8e74cbb31308196442ab144ac043 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 22 May 2016 04:21:36 -0700 Subject: change type integer to type text, and update output of db init script - update output of running pytest coverage --- docs/tutorials/wiki2/definingmodels.rst | 70 ++++++++++++++++----------------- docs/tutorials/wiki2/installation.rst | 50 +++++++++++------------ 2 files changed, 59 insertions(+), 61 deletions(-) diff --git a/docs/tutorials/wiki2/definingmodels.rst b/docs/tutorials/wiki2/definingmodels.rst index 6520613ea..9f7b82d1d 100644 --- a/docs/tutorials/wiki2/definingmodels.rst +++ b/docs/tutorials/wiki2/definingmodels.rst @@ -191,49 +191,49 @@ Success will look something like this: .. code-block:: bash - 2016-04-09 02:49:51,711 INFO [sqlalchemy.engine.base.Engine:1192][MainThread] SELECT CAST('test plain returns' AS VARCHAR(60)) AS anon_1 - 2016-04-09 02:49:51,711 INFO [sqlalchemy.engine.base.Engine:1193][MainThread] () - 2016-04-09 02:49:51,712 INFO [sqlalchemy.engine.base.Engine:1192][MainThread] SELECT CAST('test unicode returns' AS VARCHAR(60)) AS anon_1 - 2016-04-09 02:49:51,712 INFO [sqlalchemy.engine.base.Engine:1193][MainThread] () - 2016-04-09 02:49:51,713 INFO [sqlalchemy.engine.base.Engine:1097][MainThread] PRAGMA table_info("pages") - 2016-04-09 02:49:51,714 INFO [sqlalchemy.engine.base.Engine:1100][MainThread] () - 2016-04-09 02:49:51,714 INFO [sqlalchemy.engine.base.Engine:1097][MainThread] PRAGMA table_info("users") - 2016-04-09 02:49:51,714 INFO [sqlalchemy.engine.base.Engine:1100][MainThread] () - 2016-04-09 02:49:51,715 INFO [sqlalchemy.engine.base.Engine:1097][MainThread] + 2016-05-22 04:12:09,226 INFO [sqlalchemy.engine.base.Engine:1192][MainThread] SELECT CAST('test plain returns' AS VARCHAR(60)) AS anon_1 + 2016-05-22 04:12:09,226 INFO [sqlalchemy.engine.base.Engine:1193][MainThread] () + 2016-05-22 04:12:09,226 INFO [sqlalchemy.engine.base.Engine:1192][MainThread] SELECT CAST('test unicode returns' AS VARCHAR(60)) AS anon_1 + 2016-05-22 04:12:09,227 INFO [sqlalchemy.engine.base.Engine:1193][MainThread] () + 2016-05-22 04:12:09,227 INFO [sqlalchemy.engine.base.Engine:1097][MainThread] PRAGMA table_info("users") + 2016-05-22 04:12:09,227 INFO [sqlalchemy.engine.base.Engine:1100][MainThread] () + 2016-05-22 04:12:09,228 INFO [sqlalchemy.engine.base.Engine:1097][MainThread] PRAGMA table_info("pages") + 2016-05-22 04:12:09,228 INFO [sqlalchemy.engine.base.Engine:1100][MainThread] () + 2016-05-22 04:12:09,229 INFO [sqlalchemy.engine.base.Engine:1097][MainThread] CREATE TABLE users ( - id INTEGER NOT NULL, - name TEXT NOT NULL, - role TEXT NOT NULL, - password_hash TEXT, - CONSTRAINT pk_users PRIMARY KEY (id), - CONSTRAINT uq_users_name UNIQUE (name) + id INTEGER NOT NULL, + name TEXT NOT NULL, + role TEXT NOT NULL, + password_hash TEXT, + CONSTRAINT pk_users PRIMARY KEY (id), + CONSTRAINT uq_users_name UNIQUE (name) ) - 2016-04-09 02:49:51,715 INFO [sqlalchemy.engine.base.Engine:1100][MainThread] () - 2016-04-09 02:49:51,716 INFO [sqlalchemy.engine.base.Engine:686][MainThread] COMMIT - 2016-04-09 02:49:51,716 INFO [sqlalchemy.engine.base.Engine:1097][MainThread] + 2016-05-22 04:12:09,229 INFO [sqlalchemy.engine.base.Engine:1100][MainThread] () + 2016-05-22 04:12:09,230 INFO [sqlalchemy.engine.base.Engine:686][MainThread] COMMIT + 2016-05-22 04:12:09,230 INFO [sqlalchemy.engine.base.Engine:1097][MainThread] CREATE TABLE pages ( - id INTEGER NOT NULL, - name TEXT NOT NULL, - data INTEGER NOT NULL, - creator_id INTEGER NOT NULL, - CONSTRAINT pk_pages PRIMARY KEY (id), - CONSTRAINT uq_pages_name UNIQUE (name), - CONSTRAINT fk_pages_creator_id_users FOREIGN KEY(creator_id) REFERENCES users (id) + id INTEGER NOT NULL, + name TEXT NOT NULL, + data TEXT NOT NULL, + creator_id INTEGER NOT NULL, + CONSTRAINT pk_pages PRIMARY KEY (id), + CONSTRAINT uq_pages_name UNIQUE (name), + CONSTRAINT fk_pages_creator_id_users FOREIGN KEY(creator_id) REFERENCES users (id) ) - 2016-04-09 02:49:51,716 INFO [sqlalchemy.engine.base.Engine:1100][MainThread] () - 2016-04-09 02:49:51,717 INFO [sqlalchemy.engine.base.Engine:686][MainThread] COMMIT - 2016-04-09 02:49:52,256 INFO [sqlalchemy.engine.base.Engine:646][MainThread] BEGIN (implicit) - 2016-04-09 02:49:52,257 INFO [sqlalchemy.engine.base.Engine:1097][MainThread] INSERT INTO users (name, role, password_hash) VALUES (?, ?, ?) - 2016-04-09 02:49:52,257 INFO [sqlalchemy.engine.base.Engine:1100][MainThread] ('editor', 'editor', b'$2b$12$APUPJvI/kKxrbQPyQehkR.ggoOM6fFYCZ07SFCkWGltl1wJsKB98y') - 2016-04-09 02:49:52,258 INFO [sqlalchemy.engine.base.Engine:1097][MainThread] INSERT INTO users (name, role, password_hash) VALUES (?, ?, ?) - 2016-04-09 02:49:52,258 INFO [sqlalchemy.engine.base.Engine:1100][MainThread] ('basic', 'basic', b'$2b$12$GeFnypuQpZyxZLH.sN0akOrPdZMcQjqVTCim67u6f89lOFH/0ddc6') - 2016-04-09 02:49:52,259 INFO [sqlalchemy.engine.base.Engine:1097][MainThread] INSERT INTO pages (name, data, creator_id) VALUES (?, ?, ?) - 2016-04-09 02:49:52,259 INFO [sqlalchemy.engine.base.Engine:1100][MainThread] ('FrontPage', 'This is the front page', 1) - 2016-04-09 02:49:52,259 INFO [sqlalchemy.engine.base.Engine:686][MainThread] COMMIT + 2016-05-22 04:12:09,231 INFO [sqlalchemy.engine.base.Engine:1100][MainThread] () + 2016-05-22 04:12:09,231 INFO [sqlalchemy.engine.base.Engine:686][MainThread] COMMIT + 2016-05-22 04:12:09,782 INFO [sqlalchemy.engine.base.Engine:646][MainThread] BEGIN (implicit) + 2016-05-22 04:12:09,783 INFO [sqlalchemy.engine.base.Engine:1097][MainThread] INSERT INTO users (name, role, password_hash) VALUES (?, ?, ?) + 2016-05-22 04:12:09,784 INFO [sqlalchemy.engine.base.Engine:1100][MainThread] ('editor', 'editor', b'$2b$12$K/WLVKRl5fMAb6UM58ueTetXlE3rlc5cRK5zFPimK598scXBR/xWC') + 2016-05-22 04:12:09,784 INFO [sqlalchemy.engine.base.Engine:1097][MainThread] INSERT INTO users (name, role, password_hash) VALUES (?, ?, ?) + 2016-05-22 04:12:09,784 INFO [sqlalchemy.engine.base.Engine:1100][MainThread] ('basic', 'basic', b'$2b$12$JfwLyCJGv3t.RTSmIrh3B.FKXRT9FevkAqafWdK5oq7Hl4mgAQORe') + 2016-05-22 04:12:09,785 INFO [sqlalchemy.engine.base.Engine:1097][MainThread] INSERT INTO pages (name, data, creator_id) VALUES (?, ?, ?) + 2016-05-22 04:12:09,785 INFO [sqlalchemy.engine.base.Engine:1100][MainThread] ('FrontPage', 'This is the front page', 1) + 2016-05-22 04:12:09,786 INFO [sqlalchemy.engine.base.Engine:686][MainThread] COMMIT View the application in a browser diff --git a/docs/tutorials/wiki2/installation.rst b/docs/tutorials/wiki2/installation.rst index 2b8ce5dfa..0ecb6e27b 100644 --- a/docs/tutorials/wiki2/installation.rst +++ b/docs/tutorials/wiki2/installation.rst @@ -340,16 +340,14 @@ If successful, you will see output something like this: tutorial/models/__init__.py 22 0 100% tutorial/models/meta.py 5 0 100% tutorial/models/mymodel.py 8 0 100% - tutorial/routes.py 3 3 0% 1-3 + tutorial/routes.py 3 2 33% 2-3 tutorial/scripts/__init__.py 0 0 100% - tutorial/scripts/initializedb.py 26 26 0% 1-45 - tutorial/tests.py 39 0 100% + tutorial/scripts/initializedb.py 26 16 38% 22-25, 29-45 tutorial/views/__init__.py 0 0 100% tutorial/views/default.py 12 0 100% - tutorial/views/notfound.py 4 4 0% 1-7 + tutorial/views/notfound.py 4 2 50% 6-7 ---------------------------------------------------------------- - TOTAL 127 39 69% - + TOTAL 88 26 70% ===================== 2 passed in 0.57 seconds ====================== Our package doesn't quite have 100% test coverage. @@ -432,30 +430,30 @@ The output to your console should be something like this: .. code-block:: bash - 2016-04-09 00:53:37,801 INFO [sqlalchemy.engine.base.Engine:1192][MainThread] SELECT CAST('test plain returns' AS VARCHAR(60)) AS anon_1 - 2016-04-09 00:53:37,801 INFO [sqlalchemy.engine.base.Engine:1193][MainThread] () - 2016-04-09 00:53:37,802 INFO [sqlalchemy.engine.base.Engine:1192][MainThread] SELECT CAST('test unicode returns' AS VARCHAR(60)) AS anon_1 - 2016-04-09 00:53:37,802 INFO [sqlalchemy.engine.base.Engine:1193][MainThread] () - 2016-04-09 00:53:37,802 INFO [sqlalchemy.engine.base.Engine:1097][MainThread] PRAGMA table_info("models") - 2016-04-09 00:53:37,803 INFO [sqlalchemy.engine.base.Engine:1100][MainThread] () - 2016-04-09 00:53:37,803 INFO [sqlalchemy.engine.base.Engine:1097][MainThread] + 2016-05-22 04:03:28,888 INFO [sqlalchemy.engine.base.Engine:1192][MainThread] SELECT CAST('test plain returns' AS VARCHAR(60)) AS anon_1 + 2016-05-22 04:03:28,888 INFO [sqlalchemy.engine.base.Engine:1193][MainThread] () + 2016-05-22 04:03:28,888 INFO [sqlalchemy.engine.base.Engine:1192][MainThread] SELECT CAST('test unicode returns' AS VARCHAR(60)) AS anon_1 + 2016-05-22 04:03:28,889 INFO [sqlalchemy.engine.base.Engine:1193][MainThread] () + 2016-05-22 04:03:28,890 INFO [sqlalchemy.engine.base.Engine:1097][MainThread] PRAGMA table_info("models") + 2016-05-22 04:03:28,890 INFO [sqlalchemy.engine.base.Engine:1100][MainThread] () + 2016-05-22 04:03:28,892 INFO [sqlalchemy.engine.base.Engine:1097][MainThread] CREATE TABLE models ( - id INTEGER NOT NULL, - name TEXT, - value INTEGER, - CONSTRAINT pk_models PRIMARY KEY (id) + id INTEGER NOT NULL, + name TEXT, + value TEXT, + CONSTRAINT pk_models PRIMARY KEY (id) ) - 2016-04-09 00:53:37,803 INFO [sqlalchemy.engine.base.Engine:1100][MainThread] () - 2016-04-09 00:53:37,804 INFO [sqlalchemy.engine.base.Engine:686][MainThread] COMMIT - 2016-04-09 00:53:37,805 INFO [sqlalchemy.engine.base.Engine:1097][MainThread] CREATE UNIQUE INDEX my_index ON models (name) - 2016-04-09 00:53:37,805 INFO [sqlalchemy.engine.base.Engine:1100][MainThread] () - 2016-04-09 00:53:37,806 INFO [sqlalchemy.engine.base.Engine:686][MainThread] COMMIT - 2016-04-09 00:53:37,807 INFO [sqlalchemy.engine.base.Engine:646][MainThread] BEGIN (implicit) - 2016-04-09 00:53:37,808 INFO [sqlalchemy.engine.base.Engine:1097][MainThread] INSERT INTO models (name, value) VALUES (?, ?) - 2016-04-09 00:53:37,808 INFO [sqlalchemy.engine.base.Engine:1100][MainThread] ('one', 1) - 2016-04-09 00:53:37,809 INFO [sqlalchemy.engine.base.Engine:686][MainThread] COMMIT + 2016-05-22 04:03:28,892 INFO [sqlalchemy.engine.base.Engine:1100][MainThread] () + 2016-05-22 04:03:28,893 INFO [sqlalchemy.engine.base.Engine:686][MainThread] COMMIT + 2016-05-22 04:03:28,893 INFO [sqlalchemy.engine.base.Engine:1097][MainThread] CREATE UNIQUE INDEX my_index ON models (name) + 2016-05-22 04:03:28,893 INFO [sqlalchemy.engine.base.Engine:1100][MainThread] () + 2016-05-22 04:03:28,894 INFO [sqlalchemy.engine.base.Engine:686][MainThread] COMMIT + 2016-05-22 04:03:28,896 INFO [sqlalchemy.engine.base.Engine:646][MainThread] BEGIN (implicit) + 2016-05-22 04:03:28,897 INFO [sqlalchemy.engine.base.Engine:1097][MainThread] INSERT INTO models (name, value) VALUES (?, ?) + 2016-05-22 04:03:28,897 INFO [sqlalchemy.engine.base.Engine:1100][MainThread] ('one', 1) + 2016-05-22 04:03:28,898 INFO [sqlalchemy.engine.base.Engine:686][MainThread] COMMIT Success! You should now have a ``tutorial.sqlite`` file in your current working directory. This is an SQLite database with a single table defined in it -- cgit v1.2.3 From 9cd1d152c450592f29264dfdc137c8015437e1aa Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 23 May 2016 12:28:29 -0700 Subject: add optional latexpdf build for PDF to tox - Closes #2575 --- tox.ini | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tox.ini b/tox.ini index 55c723716..0156d9e51 100644 --- a/tox.ini +++ b/tox.ini @@ -64,6 +64,13 @@ commands = pip install pyramid[docs] make -C docs doctest html epub BUILDDIR={envdir} "SPHINXOPTS=-W -E" +[testenv:pdf] +basepython = python3.5 +whitelist_externals = make +commands = + pip install pyramid[docs] + make -C docs latexpdf BUILDDIR={envdir} "SPHINXOPTS=-W -E" + # we separate coverage into its own testenv because a) "last run wins" wrt # cobertura jenkins reporting and b) pypy and jython can't handle any # combination of versions of coverage and nosexcover that i can find. -- cgit v1.2.3 From f7236f8300cf38e7930a93f16a05e9ea132bad0f Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 23 May 2016 13:24:22 -0700 Subject: Merge pull request #2601 from stevepiercy/1.7-branch revert column type change in alchemy scaffold and related docs --- docs/quick_tour/sqla_demo/sqla_demo/models/mymodel.py | 2 +- docs/tutorials/wiki2/installation.rst | 2 +- docs/tutorials/wiki2/src/basiclayout/tutorial/models/mymodel.py | 2 +- docs/tutorials/wiki2/src/installation/tutorial/models/mymodel.py | 2 +- pyramid/scaffolds/alchemy/+package+/models/mymodel.py | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/quick_tour/sqla_demo/sqla_demo/models/mymodel.py b/docs/quick_tour/sqla_demo/sqla_demo/models/mymodel.py index cdb748fc7..eb645bfe6 100644 --- a/docs/quick_tour/sqla_demo/sqla_demo/models/mymodel.py +++ b/docs/quick_tour/sqla_demo/sqla_demo/models/mymodel.py @@ -12,7 +12,7 @@ class MyModel(Base): __tablename__ = 'models' id = Column(Integer, primary_key=True) name = Column(Text) - value = Column(Text) + value = Column(Integer) # End Sphinx Include diff --git a/docs/tutorials/wiki2/installation.rst b/docs/tutorials/wiki2/installation.rst index 0ecb6e27b..a214b1306 100644 --- a/docs/tutorials/wiki2/installation.rst +++ b/docs/tutorials/wiki2/installation.rst @@ -440,7 +440,7 @@ The output to your console should be something like this: CREATE TABLE models ( id INTEGER NOT NULL, name TEXT, - value TEXT, + value INTEGER, CONSTRAINT pk_models PRIMARY KEY (id) ) diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/models/mymodel.py b/docs/tutorials/wiki2/src/basiclayout/tutorial/models/mymodel.py index 1d2abaf25..d65a01a42 100644 --- a/docs/tutorials/wiki2/src/basiclayout/tutorial/models/mymodel.py +++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/models/mymodel.py @@ -12,7 +12,7 @@ class MyModel(Base): __tablename__ = 'models' id = Column(Integer, primary_key=True) name = Column(Text) - value = Column(Text) + value = Column(Integer) Index('my_index', MyModel.name, unique=True, mysql_length=255) diff --git a/docs/tutorials/wiki2/src/installation/tutorial/models/mymodel.py b/docs/tutorials/wiki2/src/installation/tutorial/models/mymodel.py index 1d2abaf25..d65a01a42 100644 --- a/docs/tutorials/wiki2/src/installation/tutorial/models/mymodel.py +++ b/docs/tutorials/wiki2/src/installation/tutorial/models/mymodel.py @@ -12,7 +12,7 @@ class MyModel(Base): __tablename__ = 'models' id = Column(Integer, primary_key=True) name = Column(Text) - value = Column(Text) + value = Column(Integer) Index('my_index', MyModel.name, unique=True, mysql_length=255) diff --git a/pyramid/scaffolds/alchemy/+package+/models/mymodel.py b/pyramid/scaffolds/alchemy/+package+/models/mymodel.py index 1d2abaf25..d65a01a42 100644 --- a/pyramid/scaffolds/alchemy/+package+/models/mymodel.py +++ b/pyramid/scaffolds/alchemy/+package+/models/mymodel.py @@ -12,7 +12,7 @@ class MyModel(Base): __tablename__ = 'models' id = Column(Integer, primary_key=True) name = Column(Text) - value = Column(Text) + value = Column(Integer) Index('my_index', MyModel.name, unique=True, mysql_length=255) -- cgit v1.2.3