diff options
| author | Bert JW Regeer <bertjw@regeer.org> | 2016-01-03 02:09:59 -0700 |
|---|---|---|
| committer | Bert JW Regeer <bertjw@regeer.org> | 2016-01-03 02:09:59 -0700 |
| commit | a2dff0592714d9cde5a0a612411aa96ce9d94b3c (patch) | |
| tree | 6dac581990ba758670a8424cafe8bf31888471f7 /docs | |
| parent | 29e1002a108d045e1f80be3137f2cde4e47ca642 (diff) | |
| parent | 5558386fd1a6181b2e8ad06659049c055a7ed023 (diff) | |
| download | pyramid-a2dff0592714d9cde5a0a612411aa96ce9d94b3c.tar.gz pyramid-a2dff0592714d9cde5a0a612411aa96ce9d94b3c.tar.bz2 pyramid-a2dff0592714d9cde5a0a612411aa96ce9d94b3c.zip | |
Merge branch 'master' into feature/alchemy-scaffold-update
Diffstat (limited to 'docs')
36 files changed, 1054 insertions, 841 deletions
diff --git a/docs/api/session.rst b/docs/api/session.rst index dde9d20e9..474e2bb32 100644 --- a/docs/api/session.rst +++ b/docs/api/session.rst @@ -17,4 +17,5 @@ .. autofunction:: BaseCookieSessionFactory + .. autoclass:: PickleSerializer diff --git a/docs/api/static.rst b/docs/api/static.rst index b6b279139..f3727e197 100644 --- a/docs/api/static.rst +++ b/docs/api/static.rst @@ -9,17 +9,11 @@ :members: :inherited-members: - .. autoclass:: PathSegmentCacheBuster + .. autoclass:: ManifestCacheBuster :members: .. autoclass:: QueryStringCacheBuster :members: - .. autoclass:: PathSegmentMd5CacheBuster - :members: - - .. autoclass:: QueryStringMd5CacheBuster - :members: - .. autoclass:: QueryStringConstantCacheBuster :members: diff --git a/docs/conf.py b/docs/conf.py index 8a9bac6ed..073811eca 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -53,12 +53,13 @@ extensions = [ 'sphinx.ext.doctest', 'repoze.sphinx.autointerface', 'sphinx.ext.viewcode', - 'sphinx.ext.intersphinx' + 'sphinx.ext.intersphinx', + 'sphinxcontrib.programoutput', ] # Looks for objects in external projects intersphinx_mapping = { - 'colander': ( 'http://docs.pylonsproject.org/projects/colander/en/latest', None), + 'colander': ('http://docs.pylonsproject.org/projects/colander/en/latest', None), 'cookbook': ('http://docs.pylonsproject.org/projects/pyramid-cookbook/en/latest/', None), 'deform': ('http://docs.pylonsproject.org/projects/deform/en/latest', None), 'jinja2': ('http://docs.pylonsproject.org/projects/pyramid-jinja2/en/latest/', None), @@ -66,8 +67,8 @@ intersphinx_mapping = { 'python': ('http://docs.python.org', None), 'python3': ('http://docs.python.org/3', None), 'sqla': ('http://docs.sqlalchemy.org/en/latest', None), - 'tm': ('http://docs.pylonsproject.org/projects/pyramid_tm/en/latest/', None), - 'toolbar': ('http://docs.pylonsproject.org/projects/pyramid-debugtoolbar/en/latest', None), + 'tm': ('http://docs.pylonsproject.org/projects/pyramid_tm/en/latest/', None), + 'toolbar': ('http://docs.pylonsproject.org/projects/pyramid-debugtoolbar/en/latest', None), 'tstring': ('http://docs.pylonsproject.org/projects/translationstring/en/latest', None), 'tutorials': ('http://docs.pylonsproject.org/projects/pyramid-tutorials/en/latest/', None), 'venusian': ('http://docs.pylonsproject.org/projects/venusian/en/latest', None), diff --git a/docs/designdefense.rst b/docs/designdefense.rst index 1ed4f65a4..bfde25246 100644 --- a/docs/designdefense.rst +++ b/docs/designdefense.rst @@ -7,98 +7,94 @@ From time to time, challenges to various aspects of :app:`Pyramid` design are lodged. To give context to discussions that follow, we detail some of the design decisions and trade-offs here. In some cases, we acknowledge that the framework can be made better and we describe future steps which will be taken -to improve it; in some cases we just file the challenge as noted, as -obviously you can't please everyone all of the time. +to improve it. In others we just file the challenge as noted, as obviously you +can't please everyone all of the time. Pyramid Provides More Than One Way to Do It ------------------------------------------- A canon of Python popular culture is "TIOOWTDI" ("there is only one way to do -it", a slighting, tongue-in-cheek reference to Perl's "TIMTOWTDI", which is -an acronym for "there is more than one way to do it"). - -:app:`Pyramid` is, for better or worse, a "TIMTOWTDI" system. For example, -it includes more than one way to resolve a URL to a :term:`view callable`: -via :term:`url dispatch` or :term:`traversal`. Multiple methods of -configuration exist: :term:`imperative configuration`, :term:`configuration -decoration`, and :term:`ZCML` (optionally via :term:`pyramid_zcml`). It works -with multiple different kinds of persistence and templating systems. And so -on. However, the existence of most of these overlapping ways to do things -are not without reason and purpose: we have a number of audiences to serve, -and we believe that TIMTOWTI at the web framework level actually *prevents* a -much more insidious and harmful set of duplication at higher levels in the -Python web community. - -:app:`Pyramid` began its life as :mod:`repoze.bfg`, written by a team of -people with many years of prior :term:`Zope` experience. The idea of +it", a slighting, tongue-in-cheek reference to Perl's "TIMTOWTDI", which is an +acronym for "there is more than one way to do it"). + +:app:`Pyramid` is, for better or worse, a "TIMTOWTDI" system. For example, it +includes more than one way to resolve a URL to a :term:`view callable`: via +:term:`url dispatch` or :term:`traversal`. Multiple methods of configuration +exist: :term:`imperative configuration`, :term:`configuration decoration`, and +:term:`ZCML` (optionally via :term:`pyramid_zcml`). It works with multiple +different kinds of persistence and templating systems. And so on. However, the +existence of most of these overlapping ways to do things are not without reason +and purpose: we have a number of audiences to serve, and we believe that +TIMTOWTDI at the web framework level actually *prevents* a much more insidious +and harmful set of duplication at higher levels in the Python web community. + +:app:`Pyramid` began its life as :mod:`repoze.bfg`, written by a team of people +with many years of prior :term:`Zope` experience. The idea of :term:`traversal` and the way :term:`view lookup` works was stolen entirely from Zope. The authorization subsystem provided by :app:`Pyramid` is a derivative of Zope's. The idea that an application can be *extended* without forking is also a Zope derivative. Implementations of these features were *required* to allow the :app:`Pyramid` -authors to build the bread-and-butter CMS-type systems for customers in the -way in which they were accustomed. No other system, save for Zope itself, -had such features, and Zope itself was beginning to show signs of its age. -We were becoming hampered by consequences of its early design mistakes. -Zope's lack of documentation was also difficult to work around: it was hard -to hire smart people to work on Zope applications, because there was no -comprehensive documentation set to point them at which explained "it all" in -one consumable place, and it was too large and self-inconsistent to document -properly. Before :mod:`repoze.bfg` went under development, its authors -obviously looked around for other frameworks that fit the bill. But no -non-Zope framework did. So we embarked on building :mod:`repoze.bfg`. +authors to build the bread-and-butter CMS-type systems for customers in the way +in which they were accustomed. No other system, save for Zope itself, had such +features, and Zope itself was beginning to show signs of its age. We were +becoming hampered by consequences of its early design mistakes. Zope's lack of +documentation was also difficult to work around. It was hard to hire smart +people to work on Zope applications because there was no comprehensive +documentation set which explained "it all" in one consumable place, and it was +too large and self-inconsistent to document properly. Before :mod:`repoze.bfg` +went under development, its authors obviously looked around for other +frameworks that fit the bill. But no non-Zope framework did. So we embarked on +building :mod:`repoze.bfg`. As the result of our research, however, it became apparent that, despite the -fact that no *one* framework had all the features we required, lots of -existing frameworks had good, and sometimes very compelling ideas. In -particular, :term:`URL dispatch` is a more direct mechanism to map URLs to -code. +fact that no *one* framework had all the features we required, lots of existing +frameworks had good, and sometimes very compelling ideas. In particular, +:term:`URL dispatch` is a more direct mechanism to map URLs to code. So, although we couldn't find a framework, save for Zope, that fit our needs, and while we incorporated a lot of Zope ideas into BFG, we also emulated the features we found compelling in other frameworks (such as :term:`url -dispatch`). After the initial public release of BFG, as time went on, -features were added to support people allergic to various Zope-isms in the -system, such as the ability to configure the application using -:term:`imperative configuration` and :term:`configuration decoration` rather -than solely using :term:`ZCML`, and the elimination of the required use of -:term:`interface` objects. It soon became clear that we had a system that -was very generic, and was beginning to appeal to non-Zope users as well as -ex-Zope users. +dispatch`). After the initial public release of BFG, as time went on, features +were added to support people allergic to various Zope-isms in the system, such +as the ability to configure the application using :term:`imperative +configuration` and :term:`configuration decoration`, rather than solely using +:term:`ZCML`, and the elimination of the required use of :term:`interface` +objects. It soon became clear that we had a system that was very generic, and +was beginning to appeal to non-Zope users as well as ex-Zope users. As the result of this generalization, it became obvious BFG shared 90% of its -featureset with the featureset of Pylons 1, and thus had a very similar -target market. Because they were so similar, choosing between the two -systems was an exercise in frustration for an otherwise non-partisan -developer. It was also strange for the Pylons and BFG development -communities to be in competition for the same set of users, given how similar -the two frameworks were. So the Pylons and BFG teams began to work together -to form a plan to merge. The features missing from BFG (notably :term:`view -handler` classes, flash messaging, and other minor missing bits), were added, -to provide familiarity to ex-Pylons users. The result is :app:`Pyramid`. - -The Python web framework space is currently notoriously balkanized. We're -truly hoping that the amalgamation of components in :app:`Pyramid` will -appeal to at least two currently very distinct sets of users: Pylons and BFG -users. By unifying the best concepts from Pylons and BFG into a single -codebase and leaving the bad concepts from their ancestors behind, we'll be -able to consolidate our efforts better, share more code, and promote our -efforts as a unit rather than competing pointlessly. We hope to be able to -shortcut the pack mentality which results in a *much larger* duplication of -effort, represented by competing but incredibly similar applications and -libraries, each built upon a specific low level stack that is incompatible -with the other. We'll also shrink the choice of credible Python web -frameworks down by at least one. We're also hoping to attract users from -other communities (such as Zope's and TurboGears') by providing the features -they require, while allowing enough flexibility to do things in a familiar -fashion. Some overlap of functionality to achieve these goals is expected -and unavoidable, at least if we aim to prevent pointless duplication at -higher levels. If we've done our job well enough, the various audiences will -be able to coexist and cooperate rather than firing at each other across some -imaginary web framework DMZ. - -Pyramid Uses A Zope Component Architecture ("ZCA") Registry +feature set with the feature set of Pylons 1, and thus had a very similar +target market. Because they were so similar, choosing between the two systems +was an exercise in frustration for an otherwise non-partisan developer. It was +also strange for the Pylons and BFG development communities to be in +competition for the same set of users, given how similar the two frameworks +were. So the Pylons and BFG teams began to work together to form a plan to +merge. The features missing from BFG (notably :term:`view handler` classes, +flash messaging, and other minor missing bits), were added to provide +familiarity to ex-Pylons users. The result is :app:`Pyramid`. + +The Python web framework space is currently notoriously balkanized. We're truly +hoping that the amalgamation of components in :app:`Pyramid` will appeal to at +least two currently very distinct sets of users: Pylons and BFG users. By +unifying the best concepts from Pylons and BFG into a single codebase, and +leaving the bad concepts from their ancestors behind, we'll be able to +consolidate our efforts better, share more code, and promote our efforts as a +unit rather than competing pointlessly. We hope to be able to shortcut the pack +mentality which results in a *much larger* duplication of effort, represented +by competing but incredibly similar applications and libraries, each built upon +a specific low level stack that is incompatible with the other. We'll also +shrink the choice of credible Python web frameworks down by at least one. We're +also hoping to attract users from other communities (such as Zope's and +TurboGears') by providing the features they require, while allowing enough +flexibility to do things in a familiar fashion. Some overlap of functionality +to achieve these goals is expected and unavoidable, at least if we aim to +prevent pointless duplication at higher levels. If we've done our job well +enough, the various audiences will be able to coexist and cooperate rather than +firing at each other across some imaginary web framework DMZ. + +Pyramid Uses a Zope Component Architecture ("ZCA") Registry ----------------------------------------------------------- :app:`Pyramid` uses a :term:`Zope Component Architecture` (ZCA) "component @@ -146,7 +142,7 @@ dictionary API, but that's not very important in this context. That's problem number two. Third of all, what does the ``getUtility`` function do? It's performing a -lookup for the ``ISettings`` "utility" that should return.. well, a utility. +lookup for the ``ISettings`` "utility" that should return... well, a utility. Note how we've already built up a dependency on the understanding of an :term:`interface` and the concept of "utility" to answer this question: a bad sign so far. Note also that the answer is circular, a *really* bad sign. @@ -156,12 +152,12 @@ registry" of course. What's a component registry? Problem number four. Fifth, assuming you buy that there's some magical registry hanging around, where *is* this registry? *Homina homina*... "around"? That's sort of the -best answer in this context (a more specific answer would require knowledge -of internals). Can there be more than one registry? Yes. So *which* -registry does it find the registration in? Well, the "current" registry of -course. In terms of :app:`Pyramid`, the current registry is a thread local -variable. Using an API that consults a thread local makes understanding how -it works non-local. +best answer in this context (a more specific answer would require knowledge of +internals). Can there be more than one registry? Yes. So in *which* registry +does it find the registration? Well, the "current" registry of course. In +terms of :app:`Pyramid`, the current registry is a thread local variable. +Using an API that consults a thread local makes understanding how it works +non-local. You've now bought in to the fact that there's a registry that is just hanging around. But how does the registry get populated? Why, via code that calls @@ -170,10 +166,10 @@ registration of ``ISettings`` is made by the framework itself under the hood: it's not present in any user configuration. This is extremely hard to comprehend. Problem number six. -Clearly there's some amount of cognitive load here that needs to be borne by -a reader of code that extends the :app:`Pyramid` framework due to its use of -the ZCA, even if he or she is already an expert Python programmer and whom is -an expert in the domain of web applications. This is suboptimal. +Clearly there's some amount of cognitive load here that needs to be borne by a +reader of code that extends the :app:`Pyramid` framework due to its use of the +ZCA, even if they are already an expert Python programmer and an expert in the +domain of web applications. This is suboptimal. Ameliorations +++++++++++++ @@ -907,23 +903,22 @@ creating a more Zope3-like environment without much effort. .. _http_exception_hierarchy: -Pyramid Uses its Own HTTP Exception Class Hierarchy Rather Than ``webob.exc`` ------------------------------------------------------------------------------ +Pyramid uses its own HTTP exception class hierarchy rather than :mod:`webob.exc` +-------------------------------------------------------------------------------- .. versionadded:: 1.1 The HTTP exception classes defined in :mod:`pyramid.httpexceptions` are very -much like the ones defined in ``webob.exc`` -(e.g. :class:`~pyramid.httpexceptions.HTTPNotFound`, -:class:`~pyramid.httpexceptions.HTTPForbidden`, etc). They have the same -names and largely the same behavior and all have a very similar -implementation, but not the same identity. Here's why they have a separate -identity: +much like the ones defined in :mod:`webob.exc`, (e.g., +:class:`~pyramid.httpexceptions.HTTPNotFound` or +:class:`~pyramid.httpexceptions.HTTPForbidden`). They have the same names and +largely the same behavior, and all have a very similar implementation, but not +the same identity. Here's why they have a separate identity: - Making them separate allows the HTTP exception classes to subclass :class:`pyramid.response.Response`. This speeds up response generation - slightly due to the way the Pyramid router works. The same speedup could - be gained by monkeypatching ``webob.response.Response`` but it's usually + slightly due to the way the Pyramid router works. The same speedup could be + gained by monkeypatching :class:`webob.response.Response`, but it's usually the case that monkeypatching turns out to be evil and wrong. - Making them separate allows them to provide alternate ``__call__`` logic @@ -933,7 +928,7 @@ identity: value of ``RequestClass`` (:class:`pyramid.request.Request`). - Making them separate allows us freedom from having to think about backwards - compatibility code present in ``webob.exc`` having to do with Python 2.4, + compatibility code present in :mod:`webob.exc` having to do with Python 2.4, which we no longer support in Pyramid 1.1+. - We change the behavior of two classes @@ -944,9 +939,9 @@ identity: - Making them separate allows us to influence the docstrings of the exception classes to provide Pyramid-specific documentation. -- Making them separate allows us to silence a stupid deprecation warning - under Python 2.6 when the response objects are used as exceptions (related - to ``self.message``). +- Making them separate allows us to silence a stupid deprecation warning under + Python 2.6 when the response objects are used as exceptions (related to + ``self.message``). .. _simpler_traversal_model: diff --git a/docs/glossary.rst b/docs/glossary.rst index 9c0ea8598..60e861597 100644 --- a/docs/glossary.rst +++ b/docs/glossary.rst @@ -273,7 +273,7 @@ Glossary (Allow, 'bob', 'read'), (Deny, 'fred', 'write')]``. If an ACL is attached to a resource instance, and that resource is findable via the context resource, it will be consulted any active security policy to - determine wither a particular request can be fulfilled given the + determine whether a particular request can be fulfilled given the :term:`authentication` information in the request. authentication @@ -1089,3 +1089,7 @@ Glossary data in a Redis database. See https://pypi.python.org/pypi/pyramid_redis_sessions for more information. + cache busting + A technique used when serving a cacheable static asset in order to force + a client to query the new version of the asset. See :ref:`cache_busting` + for more information. diff --git a/docs/index.rst b/docs/index.rst index e792b9905..8c8a0a18d 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -162,6 +162,19 @@ Comprehensive reference material for every public API exposed by api/* +``p*`` Scripts Documentation +============================ + +``p*`` scripts included with :app:`Pyramid`:. + +.. toctree:: + :maxdepth: 1 + :glob: + + pscripts/index + pscripts/* + + Change History ============== diff --git a/docs/narr/MyProject/development.ini b/docs/narr/MyProject/development.ini index a9a26e56b..749e574eb 100644 --- a/docs/narr/MyProject/development.ini +++ b/docs/narr/MyProject/development.ini @@ -11,7 +11,7 @@ pyramid.debug_authorization = false pyramid.debug_notfound = false pyramid.debug_routematch = false pyramid.default_locale_name = en -pyramid.includes = +pyramid.includes = pyramid_debugtoolbar # By default, the toolbar only appears for clients from IP addresses @@ -24,7 +24,7 @@ pyramid.includes = [server:main] use = egg:waitress#main -host = 0.0.0.0 +host = 127.0.0.1 port = 6543 ### @@ -57,4 +57,4 @@ level = NOTSET formatter = generic [formatter_generic] -format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s +format = %(asctime)s %(levelname)-5.5s [%(name)s:%(lineno)s][%(threadName)s] %(message)s diff --git a/docs/narr/MyProject/myproject/templates/mytemplate.pt b/docs/narr/MyProject/myproject/templates/mytemplate.pt index e6b00a145..65d7f0609 100644 --- a/docs/narr/MyProject/myproject/templates/mytemplate.pt +++ b/docs/narr/MyProject/myproject/templates/mytemplate.pt @@ -8,12 +8,12 @@ <meta name="author" content="Pylons Project"> <link rel="shortcut icon" href="${request.static_url('myproject:static/pyramid-16x16.png')}"> - <title>Starter Template for The Pyramid Web Framework</title> + <title>Starter Scaffold for The Pyramid Web Framework</title> <!-- Bootstrap core CSS --> <link href="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet"> - <!-- Custom styles for this template --> + <!-- Custom styles for this scaffold --> <link href="${request.static_url('myproject:static/theme.css')}" rel="stylesheet"> <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries --> @@ -33,19 +33,20 @@ </div> <div class="col-md-10"> <div class="content"> - <h1><span class="font-semi-bold">Pyramid</span> <span class="smaller">starter template</span></h1> - <p class="lead">Welcome to <span class="font-normal">${project}</span>, an application generated by<br>the <span class="font-normal">Pyramid Web Framework</span>.</p> + <h1><span class="font-semi-bold">Pyramid</span> <span class="smaller">Starter scaffold</span></h1> + <p class="lead">Welcome to <span class="font-normal">${project}</span>, an application generated by<br>the <span class="font-normal">Pyramid Web Framework 1.6b2</span>.</p> </div> </div> </div> <div class="row"> <div class="links"> <ul> - <li class="current-version">Currently v1.5</li> - <li><i class="glyphicon glyphicon-bookmark icon-muted"></i><a href="http://docs.pylonsproject.org">Docs</a></li> + <li class="current-version">Generated by v1.6b2</li> + <li><i class="glyphicon glyphicon-bookmark icon-muted"></i><a href="http://docs.pylonsproject.org/projects/pyramid/en/1.6-branch/">Docs</a></li> <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="irc://irc.freenode.net#pyramid">IRC Channel</a></li> <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="http://pylonsproject.org">Pylons Project</a></li> + </ul> </div> </div> <div class="row"> diff --git a/docs/narr/MyProject/myproject/tests.py b/docs/narr/MyProject/myproject/tests.py index 8c60407e5..37df08a2a 100644 --- a/docs/narr/MyProject/myproject/tests.py +++ b/docs/narr/MyProject/myproject/tests.py @@ -16,31 +16,6 @@ class ViewTests(unittest.TestCase): info = my_view(request) self.assertEqual(info['project'], 'MyProject') -class ViewIntegrationTests(unittest.TestCase): - def setUp(self): - """ This sets up the application registry with the - registrations your application declares in its ``includeme`` - function. - """ - self.config = testing.setUp() - self.config.include('myproject') - - def tearDown(self): - """ Clear out the application registry """ - testing.tearDown() - - def test_my_view(self): - from myproject.views import my_view - request = testing.DummyRequest() - result = my_view(request) - self.assertEqual(result.status, '200 OK') - body = result.app_iter[0] - self.assertTrue('Welcome to' in body) - self.assertEqual(len(result.headerlist), 2) - self.assertEqual(result.headerlist[0], - ('Content-Type', 'text/html; charset=UTF-8')) - self.assertEqual(result.headerlist[1], ('Content-Length', - str(len(body)))) class FunctionalTests(unittest.TestCase): def setUp(self): diff --git a/docs/narr/MyProject/production.ini b/docs/narr/MyProject/production.ini index 9eae9e03f..3ccbe6619 100644 --- a/docs/narr/MyProject/production.ini +++ b/docs/narr/MyProject/production.ini @@ -51,4 +51,4 @@ level = NOTSET formatter = generic [formatter_generic] -format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s +format = %(asctime)s %(levelname)-5.5s [%(name)s:%(lineno)s][%(threadName)s] %(message)s diff --git a/docs/narr/MyProject/setup.py b/docs/narr/MyProject/setup.py index 9f34540a7..8c019af51 100644 --- a/docs/narr/MyProject/setup.py +++ b/docs/narr/MyProject/setup.py @@ -1,42 +1,30 @@ -"""Setup for the MyProject package. - -""" import os -from setuptools import setup, find_packages - - -HERE = os.path.abspath(os.path.dirname(__file__)) - -with open(os.path.join(HERE, 'README.txt')) as fp: - README = fp.read() - - -with open(os.path.join(HERE, 'CHANGES.txt')) as fp: - CHANGES = fp.read() +from setuptools import setup, find_packages +here = os.path.abspath(os.path.dirname(__file__)) +with open(os.path.join(here, 'README.txt')) as f: + README = f.read() +with open(os.path.join(here, 'CHANGES.txt')) as f: + CHANGES = f.read() -REQUIRES = [ +requires = [ 'pyramid', 'pyramid_chameleon', 'pyramid_debugtoolbar', 'waitress', ] -TESTS_REQUIRE = [ - 'webtest' - ] - setup(name='MyProject', version='0.0', description='MyProject', long_description=README + '\n\n' + CHANGES, classifiers=[ - 'Programming Language :: Python', - 'Framework :: Pyramid', - 'Topic :: Internet :: WWW/HTTP', - 'Topic :: Internet :: WWW/HTTP :: WSGI :: Application', - ], + "Programming Language :: Python", + "Framework :: Pyramid", + "Topic :: Internet :: WWW/HTTP", + "Topic :: Internet :: WWW/HTTP :: WSGI :: Application", + ], author='', author_email='', url='', @@ -44,10 +32,11 @@ setup(name='MyProject', packages=find_packages(), include_package_data=True, zip_safe=False, - install_requires=REQUIRES, - tests_require=TESTS_REQUIRE, - test_suite='myproject', + install_requires=requires, + tests_require=requires, + test_suite="myproject", entry_points="""\ [paste.app_factory] main = myproject:main - """) + """, + ) diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst index 020794062..58f547fc9 100644 --- a/docs/narr/assets.rst +++ b/docs/narr/assets.rst @@ -356,247 +356,231 @@ may change, and then you'll want the client to load a new copy of the asset. Under normal circumstances you'd just need to wait for the client's cached copy to expire before they get the new version of the static resource. -A commonly used workaround to this problem is a technique known as "cache -busting". Cache busting schemes generally involve generating a URL for a -static asset that changes when the static asset changes. This way headers can -be sent along with the static asset instructing the client to cache the asset -for a very long time. When a static asset is changed, the URL used to refer to -it in a web page also changes, so the client sees it as a new resource and -requests the asset, regardless of any caching policy set for the resource's old -URL. +A commonly used workaround to this problem is a technique known as +:term:`cache busting`. Cache busting schemes generally involve generating a +URL for a static asset that changes when the static asset changes. This way +headers can be sent along with the static asset instructing the client to cache +the asset for a very long time. When a static asset is changed, the URL used +to refer to it in a web page also changes, so the client sees it as a new +resource and requests the asset, regardless of any caching policy set for the +resource's old URL. :app:`Pyramid` can be configured to produce cache busting URLs for static -assets by passing the optional argument, ``cachebust`` to -:meth:`~pyramid.config.Configurator.add_static_view`: +assets using :meth:`~pyramid.config.Configurator.add_cache_buster`: .. code-block:: python :linenos: + import time + from pyramid.static import QueryStringConstantCacheBuster + # config is an instance of pyramid.config.Configurator - config.add_static_view(name='static', path='mypackage:folder/static', - cachebust=True) + config.add_static_view(name='static', path='mypackage:folder/static/') + config.add_cache_buster( + 'mypackage:folder/static/', + QueryStringConstantCacheBuster(str(int(time.time())))) -Setting the ``cachebust`` argument instructs :app:`Pyramid` to use a cache -busting scheme which adds the md5 checksum for a static asset as a path segment -in the asset's URL: +Adding the cachebuster instructs :app:`Pyramid` to add the current time for +a static asset to the query string in the asset's URL: .. code-block:: python :linenos: js_url = request.static_url('mypackage:folder/static/js/myapp.js') - # Returns: 'http://www.example.com/static/c9658b3c0a314a1ca21e5988e662a09e/js/myapp.js' + # Returns: 'http://www.example.com/static/js/myapp.js?x=1445318121' -When the asset changes, so will its md5 checksum, and therefore so will its -URL. Supplying the ``cachebust`` argument also causes the static view to set -headers instructing clients to cache the asset for ten years, unless the -``cache_max_age`` argument is also passed, in which case that value is used. +When the web server restarts, the time constant will change and therefore so +will its URL. .. note:: - md5 checksums are cached in RAM, so if you change a static resource without - restarting your application, you may still generate URLs with a stale md5 - checksum. + Cache busting is an inherently complex topic as it integrates the asset + pipeline and the web application. It is expected and desired that + application authors will write their own cache buster implementations + conforming to the properties of their own asset pipelines. See + :ref:`custom_cache_busters` for information on writing your own. Disabling the Cache Buster ~~~~~~~~~~~~~~~~~~~~~~~~~~ It can be useful in some situations (e.g., development) to globally disable all configured cache busters without changing calls to -:meth:`~pyramid.config.Configurator.add_static_view`. To do this set the +:meth:`~pyramid.config.Configurator.add_cache_buster`. To do this set the ``PYRAMID_PREVENT_CACHEBUST`` environment variable or the ``pyramid.prevent_cachebust`` configuration value to a true value. +.. _custom_cache_busters: + Customizing the Cache Buster ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Revisiting from the previous section: - -.. code-block:: python - :linenos: - - # config is an instance of pyramid.config.Configurator - config.add_static_view(name='static', path='mypackage:folder/static', - cachebust=True) - -Setting ``cachebust`` to ``True`` instructs :app:`Pyramid` to use a default -cache busting implementation that should work for many situations. The -``cachebust`` may be set to any object that implements the interface -:class:`~pyramid.interfaces.ICacheBuster`. The above configuration is exactly -equivalent to: - -.. code-block:: python - :linenos: - - from pyramid.static import PathSegmentMd5CacheBuster +Calls to :meth:`~pyramid.config.Configurator.add_cache_buster` may use +any object that implements the interface +:class:`~pyramid.interfaces.ICacheBuster`. - # config is an instance of pyramid.config.Configurator - config.add_static_view(name='static', path='mypackage:folder/static', - cachebust=PathSegmentMd5CacheBuster()) - -:app:`Pyramid` includes a handful of ready to use cache buster implementations: -:class:`~pyramid.static.PathSegmentMd5CacheBuster`, which inserts an md5 -checksum token in the path portion of the asset's URL, -:class:`~pyramid.static.QueryStringMd5CacheBuster`, which adds an md5 checksum -token to the query string of the asset's URL, and +:app:`Pyramid` ships with a very simplistic :class:`~pyramid.static.QueryStringConstantCacheBuster`, which adds an -arbitrary token you provide to the query string of the asset's URL. +arbitrary token you provide to the query string of the asset's URL. This +is almost never what you want in production as it does not allow fine-grained +busting of individual assets. In order to implement your own cache buster, you can write your own class from scratch which implements the :class:`~pyramid.interfaces.ICacheBuster` interface. Alternatively you may choose to subclass one of the existing implementations. One of the most likely scenarios is you'd want to change the -way the asset token is generated. To do this just subclass either -:class:`~pyramid.static.PathSegmentCacheBuster` or +way the asset token is generated. To do this just subclass :class:`~pyramid.static.QueryStringCacheBuster` and define a -``tokenize(pathspec)`` method. Here is an example which just uses Git to get -the hash of the currently checked out code: +``tokenize(pathspec)`` method. Here is an example which uses Git to get +the hash of the current commit: .. code-block:: python :linenos: import os import subprocess - from pyramid.static import PathSegmentCacheBuster + from pyramid.static import QueryStringCacheBuster - class GitCacheBuster(PathSegmentCacheBuster): + class GitCacheBuster(QueryStringCacheBuster): """ Assuming your code is installed as a Git checkout, as opposed to an egg from an egg repository like PYPI, you can use this cachebuster to get the current commit's SHA1 to use as the cache bust token. """ - def __init__(self): - here = os.path.dirname(os.path.abspath(__file__)) + def __init__(self, param='x', repo_path=None): + super(GitCacheBuster, self).__init__(param=param) + if repo_path is None: + repo_path = os.path.dirname(os.path.abspath(__file__)) self.sha1 = subprocess.check_output( ['git', 'rev-parse', 'HEAD'], - cwd=here).strip() + cwd=repo_path).strip() def tokenize(self, pathspec): return self.sha1 -Choosing a Cache Buster -~~~~~~~~~~~~~~~~~~~~~~~ - -The default cache buster implementation, -:class:`~pyramid.static.PathSegmentMd5CacheBuster`, works very well assuming -that you're using :app:`Pyramid` to serve your static assets. The md5 checksum -is fine grained enough that browsers should only request new versions of -specific assets that have changed. Many caching HTTP proxies will fail to -cache a resource if the URL contains a query string. In general, therefore, -you should prefer a cache busting strategy which modifies the path segment to a -strategy which adds a query string. - -It is possible, however, that your static assets are being served by another -web server or externally on a CDN. In these cases modifying the path segment -for a static asset URL would cause the external service to fail to find the -asset, causing your customer to get a 404. In these cases you would need to -fall back to a cache buster which adds a query string. It is even possible -that there isn't a copy of your static assets available to the :app:`Pyramid` -application, so a cache busting implementation that generates md5 checksums -would fail since it can't access the assets. In such a case, -:class:`~pyramid.static.QueryStringConstantCacheBuster` is a reasonable -fallback. The following code would set up a cachebuster that just uses the -time at start up as a cachebust token: +A simple cache buster that modifies the path segment can be constructed as +well: .. code-block:: python :linenos: - import time - from pyramid.static import QueryStringConstantCacheBuster - - config.add_static_view( - name='http://mycdn.example.com/', - path='mypackage:static', - cachebust=QueryStringConstantCacheBuster(str(time.time()))) - -.. index:: - single: static assets view - -CSS and JavaScript source and cache busting -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Often one needs to refer to images and other static assets inside CSS and -JavaScript files. If cache busting is active, the final static asset URL is not -available until the static assets have been assembled. These URLs cannot be -handwritten. Thus, when having static asset references in CSS and JavaScript, -one needs to perform one of the following tasks. + import posixpath -* Process the files by using a precompiler which rewrites URLs to their final - cache busted form. + class PathConstantCacheBuster(object): + def __init__(self, token): + self.token = token -* Templatize JS and CSS, and call ``request.static_url()`` inside their - template code. + def __call__(self, request, subpath, kw): + base_subpath, ext = posixpath.splitext(subpath) + new_subpath = base_subpath + self.token + ext + return new_subpath, kw -* Pass static URL references to CSS and JavaScript via other means. +The caveat with this approach is that modifying the path segment +changes the file name, and thus must match what is actually on the +filesystem in order for :meth:`~pyramid.config.Configurator.add_static_view` +to find the file. It's better to use the +:class:`~pyramid.static.ManifestCacheBuster` for these situations, as +described in the next section. -Below are some simple approaches for CSS and JS programming which consider -asset cache busting. These approaches do not require additional tools or -packages. +.. _path_segment_cache_busters: -Relative cache busted URLs in CSS -+++++++++++++++++++++++++++++++++ +Path Segments and Choosing a Cache Buster +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Consider a CSS file ``/static/theme/css/site.css`` which contains the following -CSS code. +Many caching HTTP proxies will fail to cache a resource if the URL contains +a query string. Therefore, in general, you should prefer a cache busting +strategy which modifies the path segment rather than methods which add a +token to the query string. -.. code-block:: css +You will need to consider whether the :app:`Pyramid` application will be +serving your static assets, whether you are using an external asset pipeline +to handle rewriting urls internal to the css/javascript, and how fine-grained +do you want the cache busting tokens to be. - body { - background: url(/static/theme/img/background.jpg); - } +In many cases you will want to host the static assets on another web server +or externally on a CDN. In these cases your :app:`Pyramid` application may not +even have access to a copy of the static assets. In order to cache bust these +assets you will need some information about them. -Any changes to ``background.jpg`` would not appear to the visitor because the -URL path is not cache busted as it is. Instead we would have to construct an -URL to the background image with the default ``PathSegmentCacheBuster`` cache -busting mechanism:: +If you are using an external asset pipeline to generate your static files you +should consider using the :class:`~pyramid.static.ManifestCacheBuster`. +This cache buster can load a standard JSON formatted file generated by your +pipeline and use it to cache bust the assets. This has many performance +advantages as :app:`Pyramid` does not need to look at the files to generate +any cache busting tokens, but still supports fine-grained per-file tokens. - https://site/static/1eeb262c717/theme/img/background.jpg +Assuming an example ``manifest.json`` like: -Every time the image is updated, the URL would need to be changed. It is not -practical to write this non-human readable URL into a CSS file. +.. code-block:: json -However, the CSS file itself is cache busted and is located under the path for -static assets. This lets us use relative references in our CSS to cache bust -the image. + { + "css/main.css": "css/main-678b7c80.css", + "images/background.png": "images/background-a8169106.png" + } -.. code-block:: css +The following code would set up a cachebuster: - body { - background: url(../img/background.jpg); - } +.. code-block:: python + :linenos: -The browser would interpret this as having the CSS file hash in URL:: + from pyramid.static import ManifestCacheBuster - https://site/static/ab234b262c71/theme/css/../img/background.jpg + config.add_static_view( + name='http://mycdn.example.com/', + path='mypackage:static') -The downside of this approach is that if the background image changes, one -needs to bump the CSS file. The CSS file hash change signals the caches that -the relative URL to the image in the CSS has been changed. When updating CSS -and related image assets, updates usually happen hand in hand, so this does not -add extra effort to theming workflow. + config.add_cache_buster( + 'mypackage:static/', + ManifestCacheBuster('myapp:static/manifest.json')) -Passing cache busted URLs to JavaScript -+++++++++++++++++++++++++++++++++++++++ +It's important to note that the cache buster only handles generating +cache-busted URLs for static assets. It does **NOT** provide any solutions for +serving those assets. For example, if you generated a URL for +``css/main-678b7c80.css`` then that URL needs to be valid either by +configuring ``add_static_view`` properly to point to the location of the files +or some other mechanism such as the files existing on your CDN or rewriting +the incoming URL to remove the cache bust tokens. -For JavaScript, one can pass static asset URLs as function arguments or -globals. The globals can be generated in page template code, having access to -the ``request.static_url()`` function. +.. index:: + single: static assets view -Below is a simple example of passing a cached busted image URL in the Jinja2 -template language. Put the following code into the ``<head>`` section of the -relevant page. +CSS and JavaScript source and cache busting +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. code-block:: html +Often one needs to refer to images and other static assets inside CSS and +JavaScript files. If cache busting is active, the final static asset URL is not +available until the static assets have been assembled. These URLs cannot be +handwritten. Below is an example of how to integrate the cache buster into +the entire stack. Remember, it is just an example and should be modified to +fit your specific tools. - <script> - window.assets.backgroundImage = - "{{ '/theme/img/background.jpg'|static_url() }}"; - </script> +* First, process the files by using a precompiler which rewrites URLs to their + final cache-busted form. Then, you can use the + :class:`~pyramid.static.ManifestCacheBuster` to synchronize your asset + pipeline with :app:`Pyramid`, allowing the pipeline to have full control + over the final URLs of your assets. -Then in your main ``site.js`` file, put the following code. +Now that you are able to generate static URLs within :app:`Pyramid`, +you'll need to handle URLs that are out of our control. To do this you may +use some of the following options to get started: -.. code-block:: javascript +* Configure your asset pipeline to rewrite URL references inline in + CSS and JavaScript. This is the best approach because then the files + may be hosted by :app:`Pyramid` or an external CDN without having to + change anything. They really are static. - var image = new Image(window.assets.backgroundImage); +* Templatize JS and CSS, and call ``request.static_url()`` inside their + template code. While this approach may work in certain scenarios, it is not + recommended because your static assets will not really be static and are now + dependent on :app:`Pyramid` to be served correctly. See + :ref:`advanced_static` for more information on this approach. + +If your CSS and JavaScript assets use URLs to reference other assets it is +recommended that you implement an external asset pipeline that can rewrite the +generated static files with new URLs containing cache busting tokens. The +machinery inside :app:`Pyramid` will not help with this step as it has very +little knowledge of the asset types your application may use. The integration +into :app:`Pyramid` is simply for linking those assets into your HTML and +other dynamic content. .. _advanced_static: @@ -835,3 +819,56 @@ when an override is used. As of Pyramid 1.6, it is also possible to override an asset by supplying an absolute path to a file or directory. This may be useful if the assets are not distributed as part of a Python package. + +Cache Busting and Asset Overrides +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Overriding static assets that are being hosted using +:meth:`pyramid.config.Configurator.add_static_view` can affect your cache +busting strategy when using any cache busters that are asset-aware such as +:class:`pyramid.static.ManifestCacheBuster`. What sets asset-aware cache +busters apart is that they have logic tied to specific assets. For example, +a manifest is only generated for a specific set of pre-defined assets. Now, +imagine you have overridden an asset defined in this manifest with a new, +unknown version. By default, the cache buster will be invoked for an asset +it has never seen before and will likely end up returning a cache busting +token for the original asset rather than the asset that will actually end up +being served! In order to get around this issue, it's possible to attach a +different :class:`pyramid.interfaces.ICacheBuster` implementation to the +new assets. This would cause the original assets to be served by their +manifest, and the new assets served by their own cache buster. To do this, +:meth:`pyramid.config.Configurator.add_cache_buster` supports an ``explicit`` +option. For example: + +.. code-block:: python + :linenos: + + from pyramid.static import ManifestCacheBuster + + # define a static view for myapp:static assets + config.add_static_view('static', 'myapp:static') + + # setup a cache buster for your app based on the myapp:static assets + my_cb = ManifestCacheBuster('myapp:static/manifest.json') + config.add_cache_buster('myapp:static', my_cb) + + # override an asset + config.override_asset( + to_override='myapp:static/background.png', + override_with='theme:static/background.png') + + # override the cache buster for theme:static assets + theme_cb = ManifestCacheBuster('theme:static/manifest.json') + config.add_cache_buster('theme:static', theme_cb, explicit=True) + +In the above example there is a default cache buster, ``my_cb``, for all +assets served from the ``myapp:static`` folder. This would also affect +``theme:static/background.png`` when generating URLs via +``request.static_url('myapp:static/background.png')``. + +The ``theme_cb`` is defined explicitly for any assets loaded from the +``theme:static`` folder. Explicit cache busters have priority and thus +``theme_cb`` would be invoked for +``request.static_url('myapp:static/background.png')``, but ``my_cb`` would +be used for any other assets like +``request.static_url('myapp:static/favicon.ico')``. diff --git a/docs/narr/commandline.rst b/docs/narr/commandline.rst index eb79dffb6..34b12e1e9 100644 --- a/docs/narr/commandline.rst +++ b/docs/narr/commandline.rst @@ -6,6 +6,7 @@ Command-Line Pyramid Your :app:`Pyramid` application can be controlled and inspected using a variety of command-line utilities. These utilities are documented in this chapter. + .. index:: pair: matching views; printing single: pviews @@ -15,6 +16,8 @@ of command-line utilities. These utilities are documented in this chapter. Displaying Matching Views for a Given URL ----------------------------------------- +.. seealso:: See also the output of :ref:`pviews --help <pviews_script>`. + For a big application with several views, it can be hard to keep the view configuration details in your head, even if you defined all the views yourself. You can use the ``pviews`` command in a terminal window to print a summary of @@ -114,6 +117,8 @@ found* message. The Interactive Shell --------------------- +.. seealso:: See also the output of :ref:`pshell --help <pshell_script>`. + Once you've installed your program for development using ``setup.py develop``, you can use an interactive Python shell to execute expressions in a Python environment exactly like the one that will be used when your application runs @@ -179,6 +184,7 @@ hash after the filename: Press ``Ctrl-D`` to exit the interactive shell (or ``Ctrl-Z`` on Windows). + .. index:: pair: pshell; extending @@ -261,6 +267,7 @@ request is configured to generate urls from the host >>> request.route_url('home') 'https://www.example.com/' + .. _ipython_or_bpython: Alternative Shells @@ -317,6 +324,7 @@ arguments, ``env`` and ``help``, which would look like this: ``ipython`` and ``bpython`` have been moved into their respective packages ``pyramid_ipython`` and ``pyramid_bpython``. + Setting a Default Shell ~~~~~~~~~~~~~~~~~~~~~~~ @@ -331,6 +339,7 @@ specify a list of preferred shells. .. versionadded:: 1.6 + .. index:: pair: routes; printing single: proutes @@ -340,6 +349,8 @@ specify a list of preferred shells. Displaying All Application Routes --------------------------------- +.. seealso:: See also the output of :ref:`proutes --help <proutes_script>`. + You can use the ``proutes`` command in a terminal window to print a summary of routes related to your application. Much like the ``pshell`` command (see :ref:`interactive_shell`), the ``proutes`` command accepts one argument with @@ -421,6 +432,8 @@ include. The current available formats are ``name``, ``pattern``, ``view``, and Displaying "Tweens" ------------------- +.. seealso:: See also the output of :ref:`ptweens --help <ptweens_script>`. + A :term:`tween` is a bit of code that sits between the main Pyramid application request handler and the WSGI application which calls it. A user can get a representation of both the implicit tween ordering (the ordering specified by @@ -497,6 +510,7 @@ used: See :ref:`registering_tweens` for more information about tweens. + .. index:: single: invoking a request single: prequest @@ -506,6 +520,8 @@ See :ref:`registering_tweens` for more information about tweens. Invoking a Request ------------------ +.. seealso:: See also the output of :ref:`prequest --help <prequest_script>`. + You can use the ``prequest`` command-line utility to send a request to your application and see the response body without starting a server. @@ -555,6 +571,7 @@ of the ``prequest`` process is used as the ``POST`` body:: $ $VENV/bin/prequest -mPOST development.ini / < somefile + Using Custom Arguments to Python when Running ``p*`` Scripts ------------------------------------------------------------ @@ -566,11 +583,22 @@ Python interpreter at runtime. For example:: python -3 -m pyramid.scripts.pserve development.ini + +.. index:: + single: pdistreport + single: distributions, showing installed + single: showing installed distributions + +.. _showing_distributions: + Showing All Installed Distributions and Their Versions ------------------------------------------------------ .. versionadded:: 1.5 +.. seealso:: See also the output of :ref:`pdistreport --help + <pdistreport_script>`. + You can use the ``pdistreport`` command to show the :app:`Pyramid` version in use, the Python version in use, and all installed versions of Python distributions in your Python environment:: @@ -590,6 +618,7 @@ pastebin when you are having problems and need someone with more familiarity with Python packaging and distribution than you have to look at your environment. + .. _writing_a_script: Writing a Script @@ -702,6 +731,7 @@ The above example specifies the ``another`` ``app``, ``pipeline``, or object present in the ``env`` dictionary returned by :func:`pyramid.paster.bootstrap` will be a :app:`Pyramid` :term:`router`. + Changing the Request ~~~~~~~~~~~~~~~~~~~~ @@ -742,6 +772,7 @@ Now you can readily use Pyramid's APIs for generating URLs: env['request'].route_url('verify', code='1337') # will return 'https://example.com/prefix/verify/1337' + Cleanup ~~~~~~~ @@ -757,6 +788,7 @@ callback: env['closer']() + Setting Up Logging ~~~~~~~~~~~~~~~~~~ @@ -773,6 +805,7 @@ use the following command: See :ref:`logging_chapter` for more information on logging within :app:`Pyramid`. + .. index:: single: console script diff --git a/docs/narr/project.rst b/docs/narr/project.rst index 25f3931e9..5103bb6b8 100644 --- a/docs/narr/project.rst +++ b/docs/narr/project.rst @@ -53,15 +53,19 @@ The included scaffolds are these: ``alchemy`` URL mapping via :term:`URL dispatch` and persistence via :term:`SQLAlchemy` + .. index:: single: creating a project single: project + single: pcreate .. _creating_a_project: Creating the Project -------------------- +.. seealso:: See also the output of :ref:`pcreate --help <pcreate_script>`. + In :ref:`installing_chapter`, you created a virtual Python environment via the ``virtualenv`` command. To start a :app:`Pyramid` :term:`project`, use the ``pcreate`` command installed within the virtualenv. We'll choose the @@ -77,7 +81,7 @@ The below example uses the ``pcreate`` command to create a project with the On UNIX: -.. code-block:: text +.. code-block:: bash $ $VENV/bin/pcreate -s starter MyProject @@ -90,7 +94,7 @@ Or on Windows: Here's sample output from a run of ``pcreate`` on UNIX for a project we name ``MyProject``: -.. code-block:: text +.. code-block:: bash $ $VENV/bin/pcreate -s starter MyProject Creating template pyramid @@ -158,7 +162,7 @@ created project directory. On UNIX: -.. code-block:: text +.. code-block:: bash $ cd MyProject $ $VENV/bin/python setup.py develop @@ -172,7 +176,7 @@ Or on Windows: Elided output from a run of this command on UNIX is shown below: -.. code-block:: text +.. code-block:: bash $ cd MyProject $ $VENV/bin/python setup.py develop @@ -198,7 +202,7 @@ directory of your virtualenv). On UNIX: -.. code-block:: text +.. code-block:: bash $ $VENV/bin/python setup.py test -q @@ -210,7 +214,7 @@ Or on Windows: Here's sample output from a test run on UNIX: -.. code-block:: text +.. code-block:: bash $ $VENV/bin/python setup.py test -q running test @@ -221,11 +225,23 @@ Here's sample output from a test run on UNIX: writing dependency_links to MyProject.egg-info/dependency_links.txt writing entry points to MyProject.egg-info/entry_points.txt reading manifest file 'MyProject.egg-info/SOURCES.txt' + reading manifest template 'MANIFEST.in' + warning: no files found matching '*.cfg' + warning: no files found matching '*.rst' + warning: no files found matching '*.ico' under directory 'myproject' + warning: no files found matching '*.gif' under directory 'myproject' + warning: no files found matching '*.jpg' under directory 'myproject' + warning: no files found matching '*.txt' under directory 'myproject' + warning: no files found matching '*.mak' under directory 'myproject' + warning: no files found matching '*.mako' under directory 'myproject' + warning: no files found matching '*.js' under directory 'myproject' + warning: no files found matching '*.html' under directory 'myproject' + warning: no files found matching '*.xml' under directory 'myproject' writing manifest file 'MyProject.egg-info/SOURCES.txt' running build_ext - .. + . ---------------------------------------------------------------------- - Ran 1 test in 0.108s + Ran 1 test in 0.008s OK @@ -250,13 +266,15 @@ single sample test exists. Running the Project Application ------------------------------- +.. seealso:: See also the output of :ref:`pserve --help <pserve_script>`. + Once a project is installed for development, you can run the application it represents using the ``pserve`` command against the generated configuration file. In our case, this file is named ``development.ini``. On UNIX: -.. code-block:: text +.. code-block:: bash $ $VENV/bin/pserve development.ini @@ -268,38 +286,38 @@ On Windows: Here's sample output from a run of ``pserve`` on UNIX: -.. code-block:: text +.. code-block:: bash $ $VENV/bin/pserve development.ini - Starting server in PID 16601. - serving on http://0.0.0.0:6543 - -When you use ``pserve`` to start the application implied by the default -rendering of a scaffold, it will respond to requests on *all* IP addresses -possessed by your system, not just requests to ``localhost``. This is what the -``0.0.0.0`` in ``serving on http://0.0.0.0:6543`` means. The server will -respond to requests made to ``127.0.0.1`` and on any external IP address. For -example, your system might be configured to have an external IP address -``192.168.1.50``. If that's the case, if you use a browser running on the same -system as Pyramid, it will be able to access the application via -``http://127.0.0.1:6543/`` as well as via ``http://192.168.1.50:6543/``. -However, *other people* on other computers on the same network will also be -able to visit your Pyramid application in their browser by visiting -``http://192.168.1.50:6543/``. - -If you want to restrict access such that only a browser running on the same -machine as Pyramid will be able to access your Pyramid application, edit the + Starting server in PID 16208. + serving on http://127.0.0.1:6543 + +Access is restricted such that only a browser running on the same machine as +Pyramid will be able to access your Pyramid application. However, if you want +to open access to other machines on the same network, then edit the ``development.ini`` file, and replace the ``host`` value in the -``[server:main]`` section. Change it from ``0.0.0.0`` to ``127.0.0.1``. For +``[server:main]`` section, changing it from ``127.0.0.1`` to ``0.0.0.0``. For example: .. code-block:: ini [server:main] use = egg:waitress#main - host = 127.0.0.1 + host = 0.0.0.0 port = 6543 +Now when you use ``pserve`` to start the application, it will respond to +requests on *all* IP addresses possessed by your system, not just requests to +``localhost``. This is what the ``0.0.0.0`` in +``serving on http://0.0.0.0:6543`` means. The server will respond to requests +made to ``127.0.0.1`` and on any external IP address. For example, your system +might be configured to have an external IP address ``192.168.1.50``. If that's +the case, if you use a browser running on the same system as Pyramid, it will +be able to access the application via ``http://127.0.0.1:6543/`` as well as via +``http://192.168.1.50:6543/``. However, *other people* on other computers on +the same network will also be able to visit your Pyramid application in their +browser by visiting ``http://192.168.1.50:6543/``. + You can change the port on which the server runs on by changing the same portion of the ``development.ini`` file. For example, you can change the ``port = 6543`` line in the ``development.ini`` file's ``[server:main]`` @@ -347,7 +365,7 @@ For example, on UNIX: $ $VENV/bin/pserve development.ini --reload Starting subprocess with file monitor Starting server in PID 16601. - serving on http://0.0.0.0:6543 + serving on http://127.0.0.1:6543 Now if you make a change to any of your project's ``.py`` files or ``.ini`` files, you'll see the server restart automatically: @@ -357,7 +375,7 @@ files, you'll see the server restart automatically: development.ini changed; reloading... -------------------- Restarting -------------------- Starting server in PID 16602. - serving on http://0.0.0.0:6543 + serving on http://127.0.0.1:6543 Changes to template files (such as ``.pt`` or ``.mak`` files) won't cause the server to restart. Changes to template files don't require a server restart as @@ -579,18 +597,16 @@ file. The name ``main`` is a convention used by PasteDeploy signifying that it is the default application. The ``[server:main]`` section of the configuration file configures a WSGI -server which listens on TCP port 6543. It is configured to listen on all -interfaces (``0.0.0.0``). This means that any remote system which has TCP -access to your system can see your Pyramid application. +server which listens on TCP port 6543. It is configured to listen on localhost +only (``127.0.0.1``). .. _MyProject_ini_logging: -The sections that live between the markers ``# Begin logging configuration`` -and ``# End logging configuration`` represent Python's standard library -:mod:`logging` module configuration for your application. The sections between -these two markers are passed to the `logging module's config file configuration -engine <http://docs.python.org/howto/logging.html#configuring-logging>`_ when -the ``pserve`` or ``pshell`` commands are executed. The default configuration +The sections after ``# logging configuration`` represent Python's standard +library :mod:`logging` module configuration for your application. These +sections are passed to the `logging module's config file configuration engine +<http://docs.python.org/howto/logging.html#configuring-logging>`_ when the +``pserve`` or ``pshell`` commands are executed. The default configuration sends application logging output to the standard error output of your terminal. For more information about logging configuration, see :ref:`logging_chapter`. @@ -680,8 +696,8 @@ testing, packaging, and distributing your application. ``setup.py`` is the de facto standard which Python developers use to distribute their reusable code. You can read more about ``setup.py`` files and their usage in the `Setuptools documentation - <http://peak.telecommunity.com/DevCenter/setuptools>`_ and `The Hitchhiker's - Guide to Packaging <http://guide.python-distribute.org/>`_. + <http://peak.telecommunity.com/DevCenter/setuptools>`_ and `Python Packaging + User Guide <https://packaging.python.org/en/latest/>`_. Our generated ``setup.py`` looks like this: @@ -912,7 +928,7 @@ The ``tests.py`` module includes unit tests for your application. .. literalinclude:: MyProject/myproject/tests.py :language: python - :lines: 1-18 + :lines: 1-17 :linenos: This sample ``tests.py`` file has a single unit test defined within it. This diff --git a/docs/narr/scaffolding.rst b/docs/narr/scaffolding.rst index 8677359de..164ceb3bf 100644 --- a/docs/narr/scaffolding.rst +++ b/docs/narr/scaffolding.rst @@ -22,10 +22,10 @@ found by the ``pcreate`` command. To create a scaffold template, create a Python :term:`distribution` to house the scaffold which includes a ``setup.py`` that relies on the ``setuptools`` -package. See `Creating a Package -<http://guide.python-distribute.org/creation.html>`_ for more information about -how to do this. For example, we'll pretend the distribution you create is -named ``CoolExtension``, and it has a package directory within it named +package. See `Packaging and Distributing Projects +<https://packaging.python.org/en/latest/distributing/>`_ for more information +about how to do this. For example, we'll pretend the distribution you create +is named ``CoolExtension``, and it has a package directory within it named ``coolextension``. Once you've created the distribution, put a "scaffolds" directory within your diff --git a/docs/narr/startup.rst b/docs/narr/startup.rst index 485f6b181..3e168eaea 100644 --- a/docs/narr/startup.rst +++ b/docs/narr/startup.rst @@ -6,15 +6,15 @@ Startup When you cause a :app:`Pyramid` application to start up in a console window, you'll see something much like this show up on the console: -.. code-block:: text +.. code-block:: bash - $ pserve development.ini - Starting server in PID 16601. - serving on 0.0.0.0:6543 view at http://127.0.0.1:6543 + $ $VENV/bin/pserve development.ini + Starting server in PID 16305. + serving on http://127.0.0.1:6543 This chapter explains what happens between the time you press the "Return" key on your keyboard after typing ``pserve development.ini`` and the time the line -``serving on 0.0.0.0:6543 ...`` is output to your console. +``serving on http://127.0.0.1:6543`` is output to your console. .. index:: single: startup process @@ -92,11 +92,11 @@ Here's a high-level time-ordered overview of what happens when you press In this case, the ``myproject.__init__:main`` function referred to by the entry point URI ``egg:MyProject`` (see :ref:`MyProject_ini` for more information about entry point URIs, and how they relate to callables) will - receive the key/value pairs ``{'pyramid.reload_templates':'true', - 'pyramid.debug_authorization':'false', 'pyramid.debug_notfound':'false', - 'pyramid.debug_routematch':'false', 'pyramid.debug_templates':'true', - 'pyramid.default_locale_name':'en'}``. See :ref:`environment_chapter` for - the meanings of these keys. + receive the key/value pairs ``{pyramid.reload_templates = true, + pyramid.debug_authorization = false, pyramid.debug_notfound = false, + pyramid.debug_routematch = false, pyramid.default_locale_name = en, and + pyramid.includes = pyramid_debugtoolbar}``. See :ref:`environment_chapter` + for the meanings of these keys. #. The ``main`` function first constructs a :class:`~pyramid.config.Configurator` instance, passing the ``settings`` @@ -131,10 +131,9 @@ Here's a high-level time-ordered overview of what happens when you press #. ``pserve`` starts the WSGI *server* defined within the ``[server:main]`` section. In our case, this is the Waitress server (``use = egg:waitress#main``), and it will listen on all interfaces (``host = - 0.0.0.0``), on port number 6543 (``port = 6543``). The server code itself - is what prints ``serving on 0.0.0.0:6543 view at http://127.0.0.1:6543``. - The server serves the application, and the application is running, waiting - to receive requests. + 127.0.0.1``), on port number 6543 (``port = 6543``). The server code itself + is what prints ``serving on http://127.0.0.1:6543``. The server serves the + application, and the application is running, waiting to receive requests. .. seealso:: Logging configuration is described in the :ref:`logging_chapter` chapter. diff --git a/docs/narr/testing.rst b/docs/narr/testing.rst index c05ee41ad..a3f62058b 100644 --- a/docs/narr/testing.rst +++ b/docs/narr/testing.rst @@ -348,26 +348,6 @@ code's integration with the rest of :app:`Pyramid`. See also :ref:`including_configuration` -Let's demonstrate this by showing an integration test for a view. - -Given the following view definition, which assumes that your application's -:term:`package` name is ``myproject``, and within that :term:`package` there -exists a module ``views``, which in turn contains a :term:`view` function named -``my_view``: - - .. literalinclude:: MyProject/myproject/views.py - :linenos: - :lines: 1-6 - :language: python - -You'd then create a ``tests`` module within your ``myproject`` package, -containing the following test code: - - .. literalinclude:: MyProject/myproject/tests.py - :linenos: - :pyobject: ViewIntegrationTests - :language: python - Writing unit tests that use the :class:`~pyramid.config.Configurator` API to set up the right "mock" registrations is often preferred to creating integration tests. Unit tests will run faster (because they do less for each @@ -388,22 +368,53 @@ package, which provides APIs for invoking HTTP(S) requests to your application. Regardless of which testing :term:`package` you use, ensure to add a ``tests_require`` dependency on that package to your application's -``setup.py`` file: +``setup.py`` file. Using the project ``MyProject`` generated by the starter +scaffold as described in :doc:`project`, we would insert the following code immediately following the +``requires`` block in the file ``MyProject/setup.py``. - .. literalinclude:: MyProject/setup.py - :linenos: - :emphasize-lines: 26-28,48 - :language: python +.. code-block:: ini + :linenos: + :lineno-start: 11 + :emphasize-lines: 8- + + requires = [ + 'pyramid', + 'pyramid_chameleon', + 'pyramid_debugtoolbar', + 'waitress', + ] + + test_requires = [ + 'webtest', + ] + +Remember to change the dependency. + +.. code-block:: ini + :linenos: + :lineno-start: 39 + :emphasize-lines: 2 + + install_requires=requires, + tests_require=test_requires, + test_suite="myproject", + +As always, whenever you change your dependencies, make sure to run the +following command. + +.. code-block:: bash + + $VENV/bin/python setup.py develop -Let us assume your :term:`package` is named ``myproject`` which contains a -``views`` module, which in turn contains a :term:`view` function ``my_view`` -that returns a HTML body when the root URL is invoked: +In your ``MyPackage`` project, your :term:`package` is named ``myproject`` +which contains a ``views`` module, which in turn contains a :term:`view` +function ``my_view`` that returns an HTML body when the root URL is invoked: .. literalinclude:: MyProject/myproject/views.py :linenos: :language: python -Then the following example functional test demonstrates invoking the above +The following example functional test demonstrates invoking the above :term:`view`: .. literalinclude:: MyProject/myproject/tests.py @@ -414,9 +425,9 @@ Then the following example functional test demonstrates invoking the above When this test is run, each test method creates a "real" :term:`WSGI` application using the ``main`` function in your ``myproject.__init__`` module, using :term:`WebTest` to wrap that WSGI application. It assigns the result to -``self.testapp``. In the test named ``test_root``. The ``TestApp``'s ``GET`` +``self.testapp``. In the test named ``test_root``, the ``TestApp``'s ``GET`` method is used to invoke the root URL. Finally, an assertion is made that the -returned HTML contains the text ``MyProject``. +returned HTML contains the text ``Pyramid``. See the :term:`WebTest` documentation for further information about the methods available to a :class:`webtest.app.TestApp` instance. diff --git a/docs/narr/threadlocals.rst b/docs/narr/threadlocals.rst index afe56de3e..7437a3a76 100644 --- a/docs/narr/threadlocals.rst +++ b/docs/narr/threadlocals.rst @@ -8,26 +8,24 @@ Thread Locals ============= -A :term:`thread local` variable is a variable that appears to be a -"global" variable to an application which uses it. However, unlike a -true global variable, one thread or process serving the application -may receive a different value than another thread or process when that -variable is "thread local". +A :term:`thread local` variable is a variable that appears to be a "global" +variable to an application which uses it. However, unlike a true global +variable, one thread or process serving the application may receive a different +value than another thread or process when that variable is "thread local". -When a request is processed, :app:`Pyramid` makes two :term:`thread -local` variables available to the application: a "registry" and a -"request". +When a request is processed, :app:`Pyramid` makes two :term:`thread local` +variables available to the application: a "registry" and a "request". Why and How :app:`Pyramid` Uses Thread Local Variables ---------------------------------------------------------- +------------------------------------------------------ -How are thread locals beneficial to :app:`Pyramid` and application -developers who use :app:`Pyramid`? Well, usually they're decidedly -**not**. Using a global or a thread local variable in any application -usually makes it a lot harder to understand for a casual reader. Use -of a thread local or a global is usually just a way to avoid passing -some value around between functions, which is itself usually a very -bad idea, at least if code readability counts as an important concern. +How are thread locals beneficial to :app:`Pyramid` and application developers +who use :app:`Pyramid`? Well, usually they're decidedly **not**. Using a +global or a thread local variable in any application usually makes it a lot +harder to understand for a casual reader. Use of a thread local or a global is +usually just a way to avoid passing some value around between functions, which +is itself usually a very bad idea, at least if code readability counts as an +important concern. For historical reasons, however, thread local variables are indeed consulted by various :app:`Pyramid` API functions. For example, the implementation of the @@ -40,119 +38,107 @@ application registry, from which it looks up the authentication policy; it then uses the authentication policy to retrieve the authenticated user id. This is how :app:`Pyramid` allows arbitrary authentication policies to be "plugged in". -When they need to do so, :app:`Pyramid` internals use two API -functions to retrieve the :term:`request` and :term:`application -registry`: :func:`~pyramid.threadlocal.get_current_request` and -:func:`~pyramid.threadlocal.get_current_registry`. The former -returns the "current" request; the latter returns the "current" -registry. Both ``get_current_*`` functions retrieve an object from a -thread-local data structure. These API functions are documented in -:ref:`threadlocal_module`. - -These values are thread locals rather than true globals because one -Python process may be handling multiple simultaneous requests or even -multiple :app:`Pyramid` applications. If they were true globals, -:app:`Pyramid` could not handle multiple simultaneous requests or -allow more than one :app:`Pyramid` application instance to exist in -a single Python process. - -Because one :app:`Pyramid` application is permitted to call -*another* :app:`Pyramid` application from its own :term:`view` code -(perhaps as a :term:`WSGI` app with help from the -:func:`pyramid.wsgi.wsgiapp2` decorator), these variables are -managed in a *stack* during normal system operations. The stack -instance itself is a :class:`threading.local`. +When they need to do so, :app:`Pyramid` internals use two API functions to +retrieve the :term:`request` and :term:`application registry`: +:func:`~pyramid.threadlocal.get_current_request` and +:func:`~pyramid.threadlocal.get_current_registry`. The former returns the +"current" request; the latter returns the "current" registry. Both +``get_current_*`` functions retrieve an object from a thread-local data +structure. These API functions are documented in :ref:`threadlocal_module`. + +These values are thread locals rather than true globals because one Python +process may be handling multiple simultaneous requests or even multiple +:app:`Pyramid` applications. If they were true globals, :app:`Pyramid` could +not handle multiple simultaneous requests or allow more than one :app:`Pyramid` +application instance to exist in a single Python process. + +Because one :app:`Pyramid` application is permitted to call *another* +:app:`Pyramid` application from its own :term:`view` code (perhaps as a +:term:`WSGI` app with help from the :func:`pyramid.wsgi.wsgiapp2` decorator), +these variables are managed in a *stack* during normal system operations. The +stack instance itself is a :class:`threading.local`. During normal operations, the thread locals stack is managed by a -:term:`Router` object. At the beginning of a request, the Router -pushes the application's registry and the request on to the stack. At -the end of a request, the stack is popped. The topmost request and -registry on the stack are considered "current". Therefore, when the -system is operating normally, the very definition of "current" is -defined entirely by the behavior of a pyramid :term:`Router`. +:term:`Router` object. At the beginning of a request, the Router pushes the +application's registry and the request on to the stack. At the end of a +request, the stack is popped. The topmost request and registry on the stack +are considered "current". Therefore, when the system is operating normally, +the very definition of "current" is defined entirely by the behavior of a +pyramid :term:`Router`. However, during unit testing, no Router code is ever invoked, and the -definition of "current" is defined by the boundary between calls to -the :meth:`pyramid.config.Configurator.begin` and -:meth:`pyramid.config.Configurator.end` methods (or between -calls to the :func:`pyramid.testing.setUp` and -:func:`pyramid.testing.tearDown` functions). These functions push -and pop the threadlocal stack when the system is under test. See -:ref:`test_setup_and_teardown` for the definitions of these functions. - -Scripts which use :app:`Pyramid` machinery but never actually start -a WSGI server or receive requests via HTTP such as scripts which use -the :mod:`pyramid.scripting` API will never cause any Router code -to be executed. However, the :mod:`pyramid.scripting` APIs also -push some values on to the thread locals stack as a matter of course. -Such scripts should expect the -:func:`~pyramid.threadlocal.get_current_request` function to always -return ``None``, and should expect the -:func:`~pyramid.threadlocal.get_current_registry` function to return -exactly the same :term:`application registry` for every request. +definition of "current" is defined by the boundary between calls to the +:meth:`pyramid.config.Configurator.begin` and +:meth:`pyramid.config.Configurator.end` methods (or between calls to the +:func:`pyramid.testing.setUp` and :func:`pyramid.testing.tearDown` functions). +These functions push and pop the threadlocal stack when the system is under +test. See :ref:`test_setup_and_teardown` for the definitions of these +functions. + +Scripts which use :app:`Pyramid` machinery but never actually start a WSGI +server or receive requests via HTTP, such as scripts which use the +:mod:`pyramid.scripting` API, will never cause any Router code to be executed. +However, the :mod:`pyramid.scripting` APIs also push some values on to the +thread locals stack as a matter of course. Such scripts should expect the +:func:`~pyramid.threadlocal.get_current_request` function to always return +``None``, and should expect the +:func:`~pyramid.threadlocal.get_current_registry` function to return exactly +the same :term:`application registry` for every request. Why You Shouldn't Abuse Thread Locals ------------------------------------- You probably should almost never use the :func:`~pyramid.threadlocal.get_current_request` or -:func:`~pyramid.threadlocal.get_current_registry` functions, except -perhaps in tests. In particular, it's almost always a mistake to use -``get_current_request`` or ``get_current_registry`` in application -code because its usage makes it possible to write code that can be -neither easily tested nor scripted. Inappropriate usage is defined as -follows: +:func:`~pyramid.threadlocal.get_current_registry` functions, except perhaps in +tests. In particular, it's almost always a mistake to use +``get_current_request`` or ``get_current_registry`` in application code because +its usage makes it possible to write code that can be neither easily tested nor +scripted. Inappropriate usage is defined as follows: - ``get_current_request`` should never be called within the body of a - :term:`view callable`, or within code called by a view callable. - View callables already have access to the request (it's passed in to - each as ``request``). - -- ``get_current_request`` should never be called in :term:`resource` code. - If a resource needs access to the request, it should be passed the request - by a :term:`view callable`. - -- ``get_current_request`` function should never be called because it's - "easier" or "more elegant" to think about calling it than to pass a - request through a series of function calls when creating some API - design. Your application should instead almost certainly pass data - derived from the request around rather than relying on being able to - call this function to obtain the request in places that actually - have no business knowing about it. Parameters are *meant* to be - passed around as function arguments, this is why they exist. Don't - try to "save typing" or create "nicer APIs" by using this function - in the place where a request is required; this will only lead to - sadness later. - -- Neither ``get_current_request`` nor ``get_current_registry`` should - ever be called within application-specific forks of third-party - library code. The library you've forked almost certainly has - nothing to do with :app:`Pyramid`, and making it dependent on - :app:`Pyramid` (rather than making your :app:`pyramid` - application depend upon it) means you're forming a dependency in the - wrong direction. - -Use of the :func:`~pyramid.threadlocal.get_current_request` function -in application code *is* still useful in very limited circumstances. -As a rule of thumb, usage of ``get_current_request`` is useful -**within code which is meant to eventually be removed**. For -instance, you may find yourself wanting to deprecate some API that -expects to be passed a request object in favor of one that does not -expect to be passed a request object. But you need to keep -implementations of the old API working for some period of time while -you deprecate the older API. So you write a "facade" implementation -of the new API which calls into the code which implements the older -API. Since the new API does not require the request, your facade -implementation doesn't have local access to the request when it needs -to pass it into the older API implementation. After some period of -time, the older implementation code is disused and the hack that uses -``get_current_request`` is removed. This would be an appropriate -place to use the ``get_current_request``. - -Use of the :func:`~pyramid.threadlocal.get_current_registry` -function should be limited to testing scenarios. The registry made -current by use of the -:meth:`pyramid.config.Configurator.begin` method during a -test (or via :func:`pyramid.testing.setUp`) when you do not pass -one in is available to you via this API. - + :term:`view callable`, or within code called by a view callable. View + callables already have access to the request (it's passed in to each as + ``request``). + +- ``get_current_request`` should never be called in :term:`resource` code. If a + resource needs access to the request, it should be passed the request by a + :term:`view callable`. + +- ``get_current_request`` function should never be called because it's "easier" + or "more elegant" to think about calling it than to pass a request through a + series of function calls when creating some API design. Your application + should instead, almost certainly, pass around data derived from the request + rather than relying on being able to call this function to obtain the request + in places that actually have no business knowing about it. Parameters are + *meant* to be passed around as function arguments; this is why they exist. + Don't try to "save typing" or create "nicer APIs" by using this function in + the place where a request is required; this will only lead to sadness later. + +- Neither ``get_current_request`` nor ``get_current_registry`` should ever be + called within application-specific forks of third-party library code. The + library you've forked almost certainly has nothing to do with :app:`Pyramid`, + and making it dependent on :app:`Pyramid` (rather than making your + :app:`pyramid` application depend upon it) means you're forming a dependency + in the wrong direction. + +Use of the :func:`~pyramid.threadlocal.get_current_request` function in +application code *is* still useful in very limited circumstances. As a rule of +thumb, usage of ``get_current_request`` is useful **within code which is meant +to eventually be removed**. For instance, you may find yourself wanting to +deprecate some API that expects to be passed a request object in favor of one +that does not expect to be passed a request object. But you need to keep +implementations of the old API working for some period of time while you +deprecate the older API. So you write a "facade" implementation of the new API +which calls into the code which implements the older API. Since the new API +does not require the request, your facade implementation doesn't have local +access to the request when it needs to pass it into the older API +implementation. After some period of time, the older implementation code is +disused and the hack that uses ``get_current_request`` is removed. This would +be an appropriate place to use the ``get_current_request``. + +Use of the :func:`~pyramid.threadlocal.get_current_registry` function should be +limited to testing scenarios. The registry made current by use of the +:meth:`pyramid.config.Configurator.begin` method during a test (or via +:func:`pyramid.testing.setUp`) when you do not pass one in is available to you +via this API. diff --git a/docs/narr/upgrading.rst b/docs/narr/upgrading.rst index eb3194a65..db9b5e090 100644 --- a/docs/narr/upgrading.rst +++ b/docs/narr/upgrading.rst @@ -12,26 +12,26 @@ applications keep working when you upgrade the Pyramid version you're using. .. sidebar:: About Release Numbering Conventionally, application version numbering in Python is described as - ``major.minor.micro``. If your Pyramid version is "1.2.3", it means - you're running a version of Pyramid with the major version "1", the minor - version "2" and the micro version "3". A "major" release is one that - increments the first-dot number; 2.X.X might follow 1.X.X. A "minor" - release is one that increments the second-dot number; 1.3.X might follow - 1.2.X. A "micro" release is one that increments the third-dot number; - 1.2.3 might follow 1.2.2. In general, micro releases are "bugfix-only", - and contain no new features, minor releases contain new features but are - largely backwards compatible with older versions, and a major release - indicates a large set of backwards incompatibilities. + ``major.minor.micro``. If your Pyramid version is "1.2.3", it means you're + running a version of Pyramid with the major version "1", the minor version + "2" and the micro version "3". A "major" release is one that increments the + first-dot number; 2.X.X might follow 1.X.X. A "minor" release is one that + increments the second-dot number; 1.3.X might follow 1.2.X. A "micro" + release is one that increments the third-dot number; 1.2.3 might follow + 1.2.2. In general, micro releases are "bugfix-only", and contain no new + features, minor releases contain new features but are largely backwards + compatible with older versions, and a major release indicates a large set of + backwards incompatibilities. The Pyramid core team is conservative when it comes to removing features. We -don't remove features unnecessarily, but we're human, and we make mistakes -which cause some features to be evolutionary dead ends. Though we are -willing to support dead-end features for some amount of time, some eventually -have to be removed when the cost of supporting them outweighs the benefit of -keeping them around, because each feature in Pyramid represents a certain -documentation and maintenance burden. - -Deprecation and Removal Policy +don't remove features unnecessarily, but we're human and we make mistakes which +cause some features to be evolutionary dead ends. Though we are willing to +support dead-end features for some amount of time, some eventually have to be +removed when the cost of supporting them outweighs the benefit of keeping them +around, because each feature in Pyramid represents a certain documentation and +maintenance burden. + +Deprecation and removal policy ------------------------------ When a feature is scheduled for removal from Pyramid or any of its official @@ -51,50 +51,49 @@ When a deprecated feature is eventually removed: - A note is added to the :ref:`changelog` about the removal. -Features are never removed in *micro* releases. They are only removed in -minor and major releases. Deprecated features are kept around for at least -*three* minor releases from the time the feature became deprecated. -Therefore, if a feature is added in Pyramid 1.0, but it's deprecated in -Pyramid 1.1, it will be kept around through all 1.1.X releases, all 1.2.X -releases and all 1.3.X releases. It will finally be removed in the first -1.4.X release. - -Sometimes features are "docs-deprecated" instead of formally deprecated. -This means that the feature will be kept around indefinitely, but it will be -removed from the documentation or a note will be added to the documentation -telling folks to use some other newer feature. This happens when the cost of -keeping an old feature around is very minimal and the support and -documentation burden is very low. For example, we might rename a function -that is an API without changing the arguments it accepts. In this case, -we'll often rename the function, and change the docs to point at the new -function name, but leave around a backwards compatibility alias to the old -function name so older code doesn't break. +Features are never removed in *micro* releases. They are only removed in minor +and major releases. Deprecated features are kept around for at least *three* +minor releases from the time the feature became deprecated. Therefore, if a +feature is added in Pyramid 1.0, but it's deprecated in Pyramid 1.1, it will be +kept around through all 1.1.X releases, all 1.2.X releases and all 1.3.X +releases. It will finally be removed in the first 1.4.X release. + +Sometimes features are "docs-deprecated" instead of formally deprecated. This +means that the feature will be kept around indefinitely, but it will be removed +from the documentation or a note will be added to the documentation telling +folks to use some other newer feature. This happens when the cost of keeping +an old feature around is very minimal and the support and documentation burden +is very low. For example, we might rename a function that is an API without +changing the arguments it accepts. In this case, we'll often rename the +function, and change the docs to point at the new function name, but leave +around a backwards compatibility alias to the old function name so older code +doesn't break. "Docs deprecated" features tend to work "forever", meaning that they won't be removed, and they'll never generate a deprecation warning. However, such changes are noted in the :ref:`changelog`, so it's possible to know that you -should change older spellings to newer ones to ensure that people reading -your code can find the APIs you're using in the Pyramid docs. +should change older spellings to newer ones to ensure that people reading your +code can find the APIs you're using in the Pyramid docs. -Consulting the Change History +Consulting the change history ----------------------------- -Your first line of defense against application failures caused by upgrading -to a newer Pyramid release is always to read the :ref:`changelog`. to find -the deprecations and removals for each release between the release you're -currently running and the one you wish to upgrade to. The change history -notes every deprecation within a ``Deprecation`` section and every removal -within a ``Backwards Incompatibilies`` section for each release. +Your first line of defense against application failures caused by upgrading to +a newer Pyramid release is always to read the :ref:`changelog` to find the +deprecations and removals for each release between the release you're currently +running and the one to which you wish to upgrade. The change history notes +every deprecation within a ``Deprecation`` section and every removal within a +``Backwards Incompatibilies`` section for each release. -The change history often contains instructions for changing your code to -avoid deprecation warnings and how to change docs-deprecated spellings to -newer ones. You can follow along with each deprecation explanation in the -change history, simply doing a grep or other code search to your application, -using the change log examples to remediate each potential problem. +The change history often contains instructions for changing your code to avoid +deprecation warnings and how to change docs-deprecated spellings to newer ones. +You can follow along with each deprecation explanation in the change history, +simply doing a grep or other code search to your application, using the change +log examples to remediate each potential problem. .. _testing_under_new_release: -Testing Your Application Under a New Pyramid Release +Testing your application under a new Pyramid release ---------------------------------------------------- Once you've upgraded your application to a new Pyramid release and you've @@ -106,25 +105,24 @@ you can see DeprecationWarnings printed to the console when the tests run. $ python -Wd setup.py test -q -The ``-Wd`` argument is an argument that tells Python to print deprecation -warnings to the console. Note that the ``-Wd`` flag is only required for -Python 2.7 and better: Python versions 2.6 and older print deprecation -warnings to the console by default. See `the Python -W flag documentation -<http://docs.python.org/using/cmdline.html#cmdoption-W>`_ for more -information. +The ``-Wd`` argument tells Python to print deprecation warnings to the console. +Note that the ``-Wd`` flag is only required for Python 2.7 and better: Python +versions 2.6 and older print deprecation warnings to the console by default. +See `the Python -W flag documentation +<http://docs.python.org/using/cmdline.html#cmdoption-W>`_ for more information. As your tests run, deprecation warnings will be printed to the console -explaining the deprecation and providing instructions about how to prevent -the deprecation warning from being issued. For example: +explaining the deprecation and providing instructions about how to prevent the +deprecation warning from being issued. For example: -.. code-block:: text +.. code-block:: bash $ python -Wd setup.py test -q # .. elided ... running build_ext - /home/chrism/projects/pyramid/env27/myproj/myproj/views.py:3: - DeprecationWarning: static: The "pyramid.view.static" class is deprecated - as of Pyramid 1.1; use the "pyramid.static.static_view" class instead with + /home/chrism/projects/pyramid/env27/myproj/myproj/views.py:3: + DeprecationWarning: static: The "pyramid.view.static" class is deprecated + as of Pyramid 1.1; use the "pyramid.static.static_view" class instead with the "use_subpath" argument set to True. from pyramid.view import static . @@ -144,8 +142,8 @@ pyramid.view import static``) that is causing the problem: from pyramid.view import static myview = static('static', 'static') -The deprecation warning tells me how to fix it, so I can change the code to -do things the newer way: +The deprecation warning tells me how to fix it, so I can change the code to do +things the newer way: .. code-block:: python :linenos: @@ -155,10 +153,10 @@ do things the newer way: from pyramid.static import static_view myview = static_view('static', 'static', use_subpath=True) -When I run the tests again, the deprecation warning is no longer printed to -my console: +When I run the tests again, the deprecation warning is no longer printed to my +console: -.. code-block:: text +.. code-block:: bash $ python -Wd setup.py test -q # .. elided ... @@ -170,7 +168,7 @@ my console: OK -My Application Doesn't Have Any Tests or Has Few Tests +My application doesn't have any tests or has few tests ------------------------------------------------------ If your application has no tests, or has only moderate test coverage, running @@ -178,8 +176,8 @@ tests won't tell you very much, because the Pyramid codepaths that generate deprecation warnings won't be executed. In this circumstance, you can start your application interactively under a -server run with the ``PYTHONWARNINGS`` environment variable set to -``default``. On UNIX, you can do that via: +server run with the ``PYTHONWARNINGS`` environment variable set to ``default``. +On UNIX, you can do that via: .. code-block:: bash @@ -194,16 +192,15 @@ On Windows, you need to issue two commands: At this point, it's ensured that deprecation warnings will be printed to the console whenever a codepath is hit that generates one. You can then click -around in your application interactively to try to generate them, and -remediate as explained in :ref:`testing_under_new_release`. +around in your application interactively to try to generate them, and remediate +as explained in :ref:`testing_under_new_release`. See `the PYTHONWARNINGS environment variable documentation <http://docs.python.org/using/cmdline.html#envvar-PYTHONWARNINGS>`_ or `the Python -W flag documentation -<http://docs.python.org/using/cmdline.html#cmdoption-W>`_ for more -information. +<http://docs.python.org/using/cmdline.html#cmdoption-W>`_ for more information. -Upgrading to the Very Latest Pyramid Release +Upgrading to the very latest Pyramid release -------------------------------------------- When you upgrade your application to the most recent Pyramid release, @@ -220,15 +217,13 @@ advisable to do this: :ref:`testing_under_new_release`. Note any deprecation warnings and remediate. -- Upgrade to the most recent 1.3 release, 1.3.3. Run your application's - tests, note any deprecation warnings and remediate. +- Upgrade to the most recent 1.3 release, 1.3.3. Run your application's tests, + note any deprecation warnings, and remediate. - Upgrade to 1.4.4. Run your application's tests, note any deprecation - warnings and remediate. + warnings, and remediate. If you skip testing your application under each minor release (for example if -you upgrade directly from 1.2.1 to 1.4.4), you might miss a deprecation -warning and waste more time trying to figure out an error caused by a feature -removal than it would take to upgrade stepwise through each minor release. - - +you upgrade directly from 1.2.1 to 1.4.4), you might miss a deprecation warning +and waste more time trying to figure out an error caused by a feature removal +than it would take to upgrade stepwise through each minor release. diff --git a/docs/narr/zca.rst b/docs/narr/zca.rst index b0e9b1709..784886563 100644 --- a/docs/narr/zca.rst +++ b/docs/narr/zca.rst @@ -9,17 +9,16 @@ .. _zca_chapter: Using the Zope Component Architecture in :app:`Pyramid` -========================================================== +======================================================= -Under the hood, :app:`Pyramid` uses a :term:`Zope Component -Architecture` component registry as its :term:`application registry`. -The Zope Component Architecture is referred to colloquially as the -"ZCA." +Under the hood, :app:`Pyramid` uses a :term:`Zope Component Architecture` +component registry as its :term:`application registry`. The Zope Component +Architecture is referred to colloquially as the "ZCA." The ``zope.component`` API used to access data in a traditional Zope -application can be opaque. For example, here is a typical "unnamed -utility" lookup using the :func:`zope.component.getUtility` global API -as it might appear in a traditional Zope application: +application can be opaque. For example, here is a typical "unnamed utility" +lookup using the :func:`zope.component.getUtility` global API as it might +appear in a traditional Zope application: .. code-block:: python :linenos: @@ -28,23 +27,21 @@ as it might appear in a traditional Zope application: from zope.component import getUtility settings = getUtility(ISettings) -After this code runs, ``settings`` will be a Python dictionary. But -it's unlikely that any "civilian" will be able to figure this out just -by reading the code casually. When the ``zope.component.getUtility`` -API is used by a developer, the conceptual load on a casual reader of -code is high. +After this code runs, ``settings`` will be a Python dictionary. But it's +unlikely that any "civilian" will be able to figure this out just by reading +the code casually. When the ``zope.component.getUtility`` API is used by a +developer, the conceptual load on a casual reader of code is high. -While the ZCA is an excellent tool with which to build a *framework* -such as :app:`Pyramid`, it is not always the best tool with which -to build an *application* due to the opacity of the ``zope.component`` -APIs. Accordingly, :app:`Pyramid` tends to hide the presence of the -ZCA from application developers. You needn't understand the ZCA to -create a :app:`Pyramid` application; its use is effectively only a -framework implementation detail. +While the ZCA is an excellent tool with which to build a *framework* such as +:app:`Pyramid`, it is not always the best tool with which to build an +*application* due to the opacity of the ``zope.component`` APIs. Accordingly, +:app:`Pyramid` tends to hide the presence of the ZCA from application +developers. You needn't understand the ZCA to create a :app:`Pyramid` +application; its use is effectively only a framework implementation detail. -However, developers who are already used to writing :term:`Zope` -applications often still wish to use the ZCA while building a -:app:`Pyramid` application; :app:`Pyramid` makes this possible. +However, developers who are already used to writing :term:`Zope` applications +often still wish to use the ZCA while building a :app:`Pyramid` application. +:app:`Pyramid` makes this possible. .. index:: single: get_current_registry @@ -52,87 +49,81 @@ applications often still wish to use the ZCA while building a single: getSiteManager single: ZCA global API -Using the ZCA Global API in a :app:`Pyramid` Application ------------------------------------------------------------ - -:term:`Zope` uses a single ZCA registry -- the "global" ZCA registry --- for all Zope applications that run in the same Python process, -effectively making it impossible to run more than one Zope application -in a single process. - -However, for ease of deployment, it's often useful to be able to run more -than a single application per process. For example, use of a -:term:`PasteDeploy` "composite" allows you to run separate individual WSGI -applications in the same process, each answering requests for some URL -prefix. This makes it possible to run, for example, a TurboGears application -at ``/turbogears`` and a :app:`Pyramid` application at ``/pyramid``, both -served up using the same :term:`WSGI` server within a single Python process. - -Most production Zope applications are relatively large, making it -impractical due to memory constraints to run more than one Zope -application per Python process. However, a :app:`Pyramid` application -may be very small and consume very little memory, so it's a reasonable -goal to be able to run more than one :app:`Pyramid` application per -process. - -In order to make it possible to run more than one :app:`Pyramid` -application in a single process, :app:`Pyramid` defaults to using a -separate ZCA registry *per application*. - -While this services a reasonable goal, it causes some issues when -trying to use patterns which you might use to build a typical -:term:`Zope` application to build a :app:`Pyramid` application. -Without special help, ZCA "global" APIs such as -:func:`zope.component.getUtility` and :func:`zope.component.getSiteManager` -will use the ZCA "global" registry. Therefore, these APIs -will appear to fail when used in a :app:`Pyramid` application, -because they'll be consulting the ZCA global registry rather than the -component registry associated with your :app:`Pyramid` application. - -There are three ways to fix this: by disusing the ZCA global API -entirely, by using -:meth:`pyramid.config.Configurator.hook_zca` or by passing -the ZCA global registry to the :term:`Configurator` constructor at -startup time. We'll describe all three methods in this section. +Using the ZCA global API in a :app:`Pyramid` application +-------------------------------------------------------- + +:term:`Zope` uses a single ZCA registry—the "global" ZCA registry—for all Zope +applications that run in the same Python process, effectively making it +impossible to run more than one Zope application in a single process. + +However, for ease of deployment, it's often useful to be able to run more than +a single application per process. For example, use of a :term:`PasteDeploy` +"composite" allows you to run separate individual WSGI applications in the same +process, each answering requests for some URL prefix. This makes it possible +to run, for example, a TurboGears application at ``/turbogears`` and a +:app:`Pyramid` application at ``/pyramid``, both served up using the same +:term:`WSGI` server within a single Python process. + +Most production Zope applications are relatively large, making it impractical +due to memory constraints to run more than one Zope application per Python +process. However, a :app:`Pyramid` application may be very small and consume +very little memory, so it's a reasonable goal to be able to run more than one +:app:`Pyramid` application per process. + +In order to make it possible to run more than one :app:`Pyramid` application in +a single process, :app:`Pyramid` defaults to using a separate ZCA registry *per +application*. + +While this services a reasonable goal, it causes some issues when trying to use +patterns which you might use to build a typical :term:`Zope` application to +build a :app:`Pyramid` application. Without special help, ZCA "global" APIs +such as :func:`zope.component.getUtility` and +:func:`zope.component.getSiteManager` will use the ZCA "global" registry. +Therefore, these APIs will appear to fail when used in a :app:`Pyramid` +application, because they'll be consulting the ZCA global registry rather than +the component registry associated with your :app:`Pyramid` application. + +There are three ways to fix this: by disusing the ZCA global API entirely, by +using :meth:`pyramid.config.Configurator.hook_zca` or by passing the ZCA global +registry to the :term:`Configurator` constructor at startup time. We'll +describe all three methods in this section. .. index:: single: request.registry .. _disusing_the_global_zca_api: -Disusing the Global ZCA API +Disusing the global ZCA API +++++++++++++++++++++++++++ ZCA "global" API functions such as ``zope.component.getSiteManager``, ``zope.component.getUtility``, :func:`zope.component.getAdapter`, and :func:`zope.component.getMultiAdapter` aren't strictly necessary. Every -component registry has a method API that offers the same -functionality; it can be used instead. For example, presuming the -``registry`` value below is a Zope Component Architecture component -registry, the following bit of code is equivalent to -``zope.component.getUtility(IFoo)``: +component registry has a method API that offers the same functionality; it can +be used instead. For example, presuming the ``registry`` value below is a Zope +Component Architecture component registry, the following bit of code is +equivalent to ``zope.component.getUtility(IFoo)``: .. code-block:: python registry.getUtility(IFoo) -The full method API is documented in the ``zope.component`` package, -but it largely mirrors the "global" API almost exactly. +The full method API is documented in the ``zope.component`` package, but it +largely mirrors the "global" API almost exactly. -If you are willing to disuse the "global" ZCA APIs and use the method -interface of a registry instead, you need only know how to obtain the -:app:`Pyramid` component registry. +If you are willing to disuse the "global" ZCA APIs and use the method interface +of a registry instead, you need only know how to obtain the :app:`Pyramid` +component registry. There are two ways of doing so: -- use the :func:`pyramid.threadlocal.get_current_registry` - function within :app:`Pyramid` view or resource code. This will - always return the "current" :app:`Pyramid` application registry. +- use the :func:`pyramid.threadlocal.get_current_registry` function within + :app:`Pyramid` view or resource code. This will always return the "current" + :app:`Pyramid` application registry. -- use the attribute of the :term:`request` object named ``registry`` - in your :app:`Pyramid` view code, eg. ``request.registry``. This - is the ZCA component registry related to the running - :app:`Pyramid` application. +- use the attribute of the :term:`request` object named ``registry`` in your + :app:`Pyramid` view code, e.g., ``request.registry``. This is the ZCA + component registry related to the running :app:`Pyramid` application. See :ref:`threadlocals_chapter` for more information about :func:`pyramid.threadlocal.get_current_registry`. @@ -142,7 +133,7 @@ See :ref:`threadlocals_chapter` for more information about .. _hook_zca: -Enabling the ZCA Global API by Using ``hook_zca`` +Enabling the ZCA global API by using ``hook_zca`` +++++++++++++++++++++++++++++++++++++++++++++++++ Consider the following bit of idiomatic :app:`Pyramid` startup code: @@ -157,34 +148,31 @@ Consider the following bit of idiomatic :app:`Pyramid` startup code: config.include('some.other.package') return config.make_wsgi_app() -When the ``app`` function above is run, a :term:`Configurator` is -constructed. When the configurator is created, it creates a *new* -:term:`application registry` (a ZCA component registry). A new -registry is constructed whenever the ``registry`` argument is omitted -when a :term:`Configurator` constructor is called, or when a -``registry`` argument with a value of ``None`` is passed to a -:term:`Configurator` constructor. - -During a request, the application registry created by the Configurator -is "made current". This means calls to -:func:`~pyramid.threadlocal.get_current_registry` in the thread -handling the request will return the component registry associated -with the application. - -As a result, application developers can use ``get_current_registry`` -to get the registry and thus get access to utilities and such, as per -:ref:`disusing_the_global_zca_api`. But they still cannot use the -global ZCA API. Without special treatment, the ZCA global APIs will -always return the global ZCA registry (the one in -``zope.component.globalregistry.base``). - -To "fix" this and make the ZCA global APIs use the "current" -:app:`Pyramid` registry, you need to call -:meth:`~pyramid.config.Configurator.hook_zca` within your setup code. -For example: +When the ``app`` function above is run, a :term:`Configurator` is constructed. +When the configurator is created, it creates a *new* :term:`application +registry` (a ZCA component registry). A new registry is constructed whenever +the ``registry`` argument is omitted, when a :term:`Configurator` constructor +is called, or when a ``registry`` argument with a value of ``None`` is passed +to a :term:`Configurator` constructor. + +During a request, the application registry created by the Configurator is "made +current". This means calls to +:func:`~pyramid.threadlocal.get_current_registry` in the thread handling the +request will return the component registry associated with the application. + +As a result, application developers can use ``get_current_registry`` to get the +registry and thus get access to utilities and such, as per +:ref:`disusing_the_global_zca_api`. But they still cannot use the global ZCA +API. Without special treatment, the ZCA global APIs will always return the +global ZCA registry (the one in ``zope.component.globalregistry.base``). + +To "fix" this and make the ZCA global APIs use the "current" :app:`Pyramid` +registry, you need to call :meth:`~pyramid.config.Configurator.hook_zca` within +your setup code. For example: .. code-block:: python :linenos: + :emphasize-lines: 5 from pyramid.config import Configurator @@ -194,9 +182,9 @@ For example: config.include('some.other.application') return config.make_wsgi_app() -We've added a line to our original startup code, line number 6, which -calls ``config.hook_zca()``. The effect of this line under the hood -is that an analogue of the following code is executed: +We've added a line to our original startup code, line number 5, which calls +``config.hook_zca()``. The effect of this line under the hood is that an +analogue of the following code is executed: .. code-block:: python :linenos: @@ -205,17 +193,15 @@ is that an analogue of the following code is executed: from pyramid.threadlocal import get_current_registry getSiteManager.sethook(get_current_registry) -This causes the ZCA global API to start using the :app:`Pyramid` -application registry in threads which are running a :app:`Pyramid` -request. +This causes the ZCA global API to start using the :app:`Pyramid` application +registry in threads which are running a :app:`Pyramid` request. -Calling ``hook_zca`` is usually sufficient to "fix" the problem of -being able to use the global ZCA API within a :app:`Pyramid` -application. However, it also means that a Zope application that is -running in the same process may start using the :app:`Pyramid` -global registry instead of the Zope global registry, effectively -inverting the original problem. In such a case, follow the steps in -the next section, :ref:`using_the_zca_global_registry`. +Calling ``hook_zca`` is usually sufficient to "fix" the problem of being able +to use the global ZCA API within a :app:`Pyramid` application. However, it +also means that a Zope application that is running in the same process may +start using the :app:`Pyramid` global registry instead of the Zope global +registry, effectively inverting the original problem. In such a case, follow +the steps in the next section, :ref:`using_the_zca_global_registry`. .. index:: single: get_current_registry @@ -224,14 +210,15 @@ the next section, :ref:`using_the_zca_global_registry`. .. _using_the_zca_global_registry: -Enabling the ZCA Global API by Using The ZCA Global Registry +Enabling the ZCA global API by using the ZCA global registry ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -You can tell your :app:`Pyramid` application to use the ZCA global -registry at startup time instead of constructing a new one: +You can tell your :app:`Pyramid` application to use the ZCA global registry at +startup time instead of constructing a new one: .. code-block:: python :linenos: + :emphasize-lines: 5-7 from zope.component import getGlobalSiteManager from pyramid.config import Configurator @@ -243,16 +230,14 @@ registry at startup time instead of constructing a new one: config.include('some.other.application') return config.make_wsgi_app() -Lines 5, 6, and 7 above are the interesting ones. Line 5 retrieves -the global ZCA component registry. Line 6 creates a -:term:`Configurator`, passing the global ZCA registry into its -constructor as the ``registry`` argument. Line 7 "sets up" the global -registry with Pyramid-specific registrations; this is code that is -normally executed when a registry is constructed rather than created, +Lines 5, 6, and 7 above are the interesting ones. Line 5 retrieves the global +ZCA component registry. Line 6 creates a :term:`Configurator`, passing the +global ZCA registry into its constructor as the ``registry`` argument. Line 7 +"sets up" the global registry with Pyramid-specific registrations; this is code +that is normally executed when a registry is constructed rather than created, but we must call it "by hand" when we pass an explicit registry. -At this point, :app:`Pyramid` will use the ZCA global registry -rather than creating a new application-specific registry; since by -default the ZCA global API will use this registry, things will work as -you might expect a Zope app to when you use the global ZCA API. - +At this point, :app:`Pyramid` will use the ZCA global registry rather than +creating a new application-specific registry. Since by default the ZCA global +API will use this registry, things will work as you might expect in a Zope app +when you use the global ZCA API. diff --git a/docs/pscripts/index.rst b/docs/pscripts/index.rst new file mode 100644 index 000000000..857e0564f --- /dev/null +++ b/docs/pscripts/index.rst @@ -0,0 +1,12 @@ +.. _pscripts_documentation: + +``p*`` Scripts Documentation +============================ + +Command line programs (``p*`` scripts) included with :app:`Pyramid`. + +.. toctree:: + :maxdepth: 1 + :glob: + + * diff --git a/docs/pscripts/pcreate.rst b/docs/pscripts/pcreate.rst new file mode 100644 index 000000000..b5ec3f4e2 --- /dev/null +++ b/docs/pscripts/pcreate.rst @@ -0,0 +1,13 @@ +.. index:: + single: pcreate; --help + +.. _pcreate_script: + +``pcreate`` +----------- + +.. program-output:: pcreate --help + :prompt: + :shell: + +.. seealso:: :ref:`creating_a_project` diff --git a/docs/pscripts/pdistreport.rst b/docs/pscripts/pdistreport.rst new file mode 100644 index 000000000..1c53fb6e9 --- /dev/null +++ b/docs/pscripts/pdistreport.rst @@ -0,0 +1,13 @@ +.. index:: + single: pdistreport; --help + +.. _pdistreport_script: + +``pdistreport`` +--------------- + +.. program-output:: pdistreport --help + :prompt: + :shell: + +.. seealso:: :ref:`showing_distributions` diff --git a/docs/pscripts/prequest.rst b/docs/pscripts/prequest.rst new file mode 100644 index 000000000..a15827767 --- /dev/null +++ b/docs/pscripts/prequest.rst @@ -0,0 +1,13 @@ +.. index:: + single: prequest; --help + +.. _prequest_script: + +``prequest`` +------------ + +.. program-output:: prequest --help + :prompt: + :shell: + +.. seealso:: :ref:`invoking_a_request` diff --git a/docs/pscripts/proutes.rst b/docs/pscripts/proutes.rst new file mode 100644 index 000000000..09ed013e1 --- /dev/null +++ b/docs/pscripts/proutes.rst @@ -0,0 +1,13 @@ +.. index:: + single: proutes; --help + +.. _proutes_script: + +``proutes`` +----------- + +.. program-output:: proutes --help + :prompt: + :shell: + +.. seealso:: :ref:`displaying_application_routes` diff --git a/docs/pscripts/pserve.rst b/docs/pscripts/pserve.rst new file mode 100644 index 000000000..d33d4a484 --- /dev/null +++ b/docs/pscripts/pserve.rst @@ -0,0 +1,13 @@ +.. index:: + single: pserve; --help + +.. _pserve_script: + +``pserve`` +---------- + +.. program-output:: pserve --help + :prompt: + :shell: + +.. seealso:: :ref:`running_the_project_application` diff --git a/docs/pscripts/pshell.rst b/docs/pscripts/pshell.rst new file mode 100644 index 000000000..cfd84d4f8 --- /dev/null +++ b/docs/pscripts/pshell.rst @@ -0,0 +1,13 @@ +.. index:: + single: pshell; --help + +.. _pshell_script: + +``pshell`` +---------- + +.. program-output:: pshell --help + :prompt: + :shell: + +.. seealso:: :ref:`interactive_shell` diff --git a/docs/pscripts/ptweens.rst b/docs/pscripts/ptweens.rst new file mode 100644 index 000000000..02e23e49a --- /dev/null +++ b/docs/pscripts/ptweens.rst @@ -0,0 +1,13 @@ +.. index:: + single: ptweens; --help + +.. _ptweens_script: + +``ptweens`` +----------- + +.. program-output:: ptweens --help + :prompt: + :shell: + +.. seealso:: :ref:`displaying_tweens` diff --git a/docs/pscripts/pviews.rst b/docs/pscripts/pviews.rst new file mode 100644 index 000000000..b4de5c054 --- /dev/null +++ b/docs/pscripts/pviews.rst @@ -0,0 +1,13 @@ +.. index:: + single: pviews; --help + +.. _pviews_script: + +``pviews`` +---------- + +.. program-output:: pviews --help + :prompt: + :shell: + +.. seealso:: :ref:`displaying_matching_views` diff --git a/docs/whatsnew-1.0.rst b/docs/whatsnew-1.0.rst index 9541f0a28..0ed6e21fc 100644 --- a/docs/whatsnew-1.0.rst +++ b/docs/whatsnew-1.0.rst @@ -1,4 +1,4 @@ -What's New In Pyramid 1.0 +What's New in Pyramid 1.0 ========================= This article explains the new features in Pyramid version 1.0 as compared to diff --git a/docs/whatsnew-1.1.rst b/docs/whatsnew-1.1.rst index 99737b6d8..a5c7f3393 100644 --- a/docs/whatsnew-1.1.rst +++ b/docs/whatsnew-1.1.rst @@ -1,4 +1,4 @@ -What's New In Pyramid 1.1 +What's New in Pyramid 1.1 ========================= This article explains the new features in Pyramid version 1.1 as compared to diff --git a/docs/whatsnew-1.2.rst b/docs/whatsnew-1.2.rst index a9fc38908..9ff933ace 100644 --- a/docs/whatsnew-1.2.rst +++ b/docs/whatsnew-1.2.rst @@ -1,4 +1,4 @@ -What's New In Pyramid 1.2 +What's New in Pyramid 1.2 ========================= This article explains the new features in :app:`Pyramid` version 1.2 as diff --git a/docs/whatsnew-1.3.rst b/docs/whatsnew-1.3.rst index 2606c3df3..1a299e126 100644 --- a/docs/whatsnew-1.3.rst +++ b/docs/whatsnew-1.3.rst @@ -1,4 +1,4 @@ -What's New In Pyramid 1.3 +What's New in Pyramid 1.3 ========================= This article explains the new features in :app:`Pyramid` version 1.3 as diff --git a/docs/whatsnew-1.4.rst b/docs/whatsnew-1.4.rst index 505b9d798..fce889854 100644 --- a/docs/whatsnew-1.4.rst +++ b/docs/whatsnew-1.4.rst @@ -1,4 +1,4 @@ -What's New In Pyramid 1.4 +What's New in Pyramid 1.4 ========================= This article explains the new features in :app:`Pyramid` version 1.4 as diff --git a/docs/whatsnew-1.5.rst b/docs/whatsnew-1.5.rst index 1d863c937..a477ce5ec 100644 --- a/docs/whatsnew-1.5.rst +++ b/docs/whatsnew-1.5.rst @@ -1,4 +1,4 @@ -What's New In Pyramid 1.5 +What's New in Pyramid 1.5 ========================= This article explains the new features in :app:`Pyramid` version 1.5 as @@ -136,6 +136,8 @@ Feature Additions The feature additions in Pyramid 1.5 follow. +- Python 3.4 compatibility. + - Add ``pdistreport`` script, which prints the Python version in use, the Pyramid version in use, and the version number and location of all Python distributions currently installed. diff --git a/docs/whatsnew-1.6.rst b/docs/whatsnew-1.6.rst index 141a58f78..bdfcf34ab 100644 --- a/docs/whatsnew-1.6.rst +++ b/docs/whatsnew-1.6.rst @@ -1,40 +1,62 @@ -What's New In Pyramid 1.6 +What's New in Pyramid 1.6 ========================= This article explains the new features in :app:`Pyramid` version 1.6 as -compared to its predecessor, :app:`Pyramid` 1.5. It also documents backwards +compared to its predecessor, :app:`Pyramid` 1.5. It also documents backwards incompatibilities between the two versions and deprecations added to :app:`Pyramid` 1.6, as well as software dependency changes and notable documentation additions. + Backwards Incompatibilities --------------------------- +- IPython and BPython support have been removed from pshell in the core. To + continue using them on Pyramid 1.6+, you must install the binding packages + explicitly. One way to do this is by adding ``pyramid_ipython`` (or + ``pyramid_bpython``) to the ``install_requires`` section of your package's + ``setup.py`` file, then re-running ``setup.py develop``:: + + setup( + #... + install_requires=[ + 'pyramid_ipython', # new dependency + 'pyramid', + #... + ], + ) + - ``request.response`` will no longer be mutated when using the - :func:`~pyramid.renderers.render_to_response` API. It is now necessary - to pass in - a ``response=`` argument to :func:`~pyramid.renderers.render_to_response` if - you wish to supply the renderer with a custom response object for it to - use. If you do not pass one then a response object will be created using the - current response factory. Almost all renderers mutate the - ``request.response`` response object (for example, the JSON renderer sets - ``request.response.content_type`` to ``application/json``). However, when - invoking ``render_to_response`` it is not expected that the response object - being returned would be the same one used later in the request. The response - object returned from ``render_to_response`` is now explicitly different from - ``request.response``. This does not change the API of a renderer. See + :func:`~pyramid.renderers.render_to_response` API. It is now necessary to + pass in a ``response=`` argument to + :func:`~pyramid.renderers.render_to_response` if you wish to supply the + renderer with a custom response object. If you do not pass one, then a + response object will be created using the current response factory. Almost + all renderers mutate the ``request.response`` response object (for example, + the JSON renderer sets ``request.response.content_type`` to + ``application/json``). However, when invoking ``render_to_response``, it is + not expected that the response object being returned would be the same one + used later in the request. The response object returned from + ``render_to_response`` is now explicitly different from ``request.response``. + This does not change the API of a renderer. See https://github.com/Pylons/pyramid/pull/1563 Feature Additions ----------------- -- Cache busting for static assets has been added and is available via a new - argument to :meth:`pyramid.config.Configurator.add_static_view`: - ``cachebust``. Core APIs are shipped for both cache busting via query - strings and path segments and may be extended to fit into custom asset - pipelines. See https://github.com/Pylons/pyramid/pull/1380 and - https://github.com/Pylons/pyramid/pull/1583 +- Python 3.5 and pypy3 compatibility. + +- ``pserve --reload`` will no longer crash on syntax errors. See + https://github.com/Pylons/pyramid/pull/2044 + +- Cache busting for static resources has been added and is available via a new + :meth:`pyramid.config.Configurator.add_cache_buster` API. Core APIs are + shipped for both cache busting via query strings and via asset manifests for + integrating into custom asset pipelines. See + https://github.com/Pylons/pyramid/pull/1380 and + https://github.com/Pylons/pyramid/pull/1583 and + https://github.com/Pylons/pyramid/pull/2171 - Assets can now be overidden by an absolute path on the filesystem when using the :meth:`~pyramid.config.Configurator.override_asset` API. This makes it @@ -47,99 +69,129 @@ Feature Additions ``config.add_static_view('myapp:static', 'static')`` and ``config.override_asset(to_override='myapp:static/', override_with='/abs/path/')``. The ``myapp:static`` asset spec is completely - made up and does not need to exist - it is used for generating urls via - ``request.static_url('myapp:static/foo.png')``. See + made up and does not need to exist—it is used for generating URLs via + ``request.static_url('myapp:static/foo.png')``. See https://github.com/Pylons/pyramid/issues/1252 - Added :meth:`~pyramid.config.Configurator.set_response_factory` and the ``response_factory`` keyword argument to the constructor of :class:`~pyramid.config.Configurator` for defining a factory that will return - a custom ``Response`` class. See https://github.com/Pylons/pyramid/pull/1499 + a custom ``Response`` class. See https://github.com/Pylons/pyramid/pull/1499 -- Add :attr:`pyramid.config.Configurator.root_package` attribute and init - parameter to assist with includeable packages that wish to resolve - resources relative to the package in which the configurator was created. - This is especially useful for addons that need to load asset specs from - settings, in which case it is may be natural for a developer to define - imports or assets relative to the top-level package. - See https://github.com/Pylons/pyramid/pull/1337 +- Added :attr:`pyramid.config.Configurator.root_package` attribute and init + parameter to assist with includible packages that wish to resolve resources + relative to the package in which the configurator was created. This is + especially useful for add-ons that need to load asset specs from settings, in + which case it may be natural for a developer to define imports or assets + relative to the top-level package. See + https://github.com/Pylons/pyramid/pull/1337 - Overall improvments for the ``proutes`` command. Added ``--format`` and ``--glob`` arguments to the command, introduced the ``method`` column for displaying available request methods, and improved the ``view`` - output by showing the module instead of just ``__repr__``. - See https://github.com/Pylons/pyramid/pull/1488 + output by showing the module instead of just ``__repr__``. See + https://github.com/Pylons/pyramid/pull/1488 - ``pserve`` can now take a ``-b`` or ``--browser`` option to open the server URL in a web browser. See https://github.com/Pylons/pyramid/pull/1533 -- Support keyword-only arguments and function annotations in views in - Python 3. See https://github.com/Pylons/pyramid/pull/1556 +- Support keyword-only arguments and function annotations in views in Python 3. + See https://github.com/Pylons/pyramid/pull/1556 - The ``append_slash`` argument of :meth:`~pyramid.config.Configurator.add_notfound_view()` will now accept anything that implements the :class:`~pyramid.interfaces.IResponse` interface and will use that as the response class instead of the default - :class:`~pyramid.httpexceptions.HTTPFound`. See + :class:`~pyramid.httpexceptions.HTTPFound`. See https://github.com/Pylons/pyramid/pull/1610 - The :class:`~pyramid.config.Configurator` has grown the ability to allow - actions to call other actions during a commit-cycle. This enables much more + actions to call other actions during a commit cycle. This enables much more logic to be placed into actions, such as the ability to invoke other actions or group them for improved conflict detection. We have also exposed and - documented the config phases that Pyramid uses in order to further assist in - building conforming addons. See https://github.com/Pylons/pyramid/pull/1513 + documented the configuration phases that Pyramid uses in order to further + assist in building conforming add-ons. See + https://github.com/Pylons/pyramid/pull/1513 - Allow an iterator to be returned from a renderer. Previously it was only - possible to return bytes or unicode. - See https://github.com/Pylons/pyramid/pull/1417 + possible to return bytes or unicode. See + https://github.com/Pylons/pyramid/pull/1417 - Improve robustness to timing attacks in the :class:`~pyramid.authentication.AuthTktCookieHelper` and the :class:`~pyramid.session.SignedCookieSessionFactory` classes by using the - stdlib's ``hmac.compare_digest`` if it is available (such as Python 2.7.7+ and - 3.3+). See https://github.com/Pylons/pyramid/pull/1457 + stdlib's ``hmac.compare_digest`` if it is available (such as Python 2.7.7+ + and 3.3+). See https://github.com/Pylons/pyramid/pull/1457 -- Improve the readability of the ``pcreate`` shell script output. - See https://github.com/Pylons/pyramid/pull/1453 +- Improve the readability of the ``pcreate`` shell script output. See + https://github.com/Pylons/pyramid/pull/1453 -- Make it simple to define notfound and forbidden views that wish to use the - default exception-response view but with altered predicates and other - configuration options. The ``view`` argument is now optional in +- Make it simple to define ``notfound`` and ``forbidden`` views that wish to + use the default exception-response view, but with altered predicates and + other configuration options. The ``view`` argument is now optional in :meth:`~pyramid.config.Configurator.add_notfound_view` and :meth:`~pyramid.config.Configurator.add_forbidden_view` See https://github.com/Pylons/pyramid/issues/494 - The ``pshell`` script will now load a ``PYTHONSTARTUP`` file if one is - defined in the environment prior to launching the interpreter. - See https://github.com/Pylons/pyramid/pull/1448 + defined in the environment prior to launching the interpreter. See + https://github.com/Pylons/pyramid/pull/1448 -- Add new HTTP exception objects for status codes - ``428 Precondition Required``, ``429 Too Many Requests`` and - ``431 Request Header Fields Too Large`` in ``pyramid.httpexceptions``. - See https://github.com/Pylons/pyramid/pull/1372/files +- Add new HTTP exception objects for status codes ``428 Precondition + Required``, ``429 Too Many Requests`` and ``431 Request Header Fields Too + Large`` in ``pyramid.httpexceptions``. See + https://github.com/Pylons/pyramid/pull/1372/files - ``pcreate`` when run without a scaffold argument will now print information - on the missing flag, as well as a list of available scaffolds. See + on the missing flag, as well as a list of available scaffolds. See https://github.com/Pylons/pyramid/pull/1566 and https://github.com/Pylons/pyramid/issues/1297 +- ``pcreate`` will now ask for confirmation if invoked with an argument for a + project name that already exists or is importable in the current environment. + See https://github.com/Pylons/pyramid/issues/1357 and + https://github.com/Pylons/pyramid/pull/1837 + - Add :func:`pyramid.request.apply_request_extensions` function which can be used in testing to apply any request extensions configured via ``config.add_request_method``. Previously it was only possible to test the - extensions by going through Pyramid's router. See + extensions by going through Pyramid's router. See https://github.com/Pylons/pyramid/pull/1581 - Make it possible to subclass ``pyramid.request.Request`` and also use - ``pyramid.request.Request.add_request.method``. See + ``pyramid.request.Request.add_request.method``. See https://github.com/Pylons/pyramid/issues/1529 +- Additional shells for ``pshell`` can now be registered as entry points. See + https://github.com/Pylons/pyramid/pull/1891 and + https://github.com/Pylons/pyramid/pull/2012 + +- The variables injected into ``pshell`` are now displayed with their + docstrings instead of the default ``str(obj)`` when possible. See + https://github.com/Pylons/pyramid/pull/1929 + Deprecations ------------ +- The ``pserve`` command's daemonization features, as well as + ``--monitor-restart``, have been deprecated. This includes the + ``[start,stop,restart,status]`` subcommands, as well as the ``--daemon``, + ``--stop-daemon``, ``--pid-file``, ``--status``, ``--user``, and ``--group`` + flags. See https://github.com/Pylons/pyramid/pull/2120 and + https://github.com/Pylons/pyramid/pull/2189 and + https://github.com/Pylons/pyramid/pull/1641 + + Please use a real process manager in the future instead of relying on + ``pserve`` to daemonize itself. Many options exist, including your operating + system's services, such as Systemd or Upstart, as well as Python-based + solutions like Circus and Supervisor. + + See https://github.com/Pylons/pyramid/pull/1641 and + https://github.com/Pylons/pyramid/pull/2120 + - The ``principal`` argument to :func:`pyramid.security.remember` was renamed - to ``userid``. Using ``principal`` as the argument name still works and will + to ``userid``. Using ``principal`` as the argument name still works and will continue to work for the next few releases, but a deprecation warning is printed. @@ -150,27 +202,35 @@ Scaffolding Enhancements - Added line numbers to the log formatters in the scaffolds to assist with debugging. See https://github.com/Pylons/pyramid/pull/1326 -- Update scaffold generating machinery to return the version of pyramid and - pyramid docs for use in scaffolds. Updated ``starter``, ``alchemy``, and - ``zodb`` templates to have links to correctly versioned documentation and - reflect which pyramid was used to generate the scaffold. +- Updated scaffold generating machinery to return the version of :app:`Pyramid` + and its documentation for use in scaffolds. Updated ``starter``, ``alchemy`` + and ``zodb`` templates to have links to correctly versioned documentation, + and to reflect which :app:`Pyramid` was used to generate the scaffold. -- Removed non-ascii copyright symbol from templates, as this was - causing the scaffolds to fail for project generation. +- Removed non-ASCII copyright symbol from templates, as this was causing the + scaffolds to fail for project generation. Documentation Enhancements -------------------------- -- Removed logging configuration from Quick Tutorial ini files except for - scaffolding- and logging-related chapters to avoid needing to explain it too +- Removed logging configuration from Quick Tutorial ``ini`` files, except for + scaffolding- and logging-related chapters, to avoid needing to explain it too early. -- Improve and clarify the documentation on what Pyramid defines as a - ``principal`` and a ``userid`` in its security APIs. - See https://github.com/Pylons/pyramid/pull/1399 +- Improve and clarify the documentation on what :app:`Pyramid` defines as a + ``principal`` and a ``userid`` in its security APIs. See + https://github.com/Pylons/pyramid/pull/1399 + +- Moved the documentation for ``accept`` on + :meth:`pyramid.config.Configurator.add_view` to no longer be part of the + predicate list. See https://github.com/Pylons/pyramid/issues/1391 for a bug + report stating ``not_`` was failing on ``accept``. Discussion with @mcdonc + led to the conclusion that it should not be documented as a predicate. + See https://github.com/Pylons/pyramid/pull/1487 for this PR. + +- Clarify a previously-implied detail of the ``ISession.invalidate`` API + documentation. -- Updated the Quick Tour and SQLAlchemy + URL Dispatch Wiki Tutorial narrative - documentation and source files for each step using the updated scaffold. For - a list of updated files, see - https://github.com/Pylons/pyramid/pull/2024#issue-112676079 +- Add documentation of command line programs (``p*`` scripts). See + https://github.com/Pylons/pyramid/pull/2191 |
