Chris McDonough
2018-04-24 50efc321cb14d76433216783c11b9eb99a7d44c8
Merge branch 'master' of github.com:Pylons/pyramid
17 files modified
154 ■■■■■ changed files
HACKING.txt 2 ●●● patch | view | raw | blame | history
RELEASING.txt 2 ●●● patch | view | raw | blame | history
docs/glossary.rst 12 ●●●● patch | view | raw | blame | history
docs/narr/project.rst 2 ●●● patch | view | raw | blame | history
docs/narr/sessions.rst 6 ●●●● patch | view | raw | blame | history
docs/quick_tutorial/authentication.rst 2 ●●● patch | view | raw | blame | history
docs/tutorials/wiki/authorization.rst 2 ●●● patch | view | raw | blame | history
docs/tutorials/wiki/basiclayout.rst 2 ●●● patch | view | raw | blame | history
docs/tutorials/wiki/distributing.rst 2 ●●● patch | view | raw | blame | history
docs/tutorials/wiki2/definingmodels.rst 2 ●●● patch | view | raw | blame | history
docs/tutorials/wiki2/distributing.rst 2 ●●● patch | view | raw | blame | history
docs/tutorials/wiki2/installation.rst 2 ●●● patch | view | raw | blame | history
pyramid/scripting.py 19 ●●●● patch | view | raw | blame | history
pyramid/tests/test_scripting.py 43 ●●●●● patch | view | raw | blame | history
pyramid/url.py 46 ●●●● patch | view | raw | blame | history
setup.py 6 ●●●● patch | view | raw | blame | history
tox.ini 2 ●●●●● patch | view | raw | blame | history
HACKING.txt
@@ -161,7 +161,7 @@
    $ $VENV/bin/nosetests pyramid.tests.test_module:ClassName
  Optionally you can install a nose plugin, `nose-selecttests
  <https://pypi.python.org/pypi/nose-selecttests/>`_, and use a regular
  <https://pypi.org/project/nose-selecttests/>`_, and use a regular
  expression with the ``-t`` parameter to run tests.
    # run a single test
RELEASING.txt
@@ -139,7 +139,7 @@
Pyramid 1.x released.
PyPI
https://pypi.python.org/pypi/pyramid/1.x
https://pypi.org/project/pyramid/1.x/
=== One time only for new version, first pre-release ===
What's New
docs/glossary.rst
@@ -332,7 +332,7 @@
     for middleware exist, such as caching, content-transport
     encoding, and other functions.  See `WSGI documentation
     <https://wsgi.readthedocs.io/en/latest/>`_ or `PyPI
     <https://pypi.python.org/pypi>`_ to find middleware for your application.
     <https://pypi.org/>`_ to find middleware for your application.
   pipeline
     The :term:`PasteDeploy` term for a single configuration of a WSGI
@@ -394,7 +394,7 @@
     between templates.
   Genshi
     An `XML templating language <https://pypi.python.org/pypi/Genshi/>`_
     An `XML templating language <https://pypi.org/project/Genshi/>`_
     by Christopher Lenz.
   Jinja2
@@ -449,7 +449,7 @@
     subpath.  See :ref:`star_subpath` for more information.
   interface
     A `Zope interface <https://pypi.python.org/pypi/zope.interface>`_
     A `Zope interface <https://pypi.org/project/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
@@ -495,7 +495,7 @@
   repoze.catalog
     An indexing and search facility (fielded and full-text) based on
     `zope.index <https://pypi.python.org/pypi/zope.index>`_.  See `the
     `zope.index <https://pypi.org/project/zope.index/>`_.  See `the
     documentation <http://docs.repoze.org/catalog>`_ for more
     information.
@@ -707,7 +707,7 @@
     :ref:`multidict_narr` and :class:`pyramid.interfaces.IMultiDict`.
   PyPI
     `The Python Package Index <https://pypi.python.org/pypi>`_, a collection
     `The Python Package Index <https://pypi.org/>`_, a collection
     of software available for Python.
   Agendaless Consulting
@@ -1100,7 +1100,7 @@
   pyramid_redis_sessions
      A package by Eric Rasmussen which allows you to store Pyramid session 
      data in a Redis database.  See 
      https://pypi.python.org/pypi/pyramid_redis_sessions for more information.
      https://pypi.org/project/pyramid_redis_sessions/ for more information.
   cache busting
      A technique used when serving a cacheable static asset in order to force
