diff options
59 files changed, 244 insertions, 238 deletions
diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml index 625c6a60f..605ebdae0 100644 --- a/.github/workflows/ci-tests.yml +++ b/.github/workflows/ci-tests.yml @@ -15,36 +15,33 @@ jobs: strategy: matrix: py: - - "3.6" - "3.7" - "3.8" - "3.9" - - "pypy3" + - "3.10" + - "pypy-3.8" os: - - "ubuntu-latest" - - "windows-latest" - - "macos-latest" + - "ubuntu-20.04" + - "windows-2022" + - "macos-11" architecture: - x64 - x86 include: - # Only run coverage on ubuntu-latest, except on pypy3 - - os: "ubuntu-latest" + # Only run coverage on ubuntu-20.04, except on pypy3 + - os: "ubuntu-20.04" pytest-args: "--cov" - - os: "ubuntu-latest" - py: "pypy3" + - os: "ubuntu-20.04" + py: "pypy-3.8" pytest-args: "" exclude: # Linux and macOS don't have x86 python - - os: "ubuntu-latest" + - os: "ubuntu-20.04" architecture: x86 - - os: "macos-latest" + - os: "macos-11" architecture: x86 - # PyPy3 on Windows doesn't seem to work - - os: "windows-latest" - py: "pypy3" name: "Python: ${{ matrix.py }}-${{ matrix.architecture }} on ${{ matrix.os }}" runs-on: ${{ matrix.os }} @@ -59,7 +56,7 @@ jobs: - name: Running tox run: tox -e py -- ${{ matrix.pytest-args }} coverage: - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 name: Validate coverage steps: - uses: actions/checkout@v2 @@ -71,7 +68,7 @@ jobs: - run: pip install tox - run: tox -e py38-cover,coverage docs: - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 name: Build the documentation steps: - uses: actions/checkout@v2 @@ -83,7 +80,7 @@ jobs: - run: pip install tox - run: tox -e docs lint: - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 name: Lint the package steps: - uses: actions/checkout@v2 diff --git a/CHANGES.rst b/CHANGES.rst index 4bb847a25..0ee6fd30d 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -10,5 +10,7 @@ Bug Fixes Backward Incompatibilities -------------------------- +- Pyramid is no longer tested on, nor supports Python 3.6 + Documentation Changes --------------------- diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index d527b1a04..edce6e9c7 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -353,4 +353,8 @@ Contributors - Sergey Maranchuk, 2020/04/18 -- Thibault Ravera, 2020/06/03
\ No newline at end of file +- Thibault Ravera, 2020/06/03 + +- Jens Troeger, 2021/04/08 + +- Karthikeyan Singaravelan, 2021/08/24 diff --git a/HACKING.txt b/HACKING.txt index b9cdcc940..9cc2e8edb 100644 --- a/HACKING.txt +++ b/HACKING.txt @@ -50,7 +50,7 @@ In order to add a feature to Pyramid: - The feature must be documented in both the API and narrative documentation (in `docs/`). -- The feature must work fully on the following CPython versions: 3.6, 3.7, 3.8, and 3.9 on both UNIX and Windows. +- The feature must work fully on the following CPython versions: 3.7, 3.8, 3.9, and 3.10 on both UNIX and Windows. - The feature must work on the latest version of PyPy3. @@ -69,6 +69,12 @@ Coding Style $ $TOX -e format +- Pyramid uses flake8 (https://pypi.org/project/flake8/) to enforce PEP8 style guidelines. + To run flake8, as well as running checks for Black and isort: + + $ $TOX -e lint + +Black, isort, and flake8 versions are pinned for stability and reproducibility. Running Tests ------------- @@ -80,9 +86,9 @@ Running Tests $ $TOX -e py - To run `tox` for Python 3.9 explicitly, you may use: + To run `tox` for Python 3.10 explicitly, you may use: - $ $TOX -e py39 + $ $TOX -e py310 - To run individual tests (i.e., during development), you can use `pytest` syntax as follows, where `$VENV` is an environment variable set to the path @@ -103,7 +109,7 @@ Test Coverage ------------- - The codebase *must* have 100% test statement coverage after each commit. You - can test coverage via `tox -e py39`. + can test coverage via `tox -e py310`. Documentation Coverage and Building HTML Documentation diff --git a/README.rst b/README.rst index 82f171f89..027a4e236 100644 --- a/README.rst +++ b/README.rst @@ -3,15 +3,15 @@ Pyramid .. image:: https://github.com/Pylons/Pyramid/workflows/Build%20and%20test/badge.svg?branch=master :target: https://github.com/Pylons/Pyramid/actions?query=workflow%3A%22Build+and+test%22 - :alt: master Travis CI Status + :alt: master CI Status .. image:: https://readthedocs.org/projects/pyramid/badge/?version=master :target: https://docs.pylonsproject.org/projects/pyramid/en/master :alt: master Documentation Status -.. image:: https://img.shields.io/badge/irc-freenode-blue.svg - :target: https://webchat.freenode.net/?channels=pyramid - :alt: IRC Freenode +.. image:: https://img.shields.io/badge/IRC-Libera.Chat-blue.svg + :target: https://web.libera.chat/#pyramid + :alt: IRC Libera.Chat `Pyramid <https://trypyramid.com/>`_ is a small, fast, down-to-earth, open source Python web framework. It makes real-world web application development diff --git a/contributing.md b/contributing.md index ffe050035..75dbfb86b 100644 --- a/contributing.md +++ b/contributing.md @@ -6,7 +6,7 @@ You can contribute to this project in several ways. * [File an Issue on GitHub](https://github.com/Pylons/pyramid/issues) * Fork this project and create a branch with your suggested change. When ready, submit a pull request for consideration. [GitHub Flow](https://guides.github.com/introduction/flow/index.html) describes the workflow process and why it's a good practice. When submitting a pull request, sign [CONTRIBUTORS.txt](https://github.com/Pylons/pyramid/blob/master/CONTRIBUTORS.txt) if you have not yet done so. -* Join the [IRC channel #pyramid on irc.freenode.net](https://webchat.freenode.net/?channels=pyramid). +* Join the [IRC channel #pyramid on irc.libera.chat](https://web.libera.chat/#pyramid). ## Git Branches diff --git a/docs/conf.py b/docs/conf.py index 0e2c6b2cd..8e1550798 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -14,7 +14,6 @@ import sys import os import datetime -import inspect import warnings warnings.simplefilter('ignore', DeprecationWarning) @@ -385,20 +384,8 @@ def setup(app): app.add_directive('frontmatter', FrontMatter) app.add_directive('mainmatter', MainMatter) app.add_directive('backmatter', BackMatter) - app.connect('autodoc-process-signature', resig) -def resig(app, what, name, obj, options, signature, return_annotation): - """ Allow for preservation of ``@action_method`` decorated methods - in configurator """ - docobj = getattr(obj, '__docobj__', None) - if docobj is not None: - argspec = inspect.getargspec(docobj) - if argspec[0] and argspec[0][0] in ('cls', 'self'): - del argspec[0][0] - signature = inspect.formatargspec(*argspec) - return signature, return_annotation - # turn off all line numbers in latex formatting ## from pygments.formatters import LatexFormatter @@ -452,5 +439,5 @@ epub_tocdepth = 3 linkcheck_ignore = [ r'http://localhost:\d+', r'http://localhost', - r'https://webchat.freenode.net/#pyramid', # JavaScript "anchor" + r'https://web.libera.chat/#pyramid', # JavaScript "anchor" ] diff --git a/docs/designdefense.rst b/docs/designdefense.rst index 0fa609aa1..6cd5f0047 100644 --- a/docs/designdefense.rst +++ b/docs/designdefense.rst @@ -1656,8 +1656,8 @@ If you can understand this "hello world" program, you can use Pyramid: 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 -<https://webchat.freenode.net/#pyramid>`_ and see. +`#pyramid IRC channel on Libera.Chat +<https://web.libera.chat/#pyramid>`_ and see. Hate Zope +++++++++ diff --git a/docs/index.rst b/docs/index.rst index c1f6db81a..b5542213a 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -77,7 +77,7 @@ If you've got questions that aren't answered by this documentation, contact the `Pylons-discuss maillist <https://groups.google.com/forum/#!forum/pylons-discuss>`_ or join the `#pyramid IRC channel -<https://webchat.freenode.net/#pyramid>`_. +<https://web.libera.chat/#pyramid>`_. Browse and check out tagged and trunk versions of :app:`Pyramid` via the `Pyramid GitHub repository <https://github.com/Pylons/pyramid/>`_. To check out diff --git a/docs/narr/install.rst b/docs/narr/install.rst index 1801f3c9a..882b40d10 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.6 and greater for + This installation guide emphasizes the use of Python 3.7 and greater for simplicity. @@ -15,13 +15,14 @@ Installing :app:`Pyramid` Before You Install Pyramid -------------------------- -Install Python version 3.6 or greater for your operating system, and satisfy +Install Python version 3.7 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.6, 3.7, 3.8, and 3.9 and PyPy3. + As of this writing, :app:`Pyramid` is tested against Python 3.7, 3.8, 3.9, + and 3.10 and PyPy (matches CPython version 3.8). :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/introduction.rst b/docs/narr/introduction.rst index f62e28905..eddb02b21 100644 --- a/docs/narr/introduction.rst +++ b/docs/narr/introduction.rst @@ -70,7 +70,7 @@ You can get help quickly with :app:`Pyramid`. It's our goal that no :app:`Pyrami .. seealso:: - See also our `#pyramid IRC channel <https://webchat.freenode.net/#pyramid>`_, our `pylons-discuss mailing list <https://groups.google.com/forum/#!forum/pylons-discuss>`_, and :ref:`support-and-development`. + See also our `#pyramid IRC channel <https://web.libera.chat/#pyramid>`_, our `pylons-discuss mailing list <https://groups.google.com/forum/#!forum/pylons-discuss>`_, and :ref:`support-and-development`. .. _what_makes_pyramid_unique: diff --git a/docs/narr/myproject/myproject/templates/layout.jinja2 b/docs/narr/myproject/myproject/templates/layout.jinja2 index 38f5ae7a8..fc5c05941 100644 --- a/docs/narr/myproject/myproject/templates/layout.jinja2 +++ b/docs/narr/myproject/myproject/templates/layout.jinja2 @@ -41,7 +41,7 @@ <div class="links"> <ul> <li><i class="glyphicon glyphicon-cog icon-muted"></i><a href="https://github.com/Pylons/pyramid">Github Project</a></li> - <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://webchat.freenode.net/?channels=pyramid">IRC Channel</a></li> + <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://web.libera.chat/#pyramid">IRC Channel</a></li> <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="https://pylonsproject.org">Pylons Project</a></li> </ul> </div> diff --git a/docs/narr/upgrading.rst b/docs/narr/upgrading.rst index d6882809a..020f2ed37 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.6 Lifespan <https://devguide.python.org/#status-of-python-branches>`_ 2021-12-23. - `Python 3.7 Lifespan <https://devguide.python.org/#status-of-python-branches>`_ 2023-06-27. -- `Python 3.8 Lifespan <https://devguide.python.org/#status-of-python-branches>`_ 2024-10-??. -- `Python 3.9 Lifespan <https://devguide.python.org/#status-of-python-branches>`_ TBD. +- `Python 3.8 Lifespan <https://devguide.python.org/#status-of-python-branches>`_ 2024-10. +- `Python 3.9 Lifespan <https://devguide.python.org/#status-of-python-branches>`_ 2025-10. +- `Python 3.10 Lifespan <https://devguide.python.org/#status-of-python-branches>`_ 2026-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_tour/logging/hello_world/templates/layout.jinja2 b/docs/quick_tour/logging/hello_world/templates/layout.jinja2 index 45226b9e3..fd5bf0100 100644 --- a/docs/quick_tour/logging/hello_world/templates/layout.jinja2 +++ b/docs/quick_tour/logging/hello_world/templates/layout.jinja2 @@ -41,7 +41,7 @@ <div class="links"> <ul> <li><i class="glyphicon glyphicon-cog icon-muted"></i><a href="https://github.com/Pylons/pyramid">Github Project</a></li> - <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://webchat.freenode.net/?channels=pyramid">IRC Channel</a></li> + <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://web.libera.chat/#pyramid">IRC Channel</a></li> <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="https://pylonsproject.org">Pylons Project</a></li> </ul> </div> diff --git a/docs/quick_tour/package/hello_world/templates/layout.jinja2 b/docs/quick_tour/package/hello_world/templates/layout.jinja2 index 45226b9e3..fd5bf0100 100644 --- a/docs/quick_tour/package/hello_world/templates/layout.jinja2 +++ b/docs/quick_tour/package/hello_world/templates/layout.jinja2 @@ -41,7 +41,7 @@ <div class="links"> <ul> <li><i class="glyphicon glyphicon-cog icon-muted"></i><a href="https://github.com/Pylons/pyramid">Github Project</a></li> - <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://webchat.freenode.net/?channels=pyramid">IRC Channel</a></li> + <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://web.libera.chat/#pyramid">IRC Channel</a></li> <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="https://pylonsproject.org">Pylons Project</a></li> </ul> </div> diff --git a/docs/quick_tour/sessions/hello_world/templates/layout.jinja2 b/docs/quick_tour/sessions/hello_world/templates/layout.jinja2 index 45226b9e3..fd5bf0100 100644 --- a/docs/quick_tour/sessions/hello_world/templates/layout.jinja2 +++ b/docs/quick_tour/sessions/hello_world/templates/layout.jinja2 @@ -41,7 +41,7 @@ <div class="links"> <ul> <li><i class="glyphicon glyphicon-cog icon-muted"></i><a href="https://github.com/Pylons/pyramid">Github Project</a></li> - <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://webchat.freenode.net/?channels=pyramid">IRC Channel</a></li> + <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://web.libera.chat/#pyramid">IRC Channel</a></li> <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="https://pylonsproject.org">Pylons Project</a></li> </ul> </div> diff --git a/docs/quick_tour/sqla_demo/sqla_demo/templates/layout.jinja2 b/docs/quick_tour/sqla_demo/sqla_demo/templates/layout.jinja2 index 82017688a..e2bdcd7ea 100644 --- a/docs/quick_tour/sqla_demo/sqla_demo/templates/layout.jinja2 +++ b/docs/quick_tour/sqla_demo/sqla_demo/templates/layout.jinja2 @@ -41,7 +41,7 @@ <div class="links"> <ul> <li><i class="glyphicon glyphicon-cog icon-muted"></i><a href="https://github.com/Pylons/pyramid">Github Project</a></li> - <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://webchat.freenode.net/?channels=pyramid">IRC Channel</a></li> + <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://web.libera.chat/#pyramid">IRC Channel</a></li> <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="https://pylonsproject.org">Pylons Project</a></li> </ul> </div> diff --git a/docs/quick_tutorial/cookiecutters/cc_starter/templates/layout.jinja2 b/docs/quick_tutorial/cookiecutters/cc_starter/templates/layout.jinja2 index 90d2d106a..4fb4cf174 100644 --- a/docs/quick_tutorial/cookiecutters/cc_starter/templates/layout.jinja2 +++ b/docs/quick_tutorial/cookiecutters/cc_starter/templates/layout.jinja2 @@ -41,7 +41,7 @@ <div class="links"> <ul> <li><i class="glyphicon glyphicon-cog icon-muted"></i><a href="https://github.com/Pylons/pyramid">Github Project</a></li> - <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://webchat.freenode.net/?channels=pyramid">IRC Channel</a></li> + <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://web.libera.chat/#pyramid">IRC Channel</a></li> <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="https://pylonsproject.org">Pylons Project</a></li> </ul> </div> diff --git a/docs/quick_tutorial/requirements.rst b/docs/quick_tutorial/requirements.rst index 901f6134d..5f5c0b10b 100644 --- a/docs/quick_tutorial/requirements.rst +++ b/docs/quick_tutorial/requirements.rst @@ -19,7 +19,7 @@ virtual environment.) This *Quick Tutorial* is based on: -* **Python 3.8**. Pyramid fully supports Python 3.6+. +* **Python 3.8**. Pyramid fully supports Python 3.7+. This tutorial uses **Python 3.8**. * **venv**. We believe in virtual environments. diff --git a/docs/tutorials/wiki/src/authorization/tutorial/templates/layout.pt b/docs/tutorials/wiki/src/authorization/tutorial/templates/layout.pt index 61042da24..369b2be1a 100644 --- a/docs/tutorials/wiki/src/authorization/tutorial/templates/layout.pt +++ b/docs/tutorials/wiki/src/authorization/tutorial/templates/layout.pt @@ -52,7 +52,7 @@ <div class="links"> <ul> <li><i class="glyphicon glyphicon-cog icon-muted"></i><a href="https://github.com/Pylons/pyramid">Github Project</a></li> - <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://webchat.freenode.net/?channels=pyramid">IRC Channel</a></li> + <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://web.libera.chat/#pyramid">IRC Channel</a></li> <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="https://pylonsproject.org">Pylons Project</a></li> </ul> </div> diff --git a/docs/tutorials/wiki/src/basiclayout/tutorial/templates/layout.pt b/docs/tutorials/wiki/src/basiclayout/tutorial/templates/layout.pt index 9ca01382b..2e65a93c4 100644 --- a/docs/tutorials/wiki/src/basiclayout/tutorial/templates/layout.pt +++ b/docs/tutorials/wiki/src/basiclayout/tutorial/templates/layout.pt @@ -39,7 +39,7 @@ <div class="links"> <ul> <li><i class="glyphicon glyphicon-cog icon-muted"></i><a href="https://github.com/Pylons/pyramid">Github Project</a></li> - <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://webchat.freenode.net/?channels=pyramid">IRC Channel</a></li> + <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://web.libera.chat/#pyramid">IRC Channel</a></li> <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="https://pylonsproject.org">Pylons Project</a></li> </ul> </div> diff --git a/docs/tutorials/wiki/src/installation/tutorial/templates/layout.pt b/docs/tutorials/wiki/src/installation/tutorial/templates/layout.pt index 9ca01382b..2e65a93c4 100644 --- a/docs/tutorials/wiki/src/installation/tutorial/templates/layout.pt +++ b/docs/tutorials/wiki/src/installation/tutorial/templates/layout.pt @@ -39,7 +39,7 @@ <div class="links"> <ul> <li><i class="glyphicon glyphicon-cog icon-muted"></i><a href="https://github.com/Pylons/pyramid">Github Project</a></li> - <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://webchat.freenode.net/?channels=pyramid">IRC Channel</a></li> + <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://web.libera.chat/#pyramid">IRC Channel</a></li> <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="https://pylonsproject.org">Pylons Project</a></li> </ul> </div> diff --git a/docs/tutorials/wiki/src/models/tutorial/templates/layout.pt b/docs/tutorials/wiki/src/models/tutorial/templates/layout.pt index 9ca01382b..2e65a93c4 100644 --- a/docs/tutorials/wiki/src/models/tutorial/templates/layout.pt +++ b/docs/tutorials/wiki/src/models/tutorial/templates/layout.pt @@ -39,7 +39,7 @@ <div class="links"> <ul> <li><i class="glyphicon glyphicon-cog icon-muted"></i><a href="https://github.com/Pylons/pyramid">Github Project</a></li> - <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://webchat.freenode.net/?channels=pyramid">IRC Channel</a></li> + <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://web.libera.chat/#pyramid">IRC Channel</a></li> <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="https://pylonsproject.org">Pylons Project</a></li> </ul> </div> diff --git a/docs/tutorials/wiki/src/tests/tutorial/templates/layout.pt b/docs/tutorials/wiki/src/tests/tutorial/templates/layout.pt index 61042da24..369b2be1a 100644 --- a/docs/tutorials/wiki/src/tests/tutorial/templates/layout.pt +++ b/docs/tutorials/wiki/src/tests/tutorial/templates/layout.pt @@ -52,7 +52,7 @@ <div class="links"> <ul> <li><i class="glyphicon glyphicon-cog icon-muted"></i><a href="https://github.com/Pylons/pyramid">Github Project</a></li> - <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://webchat.freenode.net/?channels=pyramid">IRC Channel</a></li> + <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://web.libera.chat/#pyramid">IRC Channel</a></li> <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="https://pylonsproject.org">Pylons Project</a></li> </ul> </div> diff --git a/docs/tutorials/wiki/src/views/tutorial/templates/layout.pt b/docs/tutorials/wiki/src/views/tutorial/templates/layout.pt index 1e8b808d4..62d5f28aa 100644 --- a/docs/tutorials/wiki/src/views/tutorial/templates/layout.pt +++ b/docs/tutorials/wiki/src/views/tutorial/templates/layout.pt @@ -44,7 +44,7 @@ <div class="links"> <ul> <li><i class="glyphicon glyphicon-cog icon-muted"></i><a href="https://github.com/Pylons/pyramid">Github Project</a></li> - <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://webchat.freenode.net/?channels=pyramid">IRC Channel</a></li> + <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://web.libera.chat/#pyramid">IRC Channel</a></li> <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="https://pylonsproject.org">Pylons Project</a></li> </ul> </div> diff --git a/docs/tutorials/wiki2/src/authentication/tutorial/templates/layout.jinja2 b/docs/tutorials/wiki2/src/authentication/tutorial/templates/layout.jinja2 index 55f4a85dc..361d8f1cf 100644 --- a/docs/tutorials/wiki2/src/authentication/tutorial/templates/layout.jinja2 +++ b/docs/tutorials/wiki2/src/authentication/tutorial/templates/layout.jinja2 @@ -52,7 +52,7 @@ <div class="links"> <ul> <li><i class="glyphicon glyphicon-cog icon-muted"></i><a href="https://github.com/Pylons/pyramid">Github Project</a></li> - <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://webchat.freenode.net/?channels=pyramid">IRC Channel</a></li> + <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://web.libera.chat/#pyramid">IRC Channel</a></li> <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="https://pylonsproject.org">Pylons Project</a></li> </ul> </div> diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/templates/layout.jinja2 b/docs/tutorials/wiki2/src/authorization/tutorial/templates/layout.jinja2 index 55f4a85dc..361d8f1cf 100644 --- a/docs/tutorials/wiki2/src/authorization/tutorial/templates/layout.jinja2 +++ b/docs/tutorials/wiki2/src/authorization/tutorial/templates/layout.jinja2 @@ -52,7 +52,7 @@ <div class="links"> <ul> <li><i class="glyphicon glyphicon-cog icon-muted"></i><a href="https://github.com/Pylons/pyramid">Github Project</a></li> - <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://webchat.freenode.net/?channels=pyramid">IRC Channel</a></li> + <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://web.libera.chat/#pyramid">IRC Channel</a></li> <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="https://pylonsproject.org">Pylons Project</a></li> </ul> </div> diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/templates/layout.jinja2 b/docs/tutorials/wiki2/src/basiclayout/tutorial/templates/layout.jinja2 index f5a086f0e..a8cefba34 100644 --- a/docs/tutorials/wiki2/src/basiclayout/tutorial/templates/layout.jinja2 +++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/templates/layout.jinja2 @@ -41,7 +41,7 @@ <div class="links"> <ul> <li><i class="glyphicon glyphicon-cog icon-muted"></i><a href="https://github.com/Pylons/pyramid">Github Project</a></li> - <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://webchat.freenode.net/?channels=pyramid">IRC Channel</a></li> + <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://web.libera.chat/#pyramid">IRC Channel</a></li> <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="https://pylonsproject.org">Pylons Project</a></li> </ul> </div> diff --git a/docs/tutorials/wiki2/src/installation/tutorial/templates/layout.jinja2 b/docs/tutorials/wiki2/src/installation/tutorial/templates/layout.jinja2 index f5a086f0e..a8cefba34 100644 --- a/docs/tutorials/wiki2/src/installation/tutorial/templates/layout.jinja2 +++ b/docs/tutorials/wiki2/src/installation/tutorial/templates/layout.jinja2 @@ -41,7 +41,7 @@ <div class="links"> <ul> <li><i class="glyphicon glyphicon-cog icon-muted"></i><a href="https://github.com/Pylons/pyramid">Github Project</a></li> - <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://webchat.freenode.net/?channels=pyramid">IRC Channel</a></li> + <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://web.libera.chat/#pyramid">IRC Channel</a></li> <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="https://pylonsproject.org">Pylons Project</a></li> </ul> </div> diff --git a/docs/tutorials/wiki2/src/models/tutorial/templates/layout.jinja2 b/docs/tutorials/wiki2/src/models/tutorial/templates/layout.jinja2 index f5a086f0e..a8cefba34 100644 --- a/docs/tutorials/wiki2/src/models/tutorial/templates/layout.jinja2 +++ b/docs/tutorials/wiki2/src/models/tutorial/templates/layout.jinja2 @@ -41,7 +41,7 @@ <div class="links"> <ul> <li><i class="glyphicon glyphicon-cog icon-muted"></i><a href="https://github.com/Pylons/pyramid">Github Project</a></li> - <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://webchat.freenode.net/?channels=pyramid">IRC Channel</a></li> + <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://web.libera.chat/#pyramid">IRC Channel</a></li> <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="https://pylonsproject.org">Pylons Project</a></li> </ul> </div> diff --git a/docs/tutorials/wiki2/src/tests/tutorial/templates/layout.jinja2 b/docs/tutorials/wiki2/src/tests/tutorial/templates/layout.jinja2 index 55f4a85dc..361d8f1cf 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/templates/layout.jinja2 +++ b/docs/tutorials/wiki2/src/tests/tutorial/templates/layout.jinja2 @@ -52,7 +52,7 @@ <div class="links"> <ul> <li><i class="glyphicon glyphicon-cog icon-muted"></i><a href="https://github.com/Pylons/pyramid">Github Project</a></li> - <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://webchat.freenode.net/?channels=pyramid">IRC Channel</a></li> + <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://web.libera.chat/#pyramid">IRC Channel</a></li> <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="https://pylonsproject.org">Pylons Project</a></li> </ul> </div> diff --git a/docs/tutorials/wiki2/src/views/tutorial/templates/layout.jinja2 b/docs/tutorials/wiki2/src/views/tutorial/templates/layout.jinja2 index 17e8f7688..54c6e5fe7 100644 --- a/docs/tutorials/wiki2/src/views/tutorial/templates/layout.jinja2 +++ b/docs/tutorials/wiki2/src/views/tutorial/templates/layout.jinja2 @@ -41,7 +41,7 @@ <div class="links"> <ul> <li><i class="glyphicon glyphicon-cog icon-muted"></i><a href="https://github.com/Pylons/pyramid">Github Project</a></li> - <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://webchat.freenode.net/?channels=pyramid">IRC Channel</a></li> + <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://web.libera.chat/#pyramid">IRC Channel</a></li> <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="https://pylonsproject.org">Pylons Project</a></li> </ul> </div> diff --git a/pyproject.toml b/pyproject.toml index eddde46d9..9069096f7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta" [tool.black] line-length = 79 skip-string-normalization = true -py36 = false +target-version = ['py37', 'py38', 'py39', 'py310'] exclude = ''' /( \.git @@ -1,10 +1,3 @@ -[easy_install] -zip_ok = false - -[aliases] -dev = develop easy_install pyramid[testing] -docs = develop easy_install pyramid[docs] - [metadata] license_file = LICENSE.txt @@ -68,15 +68,16 @@ setup( version=VERSION, description='The Pyramid Web Framework, a Pylons project', long_description=README + '\n\n' + CHANGES, + long_description_content_type='text/x-rst', classifiers=[ "Development Status :: 6 - Mature", "Intended Audience :: Developers", "Programming Language :: Python", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Framework :: Pyramid", @@ -98,7 +99,7 @@ setup( package_dir={'': 'src'}, include_package_data=True, zip_safe=False, - python_requires='>=3.6', + python_requires='>=3.7', install_requires=install_requires, extras_require={'testing': testing_extras, 'docs': docs_extras}, tests_require=tests_require, diff --git a/src/pyramid/authentication.py b/src/pyramid/authentication.py index 8faf84d68..9120ad03b 100644 --- a/src/pyramid/authentication.py +++ b/src/pyramid/authentication.py @@ -24,7 +24,7 @@ VALID_TOKEN = re.compile(r"^[A-Za-z][A-Za-z0-9+_-]*$") class CallbackAuthenticationPolicy: - """ Abstract class """ + """Abstract class""" debug = False callback = None @@ -265,7 +265,7 @@ class RepozeWho1AuthenticationPolicy(CallbackAuthenticationPolicy): return userid def unauthenticated_userid(self, request): - """ Return the ``repoze.who.userid`` key from the detected identity.""" + """Return the ``repoze.who.userid`` key from the detected identity.""" identity = self._get_identity(request) if identity is None: return None @@ -411,7 +411,7 @@ class RemoteUserAuthenticationPolicy(CallbackAuthenticationPolicy): self.debug = debug def unauthenticated_userid(self, request): - """ The ``REMOTE_USER`` value found within the ``environ``.""" + """The ``REMOTE_USER`` value found within the ``environ``.""" return request.environ.get(self.environ_key) def remember(self, request, userid, **kw): @@ -631,7 +631,7 @@ class AuthTktAuthenticationPolicy(CallbackAuthenticationPolicy): self.debug = debug def unauthenticated_userid(self, request): - """ The userid key within the auth_tkt cookie.""" + """The userid key within the auth_tkt cookie.""" result = self.cookie.identify(request) if result: return result['userid'] @@ -647,7 +647,7 @@ class AuthTktAuthenticationPolicy(CallbackAuthenticationPolicy): return self.cookie.remember(request, userid, **kw) def forget(self, request): - """ A list of headers which will delete appropriate cookies.""" + """A list of headers which will delete appropriate cookies.""" return self.cookie.forget(request) @@ -1235,11 +1235,11 @@ class SessionAuthenticationPolicy(CallbackAuthenticationPolicy): self.helper = SessionAuthenticationHelper(prefix) def remember(self, request, userid, **kw): - """ Store a userid in the session.""" + """Store a userid in the session.""" return self.helper.remember(request, userid, **kw) def forget(self, request): - """ Remove the stored userid from the session.""" + """Remove the stored userid from the session.""" return self.helper.forget(request) def unauthenticated_userid(self, request): @@ -1263,18 +1263,18 @@ class SessionAuthenticationHelper: self.userid_key = prefix + 'userid' def remember(self, request, userid, **kw): - """ Store a userid in the session.""" + """Store a userid in the session.""" request.session[self.userid_key] = userid return [] def forget(self, request, **kw): - """ Remove the stored userid from the session.""" + """Remove the stored userid from the session.""" if self.userid_key in request.session: del request.session[self.userid_key] return [] def authenticated_userid(self, request): - """ Return the stored userid.""" + """Return the stored userid.""" return request.session.get(self.userid_key) @@ -1332,7 +1332,7 @@ class BasicAuthAuthenticationPolicy(CallbackAuthenticationPolicy): self.debug = debug def unauthenticated_userid(self, request): - """ The userid parsed from the ``Authorization`` request header.""" + """The userid parsed from the ``Authorization`` request header.""" credentials = extract_http_basic_credentials(request) if credentials: return credentials.username diff --git a/src/pyramid/config/__init__.py b/src/pyramid/config/__init__.py index fa90f2dd2..c500c53f6 100644 --- a/src/pyramid/config/__init__.py +++ b/src/pyramid/config/__init__.py @@ -805,7 +805,7 @@ class Configurator( categories=('pyramid',), onerror=None, ignore=None, - **kw + **kw, ): """Scan a Python package and any of its subpackages for objects marked with :term:`configuration decoration` such as diff --git a/src/pyramid/config/actions.py b/src/pyramid/config/actions.py index e13358ce9..d80f840ac 100644 --- a/src/pyramid/config/actions.py +++ b/src/pyramid/config/actions.py @@ -35,7 +35,7 @@ class ActionConfiguratorMixin: kw=None, order=0, introspectables=(), - **extra + **extra, ): """Register an action which will be executed when :meth:`pyramid.config.Configurator.commit` is called (or executed @@ -185,7 +185,7 @@ class ActionState: includepath=(), info=None, introspectables=(), - **extra + **extra, ): """Add an action with the given discriminator, callable, and arguments""" @@ -557,13 +557,6 @@ def action_method(wrapped): if info is None: try: f = traceback.extract_stack(limit=4) - - # Work around a Python 3.5 issue whereby it would insert an - # extra stack frame. This should no longer be necessary in - # Python 3.5.1 - last_frame = ActionInfo(*f[-1]) - if last_frame.function == 'extract_stack': # pragma: no cover - f.pop() info = ActionInfo(*f[-backframes]) except Exception: # pragma: no cover info = ActionInfo(None, 0, '', '') diff --git a/src/pyramid/config/assets.py b/src/pyramid/config/assets.py index 0dd7cf2c2..d62b04e57 100644 --- a/src/pyramid/config/assets.py +++ b/src/pyramid/config/assets.py @@ -34,7 +34,7 @@ class OverrideProvider(pkg_resources.DefaultProvider): ) def get_resource_stream(self, manager, resource_name): - """ Return a readable file-like object for resource_name.""" + """Return a readable file-like object for resource_name.""" overrides = self._get_overrides() if overrides is not None: stream = overrides.get_stream(resource_name) @@ -45,7 +45,7 @@ class OverrideProvider(pkg_resources.DefaultProvider): ) def get_resource_string(self, manager, resource_name): - """ Return a string containing the contents of resource_name.""" + """Return a string containing the contents of resource_name.""" overrides = self._get_overrides() if overrides is not None: string = overrides.get_string(resource_name) diff --git a/src/pyramid/config/routes.py b/src/pyramid/config/routes.py index 4ebae89cc..59bc368fe 100644 --- a/src/pyramid/config/routes.py +++ b/src/pyramid/config/routes.py @@ -38,7 +38,7 @@ class RoutesConfiguratorMixin: pregenerator=None, static=False, inherit_slash=None, - **predicates + **predicates, ): """Add a :term:`route configuration` to the current configuration state. Arguments to ``add_route`` are divided into *predicate* diff --git a/src/pyramid/config/views.py b/src/pyramid/config/views.py index 0d0002f83..e75fdd1ef 100644 --- a/src/pyramid/config/views.py +++ b/src/pyramid/config/views.py @@ -264,7 +264,7 @@ class ViewsConfiguratorMixin: match_param=None, require_csrf=None, exception_only=False, - **view_options + **view_options, ): """Add a :term:`view configuration` to the current configuration state. Arguments to ``add_view`` are broken @@ -1611,7 +1611,7 @@ class ViewsConfiguratorMixin: decorator=None, mapper=None, match_param=None, - **view_options + **view_options, ): """Add a forbidden view to the current configuration state. The view will be called when Pyramid or application code raises a @@ -1712,7 +1712,7 @@ class ViewsConfiguratorMixin: mapper=None, match_param=None, append_slash=False, - **view_options + **view_options, ): """Add a default :term:`Not Found View` to the current configuration state. The view will be called when Pyramid or application code raises @@ -1850,7 +1850,7 @@ class ViewsConfiguratorMixin: view=None, context=None, # force all other arguments to be specified as key=value - **view_options + **view_options, ): """Add an :term:`exception view` for the specified ``exception`` to the current configuration state. The view will be called when Pyramid diff --git a/src/pyramid/csrf.py b/src/pyramid/csrf.py index 7f4f72f44..0ade5f2d6 100644 --- a/src/pyramid/csrf.py +++ b/src/pyramid/csrf.py @@ -32,7 +32,7 @@ class LegacySessionCSRFStoragePolicy: """ def new_csrf_token(self, request): - """ Sets a new CSRF token into the session and returns it. """ + """Sets a new CSRF token into the session and returns it.""" return request.session.new_csrf_token() def get_csrf_token(self, request): @@ -41,7 +41,7 @@ class LegacySessionCSRFStoragePolicy: return request.session.get_csrf_token() def check_csrf_token(self, request, supplied_token): - """ Returns ``True`` if the ``supplied_token`` is valid.""" + """Returns ``True`` if the ``supplied_token`` is valid.""" expected_token = self.get_csrf_token(request) return not strings_differ( bytes_(expected_token), bytes_(supplied_token) @@ -70,7 +70,7 @@ class SessionCSRFStoragePolicy: self.key = key def new_csrf_token(self, request): - """ Sets a new CSRF token into the session and returns it. """ + """Sets a new CSRF token into the session and returns it.""" token = self._token_factory() request.session[self.key] = token return token @@ -84,7 +84,7 @@ class SessionCSRFStoragePolicy: return token def check_csrf_token(self, request, supplied_token): - """ Returns ``True`` if the ``supplied_token`` is valid.""" + """Returns ``True`` if the ``supplied_token`` is valid.""" expected_token = self.get_csrf_token(request) return not strings_differ( bytes_(expected_token), bytes_(supplied_token) @@ -134,7 +134,7 @@ class CookieCSRFStoragePolicy: self.cookie_name = cookie_name def new_csrf_token(self, request): - """ Sets a new CSRF token into the request and returns it. """ + """Sets a new CSRF token into the request and returns it.""" token = self._token_factory() request.cookies[self.cookie_name] = token @@ -154,7 +154,7 @@ class CookieCSRFStoragePolicy: return token def check_csrf_token(self, request, supplied_token): - """ Returns ``True`` if the ``supplied_token`` is valid.""" + """Returns ``True`` if the ``supplied_token`` is valid.""" expected_token = self.get_csrf_token(request) return not strings_differ( bytes_(expected_token), bytes_(supplied_token) diff --git a/src/pyramid/decorator.py b/src/pyramid/decorator.py index 3215b1b38..9b8d10618 100644 --- a/src/pyramid/decorator.py +++ b/src/pyramid/decorator.py @@ -32,6 +32,7 @@ class reify: def __init__(self, wrapped): self.wrapped = wrapped + self.__name__ = wrapped.__name__ self.__doc__ = wrapped.__doc__ def __get__(self, inst, objtype=None): diff --git a/src/pyramid/httpexceptions.py b/src/pyramid/httpexceptions.py index 9fd5f7d55..06894f9b4 100644 --- a/src/pyramid/httpexceptions.py +++ b/src/pyramid/httpexceptions.py @@ -50,6 +50,7 @@ Exception * 415 - HTTPUnsupportedMediaType * 416 - HTTPRequestRangeNotSatisfiable * 417 - HTTPExpectationFailed + * 418 - HTTPImATeapot * 422 - HTTPUnprocessableEntity * 423 - HTTPLocked * 424 - HTTPFailedDependency @@ -214,7 +215,7 @@ ${body}''' </html>''' ) - # Set this to True for responses that should have no request body + # Set this to True for responses that should have no response body empty_body = False def __init__( @@ -224,7 +225,7 @@ ${body}''' comment=None, body_template=None, json_formatter=None, - **kw + **kw, ): status = '%s %s' % (self.code, self.title) Response.__init__(self, status=status, **kw) @@ -528,7 +529,7 @@ ${html_comment}''' headers=None, comment=None, body_template=None, - **kw + **kw, ): if location is None: raise ValueError("HTTP redirects need a location to redirect to.") @@ -538,7 +539,7 @@ ${html_comment}''' comment=comment, body_template=body_template, location=location, - **kw + **kw, ) @@ -786,7 +787,7 @@ class HTTPForbidden(HTTPClientError): comment=None, body_template=None, result=None, - **kw + **kw, ): HTTPClientError.__init__( self, @@ -794,7 +795,7 @@ class HTTPForbidden(HTTPClientError): headers=headers, comment=comment, body_template=body_template, - **kw + **kw, ) self.result = result @@ -1045,6 +1046,24 @@ class HTTPExpectationFailed(HTTPClientError): explanation = 'Expectation failed.' +class HTTPImATeapot(HTTPClientError): + """ + subclass of :class:`~HTTPClientError` + + This indicates that the server refuses to brew coffee because + it is, in fact and permanently, a teapot. The resulting entity + body may be short and stout. + + See RFC2324 and RFC7168 for more information. + + code: 418, title: I'm a teapot + """ + + code = 418 + title = "I'm a teapot" + explanation = "Refusing to brew coffee because I'm a teapot." + + class HTTPUnprocessableEntity(HTTPClientError): """ subclass of :class:`~HTTPClientError` diff --git a/src/pyramid/i18n.py b/src/pyramid/i18n.py index 793b25015..7c9ef3b4b 100644 --- a/src/pyramid/i18n.py +++ b/src/pyramid/i18n.py @@ -221,7 +221,7 @@ def get_localizer(request): class Translations(gettext.GNUTranslations): - """An extended translation catalog class (ripped off from Babel) """ + """An extended translation catalog class (ripped off from Babel)""" DEFAULT_DOMAIN = 'messages' @@ -369,7 +369,7 @@ class Translations(gettext.GNUTranslations): class LocalizerRequestMixin: @reify def localizer(self): - """ Convenience property to return a localizer """ + """Convenience property to return a localizer""" registry = self.registry current_locale_name = self.locale_name diff --git a/src/pyramid/interfaces.py b/src/pyramid/interfaces.py index 6704f7c7c..6221cc21e 100644 --- a/src/pyramid/interfaces.py +++ b/src/pyramid/interfaces.py @@ -79,9 +79,7 @@ class IResponse(Interface): :class:`pyramid.response.Response` and the HTTP exception classes in :mod:`pyramid.httpexceptions`.""" - RequestClass = Attribute( - """ Alias for :class:`pyramid.request.Request` """ - ) + RequestClass = Attribute("""Alias for :class:`pyramid.request.Request`""") def __call__(environ, start_response): """:term:`WSGI` call interface, should call the start_response @@ -138,8 +136,8 @@ class IResponse(Interface): ) cache_expires = Attribute( - """ Get/set the Cache-Control and Expires headers. This sets the - response to expire in the number of seconds passed when set. """ + """Get/set the Cache-Control and Expires headers. This sets the + response to expire in the number of seconds passed when set.""" ) charset = Attribute("""Get/set the charset (in the Content-Type)""") @@ -174,7 +172,7 @@ class IResponse(Interface): content_length = Attribute( """Gets and sets and deletes the Content-Length header. For more information on Content-Length see RFC 2616 section 14.17. - Converts using int. """ + Converts using int.""" ) content_location = Attribute( @@ -207,7 +205,7 @@ class IResponse(Interface): ) def copy(): - """ Makes a copy of the response and returns the copy. """ + """Makes a copy of the response and returns the copy.""" date = Attribute( """Gets and sets and deletes the Date header. For more information on @@ -229,19 +227,19 @@ class IResponse(Interface): ) etag = Attribute( - """ Gets and sets and deletes the ETag header. For more information + """Gets and sets and deletes the ETag header. For more information on ETag see RFC 2616 section 14.19. Converts using Entity tag.""" ) expires = Attribute( - """ Gets and sets and deletes the Expires header. For more + """Gets and sets and deletes the Expires header. For more information on Expires see RFC 2616 section 14.21. Converts using HTTP date.""" ) - headerlist = Attribute(""" The list of response headers. """) + headerlist = Attribute("""The list of response headers.""") - headers = Attribute(""" The headers in a dictionary-like object """) + headers = Attribute("""The headers in a dictionary-like object""") is_authenticated = Attribute( """A boolean indicating whether the request has an authenticated @@ -253,13 +251,13 @@ class IResponse(Interface): ) last_modified = Attribute( - """ Gets and sets and deletes the Last-Modified header. For more + """Gets and sets and deletes the Last-Modified header. For more information on Last-Modified see RFC 2616 section 14.29. Converts using HTTP date.""" ) location = Attribute( - """ Gets and sets and deletes the Location header. For more + """Gets and sets and deletes the Location header. For more information on Location see RFC 2616 section 14.30.""" ) @@ -275,23 +273,23 @@ class IResponse(Interface): in-place.""" pragma = Attribute( - """ Gets and sets and deletes the Pragma header. For more information - on Pragma see RFC 2616 section 14.32. """ + """Gets and sets and deletes the Pragma header. For more information + on Pragma see RFC 2616 section 14.32.""" ) request = Attribute( - """ Return the request associated with this response if any. """ + """Return the request associated with this response if any.""" ) retry_after = Attribute( - """ Gets and sets and deletes the Retry-After header. For more + """Gets and sets and deletes the Retry-After header. For more information on Retry-After see RFC 2616 section 14.37. Converts using HTTP date or delta seconds.""" ) server = Attribute( - """ Gets and sets and deletes the Server header. For more information - on Server see RFC216 section 14.38. """ + """Gets and sets and deletes the Server header. For more information + on Server see RFC216 section 14.38.""" ) def set_cookie( @@ -306,14 +304,14 @@ class IResponse(Interface): expires=None, overwrite=False, ): - """ Set (add) a cookie for the response """ + """Set (add) a cookie for the response""" - status = Attribute(""" The status string. """) + status = Attribute("""The status string.""") - status_int = Attribute(""" The status as an integer """) + status_int = Attribute("""The status as an integer""") unicode_body = Attribute( - """ Get/set the unicode value of the body (using the charset of + """Get/set the unicode value of the body (using the charset of the Content-Type)""" ) @@ -327,14 +325,14 @@ class IResponse(Interface): ) www_authenticate = Attribute( - """ Gets and sets and deletes the WWW-Authenticate header. For more + """Gets and sets and deletes the WWW-Authenticate header. For more information on WWW-Authenticate see RFC 2616 section 14.47. Converts - using 'parse_auth' and 'serialize_auth'. """ + using 'parse_auth' and 'serialize_auth'.""" ) class IException(Interface): # not an API - """ An interface representing a generic exception """ + """An interface representing a generic exception""" class IExceptionResponse(IException, IResponse): @@ -347,17 +345,17 @@ class IExceptionResponse(IException, IResponse): :class:`pyramid.httpexceptions.HTTPForbidden`).""" def prepare(environ): - """ Prepares the response for being called as a WSGI application """ + """Prepares the response for being called as a WSGI application""" class IDict(Interface): # Documentation-only interface def __contains__(k): - """ Return ``True`` if key ``k`` exists in the dictionary.""" + """Return ``True`` if key ``k`` exists in the dictionary.""" def __setitem__(k, value): - """ Set a key/value pair into the dictionary""" + """Set a key/value pair into the dictionary""" def __delitem__(k): """Delete an item from the dictionary which is passed to the @@ -368,20 +366,20 @@ class IDict(Interface): KeyError if the key doesn't exist""" def __iter__(): - """ Return an iterator over the keys of this dictionary """ + """Return an iterator over the keys of this dictionary""" def get(k, default=None): """Return the value for key ``k`` from the renderer dictionary, or the default if no such value exists.""" def items(): - """ Return a list of [(k,v)] pairs from the dictionary """ + """Return a list of [(k,v)] pairs from the dictionary""" def keys(): - """ Return a list of keys from the dictionary """ + """Return a list of keys from the dictionary""" def values(): - """ Return a list of values from the dictionary """ + """Return a list of values from the dictionary""" def pop(k, default=None): """Pop the key k from the dictionary and return its value. If k @@ -400,10 +398,10 @@ class IDict(Interface): the dictionary, return the default""" def update(d): - """ Update the renderer dictionary with another dictionary ``d``.""" + """Update the renderer dictionary with another dictionary ``d``.""" def clear(): - """ Clear all values from the dictionary """ + """Clear all values from the dictionary""" class IBeforeRender(IDict): @@ -453,7 +451,7 @@ class IRendererInfo(Interface): ) def clone(): - """ Return a shallow copy that does not share any mutable state.""" + """Return a shallow copy that does not share any mutable state.""" class IRendererFactory(Interface): @@ -633,7 +631,7 @@ class IMultiDict(IDict): # docs-only interface """ def add(key, value): - """ Add the key and value, not overwriting any previous value. """ + """Add the key and value, not overwriting any previous value.""" def dict_of_lists(): """ @@ -666,7 +664,7 @@ class IMultiDict(IDict): # docs-only interface class IRequest(Interface): - """ Request type interface attached to all request objects """ + """Request type interface attached to all request objects""" class ITweens(Interface): @@ -710,20 +708,20 @@ class IAcceptOrder(Interface): class IStaticURLInfo(Interface): - """ A policy for generating URLs to static assets """ + """A policy for generating URLs to static assets""" def add(config, name, spec, **extra): - """ Add a new static info registration """ + """Add a new static info registration""" def generate(path, request, **kw): - """ Generate a URL for the given path """ + """Generate a URL for the given path""" def add_cache_buster(config, spec, cache_buster): - """ Add a new cache buster to a particular set of assets """ + """Add a new cache buster to a particular set of assets""" class IResponseFactory(Interface): - """ A utility which generates a response """ + """A utility which generates a response""" def __call__(request): """Return a response object implementing IResponse, @@ -732,10 +730,10 @@ class IResponseFactory(Interface): class IRequestFactory(Interface): - """ A utility which generates a request """ + """A utility which generates a request""" def __call__(environ): - """ Return an instance of ``pyramid.request.Request``""" + """Return an instance of ``pyramid.request.Request``""" def blank(path): """Return an empty request object (see @@ -743,23 +741,23 @@ class IRequestFactory(Interface): class IViewClassifier(Interface): - """ *Internal only* marker interface for views.""" + """*Internal only* marker interface for views.""" class IExceptionViewClassifier(Interface): - """ *Internal only* marker interface for exception views.""" + """*Internal only* marker interface for exception views.""" class IView(Interface): def __call__(context, request): - """ Must return an object that implements IResponse. """ + """Must return an object that implements IResponse.""" class ISecuredView(IView): - """ *Internal only* interface. Not an API. """ + """*Internal only* interface. Not an API.""" def __call_permissive__(context, request): - """ Guaranteed-permissive version of __call__ """ + """Guaranteed-permissive version of __call__""" def __permitted__(context, request): """Return True if view execution will be permitted using the @@ -772,17 +770,17 @@ class IMultiView(ISecuredView): zero or more predicates. Not an API.""" def add(view, predicates, order, accept=None, phash=None): - """ Add a view to the multiview. """ + """Add a view to the multiview.""" class IRootFactory(Interface): def __call__(request): - """ Return a root object based on the request """ + """Return a root object based on the request""" class IDefaultRootFactory(Interface): def __call__(request): - """ Return the *default* root object for an application """ + """Return the *default* root object for an application""" class ITraverser(Interface): @@ -915,7 +913,7 @@ class ILocation(Interface): class IDebugLogger(Interface): - """ Interface representing a PEP 282 logger """ + """Interface representing a PEP 282 logger""" ILogger = IDebugLogger # b/c @@ -988,14 +986,14 @@ class IRoute(Interface): class IRoutesMapper(Interface): - """ Interface representing a Routes ``Mapper`` object """ + """Interface representing a Routes ``Mapper`` object""" def get_routes(): """Return a sequence of Route objects registered in the mapper. Static routes will not be returned in this sequence.""" def has_routes(): - """ Returns ``True`` if any route has been registered. """ + """Returns ``True`` if any route has been registered.""" def get_route(name): """Returns an ``IRoute`` object if a route with the name ``name`` @@ -1009,7 +1007,7 @@ class IRoutesMapper(Interface): pregenerator=None, static=True, ): - """ Add a new route. """ + """Add a new route.""" def generate(name, kw): """Generate a URL using the route named ``name`` with the @@ -1080,7 +1078,7 @@ class IPEP302Loader(Interface): class IPackageOverrides(IPEP302Loader): - """ Utility for pkg_resources overrides """ + """Utility for pkg_resources overrides""" # VH_ROOT_KEY is an interface; its imported from other packages (e.g. @@ -1089,12 +1087,12 @@ VH_ROOT_KEY = 'HTTP_X_VHM_ROOT' class ILocalizer(Interface): - """ Localizer for a specific language """ + """Localizer for a specific language""" class ILocaleNegotiator(Interface): def __call__(request): - """ Return a locale name """ + """Return a locale name""" class ITranslationDirectories(Interface): @@ -1131,7 +1129,7 @@ class ISessionFactory(Interface): returns an ISession object""" def __call__(request): - """ Return an ISession object """ + """Return an ISession object""" class ISession(IDict): @@ -1457,7 +1455,7 @@ class IJSONAdapter(Interface): class IPredicateList(Interface): - """ Interface representing a predicate list """ + """Interface representing a predicate list""" class IPredicateInfo(Interface): @@ -1589,7 +1587,7 @@ class IViewDeriverInfo(Interface): class IViewDerivers(Interface): - """ Interface for view derivers list """ + """Interface for view derivers list""" class ICacheBuster(Interface): diff --git a/src/pyramid/path.py b/src/pyramid/path.py index 3c0c1a682..3db4bf0ff 100644 --- a/src/pyramid/path.py +++ b/src/pyramid/path.py @@ -45,7 +45,7 @@ def package_name(pkg_or_module): def package_of(pkg_or_module): - """ Return the package of a module or return the package itself """ + """Return the package of a module or return the package itself""" pkg_name = package_name(pkg_or_module) __import__(pkg_name) return sys.modules[pkg_name] @@ -334,7 +334,7 @@ class DottedNameResolver(Resolver): return self._zope_dottedname_style(dotted, package) def _pkg_resources_style(self, value, package): - """ package.module:attr style """ + """package.module:attr style""" if value.startswith(('.', ':')): if not package: raise ValueError( @@ -354,7 +354,7 @@ class DottedNameResolver(Resolver): return ep.load(False) # pragma: NO COVER def _zope_dottedname_style(self, value, package): - """ package.module.attr style """ + """package.module.attr style""" module = getattr(package, '__name__', None) # package may be None if not module: module = None diff --git a/src/pyramid/registry.py b/src/pyramid/registry.py index 66519398c..2d790015a 100644 --- a/src/pyramid/registry.py +++ b/src/pyramid/registry.py @@ -295,7 +295,7 @@ def undefer(v): class predvalseq(tuple): - """ A subtype of tuple used to represent a sequence of predicate values """ + """A subtype of tuple used to represent a sequence of predicate values""" global_registry = Registry('global') diff --git a/src/pyramid/scripts/pserve.py b/src/pyramid/scripts/pserve.py index 6906a0410..1bcf6c543 100644 --- a/src/pyramid/scripts/pserve.py +++ b/src/pyramid/scripts/pserve.py @@ -231,7 +231,7 @@ class PServeCommand: webbrowser.open(url) t = threading.Thread(target=open_browser) - t.setDaemon(True) + t.daemon = True t.start() if self.args.reload and not hupper.is_active(): diff --git a/src/pyramid/security.py b/src/pyramid/security.py index a0ab39701..e1de9d9a6 100644 --- a/src/pyramid/security.py +++ b/src/pyramid/security.py @@ -171,7 +171,7 @@ class PermitsResult(int): @property def msg(self): - """ A string indicating why the result was generated.""" + """A string indicating why the result was generated.""" return self.s % self.args def __str__(self): @@ -212,7 +212,7 @@ class Allowed(PermitsResult): class SecurityAPIMixin: - """ Mixin for Request class providing auth-related properties. """ + """Mixin for Request class providing auth-related properties.""" @property def identity(self): @@ -278,7 +278,7 @@ class SecurityAPIMixin: class AuthenticationAPIMixin: - """ Mixin for Request class providing compatibility properties. """ + """Mixin for Request class providing compatibility properties.""" @property def unauthenticated_userid(self): @@ -396,7 +396,7 @@ Deny = 'Deny' class AllPermissionsList: - """ Stand in 'permission list' to represent all permissions """ + """Stand in 'permission list' to represent all permissions""" def __iter__(self): return iter(()) diff --git a/src/pyramid/session.py b/src/pyramid/session.py index 032d58a8b..431fdd5ec 100644 --- a/src/pyramid/session.py +++ b/src/pyramid/session.py @@ -189,7 +189,7 @@ def BaseCookieSessionFactory( @implementer(ISession) class CookieSession(dict): - """ Dictionary-like session object """ + """Dictionary-like session object""" # configuration parameters _cookie_name = cookie_name diff --git a/src/pyramid/static.py b/src/pyramid/static.py index 8b19c7b16..5363c1671 100644 --- a/src/pyramid/static.py +++ b/src/pyramid/static.py @@ -171,7 +171,7 @@ class static_view: return name def get_possible_files(self, resource_name): - """ Return a sorted list of ``(size, encoding, path)`` entries.""" + """Return a sorted list of ``(size, encoding, path)`` entries.""" result = self.filemap.get(resource_name) if result is not None: return result @@ -206,7 +206,7 @@ class static_view: return result def find_best_match(self, request, files): - """ Return ``(path | None, encoding)``.""" + """Return ``(path | None, encoding)``.""" # if the client did not specify encodings then assume only the # identity is acceptable if not request.accept_encoding: @@ -408,7 +408,7 @@ class ManifestCacheBuster: @property def manifest(self): - """ The current manifest dictionary.""" + """The current manifest dictionary.""" if self.reload: if not self.exists(self.manifest_path): return {} diff --git a/src/pyramid/testing.py b/src/pyramid/testing.py index 621a69d4b..1fba3ff31 100644 --- a/src/pyramid/testing.py +++ b/src/pyramid/testing.py @@ -31,7 +31,7 @@ class DummyRootFactory: class DummySecurityPolicy: - """ A standin for a :term:`security policy`.""" + """A standin for a :term:`security policy`.""" def __init__( self, @@ -105,7 +105,7 @@ class DummyTemplateRenderer: return self.string_response def __getattr__(self, k): - """ Backwards compatibility """ + """Backwards compatibility""" val = self._received.get(k, _marker) if val is _marker: val = self._implementation._received.get(k, _marker) @@ -140,7 +140,7 @@ class DummyTemplateRenderer: class DummyResource: - """ A dummy :app:`Pyramid` :term:`resource` object.""" + """A dummy :app:`Pyramid` :term:`resource` object.""" def __init__( self, __name__=None, __parent__=None, __provides__=None, **kw @@ -179,7 +179,7 @@ class DummyResource: self.subs[name] = val def __getitem__(self, name): - """ Return a named subobject (see ``__setitem__``)""" + """Return a named subobject (see ``__setitem__``)""" ob = self.subs[name] return ob @@ -190,15 +190,15 @@ class DummyResource: return self.subs.get(name, default) def values(self): - """ Return the values set by __setitem__ """ + """Return the values set by __setitem__""" return self.subs.values() def items(self): - """ Return the items set by __setitem__ """ + """Return the items set by __setitem__""" return self.subs.items() def keys(self): - """ Return the keys set by __setitem__ """ + """Return the keys set by __setitem__""" return self.subs.keys() __iter__ = keys @@ -327,7 +327,7 @@ class DummyRequest( cookies=None, post=None, accept=None, - **kw + **kw, ): if environ is None: environ = {} @@ -545,7 +545,7 @@ def tearDown(unhook_zca=True): def cleanUp(*arg, **kw): - """ An alias for :func:`pyramid.testing.setUp`. """ + """An alias for :func:`pyramid.testing.setUp`.""" package = kw.get('package', None) if package is None: package = caller_package() diff --git a/src/pyramid/util.py b/src/pyramid/util.py index f8d082348..191768eb3 100644 --- a/src/pyramid/util.py +++ b/src/pyramid/util.py @@ -182,7 +182,7 @@ class InstancePropertyHelper: self.properties[name] = fn def apply(self, target): - """ Apply all configured properties to the ``target`` instance.""" + """Apply all configured properties to the ``target`` instance.""" if self.properties: self.apply_properties(target, self.properties) @@ -275,7 +275,7 @@ class WeakOrderedSet: self._order = [] def add(self, item): - """ Add an item to the set.""" + """Add an item to the set.""" oid = id(item) if oid in self._items: self._order.remove(oid) @@ -286,17 +286,17 @@ class WeakOrderedSet: self._order.append(oid) def _remove_by_id(self, oid): - """ Remove an item from the set.""" + """Remove an item from the set.""" if oid in self._items: del self._items[oid] self._order.remove(oid) def remove(self, item): - """ Remove an item from the set.""" + """Remove an item from the set.""" self._remove_by_id(id(item)) def empty(self): - """ Clear all objects from the set.""" + """Clear all objects from the set.""" self._items = {} self._order = [] @@ -445,7 +445,7 @@ class TopologicalSorter: return self.name2val.values() def remove(self, name): - """ Remove a node from the sort input """ + """Remove a node from the sort input""" self.names.remove(name) del self.name2val[name] after = self.name2after.pop(name, []) @@ -499,7 +499,7 @@ class TopologicalSorter: self.req_before.add(name) def sorted(self): - """ Returns the sort input values in topologically sorted order""" + """Returns the sort input values in topologically sorted order""" order = [(self.first, self.last)] roots = [] graph = {} diff --git a/tests/pkgs/restbugapp/views.py b/tests/pkgs/restbugapp/views.py index 6930d3668..d7e253ac2 100644 --- a/tests/pkgs/restbugapp/views.py +++ b/tests/pkgs/restbugapp/views.py @@ -8,7 +8,7 @@ class BaseRESTView: class PetRESTView(BaseRESTView): - """ REST Controller to control action of an avatar """ + """REST Controller to control action of an avatar""" def __init__(self, context, request): super().__init__(context, request) diff --git a/tests/test_config/test_init.py b/tests/test_config/test_init.py index 0a9e2988c..4ecd081e0 100644 --- a/tests/test_config/test_init.py +++ b/tests/test_config/test_init.py @@ -1349,7 +1349,7 @@ class TestConfigurator__add_predicate(unittest.TestCase): kw=None, order=0, introspectables=(), - **extra + **extra, ): self.assertEqual(len(introspectables), 1) self.assertEqual(introspectables[0]['name'], 'testing') @@ -1368,7 +1368,7 @@ class TestConfigurator__add_predicate(unittest.TestCase): kw=None, order=0, introspectables=(), - **extra + **extra, ): self.assertEqual(len(introspectables), 1) self.assertEqual(introspectables[0]['name'], 'testing') diff --git a/tests/test_config/test_views.py b/tests/test_config/test_views.py index fcccbfba3..72f8f0145 100644 --- a/tests/test_config/test_views.py +++ b/tests/test_config/test_views.py @@ -248,7 +248,7 @@ class TestViewsConfigurationMixin(unittest.TestCase): from pyramid.renderers import null_renderer def view(request): - """ ABC """ + """ABC""" return 'OK' def view_wrapper(fn): @@ -271,7 +271,7 @@ class TestViewsConfigurationMixin(unittest.TestCase): from pyramid.renderers import null_renderer def view(request): - """ ABC """ + """ABC""" return 'OK' def view_wrapper1(fn): @@ -306,7 +306,7 @@ class TestViewsConfigurationMixin(unittest.TestCase): response = Response('OK') def view(request): - """ ABC """ + """ABC""" return response config = self._makeOne(autocommit=True) @@ -3790,7 +3790,7 @@ class Test_preserve_view_attrs(unittest.TestCase): def test_it_different(self): class DummyView1: - """ 1 """ + """1""" __name__ = '1' __module__ = '1' @@ -3808,7 +3808,7 @@ class Test_preserve_view_attrs(unittest.TestCase): """ """ class DummyView2: - """ 2 """ + """2""" __name__ = '2' __module__ = '2' diff --git a/tests/test_router.py b/tests/test_router.py index 857e8aea5..f136e5ab3 100644 --- a/tests/test_router.py +++ b/tests/test_router.py @@ -56,7 +56,7 @@ class TestRouter(unittest.TestCase): virtual_root=None, virtual_root_path=None, raise_error=None, - **kw + **kw, ): from pyramid.interfaces import ITraverser @@ -1,7 +1,7 @@ [tox] envlist = lint, - py36,py37,py38,py39,pypy3, + py37,py38,py39,py310,pypy3, py38-cover,coverage, docs @@ -28,9 +28,9 @@ commands = python setup.py check -r -s -m check-manifest deps = - flake8 - black - isort + flake8~=4.0.1 + black~=22.1.0 + isort~=5.10 readme_renderer check-manifest @@ -66,19 +66,23 @@ commands = isort src/pyramid tests setup.py black src/pyramid tests setup.py deps = - black - isort + black~=22.1.0 + isort~=5.10 [testenv:build] skip_install = true commands = # clean up build/ and dist/ folders - python -c 'import shutil; shutil.rmtree("dist", ignore_errors=True)' - python setup.py clean --all - # build sdist - python setup.py sdist --dist-dir {toxinidir}/dist - # build wheel from sdist - pip wheel -v --no-deps --no-index --no-build-isolation --wheel-dir {toxinidir}/dist --find-links {toxinidir}/dist pyramid + python -c 'import shutil; shutil.rmtree("build", ignore_errors=True)' + # Make sure we aren't forgetting anything + check-manifest + # build sdist/wheel + python -m build . + # Verify all is well + twine check dist/* + deps = - setuptools - wheel + build + check-manifest + readme_renderer + twine |
