From 8fe8725d4d20b18715291d3b45899d3389fe1d8b Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Sun, 15 Dec 2019 20:46:12 -0600 Subject: handle a missing content negotiation case where the unencoded option is not available and the client requests an encoded variant that doesn't exist --- src/pyramid/static.py | 1 + tests/fixtures/static/only_encoded.html.gz | Bin 0 -> 187 bytes tests/test_static.py | 81 +++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+) create mode 100644 tests/fixtures/static/only_encoded.html.gz diff --git a/src/pyramid/static.py b/src/pyramid/static.py index 7870b803e..499706554 100644 --- a/src/pyramid/static.py +++ b/src/pyramid/static.py @@ -236,6 +236,7 @@ class static_view(object): for path, encoding in files: if encoding in acceptable_encodings: return path, encoding + return None, None def add_slash_redirect(self, request): url = request.path_url + '/' diff --git a/tests/fixtures/static/only_encoded.html.gz b/tests/fixtures/static/only_encoded.html.gz new file mode 100644 index 000000000..afcc25768 Binary files /dev/null and b/tests/fixtures/static/only_encoded.html.gz differ diff --git a/tests/test_static.py b/tests/test_static.py index 3d0deda3f..73814e222 100644 --- a/tests/test_static.py +++ b/tests/test_static.py @@ -458,6 +458,87 @@ class Test_static_view_content_encodings(unittest.TestCase): self.assertEqual(res.headers['Content-Encoding'], 'gzip') self.assertEqual(len(res.body), 187) + def test_call_for_encoded_variant_without_unencoded_variant_no_accept( + self, + ): + inst = self._makeOne( + 'tests:fixtures/static', content_encodings=['gzip'] + ) + request = self._makeRequest({'PATH_INFO': '/only_encoded.html.gz'}) + context = DummyContext() + + res = inst(context, request) + self.assertNotIn('Vary', res.headers) + self.assertNotIn('Content-Encoding', res.headers) + self.assertEqual(len(res.body), 187) + + def test_call_for_encoded_variant_without_unencoded_variant_with_accept( + self, + ): + inst = self._makeOne( + 'tests:fixtures/static', content_encodings=['gzip'] + ) + request = self._makeRequest( + { + 'PATH_INFO': '/only_encoded.html.gz', + 'HTTP_ACCEPT_ENCODING': 'gzip', + } + ) + context = DummyContext() + + res = inst(context, request) + self.assertNotIn('Vary', res.headers) + self.assertNotIn('Content-Encoding', res.headers) + self.assertEqual(len(res.body), 187) + + def test_call_for_unencoded_variant_with_only_encoded_variant_no_accept( + self, + ): + inst = self._makeOne( + 'tests:fixtures/static', content_encodings=['gzip'] + ) + request = self._makeRequest({'PATH_INFO': '/only_encoded.html'}) + context = DummyContext() + + res = inst(context, request) + self.assertNotIn('Vary', res.headers) + self.assertNotIn('Content-Encoding', res.headers) + self.assertEqual(len(res.body), 187) + + def test_call_for_unencoded_variant_with_only_encoded_variant_with_accept( + self, + ): + inst = self._makeOne( + 'tests:fixtures/static', content_encodings=['gzip'] + ) + request = self._makeRequest( + { + 'PATH_INFO': '/only_encoded.html', + 'HTTP_ACCEPT_ENCODING': 'gzip', + } + ) + context = DummyContext() + + res = inst(context, request) + self.assertNotIn('Vary', res.headers) + self.assertEqual(res.headers['Content-Encoding'], 'gzip') + self.assertEqual(len(res.body), 187) + + def test_call_for_unencoded_variant_with_only_encoded_variant_bad_accept( + self, + ): + from pyramid.httpexceptions import HTTPNotFound + + inst = self._makeOne( + 'tests:fixtures/static', content_encodings=['gzip'] + ) + request = self._makeRequest( + {'PATH_INFO': '/only_encoded.html', 'HTTP_ACCEPT_ENCODING': 'br',} + ) + context = DummyContext() + + self.assertRaises(HTTPNotFound, lambda: inst(context, request)) + def test_call_get_possible_files_is_cached(self): inst = self._makeOne('tests:fixtures/static') result1 = inst.get_possible_files('tests:fixtures/static/encoded.html') -- cgit v1.2.3 From 08933ad17a230792a886020e06725e44522974d4 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Sun, 15 Dec 2019 20:52:01 -0600 Subject: fix lint --- tests/test_static.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_static.py b/tests/test_static.py index 73814e222..2933e4310 100644 --- a/tests/test_static.py +++ b/tests/test_static.py @@ -533,7 +533,7 @@ class Test_static_view_content_encodings(unittest.TestCase): 'tests:fixtures/static', content_encodings=['gzip'] ) request = self._makeRequest( - {'PATH_INFO': '/only_encoded.html', 'HTTP_ACCEPT_ENCODING': 'br',} + {'PATH_INFO': '/only_encoded.html', 'HTTP_ACCEPT_ENCODING': 'br'} ) context = DummyContext() -- cgit v1.2.3 From 497e667e41b83193d7c5a4f74e9419320d755c46 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Sun, 15 Dec 2019 20:53:52 -0600 Subject: fix failing test --- tests/test_static.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/test_static.py b/tests/test_static.py index 2933e4310..7b6e74a64 100644 --- a/tests/test_static.py +++ b/tests/test_static.py @@ -494,16 +494,15 @@ class Test_static_view_content_encodings(unittest.TestCase): def test_call_for_unencoded_variant_with_only_encoded_variant_no_accept( self, ): + from pyramid.httpexceptions import HTTPNotFound + inst = self._makeOne( 'tests:fixtures/static', content_encodings=['gzip'] ) request = self._makeRequest({'PATH_INFO': '/only_encoded.html'}) context = DummyContext() - res = inst(context, request) - self.assertNotIn('Vary', res.headers) - self.assertNotIn('Content-Encoding', res.headers) - self.assertEqual(len(res.body), 187) + self.assertRaises(HTTPNotFound, lambda: inst(context, request)) def test_call_for_unencoded_variant_with_only_encoded_variant_with_accept( self, -- cgit v1.2.3 From 3f42e5f2c848e69f282337f6fbf56e69b295b58e Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 15 Dec 2019 23:14:19 -0800 Subject: Remove Python 3.4, Python 3.5, and add Python 3.8 --- docs/narr/install.rst | 6 +++--- docs/narr/logging.rst | 2 +- docs/narr/upgrading.rst | 6 +++--- docs/quick_tutorial/requirements.rst | 4 ++-- docs/tutorials/modwsgi/index.rst | 2 +- docs/tutorials/wiki/installation.rst | 2 -- docs/tutorials/wiki/tests.rst | 3 --- setup.py | 3 +-- 8 files changed, 11 insertions(+), 17 deletions(-) diff --git a/docs/narr/install.rst b/docs/narr/install.rst index 268ae5f8d..903769b59 100644 --- a/docs/narr/install.rst +++ b/docs/narr/install.rst @@ -5,7 +5,7 @@ Installing :app:`Pyramid` .. note:: - This installation guide emphasizes the use of Python 3.4 and greater for + This installation guide emphasizes the use of Python 3.6 and greater for simplicity. @@ -15,13 +15,13 @@ Installing :app:`Pyramid` Before You Install Pyramid -------------------------- -Install Python version 3.4 or greater for your operating system, and satisfy +Install Python version 3.6 or greater for your operating system, and satisfy the :ref:`requirements-for-installing-packages`, as described in the following sections. .. sidebar:: Python Versions - As of this writing, :app:`Pyramid` is tested against Python 3.4, Python 3.5, Python 3.6, Python 3.7, Python 3.8 (with allowed failures), and PyPy3. + As of this writing, :app:`Pyramid` is tested against Python 3.6, Python 3.7, Python 3.8, and PyPy3. :app:`Pyramid` is known to run on all popular Unix-like systems such as Linux, macOS, and FreeBSD, as well as on Windows platforms. It is also known to diff --git a/docs/narr/logging.rst b/docs/narr/logging.rst index 58bd2d4ec..844128758 100644 --- a/docs/narr/logging.rst +++ b/docs/narr/logging.rst @@ -32,7 +32,7 @@ you to send messages to :mod:`Python standard library logging package :term:`PasteDeploy` ``development.ini`` and ``production.ini`` files created when you use our cookiecutter include a basic configuration for the Python :mod:`logging` package. -These ``.ini`` file sections are passed to the `logging module's config file configuration engine `_. +These ``.ini`` file sections are passed to the `logging module's config file configuration engine `_. PasteDeploy ``.ini`` files use the Python standard library :mod:`ConfigParser format `. This is the same format used as the Python diff --git a/docs/narr/upgrading.rst b/docs/narr/upgrading.rst index af552741c..31ca6adfa 100644 --- a/docs/narr/upgrading.rst +++ b/docs/narr/upgrading.rst @@ -86,10 +86,10 @@ At the time of a Pyramid version release, each supports all versions of Python through the end of their lifespans. The end-of-life for a given version of Python is when security updates are no longer released. -- `Python 3.4 Lifespan `_ 2019-03-16 . -- `Python 3.5 Lifespan `_ 2020-09-13 . +- `Python 3.5 Lifespan `_ 2020-09-13. - `Python 3.6 Lifespan `_ 2021-12-23. -- `Python 3.7 Lifespan `_ 2023-06-27 . +- `Python 3.7 Lifespan `_ 2023-06-27. +- `Python 3.8 Lifespan `_ 2024-10-??. To determine the Python support for a specific release of Pyramid, view its ``tox.ini`` file at the root of the repository's version. diff --git a/docs/quick_tutorial/requirements.rst b/docs/quick_tutorial/requirements.rst index 2ed9b8b55..901f6134d 100644 --- a/docs/quick_tutorial/requirements.rst +++ b/docs/quick_tutorial/requirements.rst @@ -19,8 +19,8 @@ virtual environment.) This *Quick Tutorial* is based on: -* **Python 3.7**. Pyramid fully supports Python 3.4+. - This tutorial uses **Python 3.7**. +* **Python 3.8**. Pyramid fully supports Python 3.6+. + This tutorial uses **Python 3.8**. * **venv**. We believe in virtual environments. For this tutorial, we use Python 3's built-in solution :term:`venv`. diff --git a/docs/tutorials/modwsgi/index.rst b/docs/tutorials/modwsgi/index.rst index fa0d4f0cb..be72c014c 100644 --- a/docs/tutorials/modwsgi/index.rst +++ b/docs/tutorials/modwsgi/index.rst @@ -117,7 +117,7 @@ specific path information for commands and files. WSGIApplicationGroup %{GLOBAL} WSGIPassAuthorization On WSGIDaemonProcess pyramid user=chrism group=staff threads=4 \ - python-path=/Users/chrism/myproject/env/lib/python3.5/site-packages + python-path=/Users/chrism/myproject/env/lib/python3.8/site-packages WSGIScriptAlias /myapp /Users/chrism/myproject/pyramid.wsgi diff --git a/docs/tutorials/wiki/installation.rst b/docs/tutorials/wiki/installation.rst index 37e3498b2..cfa021540 100644 --- a/docs/tutorials/wiki/installation.rst +++ b/docs/tutorials/wiki/installation.rst @@ -127,8 +127,6 @@ On Unix On Windows ^^^^^^^^^^ -Python 3.7: - .. code-block:: doscon python -m venv %VENV% diff --git a/docs/tutorials/wiki/tests.rst b/docs/tutorials/wiki/tests.rst index a0872e605..9dacc5f96 100644 --- a/docs/tutorials/wiki/tests.rst +++ b/docs/tutorials/wiki/tests.rst @@ -73,6 +73,3 @@ The expected result should look like the following: ......................... 25 passed in 6.87 seconds - -If you use Python 3.7, you may see deprecation warnings from the docutils 0.14 package. -You can apply a [patch](https://sourceforge.net/p/docutils/patches/144/) to fix the issue, or ignore it and wait for the next release of docutils. diff --git a/setup.py b/setup.py index 189f0700f..02abf6471 100644 --- a/setup.py +++ b/setup.py @@ -69,10 +69,9 @@ setup( "Intended Audience :: Developers", "Programming Language :: Python", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.4", - "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Framework :: Pyramid", -- cgit v1.2.3