docs/narr/project.rst
@@ -763,7 +763,7 @@
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
<https://pypi.python.org/pypi?%3Aaction=list_classifiers>`_ describing your
<https://pypi.org/pypi?%3Aaction=list_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
docs/narr/sessions.rst
@@ -170,13 +170,13 @@
                                sessioning system.
======================= ======= =============================
.. _pyramid_nacl_session: https://pypi.python.org/pypi/pyramid_nacl_session
.. _pyramid_nacl_session: https://pypi.org/project/pyramid_nacl_session/
.. _PyNaCl: https://pynacl.readthedocs.io/en/latest/secret/
.. _pyramid_redis_sessions: https://pypi.python.org/pypi/pyramid_redis_sessions
.. _pyramid_redis_sessions: https://pypi.org/project/pyramid_redis_sessions/
.. _Redis: https://redis.io/
.. _pyramid_beaker: https://pypi.python.org/pypi/pyramid_beaker
.. _pyramid_beaker: https://pypi.org/project/pyramid_beaker/
.. _Beaker: https://beaker.readthedocs.io/en/latest/
.. index::
docs/quick_tutorial/authentication.rst
@@ -152,4 +152,4 @@
.. seealso:: See also :ref:`security_chapter`,
   :ref:`AuthTktAuthenticationPolicy <authentication_module>`, `bcrypt
   <https://pypi.python.org/pypi/bcrypt>`_
   <https://pypi.org/project/bcrypt/>`_
docs/tutorials/wiki/authorization.rst
@@ -43,7 +43,7 @@
Add dependencies
~~~~~~~~~~~~~~~~
Just like in :ref:`wiki_defining_views`, we need a new dependency. We need to add the `bcrypt <https://pypi.python.org/pypi/bcrypt>`_ package, to our tutorial package's ``setup.py`` file by assigning this dependency to the ``requires`` parameter in the ``setup()`` function.
Just like in :ref:`wiki_defining_views`, we need a new dependency. We need to add the `bcrypt <https://pypi.org/project/bcrypt/>`_ package, to our tutorial package's ``setup.py`` file by assigning this dependency to the ``requires`` parameter in the ``setup()`` function.
Open ``setup.py`` and edit it to look like the following:
docs/tutorials/wiki/basiclayout.rst
@@ -44,7 +44,7 @@
#. *Line 16*.  Include support for the :term:`Chameleon` template rendering
   bindings, allowing us to use the ``.pt`` templates.
#. *Line 17*.  Include support for ``pyramid_tm``, allowing Pyramid requests to join the active transaction as provided by the `transaction <https://pypi.python.org/pypi/transaction>`_ package.
#. *Line 17*.  Include support for ``pyramid_tm``, allowing Pyramid requests to join the active transaction as provided by the `transaction <https://pypi.org/project/transaction/>`_ package.
#. *Line 18*.  Include support for ``pyramid_retry`` to retry a request when transient exceptions occur.
docs/tutorials/wiki/distributing.rst
@@ -35,6 +35,6 @@
``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
<https://pypi.python.org/pypi>`_ and share it with the rest of the world, where
<https://pypi.org/>`_ 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.
docs/tutorials/wiki2/definingmodels.rst
@@ -25,7 +25,7 @@
application was generated by the cookiecutter; it doesn't know about our
custom application requirements.
We need to add a dependency, the `bcrypt <https://pypi.python.org/pypi/bcrypt>`_ package, to our ``tutorial``
We need to add a dependency, the `bcrypt <https://pypi.org/project/bcrypt/>`_ package, to our ``tutorial``
package's ``setup.py`` file by assigning this dependency to the ``requires``
parameter in the ``setup()`` function.
docs/tutorials/wiki2/distributing.rst
@@ -35,6 +35,6 @@
``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
<https://pypi.python.org/pypi>`_ and share it with the rest of the world, where
<https://pypi.org/>`_ 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.
docs/tutorials/wiki2/installation.rst
@@ -468,7 +468,7 @@
   https://docs.pylonsproject.org/projects/pyramid-tm/en/latest/
.. _zope.sqlalchemy:
   https://pypi.python.org/pypi/zope.sqlalchemy
   https://pypi.org/project/zope.sqlalchemy/
.. _transaction:
   https://zodb.readthedocs.io/en/latest/transactions.html
