diff options
117 files changed, 706 insertions, 1042 deletions
diff --git a/CHANGES.txt b/CHANGES.txt index 7440794ee..42f07a275 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -6,6 +6,9 @@ Features - Python 3.2 compatibility. +- New ``pyramid.compat`` module and API documentation which provides Python + 2/3 straddling support for Pyramid add-ons and development environments. + - A ``mako.directories`` setting is no longer required to use Mako templates Rationale: Mako template renderers can be specified using an absolute asset spec. An entire application can be written with such asset specs, @@ -27,6 +30,9 @@ Bug Fixes - The AuthTktAuthenticationPolicy did not use a timing-attack-aware string comparator. See https://github.com/Pylons/pyramid/pull/320 for more info. +- The DummySession in ``pyramid.testing`` now generates a new CSRF token if + one doesn't yet exist. + Backwards Incompatibilities --------------------------- @@ -61,3 +67,13 @@ Dependencies - Pyramid no longer depends on the Paste or PasteScript packages. +Scaffolds +--------- + +- Rendered scaffolds have now been changed to be more relocatable (fewer + mentions of the package name within files in the package). + +- The ``alchemy`` scaffold has been removed. + +- The ``routesalchemy`` scaffold has been renamed ``alchemy``. + diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index 648f67c72..a449333cb 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -1,4 +1,4 @@ -Pylons Project Contributor Agreement + Pylons Project Contributor Agreement ==================================== The submitter agrees by adding his or her name within the section below named @@ -149,4 +149,12 @@ Contributors - Manuel Hermann, 2011/07/11 +- Richard Barrell, 2011/11/07 + +- Chris Shenton, 2011/11/07 + +- Ken Manheimer, 2011/11/07 + +- Reed O'Brien, 2011/11/07 + - Klee Dienes, 2011/10/30 diff --git a/HACKING.txt b/HACKING.txt index 0194e9bab..d122a7a25 100644 --- a/HACKING.txt +++ b/HACKING.txt @@ -29,11 +29,6 @@ checkout. $ env/bin/easy_install setuptools-git -- Install ``nose`` and ``coverage`` into the virtualenv (for running nose - tests with coverage via ``setup.py nosetests --with-coverage``):: - - $ env/bin/easy_install nose coverage - - Install Pyramid from the checkout into the virtualenv using ``setup.py develop`` (running ``setup.py develop`` *must* be done while the current working directory is the ``pyramid`` checkout directory):: @@ -42,10 +37,10 @@ checkout. $ ../env/bin/python setup.py develop - At that point, you should be able to create new Pyramid projects by using - ``paster create``:: + ``pcreate``:: $ cd ../env - $ bin/paster create -t pyramid_starter starter + $ bin/pcreate -s starter starter - And install those projects (also using ``setup.py develop``) into the virtualenv:: @@ -61,8 +56,10 @@ In order to add a feature to Pyramid: - The feature must be documented in both the API and narrative documentation (in ``docs/``). -- The feature must work fully on the following CPython versions: 2.4, - 2.5, 2.6, and 2.7 on both UNIX and Windows. +- The feature must work fully on the following CPython versions: 2.6, + 2.7, and 3.2 on both UNIX and Windows. + +- The feature must work on the latest version of PyPy. - The feature must not cause installation or runtime failure on Jython or App Engine. If it doesn't cause installation or runtime failure, @@ -88,12 +85,33 @@ Coding Style 2 newlines between classes. But 80-column lines, in particular, are mandatory. +Running Tests +-------------- + +- To run tests for Pyramid on a single Python version, run ``python setup.py + test`` against the using the Python interpreter from virtualenv into which + you've ``setup.py develop``-ed Pyramid. + +- To run the full set of Pyramid tests on all platforms, install ``tox`` + (http://codespeak.net/~hpk/tox/) into a system Python. The ``tox`` console + script will be installed into the scripts location for that Python. While + ``cd``'ed to the Pyramid checkout root directory (it contains ``tox.ini``), + invoke the ``tox`` console script. This will read the ``tox.ini`` file and + execute the tests on multiple Python versions and platforms; while it runs, + it creates a virtualenv for each version/platform combination. For + example:: + + $ /usr/bin/easy_install tox + $ cd ~/hack-on-pyramid/pyramid + $ /usr/bin/tox + Test Coverage ------------- -- The codebase *must* have 100% test statement coverage after each - commit. You can test coverage via ``python setup.py nosetests - --with-coverage`` (requires the ``nose`` and ``coverage`` packages). +- The codebase *must* have 100% test statement coverage after each commit. + You can test coverage via ``tox -e coverage``, or alternately by installing + ``nose`` and ``coverage`` into your virtualenv, and running ``setup.py + nosetests --with-coverage``. Documentation Coverage ---------------------- @@ -1,6 +1,18 @@ Pyramid TODOs ============= +Must-Have +--------- + +- Fix ZODB tutorial docs to match ZODB tutorial code (I removed program name + from ``scan``). + +- Fix SQLA tutorial to match ZODB tutorial. + +- Fix routesalchemy scaffold to match ZODB scaffold. + +- Remove alchemy scaffold. + Nice-to-Have ------------ @@ -106,4 +118,3 @@ Probably Bad Ideas - Have ``remember`` and ``forget`` actually set headers on the response using a response callback (and return the empty list)? - diff --git a/docs/api.rst b/docs/api.rst index 6ff6e9fb1..dc75e45e0 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -12,6 +12,7 @@ documentation is organized alphabetically by module name. api/authentication api/chameleon_text api/chameleon_zpt + api/compat api/config api/events api/exceptions diff --git a/docs/api/compat.rst b/docs/api/compat.rst new file mode 100644 index 000000000..bb34f38e4 --- /dev/null +++ b/docs/api/compat.rst @@ -0,0 +1,156 @@ +.. _compat_module: + +:mod:`pyramid.compat` +---------------------- + +The ``pyramid.compat`` module provides platform and version compatibility for +Pyramid and its add-ons across Python platform and version differences. APIs +will be removed from this module over time as Pyramid ceases to support +systems which require compatibility imports. + +.. automodule:: pyramid.compat + + .. autofunction:: ascii_native_ + + .. attribute:: binary_type + + Binary type for this platform. For Python 3, it's ``bytes``. For + Python 2, it's ``str``. + + .. autofunction:: bytes_ + + .. attribute:: class_types + + Sequence of class types for this platform. For Python 3, it's + ``(type,)``. For Python 2, it's ``(type, types.ClassType)``. + + .. attribute:: configparser + + On Python 2, the ``ConfigParser`` module, on Python 3, the + ``configparser`` module. + + .. function:: escape(v) + + On Python 2, the ``cgi.escape`` function, on Python 3, the + ``html.escape`` function. + + .. function:: exec_(code, globs=None, locs=None) + + Exec code in a compatible way on both Python 2 and 3. + + .. attribute:: im_func + + On Python 2, the string value ``im_func``, on Python 3, the string + value ``__func__``. + + .. function:: input_(v) + + On Python 2, the ``raw_input`` function, on Python 3, the + ``input`` function. + + .. attribute:: integer_types + + Sequence of integer types for this platform. For Python 3, it's + ``(int,)``. For Python 2, it's ``(int, long)``. + + .. function:: is_nonstr_iter(v) + + Return ``True`` if ``v`` is a non-``str`` iterable on both Python 2 and + Python 3. + + .. function:: iteritems_(d) + + Return ``d.items()`` on Python 3, ``d.iteritems()`` on Python 2. + + .. function:: itervalues_(d) + + Return ``d.values()`` on Python 3, ``d.itervalues()`` on Python 2. + + .. function:: iterkeys_(d) + + Return ``d.keys()`` on Python 3, ``d.iterkeys()`` on Python 2. + + .. attribute:: long + + Long type for this platform. For Python 3, it's ``int``. For + Python 2, it's ``long``. + + .. function:: map_(v) + + Return ``list(map(v))`` on Python 3, ``map(v)`` on Python 2. + + .. attribute:: pickle + + ``cPickle`` module if it exists, ``pickle`` module otherwise. + + .. attribute:: PY3 + + ``True`` if running on Python 3, ``False`` otherwise. + + .. attribute:: PYPY + + ``True`` if running on PyPy, ``False`` otherwise. + + .. function:: reraise(tp, value, tb=None) + + Reraise an exception in a compatible way on both Python 2 and Python 3, + e.g. ``reraise(*sys.exc_info())``. + + .. attribute:: string_types + + Sequence of string types for this platform. For Python 3, it's + ``(str,)``. For Python 2, it's ``(basestring,)``. + + .. attribute:: SimpleCookie + + On Python 2, the ``Cookie.SimpleCookie`` class, on Python 3, the + ``http.cookies.SimpleCookie`` module. + + .. autofunction:: text_ + + .. attribute:: text_type + + Text type for this platform. For Python 3, it's ``str``. For Python + 2, it's ``unicode``. + + .. autofunction:: native_ + + .. attribute:: urlparse + + ``urlparse`` module on Python 2, ``urllib.parse`` module on Python 3. + + .. attribute:: url_quote + + ``urllib.quote`` function on Python 2, ``urllib.parse.quote`` function + on Python 3. + + .. attribute:: url_quote_plus + + ``urllib.quote_plus`` function on Python 2, ``urllib.parse.quote_plus`` + function on Python 3. + + .. attribute:: url_unquote + + ``urllib.unquote`` function on Python 2, ``urllib.parse.unquote`` + function on Python 3. + + .. attribute:: url_encode + + ``urllib.urlencode`` function on Python 2, ``urllib.parse.urlencode`` + function on Python 3. + + .. attribute:: url_open + + ``urllib2.urlopen`` function on Python 2, ``urllib.request.urlopen`` + function on Python 3. + + .. function:: url_unquote_text(v, encoding='utf-8', errors='replace') + + On Python 2, return ``url_unquote(v).decode(encoding(encoding, errors))``; + on Python 3, return the result of ``urllib.parse.unquote``. + + .. function:: url_unquote_native(v, encoding='utf-8', errors='replace') + + On Python 2, return ``native_(url_unquote_text_v, encoding, errors))``; + on Python 3, return the result of ``urllib.parse.unquote``. + diff --git a/docs/api/settings.rst b/docs/api/settings.rst index ac1cd3f9c..6b12c038c 100644 --- a/docs/api/settings.rst +++ b/docs/api/settings.rst @@ -9,4 +9,6 @@ .. autofunction:: asbool + .. autofunction:: aslist + diff --git a/docs/narr/MyProject/myproject/__init__.py b/docs/narr/MyProject/myproject/__init__.py index 04e219e36..ddcdd7162 100644 --- a/docs/narr/MyProject/myproject/__init__.py +++ b/docs/narr/MyProject/myproject/__init__.py @@ -1,12 +1,10 @@ from pyramid.config import Configurator -from myproject.resources import Root +from .resources import Root def main(global_config, **settings): """ This function returns a Pyramid WSGI application. """ config = Configurator(root_factory=Root, settings=settings) - config.add_view('myproject.views.my_view', - context='myproject.resources.Root', - renderer='myproject:templates/mytemplate.pt') - config.add_static_view('static', 'myproject:static') + config.add_static_view('static', 'static', cache_max_age=3600) + config.scan() return config.make_wsgi_app() diff --git a/docs/narr/MyProject/myproject/tests.py b/docs/narr/MyProject/myproject/tests.py index 5fa710278..a32165471 100644 --- a/docs/narr/MyProject/myproject/tests.py +++ b/docs/narr/MyProject/myproject/tests.py @@ -10,7 +10,7 @@ class ViewTests(unittest.TestCase): testing.tearDown() def test_my_view(self): - from myproject.views import my_view + from .views import my_view request = testing.DummyRequest() info = my_view(request) self.assertEqual(info['project'], 'MyProject') diff --git a/docs/narr/MyProject/myproject/views.py b/docs/narr/MyProject/myproject/views.py index c43b34460..5b5d230f2 100644 --- a/docs/narr/MyProject/myproject/views.py +++ b/docs/narr/MyProject/myproject/views.py @@ -1,2 +1,6 @@ +from pyramid.view import view_config +from .resources import Root + +@view_config(context=Root, renderer='templates/mytemplate.pt') def my_view(request): return {'project':'MyProject'} diff --git a/docs/narr/project.rst b/docs/narr/project.rst index 8fa4fbe9f..4c528ab58 100644 --- a/docs/narr/project.rst +++ b/docs/narr/project.rst @@ -28,7 +28,6 @@ as part of Pyramid. single: starter scaffold single: zodb scaffold single: alchemy scaffold - single: routesalchemy scaffold .. _additional_paster_scaffolds: @@ -52,12 +51,8 @@ The included scaffolds are these: ``zodb`` URL mapping via :term:`traversal` and persistence via :term:`ZODB`. -``routesalchemy`` - URL mapping via :term:`URL dispatch` and persistence via - :term:`SQLAlchemy` - ``alchemy`` - URL mapping via :term:`traversal` and persistence via + URL mapping via :term:`URL dispatch` and persistence via :term:`SQLAlchemy` .. note:: @@ -99,18 +94,18 @@ Or on Windows: The above command uses the ``pcreate`` command to create a project with the ``starter`` scaffold. To use a different scaffold, such as -``routesalchemy``, you'd just change the ``-s`` argument value. For example, +``alchemy``, you'd just change the ``-s`` argument value. For example, on UNIX: .. code-block:: text - $ bin/pcreate -s routesalchemy MyProject + $ bin/pcreate -s alchemy MyProject Or on Windows: .. code-block:: text - $ Scripts\pcreate routesalchemy MyProject + $ Scripts\pcreate alchemy MyProject Here's sample output from a run of ``pcreate`` on UNIX for a project we name ``MyProject``: @@ -727,31 +722,22 @@ also informs Python that the directory which contains it is a *package*. #. Line 2 imports the ``Root`` class from :mod:`myproject.resources` that we use later. -#. Lines 4-12 define a function named ``main`` that returns a :app:`Pyramid` +#. Lines 4-10 define a function named ``main`` that returns a :app:`Pyramid` WSGI application. This function is meant to be called by the :term:`PasteDeploy` framework as a result of running ``pserve``. Within this function, application configuration is performed. - Lines 8-10 register a "default view" (a view that has no ``name`` - attribute). It is registered so that it will be found when the - :term:`context` of the request is an instance of the - :class:`myproject.resources.Root` class. The first argument to - ``add_view`` points at a Python function that does all the work for this - view, also known as a :term:`view callable`, via a :term:`dotted Python - name`. The view declaration also names a ``renderer``, which in this case - is a template that will be used to render the result of the view callable. - This particular view declaration points at - ``myproject:templates/mytemplate.pt``, which is a :term:`asset - specification` that specifies the ``mytemplate.pt`` file within the - ``templates`` directory of the ``myproject`` package. The template file - it actually points to is a :term:`Chameleon` ZPT template file. - - Line 11 registers a static view, which will serve up the files from the + Line 7 creates an instance of a :term:`Configurator`. + + Line 8 registers a static view, which will serve up the files from the ``mypackage:static`` :term:`asset specification` (the ``static`` directory of the ``mypackage`` package). - Line 12 returns a :term:`WSGI` application to the caller of the function + Line 9 calls ``config.scan()``, which picks up view registrations declared + elsewhere in the package (in this case, in the ``view.py`` module). + + Line 10 returns a :term:`WSGI` application to the caller of the function (Pyramid's pserve). .. index:: @@ -769,10 +755,20 @@ and which returns a :term:`response`. :language: python :linenos: -This bit of code was registered as the view callable within ``__init__.py`` -(via ``add_view``). ``add_view`` said that the default URL for instances -that are of the class :class:`myproject.resources.Root` should run this -:func:`myproject.views.my_view` function. +Lines 4-6 define and register a :term:`view callable` named ``my_view``. The +function named ``my_view`` is decorated with a ``view_config`` decorator +(which is processed by the ``config.scan()`` line in our ``__init__.py``). +The view_config decorator asserts that this view be found when the +:term:`context` of the request is an instance of the +:class:`myproject.resources.Root` class. The view_config decorator also +names a ``renderer``, which in this case is a template that will be used to +render the result of the view callable. This particular view declaration +points at ``templates/mytemplate.pt``, which is a :term:`asset specification` +that specifies the ``mytemplate.pt`` file within the ``templates`` directory +of the ``myproject`` package. The asset specification could have also been +specified as ``myproject:templates/mytemplate.pt``; the leading package name +and colon is optional. The template file it actually points to is a +:term:`Chameleon` ZPT template file. This view callable function is handed a single piece of information: the :term:`request`. The *request* is an instance of the :term:`WebOb` @@ -839,11 +835,11 @@ template. It includes CSS and images. ``templates/mytemplate.pt`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The single :term:`Chameleon` template that exists in the project. Its contents -are too long to show here, but it displays a default page when rendered. It -is referenced by the call to ``add_view`` as the ``renderer`` attribute in -the ``__init__`` file. See :ref:`views_which_use_a_renderer` for more -information about renderers. +The single :term:`Chameleon` template that exists in the project. Its +contents are too long to show here, but it displays a default page when +rendered. It is referenced by the call to ``@view_config`` as the +``renderer`` of the ``my_view`` view callable in the ``views.py`` file. See +:ref:`views_which_use_a_renderer` for more information about renderers. Templates are accessed and used by view configurations and sometimes by view functions themselves. See :ref:`templates_used_directly` and diff --git a/docs/tutorials/wiki/NOTE-relocatable.txt b/docs/tutorials/wiki/NOTE-relocatable.txt new file mode 100644 index 000000000..cec2639f3 --- /dev/null +++ b/docs/tutorials/wiki/NOTE-relocatable.txt @@ -0,0 +1,13 @@ +We specifically use relative package references where possible so this demo +works even if the user names their package (in the 'bin/paster create -t +zodb ...' step) something other than 'tutorial'. + +Specifically: + +- use relative imports +- use plain relative URLs for resources (like stylesheets and images) in + page templates. + +Direct uses of the package name, like in __init__.py 'config.scan()' +statements, are already adjusted by the paster/pcreate, so we don't have to +worry about them. diff --git a/docs/tutorials/wiki/authorization.rst b/docs/tutorials/wiki/authorization.rst index 1835ce7ea..bf88c3bd8 100644 --- a/docs/tutorials/wiki/authorization.rst +++ b/docs/tutorials/wiki/authorization.rst @@ -4,7 +4,7 @@ Adding Authorization Our application currently allows anyone with access to the server to view, edit, and add pages to our wiki. For purposes of demonstration we'll change -our application to allow people whom are members of a *group* named +our application to allow people who are members of a *group* named ``group:editors`` to add and edit wiki pages but we'll continue allowing anyone with access to the server to view pages. :app:`Pyramid` provides facilities for :term:`authorization` and :term:`authentication`. We'll make @@ -27,8 +27,8 @@ The source code for this tutorial stage can be browsed via `http://github.com/Pylons/pyramid/tree/master/docs/tutorials/wiki/src/authorization/ <http://github.com/Pylons/pyramid/tree/master/docs/tutorials/wiki/src/authorization/>`_. -Adding Authentication and Authorization Policies -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Add Authentication and Authorization Policies +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ We'll change our package's ``__init__.py`` file to enable an ``AuthTktAuthenticationPolicy`` and an ``ACLAuthorizationPolicy`` to enable @@ -60,8 +60,12 @@ look like so: :linenos: :language: python -Adding ``security.py`` -~~~~~~~~~~~~~~~~~~~~~~ +.. note:: + (Your ``config.scan('tutorial')`` needs the package name you used + instead of "tutorial", if you used a different name.) + +Add ``security.py`` +~~~~~~~~~~~~~~~~~~~ Add a ``security.py`` module within your package (in the same directory as ``__init__.py``, ``views.py``, etc.) with the following @@ -82,8 +86,8 @@ user and groups sources. Note that the ``editor`` user is a member of the ``group:editors`` group in our dummy group data (the ``GROUPS`` data structure). -Giving Our Root Resource an ACL -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Give Our Root Resource an ACL +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ We need to give our root resource object an :term:`ACL`. This ACL will be sufficient to provide enough information to the :app:`Pyramid` security @@ -119,8 +123,8 @@ Our resulting ``models.py`` file will now look like so: :linenos: :language: python -Adding Login and Logout Views -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Add Login and Logout Views +~~~~~~~~~~~~~~~~~~~~~~~~~~ We'll add a ``login`` view which renders a login form and processes the post from the login form, checking credentials. @@ -157,8 +161,8 @@ login form. Before being allowed to continue on to the add or edit form, he will have to provide credentials that give him permission to add or edit via this login form. -Changing Existing Views -~~~~~~~~~~~~~~~~~~~~~~~ +Change Existing Views +~~~~~~~~~~~~~~~~~~~~~ Then we need to change each of our ``view_page``, ``edit_page`` and ``add_page`` views in ``views.py`` to pass a "logged in" parameter @@ -184,8 +188,8 @@ template. For example: logged_in = logged_in, edit_url = edit_url) -Adding ``permission`` Declarations to our ``view_config`` Decorators -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Add ``permission`` Declarations to our ``view_config`` Decorators +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ To protect each of our views with a particular permission, we need to pass a ``permission`` argument to each of our :class:`pyramid.view.view_config` @@ -216,8 +220,8 @@ decorators. To do so, within ``views.py``: function consults the ``GROUPS`` data structure. This means that the ``editor`` user can add and edit pages. -Adding the ``login.pt`` Template -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Add the ``login.pt`` Template +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Add a ``login.pt`` template to your templates directory. It's referred to within the login view we just added to ``login.py``. @@ -241,8 +245,8 @@ class="app-welcome align-right">`` div: <a href="${request.application_url}/logout">Logout</a> </span> -Seeing Our Changes To ``views.py`` and our Templates -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +See Our Changes To ``views.py`` and our Templates +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Our ``views.py`` module will look something like this when we're done: @@ -262,8 +266,8 @@ Our ``view.pt`` template will look something like this when we're done: :linenos: :language: xml -Viewing the Application in a Browser -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +View the Application in a Browser +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ We can finally examine our application in a browser. The views we'll try are as follows: diff --git a/docs/tutorials/wiki/basiclayout.rst b/docs/tutorials/wiki/basiclayout.rst index 47cac597b..897775428 100644 --- a/docs/tutorials/wiki/basiclayout.rst +++ b/docs/tutorials/wiki/basiclayout.rst @@ -2,7 +2,7 @@ Basic Layout ============ -The starter files generated by the ``pyramid_zodb`` scaffold are basic, but +The starter files generated by the ``zodb`` scaffold are basic, but they provide a good orientation for the high-level patterns common to most :term:`traversal` -based :app:`Pyramid` (and :term:`ZODB` based) projects. @@ -35,7 +35,7 @@ point happens to be the ``main`` function within the file named #. *Line 12*. We construct a :term:`Configurator` with a :term:`root factory` and the settings keywords parsed by :term:`PasteDeploy`. The root - factory is named ``get_root``. + factory is named ``root_factory``. #. *Line 13*. Register a 'static view' which answers requests which start with with URL path ``/static`` using the @@ -69,7 +69,7 @@ hierarchically in a :term:`resource tree`. This tree is consulted by tree represents the site structure, but it *also* represents the :term:`domain model` of the application, because each resource is a node stored persistently in a :term:`ZODB` database. The ``models.py`` file is -where the ``pyramid_zodb`` scaffold put the classes that implement our +where the ``zodb`` scaffold put the classes that implement our resource objects, each of which happens also to be a domain model object. Here is the source for ``models.py``: @@ -144,7 +144,7 @@ Let's try to understand the components in this module: #. *Lines 5-6*. We define a :term:`view callable` named ``my_view``, which we decorated in the step above. This view callable is a *function* we - write generated by the ``pyramid_zodb`` scaffold that is given a + write generated by the ``zodb`` scaffold that is given a ``request`` and which returns a dictionary. The ``mytemplate.pt`` :term:`renderer` named by the asset specification in the step above will convert this dictionary to a :term:`response` on our behalf. diff --git a/docs/tutorials/wiki/definingmodels.rst b/docs/tutorials/wiki/definingmodels.rst index ee9c13ab2..cdf3b6092 100644 --- a/docs/tutorials/wiki/definingmodels.rst +++ b/docs/tutorials/wiki/definingmodels.rst @@ -18,8 +18,8 @@ The source code for this tutorial stage can be browsed via `http://github.com/Pylons/pyramid/tree/master/docs/tutorials/wiki/src/models/ <http://github.com/Pylons/pyramid/tree/master/docs/tutorials/wiki/src/models/>`_. -Deleting the Database ---------------------- +Delete the Database +------------------- In the next step, we're going to remove the ``MyModel`` Python model class from our ``models.py`` file. Since this class is referred to within @@ -30,8 +30,8 @@ directory before proceeding any further. It's always fine to do this as long as you don't care about the content of the database; the database itself will be recreated as necessary. -Making Edits to ``models.py`` ------------------------------ +Edit ``models.py`` +------------------ .. note:: @@ -73,8 +73,8 @@ front page) into the Wiki within the ``appmaker``. This will provide :term:`traversal` a :term:`resource tree` to work against when it attempts to resolve URLs to resources. -Looking at the Result of Our Edits to ``models.py`` ---------------------------------------------------- +Look at the Result of Our Edits to ``models.py`` +------------------------------------------------ The result of all of our edits to ``models.py`` will end up looking something like this: @@ -83,8 +83,8 @@ something like this: :linenos: :language: python -Viewing the Application in a Browser ------------------------------------- +View the Application in a Browser +--------------------------------- We can't. At this point, our system is in a "non-runnable" state; we'll need to change view-related files in the next chapter to be able to start the diff --git a/docs/tutorials/wiki/definingviews.rst b/docs/tutorials/wiki/definingviews.rst index c21367559..15b9f13ab 100644 --- a/docs/tutorials/wiki/definingviews.rst +++ b/docs/tutorials/wiki/definingviews.rst @@ -296,9 +296,7 @@ This CSS file will be accessed via e.g. ``http://localhost:6543/static/pylons.css`` by virtue of the call to ``add_static_view`` directive we've made in the ``__init__.py`` file. Any number and type of static assets can be placed in this directory (or -subdirectories) and are just referred to by URL or by using the convenience -method ``static_url`` e.g. ``request.static_url('{{package}}:static/foo.css')`` -within templates. +subdirectories) and are just referred to by URL. Viewing the Application in a Browser ==================================== diff --git a/docs/tutorials/wiki/installation.rst b/docs/tutorials/wiki/installation.rst index c55c310ef..330b17c86 100644 --- a/docs/tutorials/wiki/installation.rst +++ b/docs/tutorials/wiki/installation.rst @@ -127,8 +127,8 @@ Preparation, Windows .. _making_a_project: -Making a Project -================ +Make a Project +============== Your next step is to create a project. :app:`Pyramid` supplies a variety of scaffolds to generate sample projects. For this tutorial, we will use the @@ -149,14 +149,18 @@ On Windows: c:\pyramidtut> Scripts\pcreate -s zodb tutorial +.. note:: You don't have to call it `tutorial` -- the code uses + relative paths for imports and finding templates and static + resources. + .. note:: If you are using Windows, the ``zodb`` scaffold doesn't currently deal gracefully with installation into a location that contains spaces in the path. If you experience startup problems, try putting both the virtualenv and the project into directories that do not contain spaces in their paths. -Installing the Project in "Development Mode" -============================================ +Install the Project in "Development Mode" +========================================= In order to do development on the project easily, you must "register" the project as a development egg in your workspace using the @@ -180,8 +184,8 @@ On Windows: .. _running_tests: -Running the Tests -================= +Run the Tests +============= After you've installed the project in development mode, you may run the tests for the project. @@ -198,48 +202,53 @@ On Windows: c:\pyramidtut\tutorial> ..\Scripts\python setup.py test -q -Starting the Application -======================== +Expose Test Coverage Information +================================ -Start the application. +You can run the ``nosetests`` command to see test coverage +information. This runs the tests in the same way that ``setup.py +test`` does but provides additional "coverage" information, exposing +which lines of your project are "covered" (or not covered) by the +tests. On UNIX: .. code-block:: text - $ ../bin/pserve development.ini --reload + $ ../bin/nosetests --cover-package=tutorial --cover-erase --with-coverage On Windows: .. code-block:: text - c:\pyramidtut\tutorial> ..\Scripts\pserve development.ini --reload + c:\pyramidtut\tutorial> ..\Scripts\nosetests --cover-package=tutorial ^ + --cover-erase --with-coverage -Exposing Test Coverage Information -================================== +Looks like the code in the ``zodb`` scaffold for ZODB projects is +missing some test coverage, particularly in the file named +``models.py``. -You can run the ``nosetests`` command to see test coverage -information. This runs the tests in the same way that ``setup.py -test`` does but provides additional "coverage" information, exposing -which lines of your project are "covered" (or not covered) by the -tests. +Start the Application +===================== + +Start the application. On UNIX: .. code-block:: text - $ ../bin/nosetests --cover-package=tutorial --cover-erase --with-coverage + $ ../bin/pserve development.ini --reload On Windows: .. code-block:: text - c:\pyramidtut\tutorial> ..\Scripts\nosetests --cover-package=tutorial ^ - --cover-erase --with-coverage + c:\pyramidtut\tutorial> ..\Scripts\pserve development.ini --reload -Looks like the code in the ``pyramid_zodb`` scaffold for ZODB projects is -missing some test coverage, particularly in the file named -``models.py``. +.. note:: + + Your OS firewall, if any, may pop up a dialog asking for authorization + to allow python to accept incoming network connections. Visit the Application in a Browser ================================== @@ -252,10 +261,10 @@ page. You can read more about the purpose of the icon at :ref:`debug_toolbar`. It allows you to get information about your application while you develop. -Decisions the ``pyramid_zodb`` Scaffold Has Made For You -======================================================== +Decisions the ``zodb`` Scaffold Has Made For You +================================================ -Creating a project using the ``pyramid_zodb`` scaffold makes the following +Creating a project using the ``zodb`` scaffold makes the following assumptions: - you are willing to use :term:`ZODB` as persistent storage diff --git a/docs/tutorials/wiki/src/authorization/tutorial/__init__.py b/docs/tutorials/wiki/src/authorization/tutorial/__init__.py index 2d6eb5ecb..20ee685ee 100644 --- a/docs/tutorials/wiki/src/authorization/tutorial/__init__.py +++ b/docs/tutorials/wiki/src/authorization/tutorial/__init__.py @@ -4,8 +4,8 @@ from pyramid_zodbconn import get_connection from pyramid.authentication import AuthTktAuthenticationPolicy from pyramid.authorization import ACLAuthorizationPolicy -from tutorial.models import appmaker -from tutorial.security import groupfinder +from .models import appmaker +from .security import groupfinder def root_factory(request): conn = get_connection(request) @@ -20,6 +20,6 @@ def main(global_config, **settings): config = Configurator(root_factory=root_factory, settings=settings, authentication_policy=authn_policy, authorization_policy=authz_policy) - config.add_static_view('static', 'tutorial:static', cache_max_age=3600) - config.scan('tutorial') + config.add_static_view('static', 'static', cache_max_age=3600) + config.scan() return config.make_wsgi_app() diff --git a/docs/tutorials/wiki/src/authorization/tutorial/login.py b/docs/tutorials/wiki/src/authorization/tutorial/login.py index d608a7d0b..11dea050f 100644 --- a/docs/tutorials/wiki/src/authorization/tutorial/login.py +++ b/docs/tutorials/wiki/src/authorization/tutorial/login.py @@ -4,9 +4,9 @@ from pyramid.security import remember from pyramid.security import forget from pyramid.view import view_config -from tutorial.security import USERS +from .security import USERS -@view_config(context='tutorial.models.Wiki', name='login', +@view_config(context='.models.Wiki', name='login', renderer='templates/login.pt') @view_config(context='pyramid.httpexceptions.HTTPForbidden', renderer='templates/login.pt') @@ -35,10 +35,9 @@ def login(request): login = login, password = password, ) - -@view_config(context='tutorial.models.Wiki', name='logout') + +@view_config(context='.models.Wiki', name='logout') def logout(request): headers = forget(request) return HTTPFound(location = request.resource_url(request.context), headers = headers) - diff --git a/docs/tutorials/wiki/src/authorization/tutorial/security.py b/docs/tutorials/wiki/src/authorization/tutorial/security.py index cfd13071e..d88c9c71f 100644 --- a/docs/tutorials/wiki/src/authorization/tutorial/security.py +++ b/docs/tutorials/wiki/src/authorization/tutorial/security.py @@ -5,4 +5,3 @@ GROUPS = {'editor':['group:editors']} def groupfinder(userid, request): if userid in USERS: return GROUPS.get(userid, []) - diff --git a/docs/tutorials/wiki/src/authorization/tutorial/templates/edit.pt b/docs/tutorials/wiki/src/authorization/tutorial/templates/edit.pt index f9da6c414..0d0738f7f 100644 --- a/docs/tutorials/wiki/src/authorization/tutorial/templates/edit.pt +++ b/docs/tutorials/wiki/src/authorization/tutorial/templates/edit.pt @@ -9,13 +9,13 @@ <meta name="keywords" content="python web application" /> <meta name="description" content="pyramid web application" /> <link rel="shortcut icon" - href="${request.static_url('tutorial:static/favicon.ico')}" /> + href="/static/favicon.ico" /> <link rel="stylesheet" - href="${request.static_url('tutorial:static/pylons.css')}" + href="/static/pylons.css" type="text/css" media="screen" charset="utf-8" /> <!--[if lte IE 6]> <link rel="stylesheet" - href="${request.static_url('tutorial:static/ie6.css')}" + href="/static/ie6.css" type="text/css" media="screen" charset="utf-8" /> <![endif]--> </head> @@ -25,7 +25,7 @@ <div class="top-small align-center"> <div> <img width="220" height="50" alt="pyramid" - src="${request.static_url('tutorial:static/pyramid-small.png')}" /> + src="/static/pyramid-small.png" /> </div> </div> </div> diff --git a/docs/tutorials/wiki/src/authorization/tutorial/templates/login.pt b/docs/tutorials/wiki/src/authorization/tutorial/templates/login.pt index 64e592ea9..2c7235761 100644 --- a/docs/tutorials/wiki/src/authorization/tutorial/templates/login.pt +++ b/docs/tutorials/wiki/src/authorization/tutorial/templates/login.pt @@ -9,13 +9,13 @@ <meta name="keywords" content="python web application" /> <meta name="description" content="pyramid web application" /> <link rel="shortcut icon" - href="${request.static_url('tutorial:static/favicon.ico')}" /> + href="/static/favicon.ico" /> <link rel="stylesheet" - href="${request.static_url('tutorial:static/pylons.css')}" + href="/static/pylons.css" type="text/css" media="screen" charset="utf-8" /> <!--[if lte IE 6]> <link rel="stylesheet" - href="${request.static_url('tutorial:static/ie6.css')}" + href="/static/ie6.css" type="text/css" media="screen" charset="utf-8" /> <![endif]--> </head> @@ -25,7 +25,7 @@ <div class="top-small align-center"> <div> <img width="220" height="50" alt="pyramid" - src="${request.static_url('tutorial:static/pyramid-small.png')}" /> + src="/static/pyramid-small.png" /> </div> </div> </div> diff --git a/docs/tutorials/wiki/src/authorization/tutorial/templates/mytemplate.pt b/docs/tutorials/wiki/src/authorization/tutorial/templates/mytemplate.pt index 14b88d16a..3597c679b 100644 --- a/docs/tutorials/wiki/src/authorization/tutorial/templates/mytemplate.pt +++ b/docs/tutorials/wiki/src/authorization/tutorial/templates/mytemplate.pt @@ -5,19 +5,19 @@ <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/> <meta name="keywords" content="python web application" /> <meta name="description" content="pyramid web application" /> - <link rel="shortcut icon" href="${request.static_url('tutorial:static/favicon.ico')}" /> + <link rel="shortcut icon" href="/static/favicon.ico" /> <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/nobile/stylesheet.css" media="screen" /> <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/neuton/stylesheet.css" media="screen" /> - <link rel="stylesheet" href="${request.static_url('tutorial:static/pylons.css')}" type="text/css" media="screen" charset="utf-8" /> + <link rel="stylesheet" href="/static/pylons.css" type="text/css" media="screen" charset="utf-8" /> <!--[if lte IE 6]> - <link rel="stylesheet" href="${request.static_url('tutorial:static/ie6.css')}" type="text/css" media="screen" charset="utf-8" /> + <link rel="stylesheet" href="/static/ie6.css" type="text/css" media="screen" charset="utf-8" /> <![endif]--> </head> <body> <div id="wrap"> <div id="top"> <div class="top align-center"> - <div><img src="${request.static_url('tutorial:static/pyramid.png')}" width="750" height="169" alt="pyramid"/></div> + <div><img src="/static/pyramid.png" width="750" height="169" alt="pyramid"/></div> </div> </div> <div id="middle"> diff --git a/docs/tutorials/wiki/src/authorization/tutorial/templates/view.pt b/docs/tutorials/wiki/src/authorization/tutorial/templates/view.pt index d207a0c23..9dd6540cf 100644 --- a/docs/tutorials/wiki/src/authorization/tutorial/templates/view.pt +++ b/docs/tutorials/wiki/src/authorization/tutorial/templates/view.pt @@ -9,13 +9,13 @@ <meta name="keywords" content="python web application" /> <meta name="description" content="pyramid web application" /> <link rel="shortcut icon" - href="${request.static_url('tutorial:static/favicon.ico')}" /> + href="/static/favicon.ico" /> <link rel="stylesheet" - href="${request.static_url('tutorial:static/pylons.css')}" + href="/static/pylons.css" type="text/css" media="screen" charset="utf-8" /> <!--[if lte IE 6]> <link rel="stylesheet" - href="${request.static_url('tutorial:static/ie6.css')}" + href="/static/ie6.css" type="text/css" media="screen" charset="utf-8" /> <![endif]--> </head> @@ -25,7 +25,7 @@ <div class="top-small align-center"> <div> <img width="220" height="50" alt="pyramid" - src="${request.static_url('tutorial:static/pyramid-small.png')}" /> + src="/static/pyramid-small.png" /> </div> </div> </div> diff --git a/docs/tutorials/wiki/src/authorization/tutorial/tests.py b/docs/tutorials/wiki/src/authorization/tutorial/tests.py index a4a4e2754..77e7cce29 100644 --- a/docs/tutorials/wiki/src/authorization/tutorial/tests.py +++ b/docs/tutorials/wiki/src/authorization/tutorial/tests.py @@ -5,7 +5,7 @@ from pyramid import testing class PageModelTests(unittest.TestCase): def _getTargetClass(self): - from tutorial.models import Page + from .models import Page return Page def _makeOne(self, data=u'some data'): @@ -14,11 +14,11 @@ class PageModelTests(unittest.TestCase): def test_constructor(self): instance = self._makeOne() self.assertEqual(instance.data, u'some data') - + class WikiModelTests(unittest.TestCase): def _getTargetClass(self): - from tutorial.models import Wiki + from .models import Wiki return Wiki def _makeOne(self): @@ -31,7 +31,7 @@ class WikiModelTests(unittest.TestCase): class AppmakerTests(unittest.TestCase): def _callFUT(self, zodb_root): - from tutorial.models import appmaker + from .models import appmaker return appmaker(zodb_root) def test_it(self): @@ -42,7 +42,7 @@ class AppmakerTests(unittest.TestCase): class ViewWikiTests(unittest.TestCase): def test_it(self): - from tutorial.views import view_wiki + from .views import view_wiki context = testing.DummyResource() request = testing.DummyRequest() response = view_wiki(context, request) @@ -50,7 +50,7 @@ class ViewWikiTests(unittest.TestCase): class ViewPageTests(unittest.TestCase): def _callFUT(self, context, request): - from tutorial.views import view_page + from .views import view_page return view_page(context, request) def test_it(self): @@ -72,11 +72,11 @@ class ViewPageTests(unittest.TestCase): '</p>\n</div>\n') self.assertEqual(info['edit_url'], 'http://example.com/thepage/edit_page') - - + + class AddPageTests(unittest.TestCase): def _callFUT(self, context, request): - from tutorial.views import add_page + from .views import add_page return add_page(context, request) def test_it_notsubmitted(self): @@ -88,7 +88,7 @@ class AddPageTests(unittest.TestCase): self.assertEqual(info['save_url'], request.resource_url( context, 'add_page', 'AnotherPage')) - + def test_it_submitted(self): context = testing.DummyResource() request = testing.DummyRequest({'form.submitted':True, @@ -102,7 +102,7 @@ class AddPageTests(unittest.TestCase): class EditPageTests(unittest.TestCase): def _callFUT(self, context, request): - from tutorial.views import edit_page + from .views import edit_page return edit_page(context, request) def test_it_notsubmitted(self): @@ -112,7 +112,7 @@ class EditPageTests(unittest.TestCase): self.assertEqual(info['page'], context) self.assertEqual(info['save_url'], request.resource_url(context, 'edit_page')) - + def test_it_submitted(self): context = testing.DummyResource() request = testing.DummyRequest({'form.submitted':True, diff --git a/docs/tutorials/wiki/src/authorization/tutorial/views.py b/docs/tutorials/wiki/src/authorization/tutorial/views.py index a570410ca..7ac5eeab6 100644 --- a/docs/tutorials/wiki/src/authorization/tutorial/views.py +++ b/docs/tutorials/wiki/src/authorization/tutorial/views.py @@ -5,16 +5,16 @@ from pyramid.httpexceptions import HTTPFound from pyramid.view import view_config from pyramid.security import authenticated_userid -from tutorial.models import Page +from .models import Page # regular expression used to find WikiWords wikiwords = re.compile(r"\b([A-Z]\w+[A-Z]+\w+)") -@view_config(context='tutorial.models.Wiki', permission='view') +@view_config(context='.models.Wiki', permission='view') def view_wiki(context, request): return HTTPFound(location=request.resource_url(context, 'FrontPage')) -@view_config(context='tutorial.models.Page', +@view_config(context='.models.Page', renderer='templates/view.pt', permission='view') def view_page(context, request): wiki = context.__parent__ @@ -38,7 +38,7 @@ def view_page(context, request): return dict(page = context, content = content, edit_url = edit_url, logged_in = logged_in) -@view_config(name='add_page', context='tutorial.models.Wiki', +@view_config(name='add_page', context='.models.Wiki', renderer='templates/edit.pt', permission='edit') def add_page(context, request): @@ -59,7 +59,7 @@ def add_page(context, request): return dict(page = page, save_url = save_url, logged_in = logged_in) -@view_config(name='edit_page', context='tutorial.models.Page', +@view_config(name='edit_page', context='.models.Page', renderer='templates/edit.pt', permission='edit') def edit_page(context, request): @@ -72,4 +72,3 @@ def edit_page(context, request): return dict(page = context, save_url = request.resource_url(context, 'edit_page'), logged_in = logged_in) - diff --git a/docs/tutorials/wiki/src/basiclayout/tutorial/__init__.py b/docs/tutorials/wiki/src/basiclayout/tutorial/__init__.py index e49a61129..b63933fc5 100644 --- a/docs/tutorials/wiki/src/basiclayout/tutorial/__init__.py +++ b/docs/tutorials/wiki/src/basiclayout/tutorial/__init__.py @@ -1,6 +1,6 @@ from pyramid.config import Configurator from pyramid_zodbconn import get_connection -from tutorial.models import appmaker +from .models import appmaker def root_factory(request): conn = get_connection(request) @@ -10,6 +10,6 @@ def main(global_config, **settings): """ This function returns a Pyramid WSGI application. """ config = Configurator(root_factory=root_factory, settings=settings) - config.add_static_view('static', 'tutorial:static', cache_max_age=3600) - config.scan('tutorial') + config.add_static_view('static', 'static', cache_max_age=3600) + config.scan() return config.make_wsgi_app() diff --git a/docs/tutorials/wiki/src/basiclayout/tutorial/templates/mytemplate.pt b/docs/tutorials/wiki/src/basiclayout/tutorial/templates/mytemplate.pt index f9f351c97..557e071ed 100644 --- a/docs/tutorials/wiki/src/basiclayout/tutorial/templates/mytemplate.pt +++ b/docs/tutorials/wiki/src/basiclayout/tutorial/templates/mytemplate.pt @@ -5,19 +5,19 @@ <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/> <meta name="keywords" content="python web application" /> <meta name="description" content="pyramid web application" /> - <link rel="shortcut icon" href="${request.static_url('tutorial:static/favicon.ico')}" /> + <link rel="shortcut icon" href="/static/favicon.ico" /> <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/nobile/stylesheet.css" media="screen" /> <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/neuton/stylesheet.css" media="screen" /> - <link rel="stylesheet" href="${request.static_url('tutorial:static/pylons.css')}" type="text/css" media="screen" charset="utf-8" /> + <link rel="stylesheet" href="/static/pylons.css" type="text/css" media="screen" charset="utf-8" /> <!--[if lte IE 6]> - <link rel="stylesheet" href="${request.static_url('tutorial:static/ie6.css')}" type="text/css" media="screen" charset="utf-8" /> + <link rel="stylesheet" href="/static/ie6.css" type="text/css" media="screen" charset="utf-8" /> <![endif]--> </head> <body> <div id="wrap"> <div id="top"> <div class="top align-center"> - <div><img src="${request.static_url('tutorial:static/pyramid.png')}" width="750" height="169" alt="pyramid"/></div> + <div><img src="/static/pyramid.png" width="750" height="169" alt="pyramid"/></div> </div> </div> <div id="middle"> diff --git a/docs/tutorials/wiki/src/basiclayout/tutorial/tests.py b/docs/tutorials/wiki/src/basiclayout/tutorial/tests.py index 1f3c3bb4d..8d2374be1 100644 --- a/docs/tutorials/wiki/src/basiclayout/tutorial/tests.py +++ b/docs/tutorials/wiki/src/basiclayout/tutorial/tests.py @@ -10,7 +10,7 @@ class ViewTests(unittest.TestCase): testing.tearDown() def test_my_view(self): - from tutorial.views import my_view + from .views import my_view request = testing.DummyRequest() info = my_view(request) self.assertEqual(info['project'], 'tutorial') diff --git a/docs/tutorials/wiki/src/basiclayout/tutorial/views.py b/docs/tutorials/wiki/src/basiclayout/tutorial/views.py index 157b9ac8f..9dfdee3f1 100644 --- a/docs/tutorials/wiki/src/basiclayout/tutorial/views.py +++ b/docs/tutorials/wiki/src/basiclayout/tutorial/views.py @@ -1,7 +1,7 @@ from pyramid.view import view_config -from tutorial.models import MyModel +from .models import MyModel @view_config(context=MyModel, - renderer='tutorial:templates/mytemplate.pt') + renderer='templates/mytemplate.pt') def my_view(request): return {'project':'tutorial'} diff --git a/docs/tutorials/wiki/src/models/tutorial/__init__.py b/docs/tutorials/wiki/src/models/tutorial/__init__.py index 2d637b9de..c59f36e7b 100644 --- a/docs/tutorials/wiki/src/models/tutorial/__init__.py +++ b/docs/tutorials/wiki/src/models/tutorial/__init__.py @@ -1,6 +1,6 @@ from pyramid.config import Configurator from pyramid_zodbconn import get_connection -from tutorial.models import appmaker +from .models import appmaker def root_factory(request): conn = get_connection(request) @@ -10,7 +10,7 @@ def main(global_config, **settings): """ This function returns a WSGI application. """ config = Configurator(root_factory=root_factory, settings=settings) - config.add_static_view('static', 'tutorial:static', cache_max_age=3600) - config.scan('tutorial') + config.add_static_view('static', 'static', cache_max_age=3600) + config.scan() return config.make_wsgi_app() diff --git a/docs/tutorials/wiki/src/models/tutorial/templates/mytemplate.pt b/docs/tutorials/wiki/src/models/tutorial/templates/mytemplate.pt index 14b88d16a..3597c679b 100644 --- a/docs/tutorials/wiki/src/models/tutorial/templates/mytemplate.pt +++ b/docs/tutorials/wiki/src/models/tutorial/templates/mytemplate.pt @@ -5,19 +5,19 @@ <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/> <meta name="keywords" content="python web application" /> <meta name="description" content="pyramid web application" /> - <link rel="shortcut icon" href="${request.static_url('tutorial:static/favicon.ico')}" /> + <link rel="shortcut icon" href="/static/favicon.ico" /> <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/nobile/stylesheet.css" media="screen" /> <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/neuton/stylesheet.css" media="screen" /> - <link rel="stylesheet" href="${request.static_url('tutorial:static/pylons.css')}" type="text/css" media="screen" charset="utf-8" /> + <link rel="stylesheet" href="/static/pylons.css" type="text/css" media="screen" charset="utf-8" /> <!--[if lte IE 6]> - <link rel="stylesheet" href="${request.static_url('tutorial:static/ie6.css')}" type="text/css" media="screen" charset="utf-8" /> + <link rel="stylesheet" href="/static/ie6.css" type="text/css" media="screen" charset="utf-8" /> <![endif]--> </head> <body> <div id="wrap"> <div id="top"> <div class="top align-center"> - <div><img src="${request.static_url('tutorial:static/pyramid.png')}" width="750" height="169" alt="pyramid"/></div> + <div><img src="/static/pyramid.png" width="750" height="169" alt="pyramid"/></div> </div> </div> <div id="middle"> diff --git a/docs/tutorials/wiki/src/models/tutorial/tests.py b/docs/tutorials/wiki/src/models/tutorial/tests.py index 51c97a95d..9fd13a18d 100644 --- a/docs/tutorials/wiki/src/models/tutorial/tests.py +++ b/docs/tutorials/wiki/src/models/tutorial/tests.py @@ -5,7 +5,7 @@ from pyramid import testing class PageModelTests(unittest.TestCase): def _getTargetClass(self): - from tutorial.models import Page + from .models import Page return Page def _makeOne(self, data=u'some data'): @@ -14,11 +14,11 @@ class PageModelTests(unittest.TestCase): def test_constructor(self): instance = self._makeOne() self.assertEqual(instance.data, u'some data') - + class WikiModelTests(unittest.TestCase): def _getTargetClass(self): - from tutorial.models import Wiki + from .models import Wiki return Wiki def _makeOne(self): @@ -32,7 +32,7 @@ class WikiModelTests(unittest.TestCase): class AppmakerTests(unittest.TestCase): def _callFUT(self, zodb_root): - from tutorial.models import appmaker + from .models import appmaker return appmaker(zodb_root) def test_no_app_root(self): @@ -55,7 +55,7 @@ class ViewTests(unittest.TestCase): testing.tearDown() def test_my_view(self): - from tutorial.views import my_view + from .views import my_view request = testing.DummyRequest() info = my_view(request) self.assertEqual(info['project'], 'tutorial') diff --git a/docs/tutorials/wiki/src/models/tutorial/views.py b/docs/tutorials/wiki/src/models/tutorial/views.py index 2346602c9..7c1f1d228 100644 --- a/docs/tutorials/wiki/src/models/tutorial/views.py +++ b/docs/tutorials/wiki/src/models/tutorial/views.py @@ -1,5 +1,5 @@ from pyramid.view import view_config -@view_config(renderer='tutorial:templates/mytemplate.pt') +@view_config(renderer='templates/mytemplate.pt') def my_view(request): return {'project':'tutorial'} diff --git a/docs/tutorials/wiki/src/tests/tutorial/__init__.py b/docs/tutorials/wiki/src/tests/tutorial/__init__.py index 2d6eb5ecb..20ee685ee 100644 --- a/docs/tutorials/wiki/src/tests/tutorial/__init__.py +++ b/docs/tutorials/wiki/src/tests/tutorial/__init__.py @@ -4,8 +4,8 @@ from pyramid_zodbconn import get_connection from pyramid.authentication import AuthTktAuthenticationPolicy from pyramid.authorization import ACLAuthorizationPolicy -from tutorial.models import appmaker -from tutorial.security import groupfinder +from .models import appmaker +from .security import groupfinder def root_factory(request): conn = get_connection(request) @@ -20,6 +20,6 @@ def main(global_config, **settings): config = Configurator(root_factory=root_factory, settings=settings, authentication_policy=authn_policy, authorization_policy=authz_policy) - config.add_static_view('static', 'tutorial:static', cache_max_age=3600) - config.scan('tutorial') + config.add_static_view('static', 'static', cache_max_age=3600) + config.scan() return config.make_wsgi_app() diff --git a/docs/tutorials/wiki/src/tests/tutorial/login.py b/docs/tutorials/wiki/src/tests/tutorial/login.py index d608a7d0b..11dea050f 100644 --- a/docs/tutorials/wiki/src/tests/tutorial/login.py +++ b/docs/tutorials/wiki/src/tests/tutorial/login.py @@ -4,9 +4,9 @@ from pyramid.security import remember from pyramid.security import forget from pyramid.view import view_config -from tutorial.security import USERS +from .security import USERS -@view_config(context='tutorial.models.Wiki', name='login', +@view_config(context='.models.Wiki', name='login', renderer='templates/login.pt') @view_config(context='pyramid.httpexceptions.HTTPForbidden', renderer='templates/login.pt') @@ -35,10 +35,9 @@ def login(request): login = login, password = password, ) - -@view_config(context='tutorial.models.Wiki', name='logout') + +@view_config(context='.models.Wiki', name='logout') def logout(request): headers = forget(request) return HTTPFound(location = request.resource_url(request.context), headers = headers) - diff --git a/docs/tutorials/wiki/src/tests/tutorial/security.py b/docs/tutorials/wiki/src/tests/tutorial/security.py index cfd13071e..d88c9c71f 100644 --- a/docs/tutorials/wiki/src/tests/tutorial/security.py +++ b/docs/tutorials/wiki/src/tests/tutorial/security.py @@ -5,4 +5,3 @@ GROUPS = {'editor':['group:editors']} def groupfinder(userid, request): if userid in USERS: return GROUPS.get(userid, []) - diff --git a/docs/tutorials/wiki/src/tests/tutorial/templates/edit.pt b/docs/tutorials/wiki/src/tests/tutorial/templates/edit.pt index f9da6c414..0d0738f7f 100644 --- a/docs/tutorials/wiki/src/tests/tutorial/templates/edit.pt +++ b/docs/tutorials/wiki/src/tests/tutorial/templates/edit.pt @@ -9,13 +9,13 @@ <meta name="keywords" content="python web application" /> <meta name="description" content="pyramid web application" /> <link rel="shortcut icon" - href="${request.static_url('tutorial:static/favicon.ico')}" /> + href="/static/favicon.ico" /> <link rel="stylesheet" - href="${request.static_url('tutorial:static/pylons.css')}" + href="/static/pylons.css" type="text/css" media="screen" charset="utf-8" /> <!--[if lte IE 6]> <link rel="stylesheet" - href="${request.static_url('tutorial:static/ie6.css')}" + href="/static/ie6.css" type="text/css" media="screen" charset="utf-8" /> <![endif]--> </head> @@ -25,7 +25,7 @@ <div class="top-small align-center"> <div> <img width="220" height="50" alt="pyramid" - src="${request.static_url('tutorial:static/pyramid-small.png')}" /> + src="/static/pyramid-small.png" /> </div> </div> </div> diff --git a/docs/tutorials/wiki/src/tests/tutorial/templates/login.pt b/docs/tutorials/wiki/src/tests/tutorial/templates/login.pt index 64e592ea9..2c7235761 100644 --- a/docs/tutorials/wiki/src/tests/tutorial/templates/login.pt +++ b/docs/tutorials/wiki/src/tests/tutorial/templates/login.pt @@ -9,13 +9,13 @@ <meta name="keywords" content="python web application" /> <meta name="description" content="pyramid web application" /> <link rel="shortcut icon" - href="${request.static_url('tutorial:static/favicon.ico')}" /> + href="/static/favicon.ico" /> <link rel="stylesheet" - href="${request.static_url('tutorial:static/pylons.css')}" + href="/static/pylons.css" type="text/css" media="screen" charset="utf-8" /> <!--[if lte IE 6]> <link rel="stylesheet" - href="${request.static_url('tutorial:static/ie6.css')}" + href="/static/ie6.css" type="text/css" media="screen" charset="utf-8" /> <![endif]--> </head> @@ -25,7 +25,7 @@ <div class="top-small align-center"> <div> <img width="220" height="50" alt="pyramid" - src="${request.static_url('tutorial:static/pyramid-small.png')}" /> + src="/static/pyramid-small.png" /> </div> </div> </div> diff --git a/docs/tutorials/wiki/src/tests/tutorial/templates/mytemplate.pt b/docs/tutorials/wiki/src/tests/tutorial/templates/mytemplate.pt index 14b88d16a..3597c679b 100644 --- a/docs/tutorials/wiki/src/tests/tutorial/templates/mytemplate.pt +++ b/docs/tutorials/wiki/src/tests/tutorial/templates/mytemplate.pt @@ -5,19 +5,19 @@ <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/> <meta name="keywords" content="python web application" /> <meta name="description" content="pyramid web application" /> - <link rel="shortcut icon" href="${request.static_url('tutorial:static/favicon.ico')}" /> + <link rel="shortcut icon" href="/static/favicon.ico" /> <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/nobile/stylesheet.css" media="screen" /> <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/neuton/stylesheet.css" media="screen" /> - <link rel="stylesheet" href="${request.static_url('tutorial:static/pylons.css')}" type="text/css" media="screen" charset="utf-8" /> + <link rel="stylesheet" href="/static/pylons.css" type="text/css" media="screen" charset="utf-8" /> <!--[if lte IE 6]> - <link rel="stylesheet" href="${request.static_url('tutorial:static/ie6.css')}" type="text/css" media="screen" charset="utf-8" /> + <link rel="stylesheet" href="/static/ie6.css" type="text/css" media="screen" charset="utf-8" /> <![endif]--> </head> <body> <div id="wrap"> <div id="top"> <div class="top align-center"> - <div><img src="${request.static_url('tutorial:static/pyramid.png')}" width="750" height="169" alt="pyramid"/></div> + <div><img src="/static/pyramid.png" width="750" height="169" alt="pyramid"/></div> </div> </div> <div id="middle"> diff --git a/docs/tutorials/wiki/src/tests/tutorial/templates/view.pt b/docs/tutorials/wiki/src/tests/tutorial/templates/view.pt index d207a0c23..9dd6540cf 100644 --- a/docs/tutorials/wiki/src/tests/tutorial/templates/view.pt +++ b/docs/tutorials/wiki/src/tests/tutorial/templates/view.pt @@ -9,13 +9,13 @@ <meta name="keywords" content="python web application" /> <meta name="description" content="pyramid web application" /> <link rel="shortcut icon" - href="${request.static_url('tutorial:static/favicon.ico')}" /> + href="/static/favicon.ico" /> <link rel="stylesheet" - href="${request.static_url('tutorial:static/pylons.css')}" + href="/static/pylons.css" type="text/css" media="screen" charset="utf-8" /> <!--[if lte IE 6]> <link rel="stylesheet" - href="${request.static_url('tutorial:static/ie6.css')}" + href="/static/ie6.css" type="text/css" media="screen" charset="utf-8" /> <![endif]--> </head> @@ -25,7 +25,7 @@ <div class="top-small align-center"> <div> <img width="220" height="50" alt="pyramid" - src="${request.static_url('tutorial:static/pyramid-small.png')}" /> + src="/static/pyramid-small.png" /> </div> </div> </div> diff --git a/docs/tutorials/wiki/src/tests/tutorial/tests.py b/docs/tutorials/wiki/src/tests/tutorial/tests.py index b1d4e68c3..81f7a1882 100644 --- a/docs/tutorials/wiki/src/tests/tutorial/tests.py +++ b/docs/tutorials/wiki/src/tests/tutorial/tests.py @@ -5,7 +5,7 @@ from pyramid import testing class PageModelTests(unittest.TestCase): def _getTargetClass(self): - from tutorial.models import Page + from .models import Page return Page def _makeOne(self, data=u'some data'): @@ -18,7 +18,7 @@ class PageModelTests(unittest.TestCase): class WikiModelTests(unittest.TestCase): def _getTargetClass(self): - from tutorial.models import Wiki + from .models import Wiki return Wiki def _makeOne(self): @@ -31,7 +31,7 @@ class WikiModelTests(unittest.TestCase): class AppmakerTests(unittest.TestCase): def _callFUT(self, zodb_root): - from tutorial.models import appmaker + from .models import appmaker return appmaker(zodb_root) def test_it(self): @@ -42,7 +42,7 @@ class AppmakerTests(unittest.TestCase): class ViewWikiTests(unittest.TestCase): def test_it(self): - from tutorial.views import view_wiki + from .views import view_wiki context = testing.DummyResource() request = testing.DummyRequest() response = view_wiki(context, request) @@ -50,7 +50,7 @@ class ViewWikiTests(unittest.TestCase): class ViewPageTests(unittest.TestCase): def _callFUT(self, context, request): - from tutorial.views import view_page + from .views import view_page return view_page(context, request) def test_it(self): @@ -76,7 +76,7 @@ class ViewPageTests(unittest.TestCase): class AddPageTests(unittest.TestCase): def _callFUT(self, context, request): - from tutorial.views import add_page + from .views import add_page return add_page(context, request) def test_it_notsubmitted(self): @@ -102,7 +102,7 @@ class AddPageTests(unittest.TestCase): class EditPageTests(unittest.TestCase): def _callFUT(self, context, request): - from tutorial.views import edit_page + from .views import edit_page return edit_page(context, request) def test_it_notsubmitted(self): @@ -133,7 +133,7 @@ class FunctionalTests(unittest.TestCase): def setUp(self): import tempfile import os.path - from tutorial import main + from . import main self.tmpdir = tempfile.mkdtemp() dbpath = os.path.join( self.tmpdir, 'test.db') diff --git a/docs/tutorials/wiki/src/tests/tutorial/views.py b/docs/tutorials/wiki/src/tests/tutorial/views.py index a570410ca..7ac5eeab6 100644 --- a/docs/tutorials/wiki/src/tests/tutorial/views.py +++ b/docs/tutorials/wiki/src/tests/tutorial/views.py @@ -5,16 +5,16 @@ from pyramid.httpexceptions import HTTPFound from pyramid.view import view_config from pyramid.security import authenticated_userid -from tutorial.models import Page +from .models import Page # regular expression used to find WikiWords wikiwords = re.compile(r"\b([A-Z]\w+[A-Z]+\w+)") -@view_config(context='tutorial.models.Wiki', permission='view') +@view_config(context='.models.Wiki', permission='view') def view_wiki(context, request): return HTTPFound(location=request.resource_url(context, 'FrontPage')) -@view_config(context='tutorial.models.Page', +@view_config(context='.models.Page', renderer='templates/view.pt', permission='view') def view_page(context, request): wiki = context.__parent__ @@ -38,7 +38,7 @@ def view_page(context, request): return dict(page = context, content = content, edit_url = edit_url, logged_in = logged_in) -@view_config(name='add_page', context='tutorial.models.Wiki', +@view_config(name='add_page', context='.models.Wiki', renderer='templates/edit.pt', permission='edit') def add_page(context, request): @@ -59,7 +59,7 @@ def add_page(context, request): return dict(page = page, save_url = save_url, logged_in = logged_in) -@view_config(name='edit_page', context='tutorial.models.Page', +@view_config(name='edit_page', context='.models.Page', renderer='templates/edit.pt', permission='edit') def edit_page(context, request): @@ -72,4 +72,3 @@ def edit_page(context, request): return dict(page = context, save_url = request.resource_url(context, 'edit_page'), logged_in = logged_in) - diff --git a/docs/tutorials/wiki/src/views/tutorial/__init__.py b/docs/tutorials/wiki/src/views/tutorial/__init__.py index 009013b3f..957a0b705 100644 --- a/docs/tutorials/wiki/src/views/tutorial/__init__.py +++ b/docs/tutorials/wiki/src/views/tutorial/__init__.py @@ -10,6 +10,6 @@ def main(global_config, **settings): """ This function returns a WSGI application. """ config = Configurator(root_factory=root_factory, settings=settings) - config.add_static_view('static', 'tutorial:static', cache_max_age=3600) + config.add_static_view('static', 'static', cache_max_age=3600) config.scan('tutorial') return config.make_wsgi_app() diff --git a/docs/tutorials/wiki/src/views/tutorial/templates/edit.pt b/docs/tutorials/wiki/src/views/tutorial/templates/edit.pt index 6dbb0edde..24ed2e592 100644 --- a/docs/tutorials/wiki/src/views/tutorial/templates/edit.pt +++ b/docs/tutorials/wiki/src/views/tutorial/templates/edit.pt @@ -9,13 +9,13 @@ <meta name="keywords" content="python web application" /> <meta name="description" content="pyramid web application" /> <link rel="shortcut icon" - href="${request.static_url('tutorial:static/favicon.ico')}" /> + href="/static/favicon.ico" /> <link rel="stylesheet" - href="${request.static_url('tutorial:static/pylons.css')}" + href="/static/pylons.css" type="text/css" media="screen" charset="utf-8" /> <!--[if lte IE 6]> <link rel="stylesheet" - href="${request.static_url('tutorial:static/ie6.css')}" + href="/static/ie6.css" type="text/css" media="screen" charset="utf-8" /> <![endif]--> </head> @@ -25,7 +25,7 @@ <div class="top-small align-center"> <div> <img width="220" height="50" alt="pyramid" - src="${request.static_url('tutorial:static/pyramid-small.png')}" /> + src="/static/pyramid-small.png" /> </div> </div> </div> diff --git a/docs/tutorials/wiki/src/views/tutorial/templates/mytemplate.pt b/docs/tutorials/wiki/src/views/tutorial/templates/mytemplate.pt index 14b88d16a..3597c679b 100644 --- a/docs/tutorials/wiki/src/views/tutorial/templates/mytemplate.pt +++ b/docs/tutorials/wiki/src/views/tutorial/templates/mytemplate.pt @@ -5,19 +5,19 @@ <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/> <meta name="keywords" content="python web application" /> <meta name="description" content="pyramid web application" /> - <link rel="shortcut icon" href="${request.static_url('tutorial:static/favicon.ico')}" /> + <link rel="shortcut icon" href="/static/favicon.ico" /> <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/nobile/stylesheet.css" media="screen" /> <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/neuton/stylesheet.css" media="screen" /> - <link rel="stylesheet" href="${request.static_url('tutorial:static/pylons.css')}" type="text/css" media="screen" charset="utf-8" /> + <link rel="stylesheet" href="/static/pylons.css" type="text/css" media="screen" charset="utf-8" /> <!--[if lte IE 6]> - <link rel="stylesheet" href="${request.static_url('tutorial:static/ie6.css')}" type="text/css" media="screen" charset="utf-8" /> + <link rel="stylesheet" href="/static/ie6.css" type="text/css" media="screen" charset="utf-8" /> <![endif]--> </head> <body> <div id="wrap"> <div id="top"> <div class="top align-center"> - <div><img src="${request.static_url('tutorial:static/pyramid.png')}" width="750" height="169" alt="pyramid"/></div> + <div><img src="/static/pyramid.png" width="750" height="169" alt="pyramid"/></div> </div> </div> <div id="middle"> diff --git a/docs/tutorials/wiki/src/views/tutorial/templates/view.pt b/docs/tutorials/wiki/src/views/tutorial/templates/view.pt index 537ae3a15..424c4302a 100644 --- a/docs/tutorials/wiki/src/views/tutorial/templates/view.pt +++ b/docs/tutorials/wiki/src/views/tutorial/templates/view.pt @@ -9,13 +9,13 @@ <meta name="keywords" content="python web application" /> <meta name="description" content="pyramid web application" /> <link rel="shortcut icon" - href="${request.static_url('tutorial:static/favicon.ico')}" /> + href="/static/favicon.ico" /> <link rel="stylesheet" - href="${request.static_url('tutorial:static/pylons.css')}" + href="/static/pylons.css" type="text/css" media="screen" charset="utf-8" /> <!--[if lte IE 6]> <link rel="stylesheet" - href="${request.static_url('tutorial:static/ie6.css')}" + href="/static/ie6.css" type="text/css" media="screen" charset="utf-8" /> <![endif]--> </head> @@ -25,7 +25,7 @@ <div class="top-small align-center"> <div> <img width="220" height="50" alt="pyramid" - src="${request.static_url('tutorial:static/pyramid-small.png')}" /> + src="/static/pyramid-small.png" /> </div> </div> </div> diff --git a/docs/tutorials/wiki/src/views/tutorial/views.py b/docs/tutorials/wiki/src/views/tutorial/views.py index 245cda682..862bd0da9 100644 --- a/docs/tutorials/wiki/src/views/tutorial/views.py +++ b/docs/tutorials/wiki/src/views/tutorial/views.py @@ -4,17 +4,17 @@ import re from pyramid.httpexceptions import HTTPFound from pyramid.view import view_config -from tutorial.models import Page +from .models import Page # regular expression used to find WikiWords wikiwords = re.compile(r"\b([A-Z]\w+[A-Z]+\w+)") -@view_config(context='tutorial.models.Wiki') +@view_config(context='.models.Wiki') def view_wiki(context, request): return HTTPFound(location=request.resource_url(context, 'FrontPage')) -@view_config(context='tutorial.models.Page', - renderer='tutorial:templates/view.pt') +@view_config(context='.models.Page', + renderer='templates/view.pt') def view_page(context, request): wiki = context.__parent__ @@ -33,8 +33,8 @@ def view_page(context, request): edit_url = request.resource_url(context, 'edit_page') return dict(page = context, content = content, edit_url = edit_url) -@view_config(name='add_page', context='tutorial.models.Wiki', - renderer='tutorial:templates/edit.pt') +@view_config(name='add_page', context='.models.Wiki', + renderer='templates/edit.pt') def add_page(context, request): name = request.subpath[0] if 'form.submitted' in request.params: @@ -50,8 +50,8 @@ def add_page(context, request): page.__parent__ = context return dict(page = page, save_url = save_url) -@view_config(name='edit_page', context='tutorial.models.Page', - renderer='tutorial:templates/edit.pt') +@view_config(name='edit_page', context='.models.Page', + renderer='templates/edit.pt') def edit_page(context, request): if 'form.submitted' in request.params: context.data = request.params['body'] @@ -59,5 +59,3 @@ def edit_page(context, request): return dict(page = context, save_url = request.resource_url(context, 'edit_page')) - - diff --git a/docs/tutorials/wiki/tests.rst b/docs/tutorials/wiki/tests.rst index 841baa8d1..941302d67 100644 --- a/docs/tutorials/wiki/tests.rst +++ b/docs/tutorials/wiki/tests.rst @@ -6,8 +6,8 @@ We will now add tests for the models and the views and a few functional tests in the ``tests.py``. Tests ensure that an application works, and that it continues to work after some changes are made in the future. -Testing the Models -================== +Test the Models +=============== We write tests for the model classes and the appmaker. Changing ``tests.py``, we'll write a separate test @@ -15,13 +15,13 @@ class for each model class, and we'll write a test class for the ``appmaker``. To do so, we'll retain the ``tutorial.tests.ViewTests`` class provided as a -result of the ``pyramid_zodb`` project generator. We'll add three test +result of the ``zodb`` project generator. We'll add three test classes: one for the ``Page`` model named ``PageModelTests``, one for the ``Wiki`` model named ``WikiModelTests``, and one for the appmaker named ``AppmakerTests``. -Testing the Views -================= +Test the Views +============== We'll modify our ``tests.py`` file, adding tests for each view function we added above. As a result, we'll *delete* the ``ViewTests`` test in the file, @@ -38,8 +38,8 @@ tested in the unit tests, like logging in, logging out, checking that the ``viewer`` user cannot add or edit pages, but the ``editor`` user can, and so on. -Viewing the results of all our edits to ``tests.py`` -==================================================== +View the results of all our edits to ``tests.py`` +================================================= Once we're done with the ``tests.py`` module, it will look a lot like the below: @@ -48,8 +48,8 @@ below: :linenos: :language: python -Running the Tests -================= +Run the Tests +============= We can run these tests by using ``setup.py test`` in the same way we did in :ref:`running_tests`. However, first we must edit our ``setup.py`` to diff --git a/docs/tutorials/wiki2/basiclayout.rst b/docs/tutorials/wiki2/basiclayout.rst index 8dc886373..db8ab1fbe 100644 --- a/docs/tutorials/wiki2/basiclayout.rst +++ b/docs/tutorials/wiki2/basiclayout.rst @@ -2,7 +2,7 @@ Basic Layout ============ -The starter files generated by the ``pyramid_routesalchemy`` scaffold are +The starter files generated by the ``alchemy`` scaffold are basic, but they provide a good orientation for the high-level patterns common to most :term:`url dispatch` -based :app:`Pyramid` projects. @@ -98,7 +98,7 @@ register views for the routes, mapping your patterns to code: The first positional ``add_view`` argument ``tutorial.views.my_view`` is the dotted name to a *function* we write (generated by the -``pyramid_routesalchemy`` scaffold) that is given a ``request`` object and +``alchemy`` scaffold) that is given a ``request`` object and which returns a response or a dictionary. This view also names a ``renderer``, which is a template which lives in the ``templates`` subdirectory of the package. When the ``tutorial.views.my_view`` view @@ -124,7 +124,7 @@ Content Models with ``models.py`` In a SQLAlchemy-based application, a *model* object is an object composed by querying the SQL database which backs an application. SQLAlchemy is an "object relational mapper" (an ORM). The -``models.py`` file is where the ``pyramid_routesalchemy`` scaffold +``models.py`` file is where the ``alchemy`` scaffold put the classes that implement our models. Let's take a look. First, we need some imports to support later code. diff --git a/docs/tutorials/wiki2/installation.rst b/docs/tutorials/wiki2/installation.rst index f9f5c4fba..147f7f563 100644 --- a/docs/tutorials/wiki2/installation.rst +++ b/docs/tutorials/wiki2/installation.rst @@ -84,7 +84,7 @@ Making a Project Your next step is to create a project. :app:`Pyramid` supplies a variety of scaffolds to generate sample projects. We will use the -``pyramid_routesalchemy`` scaffold, which generates an application +``alchemy`` scaffold, which generates an application that uses :term:`SQLAlchemy` and :term:`URL dispatch`. The below instructions assume your current working directory is the @@ -94,15 +94,15 @@ On UNIX: .. code-block:: text - $ bin/pcreate -s routesalchemy tutorial + $ bin/pcreate -s alchemy tutorial On Windows: .. code-block:: text - c:\pyramidtut> Scripts\pcreate -s routesalchemy tutorial + c:\pyramidtut> Scripts\pcreate -s alchemy tutorial -.. note:: If you are using Windows, the ``pyramid_routesalchemy`` +.. note:: If you are using Windows, the ``alchemy`` scaffold may not deal gracefully with installation into a location that contains spaces in the path. If you experience startup problems, try putting both the virtualenv and the project @@ -151,23 +151,6 @@ On Windows: c:\pyramidtut\tutorial> ..\Scripts\python setup.py test -q -Starting the Application -======================== - -Start the application. - -On UNIX: - -.. code-block:: text - - $ ../bin/pserve development.ini --reload - -On Windows: - -.. code-block:: text - - c:\pyramidtut\tutorial> ..\Scripts\pserve development.ini --reload - Exposing Test Coverage Information ================================== @@ -211,6 +194,23 @@ On Windows: Looks like our package's ``models`` module doesn't quite have 100% test coverage. +Starting the Application +======================== + +Start the application. + +On UNIX: + +.. code-block:: text + + $ ../bin/pserve development.ini --reload + +On Windows: + +.. code-block:: text + + c:\pyramidtut\tutorial> ..\Scripts\pserve development.ini --reload + Visit the Application in a Browser ================================== @@ -222,10 +222,10 @@ page. You can read more about the purpose of the icon at :ref:`debug_toolbar`. It allows you to get information about your application while you develop. -Decisions the ``pyramid_routesalchemy`` Scaffold Has Made For You +Decisions the ``alchemy`` Scaffold Has Made For You ================================================================= -Creating a project using the ``pyramid_routesalchemy`` scaffold makes +Creating a project using the ``alchemy`` scaffold makes the following assumptions: - you are willing to use :term:`SQLAlchemy` as a database access tool diff --git a/docs/tutorials/wiki2/tests.rst b/docs/tutorials/wiki2/tests.rst index c120b1c61..8fa8ea3ae 100644 --- a/docs/tutorials/wiki2/tests.rst +++ b/docs/tutorials/wiki2/tests.rst @@ -13,9 +13,9 @@ We write a test class for the model class ``Page`` and another test class for the ``initialize_sql`` function. To do so, we'll retain the ``tutorial.tests.ViewTests`` class provided as a -result of the ``pyramid_routesalchemy`` project generator. We'll add two -test classes: one for the ``Page`` model named ``PageModelTests``, one for the -``initialize_sql`` function named ``InitializeSqlTests``. +result of the ``alchemy`` scaffold. We'll add two test classes: one for the +``Page`` model named ``PageModelTests``, one for the ``initialize_sql`` +function named ``InitializeSqlTests``. Testing the Views ================= diff --git a/docs/whatsnew-1.0.rst b/docs/whatsnew-1.0.rst index 61d74a899..66cb9be3a 100644 --- a/docs/whatsnew-1.0.rst +++ b/docs/whatsnew-1.0.rst @@ -110,7 +110,7 @@ Scaffold Improvements (``starter``, ``routesalchemy``, ``alchemy``, ``zodb``) instead of ZCML configuration. -- The ``pyramid_zodb``, ``pyramid_routesalchemy`` and ``pyramid_alchemy`` +- The ``pyramid_zodb``, ``routesalchemy`` and ``pyramid_alchemy`` scaffolds now use a default "commit veto" hook when configuring the ``repoze.tm2`` transaction manager in ``development.ini``. This prevents a transaction from being committed when the response status code is within diff --git a/pyramid/compat.py b/pyramid/compat.py index 73f52b617..484cb7b97 100644 --- a/pyramid/compat.py +++ b/pyramid/compat.py @@ -13,14 +13,6 @@ try: except ImportError: # pragma: no cover import pickle -try: - import json -except ImportError: # pragma: no cover - try: - import simplejson as json - except NotImplementedError: - from django.utils import simplejson as json # GAE - # True if we are running on Python 3. PY3 = sys.version_info[0] == 3 @@ -40,11 +32,15 @@ else: long = long def text_(s, encoding='latin-1', errors='strict'): + """ If ``s`` is an instance of ``binary_type``, return + ``s.encode(encoding, errors)``, otherwise return ``s``""" if isinstance(s, binary_type): return s.decode(encoding, errors) return s # pragma: no cover def bytes_(s, encoding='latin-1', errors='strict'): + """ If ``s`` is an instance of ``text_type``, return + ``s.encode(encoding, errors)``, otherwise return ``s``""" if isinstance(s, text_type): return s.encode(encoding, errors) return s @@ -60,17 +56,38 @@ else: s = s.encode('ascii') return str(s) +ascii_native_.__doc__ = """ +Python 3: If ``s`` is an instance of ``text_type``, return +``s.encode('ascii')``, otherwise return ``str(s, 'ascii', 'strict')`` + +Python 2: If ``s`` is an instance of ``text_type``, return +``s.encode('ascii')``, otherwise return ``str(s)`` +""" + + if PY3: # pragma: no cover def native_(s, encoding='latin-1', errors='strict'): + """ If ``s`` is an instance of ``text_type``, return + ``s``, otherwise return ``str(s, encoding, errors)``""" if isinstance(s, text_type): return s return str(s, encoding, errors) else: def native_(s, encoding='latin-1', errors='strict'): + """ If ``s`` is an instance of ``text_type``, return + ``s.encode(encoding, errors)``, otherwise return ``str(s)``""" if isinstance(s, text_type): return s.encode(encoding, errors) return str(s) +native_.__doc__ = """ +Python 3: If ``s`` is an instance of ``text_type``, return ``s``, otherwise +return ``str(s, encoding, errors)`` + +Python 2: If ``s`` is an instance of ``text_type``, return +``s.encode(encoding, errors)``, otherwise return ``str(s)`` +""" + if PY3: # pragma: no cover from urllib import parse urlparse = parse @@ -108,7 +125,6 @@ if PY3: # pragma: no cover raise value - print_ = getattr(builtins, "print") del builtins else: # pragma: no cover @@ -130,51 +146,6 @@ else: # pragma: no cover """) - def print_(*args, **kwargs): - """The new-style print function.""" - fp = kwargs.pop("file", sys.stdout) - if fp is None: - return - def write(data): - if not isinstance(data, basestring): - data = str(data) - fp.write(data) - want_unicode = False - sep = kwargs.pop("sep", None) - if sep is not None: - if isinstance(sep, unicode): - want_unicode = True - elif not isinstance(sep, str): - raise TypeError("sep must be None or a string") - end = kwargs.pop("end", None) - if end is not None: - if isinstance(end, unicode): - want_unicode = True - elif not isinstance(end, str): - raise TypeError("end must be None or a string") - if kwargs: - raise TypeError("invalid keyword arguments to print()") - if not want_unicode: - for arg in args: - if isinstance(arg, unicode): - want_unicode = True - break - if want_unicode: - newline = unicode("\n") - space = unicode(" ") - else: - newline = "\n" - space = " " - if sep is None: - sep = space - if end is None: - end = newline - for i, arg in enumerate(args): - if i: - write(sep) - write(arg) - write(end) - if PY3: # pragma: no cover def iteritems_(d): return d.items() @@ -236,4 +207,9 @@ try: from StringIO import StringIO as NativeIO except ImportError: # pragma: no cover from io import StringIO as NativeIO + +# "json" is not an API; it's here to support older pyramid_debugtoolbar +# versions which attempt to import it +import json + diff --git a/pyramid/events.py b/pyramid/events.py index 5ef60ea89..4a2cd6240 100644 --- a/pyramid/events.py +++ b/pyramid/events.py @@ -167,7 +167,7 @@ WSGIApplicationCreatedEvent = ApplicationCreated # b/c (as of 1.0) @implementer(IBeforeRender) class BeforeRender(dict): """ - Subscribers to this event may introspect the and modify the set of + Subscribers to this event may introspect and modify the set of :term:`renderer globals` before they are passed to a :term:`renderer`. This event object iself has a dictionary-like interface that can be used for this purpose. For example:: @@ -185,20 +185,22 @@ class BeforeRender(dict): :class:`pyramid.config.Configurator.set_renderer_globals_factory`, if any, has injected its own keys into the renderer globals dictionary). - If a subscriber adds a key via ``__setitem__`` or that already exists in - the renderer globals dictionary, it will overwrite an older value that is - already in the globals dictionary. This can be problematic because event - subscribers to the BeforeRender event do not possess any relative - ordering. For maximum interoperability with other third-party - subscribers, if you write an event subscriber meant to be used as a - BeforeRender subscriber, your subscriber code will need to (using - ``.get`` or ``__contains__`` of the event object) ensure no value already - exists in the renderer globals dictionary before setting an overriding - value. + If a subscriber adds a key via ``__setitem__`` that already exists in + the renderer globals dictionary, it will overwrite the older value there. + This can be problematic because event subscribers to the BeforeRender + event do not possess any relative ordering. For maximum interoperability + with other third-party subscribers, if you write an event subscriber meant + to be used as a BeforeRender subscriber, your subscriber code will need to + ensure no value already exists in the renderer globals dictionary before + setting an overriding value (which can be done using ``.get`` or + ``__contains__`` of the event object). The event has an additional attribute named ``rendering_val``. This is the (non-system) value returned by a view or passed to ``render*`` as ``value``. This feature is new in Pyramid 1.2. + + For a description of the values present in the renderer globals dictionary, + see :ref:`renderer_system_values`. See also :class:`pyramid.interfaces.IBeforeRender`. """ diff --git a/pyramid/httpexceptions.py b/pyramid/httpexceptions.py index 4dbca7021..bd745df87 100644 --- a/pyramid/httpexceptions.py +++ b/pyramid/httpexceptions.py @@ -434,6 +434,8 @@ ${html_comment}''') def __init__(self, location='', detail=None, headers=None, comment=None, body_template=None, **kw): + if location is None: + raise ValueError("HTTP redirects need a location to redirect to.") super(_HTTPMove, self).__init__( detail=detail, headers=headers, comment=comment, body_template=body_template, location=location, **kw) diff --git a/pyramid/interfaces.py b/pyramid/interfaces.py index f08bd5fbb..fcdf72d01 100644 --- a/pyramid/interfaces.py +++ b/pyramid/interfaces.py @@ -344,7 +344,7 @@ class IDict(Interface): class IBeforeRender(IDict): """ - Subscribers to this event may introspect the and modify the set of + Subscribers to this event may introspect and modify the set of :term:`renderer globals` before they are passed to a :term:`renderer`. The event object itself provides a dictionary-like interface for adding and removing :term:`renderer globals`. The keys and values of the diff --git a/pyramid/path.py b/pyramid/path.py index 9c7be4c57..86c1c5857 100644 --- a/pyramid/path.py +++ b/pyramid/path.py @@ -25,7 +25,7 @@ def package_name(pkg_or_module): package name of the package in which the module lives. If this function is passed a package, return the dotted Python package name of the package itself.""" - if pkg_or_module is None: + if pkg_or_module is None or pkg_or_module.__name__ == '__main__': return '__main__' pkg_filename = pkg_or_module.__file__ pkg_name = pkg_or_module.__name__ diff --git a/pyramid/renderers.py b/pyramid/renderers.py index 073ce444d..3197ca6b8 100644 --- a/pyramid/renderers.py +++ b/pyramid/renderers.py @@ -1,3 +1,4 @@ +import json import os import pkg_resources import threading @@ -14,7 +15,6 @@ from pyramid.interfaces import ITemplateRenderer from pyramid.interfaces import IRendererInfo from pyramid.asset import asset_spec_from_abspath -from pyramid.compat import json from pyramid.compat import string_types from pyramid.compat import text_type from pyramid.decorator import reify diff --git a/pyramid/request.py b/pyramid/request.py index 1f62a481d..8f5dfbbb8 100644 --- a/pyramid/request.py +++ b/pyramid/request.py @@ -1,3 +1,5 @@ +import json + from zope.deprecation import deprecate from zope.deprecation.deprecation import deprecated from zope.interface import implementer @@ -10,12 +12,10 @@ from pyramid.interfaces import IResponse from pyramid.interfaces import ISessionFactory from pyramid.interfaces import IResponseFactory -from pyramid.compat import json from pyramid.compat import iterkeys_, itervalues_, iteritems_ from pyramid.compat import text_ from pyramid.compat import bytes_ from pyramid.compat import native_ -from pyramid.exceptions import ConfigurationError from pyramid.decorator import reify from pyramid.response import Response from pyramid.url import URLMethodsMixin diff --git a/pyramid/scaffolds/__init__.py b/pyramid/scaffolds/__init__.py index 4fecfc1e7..3fba05390 100644 --- a/pyramid/scaffolds/__init__.py +++ b/pyramid/scaffolds/__init__.py @@ -28,13 +28,9 @@ class StarterProjectTemplate(PyramidTemplate): class ZODBProjectTemplate(PyramidTemplate): _template_dir = 'zodb' - summary = 'Pyramid ZODB starter project' - -class RoutesAlchemyProjectTemplate(PyramidTemplate): - _template_dir = 'routesalchemy' - summary = 'Pyramid SQLAlchemy project using url dispatch (no traversal)' + summary = 'Pyramid ZODB project using traversal' class AlchemyProjectTemplate(PyramidTemplate): _template_dir = 'alchemy' - summary = 'Pyramid SQLAlchemy project using traversal' + summary = 'Pyramid SQLAlchemy project using url dispatch' diff --git a/pyramid/scaffolds/alchemy/+package+/__init__.py_tmpl b/pyramid/scaffolds/alchemy/+package+/__init__.py_tmpl index 8eb878688..24201912b 100755..100644 --- a/pyramid/scaffolds/alchemy/+package+/__init__.py_tmpl +++ b/pyramid/scaffolds/alchemy/+package+/__init__.py_tmpl @@ -1,19 +1,18 @@ from pyramid.config import Configurator from sqlalchemy import engine_from_config -from {{package}}.models import appmaker +from {{package}}.models import initialize_sql def main(global_config, **settings): - """ This function returns a WSGI application. + """ This function returns a Pyramid WSGI application. """ engine = engine_from_config(settings, 'sqlalchemy.') - get_root = appmaker(engine) - config = Configurator(settings=settings, root_factory=get_root) + initialize_sql(engine) + config = Configurator(settings=settings) config.add_static_view('static', '{{package}}:static', cache_max_age=3600) - config.add_view('{{package}}.views.view_root', - context='{{package}}.models.MyRoot', - renderer="templates/root.pt") - config.add_view('{{package}}.views.view_model', - context='{{package}}.models.MyModel', - renderer="templates/model.pt") + config.add_route('home', '/') + config.add_view('{{package}}.views.my_view', + route_name='home', + renderer='templates/mytemplate.pt') return config.make_wsgi_app() + diff --git a/pyramid/scaffolds/alchemy/+package+/models.py b/pyramid/scaffolds/alchemy/+package+/models.py index 2685da5bb..bef483d3a 100755..100644 --- a/pyramid/scaffolds/alchemy/+package+/models.py +++ b/pyramid/scaffolds/alchemy/+package+/models.py @@ -1,15 +1,14 @@ import transaction -from sqlalchemy.orm import scoped_session -from sqlalchemy.orm import sessionmaker - -from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy import Column +from sqlalchemy import Integer +from sqlalchemy import Unicode from sqlalchemy.exc import IntegrityError +from sqlalchemy.ext.declarative import declarative_base -from sqlalchemy import Integer -from sqlalchemy import Unicode -from sqlalchemy import Column +from sqlalchemy.orm import scoped_session +from sqlalchemy.orm import sessionmaker from zope.sqlalchemy import ZopeTransactionExtension @@ -26,45 +25,9 @@ class MyModel(Base): self.name = name self.value = value -class MyRoot(object): - __name__ = None - __parent__ = None - - def __getitem__(self, key): - session= DBSession() - try: - id = int(key) - except (ValueError, TypeError): - raise KeyError(key) - - item = session.query(MyModel).get(id) - if item is None: - raise KeyError(key) - - item.__parent__ = self - item.__name__ = key - return item - - def get(self, key, default=None): - try: - item = self.__getitem__(key) - except KeyError: - item = default - return item - - def __iter__(self): - session= DBSession() - query = session.query(MyModel) - return iter(query) - -root = MyRoot() - -def root_factory(request): - return root - def populate(): session = DBSession() - model = MyModel(name='test name', value=55) + model = MyModel(name='root', value=55) session.add(model) session.flush() transaction.commit() @@ -77,8 +40,3 @@ def initialize_sql(engine): populate() except IntegrityError: transaction.abort() - return DBSession - -def appmaker(engine): - initialize_sql(engine) - return root_factory diff --git a/pyramid/scaffolds/alchemy/+package+/templates/model.pt_tmpl b/pyramid/scaffolds/alchemy/+package+/templates/model.pt_tmpl deleted file mode 100644 index 83ddd768e..000000000 --- a/pyramid/scaffolds/alchemy/+package+/templates/model.pt_tmpl +++ /dev/null @@ -1,82 +0,0 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" xmlns:tal="http://xml.zope.org/namespaces/tal"> -<head> - <title>The Pyramid Web Application Development Framework</title> - <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/> - <meta name="keywords" content="python web application" /> - <meta name="description" content="pyramid web application" /> - <link rel="shortcut icon" href="${request.static_url('{{package}}:static/favicon.ico')}" /> - <link rel="stylesheet" href="${request.static_url('{{package}}:static/pylons.css')}" type="text/css" media="screen" charset="utf-8" /> - <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/nobile/stylesheet.css" media="screen" /> - <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/neuton/stylesheet.css" media="screen" /> - <!--[if lte IE 6]> - <link rel="stylesheet" href="${request.static_url('{{package}}:static/ie6.css')}" type="text/css" media="screen" charset="utf-8" /> - <![endif]--> -</head> -<body> - <div id="wrap"> - <div id="top"> - <div class="top align-center"> - <div><img src="${request.static_url('{{package}}:static/pyramid.png')}" width="750" height="169" alt="pyramid"/></div> - </div> - </div> - <div id="middle"> - <div class="middle align-center"> - <p class="app-welcome"> - Welcome to <span class="app-name">${project}</span>, an application generated by<br/> - the Pyramid web application development framework. - </p> - </div> - </div> - <div id="bottom"> - <div class="bottom"> - <div id="left" class="align-right"> - <h2>Search documentation</h2> - <form method="get" action="http://docs.pylonsproject.org/projects/pyramid/current/search.html"> - <input type="text" id="q" name="q" value="" /> - <input type="submit" id="x" value="Go" /> - </form> - <br/> - <p> - <b>Id:</b> ${item.id}<br /> - <b>Name:</b> ${item.name}<br /> - <b>Value:</b> ${item.value} - </p> - </div> - <div id="right" class="align-left"> - <h2>Pyramid links</h2> - <ul class="links"> - <li> - <a href="http://pylonsproject.org">Pylons Website</a> - </li> - <li> - <a href="http://docs.pylonsproject.org/projects/pyramid/current/#narrative-documentation">Narrative Documentation</a> - </li> - <li> - <a href="http://docs.pylonsproject.org/projects/pyramid/current/#api-documentation">API Documentation</a> - </li> - <li> - <a href="http://docs.pylonsproject.org/projects/pyramid/current/#tutorials">Tutorials</a> - </li> - <li> - <a href="http://docs.pylonsproject.org/projects/pyramid/current/#change-history">Change History</a> - </li> - <li> - <a href="http://docs.pylonsproject.org/projects/pyramid/current/#sample-applications">Sample Applications</a> - </li> - <li> - <a href="http://docs.pylonsproject.org/projects/pyramid/current/#support-and-development">Support and Development</a> - </li> - <li> - <a href="irc://irc.freenode.net#pyramid">IRC Channel</a> - </li> - </ul> - </div> - </div> - </div> - </div> - <div id="footer"> - <div class="footer">© Copyright 2008-2011, Agendaless Consulting.</div> - </div> -</body> -</html> diff --git a/pyramid/scaffolds/routesalchemy/+package+/templates/mytemplate.pt_tmpl b/pyramid/scaffolds/alchemy/+package+/templates/mytemplate.pt_tmpl index 3cd9c66a4..3cd9c66a4 100644 --- a/pyramid/scaffolds/routesalchemy/+package+/templates/mytemplate.pt_tmpl +++ b/pyramid/scaffolds/alchemy/+package+/templates/mytemplate.pt_tmpl diff --git a/pyramid/scaffolds/alchemy/+package+/templates/root.pt_tmpl b/pyramid/scaffolds/alchemy/+package+/templates/root.pt_tmpl deleted file mode 100644 index fc41ce20a..000000000 --- a/pyramid/scaffolds/alchemy/+package+/templates/root.pt_tmpl +++ /dev/null @@ -1,80 +0,0 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" xmlns:tal="http://xml.zope.org/namespaces/tal"> -<head> - <title>The Pyramid Web Application Development Framework</title> - <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/> - <meta name="keywords" content="python web application" /> - <meta name="description" content="pyramid web application" /> - <link rel="shortcut icon" href="${request.static_url('{{package}}:static/favicon.ico')}" /> - <link rel="stylesheet" href="${request.static_url('{{package}}:static/pylons.css')}" type="text/css" media="screen" charset="utf-8" /> - <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/nobile/stylesheet.css" media="screen" /> - <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/neuton/stylesheet.css" media="screen" /> - <!--[if lte IE 6]> - <link rel="stylesheet" href="${request.static_url('{{package}}:static/ie6.css')}" type="text/css" media="screen" charset="utf-8" /> - <![endif]--> -</head> -<body> - <div id="wrap"> - <div id="top"> - <div class="top align-center"> - <div><img src="${request.static_url('{{package}}:static/pyramid.png')}" width="750" height="169" alt="pyramid"/></div> - </div> - </div> - <div id="middle"> - <div class="middle align-center"> - <p class="app-welcome"> - Welcome to <span class="app-name">${project}</span>, an application generated by<br/> - the Pyramid web application development framework. - </p> - </div> - </div> - <div id="bottom"> - <div class="bottom"> - <div id="left" class="align-right"> - <h2>Search documentation</h2> - <form method="get" action="http://docs.pylonsproject.org/projects/pyramid/current/search.html"> - <input type="text" id="q" name="q" value="" /> - <input type="submit" id="x" value="Go" /> - </form> - <br/> - <p tal:repeat="item items"> - <a href="${item.id}">${item.name}</a> - </p> - </div> - <div id="right" class="align-left"> - <h2>Pyramid links</h2> - <ul class="links"> - <li> - <a href="http://pylonsproject.org">Pylons Website</a> - </li> - <li> - <a href="http://docs.pylonsproject.org/projects/pyramid/current/#narrative-documentation">Narrative Documentation</a> - </li> - <li> - <a href="http://docs.pylonsproject.org/projects/pyramid/current/#api-documentation">API Documentation</a> - </li> - <li> - <a href="http://docs.pylonsproject.org/projects/pyramid/current/#tutorials">Tutorials</a> - </li> - <li> - <a href="http://docs.pylonsproject.org/projects/pyramid/current/#change-history">Change History</a> - </li> - <li> - <a href="http://docs.pylonsproject.org/projects/pyramid/current/#sample-applications">Sample Applications</a> - </li> - <li> - <a href="http://docs.pylonsproject.org/projects/pyramid/current/#support-and-development">Support and Development</a> - </li> - <li> - <a href="irc://irc.freenode.net#pyramid">IRC Channel</a> - </li> - </ul> - </div> - </div> - </div> - </div> - <div id="footer"> - <div class="footer">© Copyright 2008-2011, Agendaless Consulting.</div> - </div> -</body> -</html> diff --git a/pyramid/scaffolds/alchemy/+package+/tests.py_tmpl b/pyramid/scaffolds/alchemy/+package+/tests.py_tmpl index 83b6a4739..29aea7258 100644 --- a/pyramid/scaffolds/alchemy/+package+/tests.py_tmpl +++ b/pyramid/scaffolds/alchemy/+package+/tests.py_tmpl @@ -1,5 +1,5 @@ import unittest - +from pyramid.config import Configurator from pyramid import testing def _initTestingDB(): @@ -8,52 +8,17 @@ def _initTestingDB(): session = initialize_sql(create_engine('sqlite://')) return session -class TestMyRoot(unittest.TestCase): +class TestMyView(unittest.TestCase): def setUp(self): self.config = testing.setUp() - self.session = _initTestingDB() + _initTestingDB() def tearDown(self): testing.tearDown() - self.session.remove() - - def _makeOne(self): - from {{package}}.models import MyRoot - return MyRoot() - - def test___getitem__hit(self): - from {{package}}.models import MyModel - root = self._makeOne() - first = root['1'] - self.assertEqual(first.__class__, MyModel) - self.assertEqual(first.__parent__, root) - self.assertEqual(first.__name__, '1') - - def test___getitem__miss(self): - root = self._makeOne() - self.assertRaises(KeyError, root.__getitem__, '100') - - def test___getitem__notint(self): - root = self._makeOne() - self.assertRaises(KeyError, root.__getitem__, 'notint') - - def test_get_hit(self): - from {{package}}.models import MyModel - root = self._makeOne() - first = root.get('1') - self.assertEqual(first.__class__, MyModel) - self.assertEqual(first.__parent__, root) - self.assertEqual(first.__name__, '1') - - def test_get_miss(self): - root = self._makeOne() - self.assertEqual(root.get('100', 'default'), 'default') - self.assertEqual(root.get('100'), None) - def test___iter__(self): - root = self._makeOne() - iterable = iter(root) - result = list(iterable) - self.assertEqual(len(result), 1) - model = result[0] - self.assertEqual(model.id, 1) + def test_it(self): + from {{package}}.views import my_view + request = testing.DummyRequest() + info = my_view(request) + self.assertEqual(info['root'].name, 'root') + self.assertEqual(info['project'], '{{project}}') diff --git a/pyramid/scaffolds/alchemy/+package+/views.py_tmpl b/pyramid/scaffolds/alchemy/+package+/views.py_tmpl index 12bce138e..45532b47b 100644 --- a/pyramid/scaffolds/alchemy/+package+/views.py_tmpl +++ b/pyramid/scaffolds/alchemy/+package+/views.py_tmpl @@ -1,5 +1,7 @@ -def view_root(context, request): - return {'items':list(context), 'project':'{{project}}'} +from {{package}}.models import DBSession +from {{package}}.models import MyModel -def view_model(context, request): - return {'item':context, 'project':'{{project}}'} +def my_view(request): + dbsession = DBSession() + root = dbsession.query(MyModel).filter(MyModel.name=='root').first() + return {'root':root, 'project':'{{project}}'} diff --git a/pyramid/scaffolds/alchemy/CHANGES.txt_tmpl b/pyramid/scaffolds/alchemy/CHANGES.txt_tmpl index 5b34f7803..35a34f332 100644 --- a/pyramid/scaffolds/alchemy/CHANGES.txt_tmpl +++ b/pyramid/scaffolds/alchemy/CHANGES.txt_tmpl @@ -1,4 +1,4 @@ -0.1 +0.0 --- -- Initial version +- Initial version diff --git a/pyramid/scaffolds/alchemy/setup.py_tmpl b/pyramid/scaffolds/alchemy/setup.py_tmpl index 68f8e6245..a2cdaac60 100644 --- a/pyramid/scaffolds/alchemy/setup.py_tmpl +++ b/pyramid/scaffolds/alchemy/setup.py_tmpl @@ -9,9 +9,10 @@ CHANGES = open(os.path.join(here, 'CHANGES.txt')).read() requires = [ 'pyramid', + 'SQLAlchemy', + 'transaction', 'pyramid_tm', 'pyramid_debugtoolbar', - 'sqlalchemy', 'zope.sqlalchemy', ] @@ -31,13 +32,12 @@ setup(name='{{project}}', author='', author_email='', url='', - keywords='web pylons pyramid', + keywords='web wsgi bfg pylons pyramid', packages=find_packages(), include_package_data=True, zip_safe=False, + test_suite='{{package}}', install_requires = requires, - tests_require = requires, - test_suite="{{package}}", entry_points = """\ [paste.app_factory] main = {{package}}:main diff --git a/pyramid/scaffolds/routesalchemy/+package+/__init__.py_tmpl b/pyramid/scaffolds/routesalchemy/+package+/__init__.py_tmpl deleted file mode 100644 index 24201912b..000000000 --- a/pyramid/scaffolds/routesalchemy/+package+/__init__.py_tmpl +++ /dev/null @@ -1,18 +0,0 @@ -from pyramid.config import Configurator -from sqlalchemy import engine_from_config - -from {{package}}.models import initialize_sql - -def main(global_config, **settings): - """ This function returns a Pyramid WSGI application. - """ - engine = engine_from_config(settings, 'sqlalchemy.') - initialize_sql(engine) - config = Configurator(settings=settings) - config.add_static_view('static', '{{package}}:static', cache_max_age=3600) - config.add_route('home', '/') - config.add_view('{{package}}.views.my_view', - route_name='home', - renderer='templates/mytemplate.pt') - return config.make_wsgi_app() - diff --git a/pyramid/scaffolds/routesalchemy/+package+/models.py b/pyramid/scaffolds/routesalchemy/+package+/models.py deleted file mode 100644 index bef483d3a..000000000 --- a/pyramid/scaffolds/routesalchemy/+package+/models.py +++ /dev/null @@ -1,42 +0,0 @@ -import transaction - -from sqlalchemy import Column -from sqlalchemy import Integer -from sqlalchemy import Unicode - -from sqlalchemy.exc import IntegrityError -from sqlalchemy.ext.declarative import declarative_base - -from sqlalchemy.orm import scoped_session -from sqlalchemy.orm import sessionmaker - -from zope.sqlalchemy import ZopeTransactionExtension - -DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension())) -Base = declarative_base() - -class MyModel(Base): - __tablename__ = 'models' - id = Column(Integer, primary_key=True) - name = Column(Unicode(255), unique=True) - value = Column(Integer) - - def __init__(self, name, value): - self.name = name - self.value = value - -def populate(): - session = DBSession() - model = MyModel(name='root', value=55) - session.add(model) - session.flush() - transaction.commit() - -def initialize_sql(engine): - DBSession.configure(bind=engine) - Base.metadata.bind = engine - Base.metadata.create_all(engine) - try: - populate() - except IntegrityError: - transaction.abort() diff --git a/pyramid/scaffolds/routesalchemy/+package+/static/favicon.ico b/pyramid/scaffolds/routesalchemy/+package+/static/favicon.ico Binary files differdeleted file mode 100644 index 71f837c9e..000000000 --- a/pyramid/scaffolds/routesalchemy/+package+/static/favicon.ico +++ /dev/null diff --git a/pyramid/scaffolds/routesalchemy/+package+/static/footerbg.png b/pyramid/scaffolds/routesalchemy/+package+/static/footerbg.png Binary files differdeleted file mode 100644 index 1fbc873da..000000000 --- a/pyramid/scaffolds/routesalchemy/+package+/static/footerbg.png +++ /dev/null diff --git a/pyramid/scaffolds/routesalchemy/+package+/static/headerbg.png b/pyramid/scaffolds/routesalchemy/+package+/static/headerbg.png Binary files differdeleted file mode 100644 index 0596f2020..000000000 --- a/pyramid/scaffolds/routesalchemy/+package+/static/headerbg.png +++ /dev/null diff --git a/pyramid/scaffolds/routesalchemy/+package+/static/ie6.css b/pyramid/scaffolds/routesalchemy/+package+/static/ie6.css deleted file mode 100644 index b7c8493d8..000000000 --- a/pyramid/scaffolds/routesalchemy/+package+/static/ie6.css +++ /dev/null @@ -1,8 +0,0 @@ -* html img, -* html .png{position:relative;behavior:expression((this.runtimeStyle.behavior="none")&&(this.pngSet?this.pngSet=true:(this.nodeName == "IMG" && this.src.toLowerCase().indexOf('.png')>-1?(this.runtimeStyle.backgroundImage = "none", -this.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.src + "',sizingMethod='image')", -this.src = "static/transparent.gif"):(this.origBg = this.origBg? this.origBg :this.currentStyle.backgroundImage.toString().replace('url("','').replace('")',''), -this.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.origBg + "',sizingMethod='crop')", -this.runtimeStyle.backgroundImage = "none")),this.pngSet=true) -);} -#wrap{display:table;height:100%} diff --git a/pyramid/scaffolds/routesalchemy/+package+/static/middlebg.png b/pyramid/scaffolds/routesalchemy/+package+/static/middlebg.png Binary files differdeleted file mode 100644 index 2369cfb7d..000000000 --- a/pyramid/scaffolds/routesalchemy/+package+/static/middlebg.png +++ /dev/null diff --git a/pyramid/scaffolds/routesalchemy/+package+/static/pylons.css b/pyramid/scaffolds/routesalchemy/+package+/static/pylons.css deleted file mode 100644 index c54499ddd..000000000 --- a/pyramid/scaffolds/routesalchemy/+package+/static/pylons.css +++ /dev/null @@ -1,65 +0,0 @@ -html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,font,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td{margin:0;padding:0;border:0;outline:0;font-size:100%;/* 16px */ -vertical-align:baseline;background:transparent;} -body{line-height:1;} -ol,ul{list-style:none;} -blockquote,q{quotes:none;} -blockquote:before,blockquote:after,q:before,q:after{content:'';content:none;} -:focus{outline:0;} -ins{text-decoration:none;} -del{text-decoration:line-through;} -table{border-collapse:collapse;border-spacing:0;} -sub{vertical-align:sub;font-size:smaller;line-height:normal;} -sup{vertical-align:super;font-size:smaller;line-height:normal;} -ul,menu,dir{display:block;list-style-type:disc;margin:1em 0;padding-left:40px;} -ol{display:block;list-style-type:decimal-leading-zero;margin:1em 0;padding-left:40px;} -li{display:list-item;} -ul ul,ul ol,ul dir,ul menu,ul dl,ol ul,ol ol,ol dir,ol menu,ol dl,dir ul,dir ol,dir dir,dir menu,dir dl,menu ul,menu ol,menu dir,menu menu,menu dl,dl ul,dl ol,dl dir,dl menu,dl dl{margin-top:0;margin-bottom:0;} -ol ul,ul ul,menu ul,dir ul,ol menu,ul menu,menu menu,dir menu,ol dir,ul dir,menu dir,dir dir{list-style-type:circle;} -ol ol ul,ol ul ul,ol menu ul,ol dir ul,ol ol menu,ol ul menu,ol menu menu,ol dir menu,ol ol dir,ol ul dir,ol menu dir,ol dir dir,ul ol ul,ul ul ul,ul menu ul,ul dir ul,ul ol menu,ul ul menu,ul menu menu,ul dir menu,ul ol dir,ul ul dir,ul menu dir,ul dir dir,menu ol ul,menu ul ul,menu menu ul,menu dir ul,menu ol menu,menu ul menu,menu menu menu,menu dir menu,menu ol dir,menu ul dir,menu menu dir,menu dir dir,dir ol ul,dir ul ul,dir menu ul,dir dir ul,dir ol menu,dir ul menu,dir menu menu,dir dir menu,dir ol dir,dir ul dir,dir menu dir,dir dir dir{list-style-type:square;} -.hidden{display:none;} -p{line-height:1.5em;} -h1{font-size:1.75em;line-height:1.7em;font-family:helvetica,verdana;} -h2{font-size:1.5em;line-height:1.7em;font-family:helvetica,verdana;} -h3{font-size:1.25em;line-height:1.7em;font-family:helvetica,verdana;} -h4{font-size:1em;line-height:1.7em;font-family:helvetica,verdana;} -html,body{width:100%;height:100%;} -body{margin:0;padding:0;background-color:#ffffff;position:relative;font:16px/24px "NobileRegular","Lucida Grande",Lucida,Verdana,sans-serif;} -a{color:#1b61d6;text-decoration:none;} -a:hover{color:#e88f00;text-decoration:underline;} -body h1, -body h2, -body h3, -body h4, -body h5, -body h6{font-family:"NeutonRegular","Lucida Grande",Lucida,Verdana,sans-serif;font-weight:normal;color:#373839;font-style:normal;} -#wrap{min-height:100%;} -#header,#footer{width:100%;color:#ffffff;height:40px;position:absolute;text-align:center;line-height:40px;overflow:hidden;font-size:12px;vertical-align:middle;} -#header{background:#000000;top:0;font-size:14px;} -#footer{bottom:0;background:#000000 url(footerbg.png) repeat-x 0 top;position:relative;margin-top:-40px;clear:both;} -.header,.footer{width:750px;margin-right:auto;margin-left:auto;} -.wrapper{width:100%} -#top,#top-small,#bottom{width:100%;} -#top{color:#000000;height:230px;background:#ffffff url(headerbg.png) repeat-x 0 top;position:relative;} -#top-small{color:#000000;height:60px;background:#ffffff url(headerbg.png) repeat-x 0 top;position:relative;} -#bottom{color:#222;background-color:#ffffff;} -.top,.top-small,.middle,.bottom{width:750px;margin-right:auto;margin-left:auto;} -.top{padding-top:40px;} -.top-small{padding-top:10px;} -#middle{width:100%;height:100px;background:url(middlebg.png) repeat-x;border-top:2px solid #ffffff;border-bottom:2px solid #b2b2b2;} -.app-welcome{margin-top:25px;} -.app-name{color:#000000;font-weight:bold;} -.bottom{padding-top:50px;} -#left{width:350px;float:left;padding-right:25px;} -#right{width:350px;float:right;padding-left:25px;} -.align-left{text-align:left;} -.align-right{text-align:right;} -.align-center{text-align:center;} -ul.links{margin:0;padding:0;} -ul.links li{list-style-type:none;font-size:14px;} -form{border-style:none;} -fieldset{border-style:none;} -input{color:#222;border:1px solid #ccc;font-family:sans-serif;font-size:12px;line-height:16px;} -input[type=text],input[type=password]{width:205px;} -input[type=submit]{background-color:#ddd;font-weight:bold;} -/*Opera Fix*/ -body:before{content:"";height:100%;float:left;width:0;margin-top:-32767px;} diff --git a/pyramid/scaffolds/routesalchemy/+package+/static/pyramid-small.png b/pyramid/scaffolds/routesalchemy/+package+/static/pyramid-small.png Binary files differdeleted file mode 100644 index a5bc0ade7..000000000 --- a/pyramid/scaffolds/routesalchemy/+package+/static/pyramid-small.png +++ /dev/null diff --git a/pyramid/scaffolds/routesalchemy/+package+/static/pyramid.png b/pyramid/scaffolds/routesalchemy/+package+/static/pyramid.png Binary files differdeleted file mode 100644 index 347e05549..000000000 --- a/pyramid/scaffolds/routesalchemy/+package+/static/pyramid.png +++ /dev/null diff --git a/pyramid/scaffolds/routesalchemy/+package+/static/transparent.gif b/pyramid/scaffolds/routesalchemy/+package+/static/transparent.gif Binary files differdeleted file mode 100644 index 0341802e5..000000000 --- a/pyramid/scaffolds/routesalchemy/+package+/static/transparent.gif +++ /dev/null diff --git a/pyramid/scaffolds/routesalchemy/+package+/tests.py_tmpl b/pyramid/scaffolds/routesalchemy/+package+/tests.py_tmpl deleted file mode 100644 index 29aea7258..000000000 --- a/pyramid/scaffolds/routesalchemy/+package+/tests.py_tmpl +++ /dev/null @@ -1,24 +0,0 @@ -import unittest -from pyramid.config import Configurator -from pyramid import testing - -def _initTestingDB(): - from sqlalchemy import create_engine - from {{package}}.models import initialize_sql - session = initialize_sql(create_engine('sqlite://')) - return session - -class TestMyView(unittest.TestCase): - def setUp(self): - self.config = testing.setUp() - _initTestingDB() - - def tearDown(self): - testing.tearDown() - - def test_it(self): - from {{package}}.views import my_view - request = testing.DummyRequest() - info = my_view(request) - self.assertEqual(info['root'].name, 'root') - self.assertEqual(info['project'], '{{project}}') diff --git a/pyramid/scaffolds/routesalchemy/+package+/views.py_tmpl b/pyramid/scaffolds/routesalchemy/+package+/views.py_tmpl deleted file mode 100644 index 45532b47b..000000000 --- a/pyramid/scaffolds/routesalchemy/+package+/views.py_tmpl +++ /dev/null @@ -1,7 +0,0 @@ -from {{package}}.models import DBSession -from {{package}}.models import MyModel - -def my_view(request): - dbsession = DBSession() - root = dbsession.query(MyModel).filter(MyModel.name=='root').first() - return {'root':root, 'project':'{{project}}'} diff --git a/pyramid/scaffolds/routesalchemy/CHANGES.txt_tmpl b/pyramid/scaffolds/routesalchemy/CHANGES.txt_tmpl deleted file mode 100644 index 35a34f332..000000000 --- a/pyramid/scaffolds/routesalchemy/CHANGES.txt_tmpl +++ /dev/null @@ -1,4 +0,0 @@ -0.0 ---- - -- Initial version diff --git a/pyramid/scaffolds/routesalchemy/MANIFEST.in_tmpl b/pyramid/scaffolds/routesalchemy/MANIFEST.in_tmpl deleted file mode 100644 index 0ff6eb7a0..000000000 --- a/pyramid/scaffolds/routesalchemy/MANIFEST.in_tmpl +++ /dev/null @@ -1,2 +0,0 @@ -include *.txt *.ini *.cfg *.rst -recursive-include {{package}} *.ico *.png *.css *.gif *.jpg *.pt *.txt *.mak *.mako *.js *.html *.xml diff --git a/pyramid/scaffolds/routesalchemy/README.txt_tmpl b/pyramid/scaffolds/routesalchemy/README.txt_tmpl deleted file mode 100644 index 40f98d14a..000000000 --- a/pyramid/scaffolds/routesalchemy/README.txt_tmpl +++ /dev/null @@ -1 +0,0 @@ -{{project}} README diff --git a/pyramid/scaffolds/routesalchemy/development.ini_tmpl b/pyramid/scaffolds/routesalchemy/development.ini_tmpl deleted file mode 100644 index d804a0b0e..000000000 --- a/pyramid/scaffolds/routesalchemy/development.ini_tmpl +++ /dev/null @@ -1,57 +0,0 @@ -[app:main] -use = egg:{{project}} - -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 -pyramid.includes = pyramid_debugtoolbar - pyramid_tm - -sqlalchemy.url = sqlite:///%(here)s/{{project}}.db - -[server:main] -use = egg:pyramid#wsgiref -host = 0.0.0.0 -port = 6543 - -# Begin logging configuration - -[loggers] -keys = root, {{package_logger}}, sqlalchemy - -[handlers] -keys = console - -[formatters] -keys = generic - -[logger_root] -level = INFO -handlers = console - -[logger_{{package_logger}}] -level = DEBUG -handlers = -qualname = {{package}} - -[logger_sqlalchemy] -level = INFO -handlers = -qualname = sqlalchemy.engine -# "level = INFO" logs SQL queries. -# "level = DEBUG" logs SQL queries and results. -# "level = WARN" logs neither. (Recommended for production systems.) - -[handler_console] -class = StreamHandler -args = (sys.stderr,) -level = NOTSET -formatter = generic - -[formatter_generic] -format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s - -# End logging configuration diff --git a/pyramid/scaffolds/routesalchemy/production.ini_tmpl b/pyramid/scaffolds/routesalchemy/production.ini_tmpl deleted file mode 100644 index 7350ce25f..000000000 --- a/pyramid/scaffolds/routesalchemy/production.ini_tmpl +++ /dev/null @@ -1,56 +0,0 @@ -[app:main] -use = egg:{{project}} - -pyramid.reload_templates = false -pyramid.debug_authorization = false -pyramid.debug_notfound = false -pyramid.debug_routematch = false -pyramid.debug_templates = false -pyramid.default_locale_name = en -pyramid.includes = pyramid_tm - -sqlalchemy.url = sqlite:///%(here)s/{{project}}.db - -[server:main] -use = egg:pyramid#wsgiref -host = 0.0.0.0 -port = 6543 - -# Begin logging configuration - -[loggers] -keys = root, {{package_logger}}, sqlalchemy - -[handlers] -keys = console - -[formatters] -keys = generic - -[logger_root] -level = WARN -handlers = console - -[logger_{{package_logger}}] -level = WARN -handlers = -qualname = {{package}} - -[logger_sqlalchemy] -level = WARN -handlers = -qualname = sqlalchemy.engine -# "level = INFO" logs SQL queries. -# "level = DEBUG" logs SQL queries and results. -# "level = WARN" logs neither. (Recommended for production systems.) - -[handler_console] -class = StreamHandler -args = (sys.stderr,) -level = NOTSET -formatter = generic - -[formatter_generic] -format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s - -# End logging configuration diff --git a/pyramid/scaffolds/routesalchemy/setup.cfg_tmpl b/pyramid/scaffolds/routesalchemy/setup.cfg_tmpl deleted file mode 100644 index 5bec29823..000000000 --- a/pyramid/scaffolds/routesalchemy/setup.cfg_tmpl +++ /dev/null @@ -1,27 +0,0 @@ -[nosetests] -match=^test -nocapture=1 -cover-package={{package}} -with-coverage=1 -cover-erase=1 - -[compile_catalog] -directory = {{package}}/locale -domain = {{project}} -statistics = true - -[extract_messages] -add_comments = TRANSLATORS: -output_file = {{package}}/locale/{{project}}.pot -width = 80 - -[init_catalog] -domain = {{project}} -input_file = {{package}}/locale/{{project}}.pot -output_dir = {{package}}/locale - -[update_catalog] -domain = {{project}} -input_file = {{package}}/locale/{{project}}.pot -output_dir = {{package}}/locale -previous = true diff --git a/pyramid/scaffolds/routesalchemy/setup.py_tmpl b/pyramid/scaffolds/routesalchemy/setup.py_tmpl deleted file mode 100644 index a2cdaac60..000000000 --- a/pyramid/scaffolds/routesalchemy/setup.py_tmpl +++ /dev/null @@ -1,46 +0,0 @@ -import os -import sys - -from setuptools import setup, find_packages - -here = os.path.abspath(os.path.dirname(__file__)) -README = open(os.path.join(here, 'README.txt')).read() -CHANGES = open(os.path.join(here, 'CHANGES.txt')).read() - -requires = [ - 'pyramid', - 'SQLAlchemy', - 'transaction', - 'pyramid_tm', - 'pyramid_debugtoolbar', - 'zope.sqlalchemy', - ] - -if sys.version_info[:3] < (2,5,0): - requires.append('pysqlite') - -setup(name='{{project}}', - version='0.0', - description='{{project}}', - long_description=README + '\n\n' + CHANGES, - classifiers=[ - "Programming Language :: Python", - "Framework :: Pylons", - "Topic :: Internet :: WWW/HTTP", - "Topic :: Internet :: WWW/HTTP :: WSGI :: Application", - ], - author='', - author_email='', - url='', - keywords='web wsgi bfg pylons pyramid', - packages=find_packages(), - include_package_data=True, - zip_safe=False, - test_suite='{{package}}', - install_requires = requires, - entry_points = """\ - [paste.app_factory] - main = {{package}}:main - """, - ) - diff --git a/pyramid/scaffolds/starter/+package+/__init__.py b/pyramid/scaffolds/starter/+package+/__init__.py new file mode 100644 index 000000000..ddcdd7162 --- /dev/null +++ b/pyramid/scaffolds/starter/+package+/__init__.py @@ -0,0 +1,10 @@ +from pyramid.config import Configurator +from .resources import Root + +def main(global_config, **settings): + """ This function returns a Pyramid WSGI application. + """ + config = Configurator(root_factory=Root, settings=settings) + config.add_static_view('static', 'static', cache_max_age=3600) + config.scan() + return config.make_wsgi_app() diff --git a/pyramid/scaffolds/starter/+package+/__init__.py_tmpl b/pyramid/scaffolds/starter/+package+/__init__.py_tmpl deleted file mode 100644 index d763b2435..000000000 --- a/pyramid/scaffolds/starter/+package+/__init__.py_tmpl +++ /dev/null @@ -1,12 +0,0 @@ -from pyramid.config import Configurator -from {{package}}.resources import Root - -def main(global_config, **settings): - """ This function returns a Pyramid WSGI application. - """ - config = Configurator(root_factory=Root, settings=settings) - config.add_view('{{package}}.views.my_view', - context='{{package}}:resources.Root', - renderer='{{package}}:templates/mytemplate.pt') - config.add_static_view('static', '{{package}}:static', cache_max_age=3600) - return config.make_wsgi_app() diff --git a/pyramid/scaffolds/zodb/+package+/templates/mytemplate.pt_tmpl b/pyramid/scaffolds/starter/+package+/templates/mytemplate.pt index 3cd9c66a4..ab698123e 100644 --- a/pyramid/scaffolds/zodb/+package+/templates/mytemplate.pt_tmpl +++ b/pyramid/scaffolds/starter/+package+/templates/mytemplate.pt @@ -5,19 +5,19 @@ <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/> <meta name="keywords" content="python web application" /> <meta name="description" content="pyramid web application" /> - <link rel="shortcut icon" href="${request.static_url('{{package}}:static/favicon.ico')}" /> - <link rel="stylesheet" href="${request.static_url('{{package}}:static/pylons.css')}" type="text/css" media="screen" charset="utf-8" /> + <link rel="shortcut icon" href="/static/favicon.ico" /> + <link rel="stylesheet" href="/static/pylons.css" type="text/css" media="screen" charset="utf-8" /> <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/nobile/stylesheet.css" media="screen" /> <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/neuton/stylesheet.css" media="screen" /> <!--[if lte IE 6]> - <link rel="stylesheet" href="${request.static_url('{{package}}:static/ie6.css')}" type="text/css" media="screen" charset="utf-8" /> + <link rel="stylesheet" href="/static/ie6.css" type="text/css" media="screen" charset="utf-8" /> <![endif]--> </head> <body> <div id="wrap"> <div id="top"> <div class="top align-center"> - <div><img src="${request.static_url('{{package}}:static/pyramid.png')}" width="750" height="169" alt="pyramid"/></div> + <div><img src="/static/pyramid.png" width="750" height="169" alt="pyramid"/></div> </div> </div> <div id="middle"> diff --git a/pyramid/scaffolds/starter/+package+/tests.py_tmpl b/pyramid/scaffolds/starter/+package+/tests.py_tmpl index 1627bf015..401260efb 100644 --- a/pyramid/scaffolds/starter/+package+/tests.py_tmpl +++ b/pyramid/scaffolds/starter/+package+/tests.py_tmpl @@ -10,7 +10,7 @@ class ViewTests(unittest.TestCase): testing.tearDown() def test_my_view(self): - from {{package}}.views import my_view + from .views import my_view request = testing.DummyRequest() info = my_view(request) self.assertEqual(info['project'], '{{project}}') diff --git a/pyramid/scaffolds/starter/+package+/views.py_tmpl b/pyramid/scaffolds/starter/+package+/views.py_tmpl index 12ed8832d..b02b2e79e 100644 --- a/pyramid/scaffolds/starter/+package+/views.py_tmpl +++ b/pyramid/scaffolds/starter/+package+/views.py_tmpl @@ -1,2 +1,6 @@ +from pyramid.view import view_config +from .resources import Root + +@view_config(context=Root, renderer='templates/mytemplate.pt') def my_view(request): return {'project':'{{project}}'} diff --git a/pyramid/scaffolds/tests.py b/pyramid/scaffolds/tests.py index 3b257a18a..8efbb934b 100644 --- a/pyramid/scaffolds/tests.py +++ b/pyramid/scaffolds/tests.py @@ -66,7 +66,7 @@ class TemplateTest(object): os.chdir(self.old_cwd) if __name__ == '__main__': # pragma: no cover - templates = ['starter', 'alchemy', 'routesalchemy',] + templates = ['starter', 'alchemy',] if sys.version_info >= (2, 6) and sys.version_info < (3, 0): templates.append('zodb') diff --git a/pyramid/scaffolds/zodb/+package+/__init__.py_tmpl b/pyramid/scaffolds/zodb/+package+/__init__.py index 935121888..b63933fc5 100644 --- a/pyramid/scaffolds/zodb/+package+/__init__.py_tmpl +++ b/pyramid/scaffolds/zodb/+package+/__init__.py @@ -1,6 +1,6 @@ from pyramid.config import Configurator from pyramid_zodbconn import get_connection -from {{package}}.models import appmaker +from .models import appmaker def root_factory(request): conn = get_connection(request) @@ -10,6 +10,6 @@ def main(global_config, **settings): """ This function returns a Pyramid WSGI application. """ config = Configurator(root_factory=root_factory, settings=settings) - config.add_static_view('static', '{{package}}:static', cache_max_age=3600) - config.scan('{{package}}') + config.add_static_view('static', 'static', cache_max_age=3600) + config.scan() return config.make_wsgi_app() diff --git a/pyramid/scaffolds/starter/+package+/templates/mytemplate.pt_tmpl b/pyramid/scaffolds/zodb/+package+/templates/mytemplate.pt index 3cd9c66a4..ab698123e 100644 --- a/pyramid/scaffolds/starter/+package+/templates/mytemplate.pt_tmpl +++ b/pyramid/scaffolds/zodb/+package+/templates/mytemplate.pt @@ -5,19 +5,19 @@ <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/> <meta name="keywords" content="python web application" /> <meta name="description" content="pyramid web application" /> - <link rel="shortcut icon" href="${request.static_url('{{package}}:static/favicon.ico')}" /> - <link rel="stylesheet" href="${request.static_url('{{package}}:static/pylons.css')}" type="text/css" media="screen" charset="utf-8" /> + <link rel="shortcut icon" href="/static/favicon.ico" /> + <link rel="stylesheet" href="/static/pylons.css" type="text/css" media="screen" charset="utf-8" /> <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/nobile/stylesheet.css" media="screen" /> <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/neuton/stylesheet.css" media="screen" /> <!--[if lte IE 6]> - <link rel="stylesheet" href="${request.static_url('{{package}}:static/ie6.css')}" type="text/css" media="screen" charset="utf-8" /> + <link rel="stylesheet" href="/static/ie6.css" type="text/css" media="screen" charset="utf-8" /> <![endif]--> </head> <body> <div id="wrap"> <div id="top"> <div class="top align-center"> - <div><img src="${request.static_url('{{package}}:static/pyramid.png')}" width="750" height="169" alt="pyramid"/></div> + <div><img src="/static/pyramid.png" width="750" height="169" alt="pyramid"/></div> </div> </div> <div id="middle"> diff --git a/pyramid/scaffolds/zodb/+package+/tests.py_tmpl b/pyramid/scaffolds/zodb/+package+/tests.py_tmpl index 1627bf015..401260efb 100644 --- a/pyramid/scaffolds/zodb/+package+/tests.py_tmpl +++ b/pyramid/scaffolds/zodb/+package+/tests.py_tmpl @@ -10,7 +10,7 @@ class ViewTests(unittest.TestCase): testing.tearDown() def test_my_view(self): - from {{package}}.views import my_view + from .views import my_view request = testing.DummyRequest() info = my_view(request) self.assertEqual(info['project'], '{{project}}') diff --git a/pyramid/scaffolds/zodb/+package+/views.py_tmpl b/pyramid/scaffolds/zodb/+package+/views.py_tmpl index d4a1147c6..083798095 100644 --- a/pyramid/scaffolds/zodb/+package+/views.py_tmpl +++ b/pyramid/scaffolds/zodb/+package+/views.py_tmpl @@ -1,6 +1,6 @@ from pyramid.view import view_config -from {{package}}.models import MyModel +from .models import MyModel -@view_config(context=MyModel, renderer='{{package}}:templates/mytemplate.pt') +@view_config(context=MyModel, renderer='templates/mytemplate.pt') def my_view(request): return {'project':'{{project}}'} diff --git a/pyramid/scripts/pcreate.py b/pyramid/scripts/pcreate.py index 47a709af4..f559e4f17 100644 --- a/pyramid/scripts/pcreate.py +++ b/pyramid/scripts/pcreate.py @@ -4,6 +4,7 @@ import optparse import os +import os.path import pkg_resources import re import sys @@ -64,8 +65,8 @@ class PCreateCommand(object): def render_scaffolds(self): options = self.options args = self.args - project_name = args[0].lstrip(os.path.sep) - output_dir = os.path.normpath(os.path.join(os.getcwd(), project_name)) + project_name = os.path.basename(args[0]) + output_dir = os.path.abspath(os.path.normpath(args[0])) pkg_name = _bad_chars_re.sub('', project_name.lower()) safe_name = pkg_resources.safe_name(project_name) egg_name = pkg_resources.to_filename(safe_name) diff --git a/pyramid/scripts/proutes.py b/pyramid/scripts/proutes.py index 0e0b345a8..570417e95 100644 --- a/pyramid/scripts/proutes.py +++ b/pyramid/scripts/proutes.py @@ -1,7 +1,6 @@ import optparse import sys -from pyramid.compat import print_ from pyramid.paster import bootstrap def main(argv=sys.argv, quiet=False): @@ -42,7 +41,7 @@ class PRoutesCommand(object): def out(self, msg): # pragma: no cover if not self.quiet: - print_(msg) + print(msg) def run(self, quiet=False): if not self.args: @@ -65,14 +64,17 @@ class PRoutesCommand(object): self.out( fmt % ('-'*len('Name'), '-'*len('Pattern'), '-'*len('View'))) for route in routes: + pattern = route.pattern + if not pattern.startswith('/'): + pattern = '/' + pattern request_iface = registry.queryUtility(IRouteRequest, name=route.name) view_callable = None if (request_iface is None) or (route.factory is not None): - self.out(fmt % (route.name, route.pattern, '<unknown>')) + self.out(fmt % (route.name, pattern, '<unknown>')) else: view_callable = registry.adapters.lookup( (IViewClassifier, request_iface, Interface), IView, name='', default=None) - self.out(fmt % (route.name, route.pattern, view_callable)) + self.out(fmt % (route.name, pattern, view_callable)) diff --git a/pyramid/scripts/pserve.py b/pyramid/scripts/pserve.py index a2eded80a..c6e8f0374 100644 --- a/pyramid/scripts/pserve.py +++ b/pyramid/scripts/pserve.py @@ -173,8 +173,8 @@ class PServeCommand(object): if self.verbose > 1: self.out('Running reloading file monitor') install_reloader(int(self.options.reload_interval)) - if self.requires_config_file: - watch_file(self.args[0]) + # if self.requires_config_file: + # watch_file(self.args[0]) else: return self.restart_with_reloader() diff --git a/pyramid/scripts/ptweens.py b/pyramid/scripts/ptweens.py index 81b4ae307..5bc0c7fbe 100644 --- a/pyramid/scripts/ptweens.py +++ b/pyramid/scripts/ptweens.py @@ -7,8 +7,6 @@ from pyramid.tweens import MAIN from pyramid.tweens import INGRESS from pyramid.paster import bootstrap -from pyramid.compat import print_ - def main(argv=sys.argv, quiet=False): command = PTweensCommand(argv, quiet) command.run() @@ -49,7 +47,7 @@ class PTweensCommand(object): def out(self, msg): # pragma: no cover if not self.quiet: - print_(msg) + print(msg) def show_chain(self, chain): fmt = '%-10s %-65s' diff --git a/pyramid/scripts/pviews.py b/pyramid/scripts/pviews.py index 2ff9d6ed2..38d510542 100644 --- a/pyramid/scripts/pviews.py +++ b/pyramid/scripts/pviews.py @@ -1,7 +1,6 @@ import optparse import sys -from pyramid.compat import print_ from pyramid.interfaces import IMultiView from pyramid.paster import bootstrap @@ -41,7 +40,7 @@ class PViewsCommand(object): def out(self, msg): # pragma: no cover if not self.quiet: - print_(msg) + print(msg) def _find_multi_routes(self, mapper, request): infos = [] diff --git a/pyramid/settings.py b/pyramid/settings.py index de91042eb..11587a8be 100644 --- a/pyramid/settings.py +++ b/pyramid/settings.py @@ -44,8 +44,13 @@ def aslist_cronly(value): value = filter(None, [x.strip() for x in value.splitlines()]) return list(value) -def aslist(value): +def aslist(value, flatten=True): + """ Return a list of strings, separating the input based on newlines + and, if flatten=True (the default), also split on spaces within + each line.""" values = aslist_cronly(value) + if not flatten: + return values result = [] for value in values: subvalues = value.split() diff --git a/pyramid/testing.py b/pyramid/testing.py index e1011f5b4..0e27c301e 100644 --- a/pyramid/testing.py +++ b/pyramid/testing.py @@ -620,7 +620,11 @@ class DummySession(dict): return token def get_csrf_token(self): - return self.get('_csrft_', None) + token = self.get('_csrft_', None) + if token is None: + token = self.new_csrf_token() + return token + @implementer(IRequest) class DummyRequest(DeprecatedRequestMethodsMixin, URLMethodsMixin, diff --git a/pyramid/tests/test_docs.py b/pyramid/tests/test_docs.py index eba95b210..0735a494a 100644 --- a/pyramid/tests/test_docs.py +++ b/pyramid/tests/test_docs.py @@ -1,5 +1,4 @@ import unittest -from pyramid.compat import print_ if 0: # no released version of manuel actually works with :lineno: @@ -32,5 +31,5 @@ if 0: if filename.endswith('.rst'): docs.append(os.path.join(root, filename)) - print_(path) + print(path) return manuel.testing.TestSuite(m, *docs) diff --git a/pyramid/tests/test_httpexceptions.py b/pyramid/tests/test_httpexceptions.py index 927d27733..84485fadc 100644 --- a/pyramid/tests/test_httpexceptions.py +++ b/pyramid/tests/test_httpexceptions.py @@ -294,6 +294,12 @@ class Test_HTTPMove(unittest.TestCase): from pyramid.httpexceptions import _HTTPMove return _HTTPMove(*arg, **kw) + def test_it_location_none_valueerrors(self): + # Constructing a HTTPMove instance with location=None should + # throw a ValueError from __init__ so that a more-confusing + # exception won't be thrown later from .prepare(environ) + self.assertRaises(ValueError, self._makeOne, location=None) + def test_it_location_not_passed(self): exc = self._makeOne() self.assertEqual(exc.location, '') diff --git a/pyramid/tests/test_path.py b/pyramid/tests/test_path.py index c2261d223..29b9baf1f 100644 --- a/pyramid/tests/test_path.py +++ b/pyramid/tests/test_path.py @@ -162,6 +162,11 @@ class TestPackageName(unittest.TestCase): def test_it_None(self): result = self._callFUT(None) self.assertEqual(result, '__main__') + + def test_it_main(self): + import __main__ + result = self._callFUT(__main__) + self.assertEqual(result, '__main__') class DummyPackageOrModule: def __init__(self, real_package_or_module, raise_exc=None): diff --git a/pyramid/tests/test_request.py b/pyramid/tests/test_request.py index 9d498e12f..546f670c0 100644 --- a/pyramid/tests/test_request.py +++ b/pyramid/tests/test_request.py @@ -249,7 +249,7 @@ class TestRequest(unittest.TestCase): self.assertEqual(request.json_body, {'a':1}) def test_json_body_alternate_charset(self): - from pyramid.compat import json + import json request = self._makeOne({'REQUEST_METHOD':'POST'}) inp = text_( b'/\xe6\xb5\x81\xe8\xa1\x8c\xe8\xb6\x8b\xe5\x8a\xbf', diff --git a/pyramid/tests/test_scripts/test_pcreate.py b/pyramid/tests/test_scripts/test_pcreate.py index cdd0daf2e..363808a1e 100644 --- a/pyramid/tests/test_scripts/test_pcreate.py +++ b/pyramid/tests/test_scripts/test_pcreate.py @@ -71,6 +71,22 @@ class TestPCreateCommand(unittest.TestCase): scaffold.vars, {'project': 'Distro', 'egg': 'Distro', 'package': 'distro'}) + def test_known_scaffold_absolute_path(self): + import os + path = os.path.abspath('Distro') + cmd = self._makeOne('-s', 'dummy', path) + scaffold = DummyScaffold('dummy') + cmd.scaffolds = [scaffold] + result = cmd.run() + self.assertEqual(result, True) + self.assertEqual( + scaffold.output_dir, + os.path.normpath(os.path.join(os.getcwd(), 'Distro')) + ) + self.assertEqual( + scaffold.vars, + {'project': 'Distro', 'egg': 'Distro', 'package': 'distro'}) + def test_known_scaffold_multiple_rendered(self): import os cmd = self._makeOne('-s', 'dummy1', '-s', 'dummy2', 'Distro') diff --git a/pyramid/tests/test_scripts/test_proutes.py b/pyramid/tests/test_scripts/test_proutes.py index af6ff19d0..328d1001d 100644 --- a/pyramid/tests/test_scripts/test_proutes.py +++ b/pyramid/tests/test_scripts/test_proutes.py @@ -43,6 +43,18 @@ class TestPRoutesCommand(unittest.TestCase): self.assertEqual(len(L), 3) self.assertEqual(L[-1].split(), ['a', '/a', '<unknown>']) + def test_route_with_no_slash_prefix(self): + command = self._makeOne() + route = dummy.DummyRoute('a', 'a') + mapper = dummy.DummyMapper(route) + command._get_mapper = lambda *arg: mapper + L = [] + command.out = L.append + result = command.run() + self.assertEqual(result, None) + self.assertEqual(len(L), 3) + self.assertEqual(L[-1].split(), ['a', '/a', '<unknown>']) + def test_single_route_no_views_registered(self): from zope.interface import Interface from pyramid.registry import Registry diff --git a/pyramid/tests/test_settings.py b/pyramid/tests/test_settings.py index d02b3cd3e..2ef15f62a 100644 --- a/pyramid/tests/test_settings.py +++ b/pyramid/tests/test_settings.py @@ -81,9 +81,9 @@ class Test_aslist_cronly(unittest.TestCase): self.assertEqual(result, ['abc', 'def']) class Test_aslist(unittest.TestCase): - def _callFUT(self, val): + def _callFUT(self, val, **kw): from pyramid.settings import aslist - return aslist(val) + return aslist(val, **kw) def test_with_list(self): result = self._callFUT(['abc', 'def']) @@ -100,3 +100,7 @@ class Test_aslist(unittest.TestCase): def test_with_string_crsep_spacesep(self): result = self._callFUT(' abc\n def ghi') self.assertEqual(result, ['abc', 'def', 'ghi']) + + def test_with_string_crsep_spacesep_no_flatten(self): + result = self._callFUT(' abc\n def ghi ', flatten=False) + self.assertEqual(result, ['abc', 'def ghi']) diff --git a/pyramid/tests/test_testing.py b/pyramid/tests/test_testing.py index 05ef36fe9..5b0073b81 100644 --- a/pyramid/tests/test_testing.py +++ b/pyramid/tests/test_testing.py @@ -894,6 +894,11 @@ class TestDummySession(unittest.TestCase): self.assertEqual(token, 'token') self.assertTrue('_csrft_' in session) + def test_get_csrf_token_generates_token(self): + session = self._makeOne() + token = session.get_csrf_token() + self.assertNotEqual(token, None) + self.assertTrue(len(token) >= 1) from zope.interface import Interface from zope.interface import implementer diff --git a/rtd_requirements.txt b/rtd.txt index 9de7ff3bb..9de7ff3bb 100644 --- a/rtd_requirements.txt +++ b/rtd.txt @@ -87,7 +87,6 @@ setup(name='pyramid', [pyramid.scaffold] starter=pyramid.scaffolds:StarterProjectTemplate zodb=pyramid.scaffolds:ZODBProjectTemplate - routesalchemy=pyramid.scaffolds:RoutesAlchemyProjectTemplate alchemy=pyramid.scaffolds:AlchemyProjectTemplate [console_scripts] bfg2pyramid = pyramid.fixers.fix_bfg_imports:main |