pyramid/scripting.py
@@ -8,7 +8,7 @@
from pyramid.request import Request
from pyramid.request import apply_request_extensions
from pyramid.threadlocal import manager as threadlocal_manager
from pyramid.threadlocal import RequestContext
from pyramid.traversal import DefaultRootFactory
def get_root(app, request=None):
@@ -26,10 +26,11 @@
    registry = app.registry
    if request is None:
        request = _make_request('/', registry)
    threadlocals = {'registry':registry, 'request':request}
    app.threadlocal_manager.push(threadlocals)
    def closer(request=request): # keep request alive via this function default
        app.threadlocal_manager.pop()
    request.registry = registry
    ctx = RequestContext(request)
    ctx.begin()
    def closer():
        ctx.end()
    root = app.root_factory(request)
    return root, closer
@@ -87,12 +88,12 @@
    # NB: even though _make_request might have already set registry on
    # request, we reset it in case someone has passed in their own
    # request.
    request.registry = registry
    threadlocals = {'registry':registry, 'request':request}
    threadlocal_manager.push(threadlocals)
    request.registry = registry
    ctx = RequestContext(request)
    ctx.begin()
    apply_request_extensions(request)
    def closer():
        threadlocal_manager.pop()
        ctx.end()
    root_factory = registry.queryUtility(IRootFactory,
                                         default=DefaultRootFactory)
    root = root_factory(request)
pyramid/tests/test_scripting.py
@@ -8,38 +8,35 @@
    def _makeRegistry(self):
        return DummyRegistry([DummyFactory])
    def setUp(self):
        from pyramid.threadlocal import manager
        self.manager = manager
        self.default = manager.get()
    def test_it_norequest(self):
        registry = self._makeRegistry()
        app = DummyApp(registry=registry)
        root, closer = self._callFUT(app)
        self.assertEqual(len(app.threadlocal_manager.pushed), 1)
        pushed = app.threadlocal_manager.pushed[0]
        self.assertEqual(dummy_root, root)
        pushed = self.manager.get()
        self.assertEqual(pushed['registry'], registry)
        self.assertEqual(pushed['request'].registry, app.registry)
        self.assertEqual(len(app.threadlocal_manager.popped), 0)
        self.assertEqual(pushed['request'].registry, registry)
        self.assertEqual(pushed['request'].environ['path'], '/')
        closer()
        self.assertEqual(len(app.threadlocal_manager.popped), 1)
        self.assertEqual(self.default, self.manager.get())
    def test_it_withrequest(self):
        registry = self._makeRegistry()
        app = DummyApp(registry=registry)
        request = DummyRequest({})
        root, closer = self._callFUT(app, request)
        self.assertEqual(len(app.threadlocal_manager.pushed), 1)
        pushed = app.threadlocal_manager.pushed[0]
        self.assertEqual(dummy_root, root)
        pushed = self.manager.get()
        self.assertEqual(pushed['registry'], registry)
        self.assertEqual(pushed['request'], request)
        self.assertEqual(len(app.threadlocal_manager.popped), 0)
        self.assertEqual(pushed['request'].registry, registry)
        closer()
        self.assertEqual(len(app.threadlocal_manager.popped), 1)
    def test_it_requestfactory_overridden(self):
        registry = self._makeRegistry()
        app = DummyApp(registry=registry)
        root, closer = self._callFUT(app)
        self.assertEqual(len(app.threadlocal_manager.pushed), 1)
        pushed = app.threadlocal_manager.pushed[0]
        self.assertEqual(pushed['request'].environ['path'], '/')
        self.assertEqual(self.default, self.manager.get())
class Test_prepare(unittest.TestCase):
    def _callFUT(self, request=None, registry=None):
@@ -206,24 +203,12 @@
class DummyApp:
    def __init__(self, registry=None):
        self.threadlocal_manager = DummyThreadLocalManager()
        if registry:
            self.registry = registry
    def root_factory(self, environ):
        return dummy_root
class DummyThreadLocalManager:
    def __init__(self):
        self.pushed = []
        self.popped = []
    def push(self, item):
        self.pushed.append(item)
    def pop(self):
        self.popped.append(True)
class DummyRequest(object):
    matchdict = None
    matched_route = None
pyramid/url.py
@@ -161,15 +161,14 @@
        ``*remainder`` replacement value, it is tacked on to the URL
        after being URL-quoted-except-for-embedded-slashes.
        If no ``_query`` keyword argument is provided, the request query string
        will be returned in the URL. If it is present, it will be used to
        compose a query string that will be tacked on to the end of the URL,
        replacing any request query string.  The value of ``_query`` may be a
        sequence of two-tuples *or* a data structure with an ``.items()``
        method that returns a sequence of two-tuples (presumably a dictionary).
        This data structure will be turned into a query string per the
        documentation of :func:`pyramid.url.urlencode` function.  This will
        produce a query string in the ``x-www-form-urlencoded`` format.  A
        If ``_query`` is provided, it will be used to compose a query string
        that will be tacked on to the end of the URL.  The value of ``_query``
        may be a sequence of two-tuples *or* a data structure with an
        ``.items()`` method that returns a sequence of two-tuples
        (presumably a dictionary). This data structure will be turned into
        a query string per the documentation of the
        :func:`pyramid.url.urlencode` function.  This will produce a query
        string in the ``x-www-form-urlencoded`` format.  A
        non-``x-www-form-urlencoded`` query string may be used by passing a
        *string* value as ``_query`` in which case it will be URL-quoted
        (e.g. query="foo bar" will become "foo%20bar").  However, the result
@@ -353,20 +352,21 @@
                     ``elements`` are used, the generated URL will *not*
                     end in a trailing slash.
        If a keyword argument ``query`` is present, it will be used to compose
        a query string that will be tacked on to the end of the URL.  The value
        of ``query`` may be a sequence of two-tuples *or* a data structure with
        an ``.items()`` method that returns a sequence of two-tuples
        (presumably a dictionary).  This data structure will be turned into a
        query string per the documentation of :func:`pyramid.url.urlencode`
        function.  This will produce a query string in the
        ``x-www-form-urlencoded`` encoding.  A non-``x-www-form-urlencoded``
        query string may be used by passing a *string* value as ``query`` in
        which case it will be URL-quoted (e.g. query="foo bar" will become
        "foo%20bar").  However, the result will not need to be in ``k=v`` form
        as required by ``x-www-form-urlencoded``.  After the query data is
        turned into a query string, a leading ``?`` is prepended, and the
        resulting string is appended to the generated URL.
        If ``query`` is provided, it will be used to compose a query string
        that will be tacked on to the end of the URL.  The value of ``query``
        may be a sequence of two-tuples *or* a data structure with an
        ``.items()`` method that returns a sequence of two-tuples
        (presumably a dictionary). This data structure will be turned into
        a query string per the documentation of the
        :func:`pyramid.url.urlencode` function.  This will produce a query
        string in the ``x-www-form-urlencoded`` format.  A
        non-``x-www-form-urlencoded`` query string may be used by passing a
        *string* value as ``query`` in which case it will be URL-quoted
        (e.g. query="foo bar" will become "foo%20bar").  However, the result
        will not need to be in ``k=v`` form as required by
        ``x-www-form-urlencoded``.  After the query data is turned into a query
        string, a leading ``?`` is prepended, and the resulting string is
        appended to the generated URL.
        .. note::
setup.py
@@ -22,10 +22,10 @@
install_requires = [
    'setuptools',
    'WebOb >= 1.7.0rc2', # Response.has_body
    'WebOb >= 1.7.0', # Response.has_body
    'zope.interface >= 3.8.0',  # has zope.interface.registry
    'zope.deprecation >= 3.5.0', # py3 compat
    'venusian >= 1.0a3', # ``ignore``
    'venusian >= 1.0', # ``ignore``
    'translationstring >= 0.4', # py3 compat
    'PasteDeploy >= 1.5.0', # py3 compat
    'plaster',
@@ -40,7 +40,7 @@
docs_extras = [
    'Sphinx >= 1.3.5',
    'Sphinx >= 1.3.5, != 1.7.3',
    'docutils',
    'repoze.sphinx.autointerface',
    'pylons_sphinx_latesturl',
tox.ini
@@ -64,7 +64,6 @@
    check-manifest
[testenv:docs]
skip_install = True
basepython = python3.5
whitelist_externals = make
commands =
@@ -72,7 +71,6 @@
    make -C docs doctest html epub BUILDDIR={envdir} "SPHINXOPTS=-W -E"
[testenv:pdf]
skip_install = True
basepython = python3.5
whitelist_externals = make
commands =