Merge branch '1.3-branch'
4 files added
25 files modified
| | |
| | | Features |
| | | -------- |
| | | |
| | | - Added a ``prequest`` script (along the lines of ``paster request``). It is |
| | | documented in the "Command-Line Pyramid" chapter in the section entitled |
| | | "Invoking a Request". |
| | | |
| | | Bug Fixes |
| | | --------- |
| | | |
| | | - Normalized exit values and ``-h`` output for all ``p*`` scripts |
| | | (``pviews``, ``proutes``, etc). |
| | | |
| | | Documentation |
| | | ------------- |
| | | |
| | | - Added a section named "Making Your Script into a Console Script" in the |
| | | "Command-Line Pyramid" chapter. |
| | | |
| | | 1.3a2 (2011-12-14) |
| | | ================== |
| | | |
| | | Features |
| | | -------- |
| | | |
| | | - New API: ``pyramid.view.view_defaults``. If you use a class as a view, you |
| | | can use the new ``view_defaults`` class decorator on the class to provide |
| | | defaults to the view configuration information used by every |
| | | ``@view_config`` decorator that decorates a method of that class. It also |
| | | works against view configurations involving a class made imperatively. |
| | | |
| | | - Added a backwards compatibility knob to ``pcreate`` to emulate ``paster |
| | | create`` handling for the ``--list-templates`` option. |
| | | |
| | | - Changed scaffolding machinery around a bit to make it easier for people who |
| | | want to have extension scaffolds that can work across Pyramid 1.0.X, 1.1.X, |
| | | 1.2.X and 1.3.X. See the new "Creating Pyramid Scaffolds" chapter in the |
| | | narrative documentation for more info. |
| | | |
| | | Documentation |
| | | ------------- |
| | |
| | | |
| | | - Added API docs for ``view_defaults`` class decorator. |
| | | |
| | | - Added an API docs chapter for ``pyramid.scaffolds``. |
| | | |
| | | - Added a narrative docs chapter named "Creating Pyramid Scaffolds". |
| | | |
| | | Backwards Incompatibilities |
| | | --------------------------- |
| | | |
| | | - The ``template_renderer`` method of ``pyramid.scaffolds.PyramidScaffold`` |
| | | was renamed to ``render_template``. If you were overriding it, you're a |
| | | bad person, because it wasn't an API before now. But we're nice so we're |
| | | letting you know. |
| | | |
| | | 1.3a1 (2011-12-09) |
| | | ================== |
| | | |
| | |
| | | - Fix deployment recipes in cookbook (discourage proxying without changing |
| | | server). |
| | | |
| | | - Allow prequest path to have query string variables. |
| | | |
| | | Nice-to-Have |
| | | ------------ |
| | |
| | | api/renderers |
| | | api/request |
| | | api/response |
| | | api/scaffolds |
| | | api/scripting |
| | | api/security |
| | | api/session |
New file |
| | |
| | | .. _scaffolds_module: |
| | | |
| | | :mod:`pyramid.scaffolds` |
| | | ------------------------ |
| | | |
| | | .. automodule:: pyramid.scaffolds |
| | | |
| | | .. autoclass:: pyramid.scaffolds.Template |
| | | :members: |
| | | |
| | | .. autoclass:: pyramid.scaffolds.PyramidTemplate |
| | | :members: |
| | | |
| | |
| | | # other places throughout the built documents. |
| | | # |
| | | # The short X.Y version. |
| | | version = '1.4dev' |
| | | version = '1.3a2' |
| | | |
| | | # The full version, including alpha/beta/rc tags. |
| | | release = version |
| | | |
| | |
| | | # -- Options for Epub output --------------------------------------------------- |
| | | |
| | | # Bibliographic Dublin Core info. |
| | | epub_title = 'The Pyramid Web Application Development Framework, Version 1.4dev' |
| | | epub_title = 'The Pyramid Web Application Development Framework, Version 1.3' |
| | | epub_author = 'Chris McDonough' |
| | | epub_publisher = 'Agendaless Consulting' |
| | | epub_copyright = '2008-2011' |
| | |
| | | epub_identifier = '0615445675' |
| | | |
| | | # A unique identification for the text. |
| | | epub_uid = 'The Pyramid Web Application Development Framework, Version 1.4dev' |
| | | epub_uid = 'The Pyramid Web Application Development Framework, Version 1.3' |
| | | |
| | | # HTML files that should be inserted before the pages created by sphinx. |
| | | # The format is a list of tuples containing the path and title. |
| | |
| | | |
| | | $ easy_install pyramid |
| | | $ python helloworld.py |
| | | serving on 0.0.0.0:8080 view at http://127.0.0.1:8080 |
| | | |
| | | And when you visit ``http://localhost:8080/hello/world`` in a browser, you |
| | | will see the text ``Hello, world!``. |
| | | When you visit ``http://localhost:8080/hello/world`` in a browser, you will |
| | | see the text ``Hello, world!``. |
| | | |
| | | See :ref:`firstapp_chapter` for a full explanation of how this application |
| | | works. Read the :ref:`html_narrative_documentation` to understand how |
| | |
| | | narr/extending |
| | | narr/advconfig |
| | | narr/extconfig |
| | | narr/scaffolding |
| | | narr/threadlocals |
| | | narr/zca |
| | | |
| | |
| | | Once you've installed your program for development using ``setup.py |
| | | develop``, you can use an interactive Python shell to execute expressions in |
| | | a Python environment exactly like the one that will be used when your |
| | | application runs "for real". To do so, use the ``pshell`` command. |
| | | application runs "for real". To do so, use the ``pshell`` command line |
| | | utility. |
| | | |
| | | The argument to ``pshell`` follows the format ``config_file#section_name`` |
| | | where ``config_file`` is the path to your application's ``.ini`` file and |
| | |
| | | .. code-block:: text |
| | | :linenos: |
| | | |
| | | [chrism@thinko MyProject]$ ../bin/proutes development.ini#MyProject |
| | | [chrism@thinko MyProject]$ ../bin/proutes development.ini |
| | | Name Pattern View |
| | | ---- ------- ---- |
| | | home / <function my_view> |
| | |
| | | .. code-block:: text |
| | | :linenos: |
| | | |
| | | [chrism@thinko pyramid]$ ptweens development.ini |
| | | [chrism@thinko pyramid]$ myenv/bin/ptweens development.ini |
| | | "pyramid.tweens" config value NOT set (implicitly ordered tweens used) |
| | | |
| | | Implicit Tween Chain |
| | |
| | | pyramid.tweens.excview_tween_factory |
| | | |
| | | See :ref:`registering_tweens` for more information about tweens. |
| | | |
| | | .. index:: |
| | | single: invoking a request |
| | | single: prequest |
| | | |
| | | .. _invoking_a_request: |
| | | |
| | | Invoking a Request |
| | | ------------------ |
| | | |
| | | You can use the ``prequest`` command-line utility to send a request to your |
| | | application and see the response body without starting a server. |
| | | |
| | | There are two required arguments to ``prequest``: |
| | | |
| | | - The config file/section: follows the format ``config_file#section_name`` |
| | | where ``config_file`` is the path to your application's ``.ini`` file and |
| | | ``section_name`` is the ``app`` section name inside the ``.ini`` file. The |
| | | ``section_name`` is optional, it defaults to ``main``. For example: |
| | | ``development.ini``. |
| | | |
| | | - The path: this should be the non-url-quoted path element of the URL to the |
| | | resource you'd like to be rendered on the server. For example, ``/``. |
| | | |
| | | For example:: |
| | | |
| | | $ bin/prequest development.ini / |
| | | |
| | | This will print the body of the response to the console on which it was |
| | | invoked. |
| | | |
| | | Several options are supported by ``prequest``. These should precede any |
| | | config file name or URL. |
| | | |
| | | ``prequest`` has a ``-d`` (aka ``--display-headers``) option which prints the |
| | | status and headers returned by the server before the output:: |
| | | |
| | | $ bin/prequest -d development.ini / |
| | | |
| | | This will print the status, then the headers, then the body of the response |
| | | to the console. |
| | | |
| | | You can add request header values by using the ``--header`` option:: |
| | | |
| | | $ bin/prequest --header=Host=example.com development.ini / |
| | | |
| | | Headers are added to the WSGI environment by converting them to their |
| | | CGI/WSGI equivalents (e.g. ``Host=example.com`` will insert the ``HTTP_HOST`` |
| | | header variable as the value ``example.com``). Multiple ``--header`` options |
| | | can be supplied. The special header value ``content-type`` sets the |
| | | ``CONTENT_TYPE`` in the WSGI environment. |
| | | |
| | | By default, ``prequest`` sends a ``GET`` request. You can change this by |
| | | using the ``-m`` (aka ``--method``) option. ``GET``, ``HEAD``, ``POST`` and |
| | | ``DELETE`` are currently supported. When you use ``POST``, the standard |
| | | input of the ``prequest`` process is used as the ``POST`` body:: |
| | | |
| | | $ bin/prequest -mPOST development.ini / < somefile |
| | | |
| | | .. _writing_a_script: |
| | | |
| | |
| | | |
| | | import logging.config |
| | | logging.config.fileConfig('/path/to/my/development.ini') |
| | | |
| | | .. index:: |
| | | single: console script |
| | | |
| | | .. _making_a_console_script: |
| | | |
| | | Making Your Script into a Console Script |
| | | ---------------------------------------- |
| | | |
| | | A "console script" is :term:`setuptools` terminology for a script that gets |
| | | installed into the ``bin`` directory of a Python :term:`virtualenv` (or |
| | | "base" Python environment) when a :term:`distribution` which houses that |
| | | script is installed. Because it's installed into the ``bin`` directory of a |
| | | virtualenv when the distribution is installed, it's a convenient way to |
| | | package and distribute functionality that you can call from the command-line. |
| | | It's often more convenient to create a console script than it is to create a |
| | | ``.py`` script and instruct people to call it with "the right Python |
| | | interpreter": because it generates a file that lives in ``bin``, when it's |
| | | invoked, it will always use "the right" Python environment, which means it |
| | | will always be invoked in an environment where all the libraries it needs |
| | | (such as Pyramid) are available. |
| | | |
| | | In general, you can make your script into a console script by doing the |
| | | following: |
| | | |
| | | - Use an existing distribution (such as one you've already created via |
| | | ``pcreate``) or create a new distribution that possesses at least one |
| | | package or module. It should, within any module within the distribution, |
| | | house a callable (usually a function) that takes no arguments and which |
| | | runs any of the code you wish to run. |
| | | |
| | | - Add a ``[console_scripts]`` section to the ``entry_points`` argument of the |
| | | distribution which creates a mapping between a script name and a dotted |
| | | name representing the callable you added to your distribution. |
| | | |
| | | - Run ``setup.py develop``, ``setup.py install``, or ``easy_install`` to get |
| | | your distribution reinstalled. When you reinstall your distribution, a |
| | | file representing the script that you named in the last step will be in the |
| | | ``bin`` directory of the virtualenv in which you installed the |
| | | distribution. It will be executable. Invoking it from a terminal will |
| | | execute your callable. |
| | | |
| | | As an example, let's create some code that can be invoked by a console script |
| | | that prints the deployment settings of a Pyramid application. To do so, |
| | | we'll pretend you have a distribution with a package in it named |
| | | ``myproject``. Within this package, we'll pretend you've added a |
| | | ``scripts.py`` module which contains the following code: |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | # myproject.scripts module |
| | | |
| | | import optparse |
| | | import sys |
| | | import textwrap |
| | | |
| | | from pyramid.paster import bootstrap |
| | | |
| | | def settings_show(): |
| | | description = """\ |
| | | Print the deployment settings for a Pyramid application. Example: |
| | | 'psettings deployment.ini' |
| | | """ |
| | | usage = "usage: %prog config_uri" |
| | | parser = optparse.OptionParser( |
| | | usage=usage, |
| | | description=textwrap.dedent(description) |
| | | ) |
| | | parser.add_option( |
| | | '-o', '--omit', |
| | | dest='omit', |
| | | metavar='PREFIX', |
| | | type='string', |
| | | action='append', |
| | | help=("Omit settings which start with PREFIX (you can use this " |
| | | "option multiple times)") |
| | | ) |
| | | |
| | | options, args = parser.parse_args(sys.argv[1:]) |
| | | if not len(args) >= 1: |
| | | print('You must provide at least one argument') |
| | | return 2 |
| | | config_uri = args[0] |
| | | omit = options.omit |
| | | if omit is None: |
| | | omit = [] |
| | | env = bootstrap(config_uri) |
| | | settings, closer = env['registry'].settings, env['closer'] |
| | | try: |
| | | for k, v in settings.items(): |
| | | if any([k.startswith(x) for x in omit]): |
| | | continue |
| | | print('%-40s %-20s' % (k, v)) |
| | | finally: |
| | | closer() |
| | | |
| | | This script uses the Python ``optparse`` module to allow us to make sense out |
| | | of extra arguments passed to the script. It uses the |
| | | :func:`pyramid.paster.bootstrap` function to get information about the the |
| | | application defined by a config file, and prints the deployment settings |
| | | defined in that config file. |
| | | |
| | | After adding this script to the package, you'll need to tell your |
| | | distribution's ``setup.py`` about its existence. Within your distribution's |
| | | top-level directory your ``setup.py`` file will look something like this: |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | import os |
| | | |
| | | 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', 'pyramid_debugtoolbar'] |
| | | |
| | | setup(name='MyProject', |
| | | version='0.0', |
| | | description='My 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 pyramid pylons', |
| | | packages=find_packages(), |
| | | include_package_data=True, |
| | | zip_safe=False, |
| | | install_requires=requires, |
| | | tests_require=requires, |
| | | test_suite="wiggystatic", |
| | | entry_points = """\ |
| | | [paste.app_factory] |
| | | main = wiggystatic:main |
| | | """, |
| | | ) |
| | | |
| | | We're going to change the setup.py file to add an ``[console_scripts]`` |
| | | section with in the ``entry_points`` string. Within this section, you should |
| | | specify a ``scriptname = dotted.path.to:yourfunction`` line. For example:: |
| | | |
| | | [console_scripts] |
| | | show_settings = myproject.scripts:settings_show |
| | | |
| | | The ``show_settings`` name will be the name of the script that is installed |
| | | into ``bin``. The colon (``:``) between ``myproject.scripts`` and |
| | | ``settings_show`` above indicates that ``myproject.scripts`` is a Python |
| | | module, and ``settings_show`` is the function in that module which contains |
| | | the code you'd like to run as the result of someone invoking the |
| | | ``show_settings`` script from their command line. |
| | | |
| | | The result will be something like: |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | import os |
| | | |
| | | 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', 'pyramid_debugtoolbar'] |
| | | |
| | | setup(name='MyProject', |
| | | version='0.0', |
| | | description='My 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 pyramid pylons', |
| | | packages=find_packages(), |
| | | include_package_data=True, |
| | | zip_safe=False, |
| | | install_requires=requires, |
| | | tests_require=requires, |
| | | test_suite="wiggystatic", |
| | | entry_points = """\ |
| | | [paste.app_factory] |
| | | main = wiggystatic:main |
| | | [console_scripts] |
| | | show_settings = myproject.scripts:settings_show |
| | | """, |
| | | ) |
| | | |
| | | Once you've done this, invoking ``$somevirtualenv/bin/python setup.py |
| | | develop`` will install a file named ``show_settings`` into the |
| | | ``$somevirtualenv/bin`` directory with a small bit of Python code that points |
| | | to your entry point. It will be executable. Running it without any |
| | | arguments will print an error and exit. Running it with a single argument |
| | | that is the path of a config file will print the settings. Running it with |
| | | an ``--omit=foo`` argument will omit the settings that have keys that start |
| | | with ``foo``. Running it with two "omit" options (e.g. ``--omit=foo |
| | | --omit=bar``) will omit all settings that have keys that start with either |
| | | ``foo`` or ``bar``:: |
| | | |
| | | [chrism@thinko somevenv]$ bin/show_settings development.ini \ |
| | | --omit=pyramid \ |
| | | --omit=debugtoolbar |
| | | debug_routematch False |
| | | debug_templates True |
| | | reload_templates True |
| | | mako.directories [] |
| | | debug_notfound False |
| | | default_locale_name en |
| | | reload_resources False |
| | | debug_authorization False |
| | | reload_assets False |
| | | prevent_http_cache False |
| | | |
| | | Pyramid's ``pserve``, ``pcreate``, ``pshell``, ``prequest``, ``ptweens`` and |
| | | other ``p*`` scripts are implemented as console scripts. When you invoke one |
| | | of those, you are using a console script. |
| | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | from pyramid.views import view_config |
| | | from pyramid.view import view_config |
| | | from pyramid.response import Response |
| | | |
| | | def forbidden_view(request): |
New file |
| | |
| | | .. _scaffolding_chapter: |
| | | |
| | | Creating Pyramid Scaffolds |
| | | ========================== |
| | | |
| | | You can extend Pyramid by creating a :term:`scaffold` template. A scaffold |
| | | template is useful if you'd like to distribute a customizable configuration |
| | | of Pyramid to other users. Once you've created a scaffold, and someone has |
| | | installed the distribution that houses the scaffold, they can use the |
| | | ``pcreate`` script to create a custom version of your scaffold's template. |
| | | Pyramid itself uses scaffolds to allow people to bootstrap new projects. For |
| | | example, ``pcreate -s alchemy MyStuff`` causes Pyramid to render the |
| | | ``alchemy`` scaffold template to the ``MyStuff`` directory. |
| | | |
| | | Basics |
| | | ------ |
| | | |
| | | A scaffold template is just a bunch of source files and directories on disk. |
| | | A small definition class points at this directory; it is in turn pointed at |
| | | by a :term:`setuptools` "entry point" which registers the scaffold so it can |
| | | be found by the ``pcreate`` command. |
| | | |
| | | To create a scaffold template, create a Python :term:`distribution` to house |
| | | the scaffold which includes a ``setup.py`` that relies on the ``setuptools`` |
| | | package. See `Creating a Package |
| | | <http://guide.python-distribute.org/creation.html>`_ for more information |
| | | about how to do this. For the sake of example, we'll pretend the |
| | | distribution you create is named ``CoolExtension``, and it has a package |
| | | directory within it named ``coolextension`` |
| | | |
| | | Once you've created the distribution put a "scaffolds" directory within your |
| | | distribution's package directory, and create a file within that directory |
| | | named ``__init__.py`` with something like the following: |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | # CoolExtension/coolextension/scaffolds/__init__.py |
| | | |
| | | from pyramid.scaffolds import PyramidTemplate |
| | | |
| | | class CoolExtensionTemplate(PyramidTemplate): |
| | | _template_dir = 'coolextension_scaffold' |
| | | summary = 'My cool extension' |
| | | |
| | | Once this is done, within the ``scaffolds`` directory, create a template |
| | | directory. Our example used a template directory named |
| | | ``coolextension_scaffold``. |
| | | |
| | | As you create files and directories within the template directory, note that: |
| | | |
| | | - Files which have a name which are suffixed with the value ``_tmpl`` will be |
| | | rendered, and replacing any instance of the literal string ``{{var}}`` with |
| | | the string value of the variable named ``var`` provided to the scaffold. |
| | | |
| | | - Files and directories with filenames that contain the string ``+var+`` will |
| | | have that string replaced with the value of the ``var`` variable provided |
| | | to the scaffold. |
| | | |
| | | Otherwise, files and directories which live in the template directory will be |
| | | copied directly without modification to the ``pcreate`` output location. |
| | | |
| | | The variables provided by the default ``PyramidTemplate`` include ``project`` |
| | | (the project name provided by the user as an argument to ``pcreate``), |
| | | ``package`` (a lowercasing and normalizing of the project name provided by |
| | | the user), ``random_string`` (a long random string), and ``package_logger`` |
| | | (the name of the package's logger). |
| | | |
| | | See Pyramid's "scaffolds" package |
| | | (https://github.com/Pylons/pyramid/tree/master/pyramid/scaffolds) for |
| | | concrete examples of scaffold directories (``zodb``, ``alchemy``, and |
| | | ``starter``, for example). |
| | | |
| | | After you've created the template directory, add the following to the |
| | | ``entry_points`` value of your distribution's ``setup.py``: |
| | | |
| | | [pyramid.scaffold] |
| | | coolextension=coolextension.scaffolds:CoolExtensionTemplate |
| | | |
| | | For example:: |
| | | |
| | | def setup( |
| | | ..., |
| | | entry_points = """\ |
| | | [pyramid.scaffold] |
| | | coolextension=coolextension.scaffolds:CoolExtensionTemplate |
| | | """ |
| | | ) |
| | | |
| | | Run your distribution's ``setup.py develop`` or ``setup.py install`` |
| | | command. After that, you should be able to see your scaffolding template |
| | | listed when you run ``pcreate -l``. It will be named ``coolextension`` |
| | | because that's the name we gave it in the entry point setup. Running |
| | | ``pcreate -s coolextension MyStuff`` will then render your scaffold to an |
| | | output directory named ``MyStuff``. |
| | | |
| | | See the module documentation for :mod:`pyramid.scaffolds` for information |
| | | about the API of the :class:`pyramid.scaffolds.PyramidScaffold` class and |
| | | related classes. You can override methods of this class to get special |
| | | behavior. |
| | | |
| | | Supporting Older Pyramid Versions |
| | | --------------------------------- |
| | | |
| | | Because different versions of Pyramid handled scaffolding differently, if you |
| | | want to have extension scaffolds that can work across Pyramid 1.0.X, 1.1.X, |
| | | 1.2.X and 1.3.X, you'll need to use something like this bit of horror while |
| | | defining your scaffold template: |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | try: # pyramid 1.0.X |
| | | # "pyramid.paster.paste_script..." doesn't exist past 1.0.X |
| | | from pyramid.paster import paste_script_template_renderer |
| | | from pyramid.paster import PyramidTemplate |
| | | except ImportError: |
| | | try: # pyramid 1.1.X, 1.2.X |
| | | # trying to import "paste_script_template_renderer" fails on 1.3.X |
| | | from pyramid.scaffolds import paste_script_template_renderer |
| | | from pyramid.scaffolds import PyramidTemplate |
| | | except ImportError: # pyramid >=1.3a2 |
| | | paste_script_template_renderer = None |
| | | from pyramid.scaffolds import PyramidTemplate |
| | | |
| | | class CoolExtensionTemplateTemplate(PyramidTemplate): |
| | | _template_dir = 'coolextension_scaffold' |
| | | summary = 'My cool extension' |
| | | template_renderer = staticmethod(paste_script_template_renderer) |
| | | |
| | | And then in the setup.py of the package that contains your scaffold, define |
| | | the template as a target of both ``paste.paster_create_template`` (for |
| | | ``paster create``) and ``pyramid.scaffold`` (for ``pcreate``):: |
| | | |
| | | [paste.paster_create_template] |
| | | coolextension=coolextension.scaffolds:CoolExtensionTemplate |
| | | [pyramid.scaffold] |
| | | coolextension=coolextension.scaffolds:CoolExtensionTemplate |
| | | |
| | | Doing this hideousness will allow your scaffold to work as a ``paster |
| | | create`` target (under 1.0, 1.1, or 1.2) or as a ``pcreate`` target (under |
| | | 1.3). If an invoker tries to run ``paster create`` against a scaffold |
| | | defined this way under 1.3, an error is raised instructing them to use |
| | | ``pcreate`` instead. |
| | | |
| | | If you want only to support Pyramid 1.3 only, it's much cleaner, and the API |
| | | is stable: |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | from pyramid.scaffolds import PyramidTemplate |
| | | |
| | | class CoolExtensionTemplate(PyramidTemplate): |
| | | _template_dir = 'coolextension_scaffold' |
| | | summary = 'My cool_extension' |
| | | |
| | | You only need to specify a ``paste.paster_create_template`` entry point |
| | | target in your ``setup.py`` if you want your scaffold to be consumable by |
| | | users of Pyramid 1.0, 1.1, or 1.2. To support only 1.3, specifying only the |
| | | ``pyramid.scaffold`` entry point is good enough. If you want to support both |
| | | ``paster create`` and ``pcreate`` (meaning you want to support Pyramid 1.2 |
| | | and some older version), you'll need to define both. |
| | | |
| | | Examples |
| | | -------- |
| | | |
| | | Existing third-party distributions which house scaffolding are available via |
| | | :term:`PyPI`. The ``pyramid_jqm``, ``pyramid_zcml`` and ``pyramid_jinja2`` |
| | | packages house scaffolds. You can install and examine these packages to see |
| | | how they work in the quest to develop your own scaffolding. |
| | |
| | | |
| | | The ``ini`` configuration file format supported by Pyramid has not changed. |
| | | As a result, Python 2-only users can install PasteScript manually and use |
| | | ``paster serve`` and ``paster create`` instead if they like. However, using |
| | | ``pserve`` and ``pcreate`` will work under both Python 2 and Python 3. |
| | | ``paster serve`` instead if they like. However, using ``pserve`` will work |
| | | under both Python 2 and Python 3. ``pcreate`` is required to be used for |
| | | internal Pyramid scaffolding; externally distributed scaffolding may allow |
| | | for both ``pcreate`` and/or ``paster create``. |
| | | |
| | | Analogues of ``paster pshell``, ``paster pviews`` and ``paster ptweens`` also |
| | | exist under the respective console script names ``pshell``, ``pviews``, and |
| | | ``ptweens``. |
| | | Analogues of ``paster pshell``, ``paster pviews``, ``paster request`` and |
| | | ``paster ptweens`` also exist under the respective console script names |
| | | ``pshell``, ``pviews``, ``prequest`` and ``ptweens``. |
| | | |
| | | We've replaced use of the Paste ``httpserver`` with the ``wsgiref`` server in |
| | | the scaffolds, so once you create a project from a scaffold, its |
| | |
| | | actually recommended if you rely on proxying from Apache or Nginx to a |
| | | ``pserve`` -invoked application. **The wsgiref server is not a production |
| | | quality server.** See :ref:`alternate_wsgi_server` for more information. |
| | | |
| | | New releases in every older major Pyramid series (1.0.2, 1.1.3, 1.2.5) also |
| | | have the ``egg:pyramid#wsgiref`` entry point, so scaffold-writers can depend |
| | | on it being there even in older major Pyramid versions. |
| | | |
| | | .. warning:: |
| | | |
| | |
| | | - A narrative documentation chapter named :ref:`using_introspection` was |
| | | added. It describes how to query the introspection system. |
| | | |
| | | - Added an API docs chapter for :mod:`pyramid.scaffolds`. |
| | | |
| | | - Added a narrative docs chapter named :ref:`scaffolding_chapter`. |
| | | |
| | | - Added a description of the ``prequest`` command-line script at |
| | | :ref:`invoking_a_request`. |
| | | |
| | | - Added a section to the "Command-Line Pyramid" chapter named |
| | | :ref:`making_a_console_script`. |
| | | |
| | | Dependency Changes |
| | | ------------------ |
| | | |
| | |
| | | |
| | | from pyramid.compat import native_ |
| | | |
| | | from pyramid.scaffolds.template import Template |
| | | from pyramid.scaffolds.template import Template # API |
| | | |
| | | class PyramidTemplate(Template): |
| | | """ |
| | | A class that can be used as a base class for Pyramid scaffolding |
| | | templates. |
| | | """ |
| | | def pre(self, command, output_dir, vars): |
| | | """ Overrides :meth:`pyramid.scaffold.template.Template.pre`, adding |
| | | several variables to the default variables list (including |
| | | ``random_string``, and ``package_logger``). It also prevents common |
| | | misnamings (such as naming a package "site" or naming a package |
| | | logger "root". |
| | | """ |
| | | if vars['package'] == 'site': |
| | | raise ValueError('Sorry, you may not name your package "site". ' |
| | | 'The package name "site" has a special meaning in ' |
| | |
| | | return Template.pre(self, command, output_dir, vars) |
| | | |
| | | def post(self, command, output_dir, vars): # pragma: no cover |
| | | """ Overrides :meth:`pyramid.scaffold.template.Template.post`, to |
| | | print "Welcome to Pyramid. Sorry for the convenience." after a |
| | | successful scaffolding rendering.""" |
| | | self.out('Welcome to Pyramid. Sorry for the convenience.') |
| | | return Template.post(self, command, output_dir, vars) |
| | | |
| | |
| | | import os |
| | | import sys |
| | | import pkg_resources |
| | | import cgi |
| | | import urllib |
| | | |
| | | from pyramid.compat import ( |
| | | input_, |
| | |
| | | fsenc = sys.getfilesystemencoding() |
| | | |
| | | class Template(object): |
| | | """ Inherit from this base class and override methods to use the Pyramid |
| | | scaffolding system.""" |
| | | copydir = copydir # for testing |
| | | _template_dir = None |
| | | |
| | | def __init__(self, name): |
| | | self.name = name |
| | | |
| | | def template_renderer(self, content, vars, filename=None): |
| | | def render_template(self, content, vars, filename=None): |
| | | """ Return a bytestring representing a templated file based on the |
| | | input (content) and the variable names defined (vars). ``filename`` |
| | | is used for exception reporting.""" |
| | | # this method must not be named "template_renderer" fbo of extension |
| | | # scaffolds that need to work under pyramid 1.2 and 1.3, and which |
| | | # need to do "template_renderer = |
| | | # staticmethod(paste_script_template_renderer)" |
| | | content = native_(content, fsenc) |
| | | try: |
| | | return bytes_( |
| | |
| | | raise |
| | | |
| | | def module_dir(self): |
| | | """Returns the module directory of this template.""" |
| | | mod = sys.modules[self.__class__.__module__] |
| | | return os.path.dirname(mod.__file__) |
| | | |
| | | def template_dir(self): |
| | | """ Return the template directory of the scaffold. By default, it |
| | | returns the value of ``os.path.join(self.module_dir(), |
| | | self._template_dir)`` (``self.module_dir()`` returns the module in |
| | | which your subclass has been defined). If ``self._template_dir`` is |
| | | a tuple this method just returns the value instead of trying to |
| | | construct a path. If _template_dir is a tuple, it should be a |
| | | 2-element tuple: ``(package_name, package_relative_path)``.""" |
| | | assert self._template_dir is not None, ( |
| | | "Template %r didn't set _template_dir" % self) |
| | | if isinstance( self._template_dir, tuple): |
| | | if isinstance(self._template_dir, tuple): |
| | | return self._template_dir |
| | | else: |
| | | return os.path.join(self.module_dir(), self._template_dir) |
| | |
| | | interactive=command.options.interactive, |
| | | overwrite=command.options.overwrite, |
| | | indent=1, |
| | | template_renderer=self.template_renderer |
| | | template_renderer=self.render_template, |
| | | ) |
| | | |
| | | def makedirs(self, dir): # pragma: no cover |
| | |
| | | def out(self, msg): # pragma: no cover |
| | | print(msg) |
| | | |
| | | # hair for exit with usage when paster create is used under 1.3 instead |
| | | # of pcreate for extension scaffolds which need to support multiple |
| | | # versions of pyramid; the check_vars method is called by pastescript |
| | | # only as the result of "paster create"; pyramid doesn't use it. the |
| | | # required_templates tuple is required to allow it to get as far as |
| | | # calling check_vars. |
| | | required_templates = () |
| | | def check_vars(self, vars, other): |
| | | raise RuntimeError( |
| | | 'Under Pyramid 1.3, you should use the "pcreate" command rather ' |
| | | 'than "paster create"') |
| | | |
| | | class TypeMapper(dict): |
| | | |
| | | def __getitem__(self, item): |
| | |
| | | |
| | | def main(argv=sys.argv, quiet=False): |
| | | command = PCreateCommand(argv, quiet) |
| | | command.run() |
| | | return command.run() |
| | | |
| | | class PCreateCommand(object): |
| | | verbosity = 1 |
| | | usage = "usage: %prog [options] distribution_name" |
| | | parser = optparse.OptionParser(usage) |
| | | verbosity = 1 # required |
| | | description = "Render Pyramid scaffolding to an output directory" |
| | | usage = "usage: %prog [options] output_directory" |
| | | parser = optparse.OptionParser(usage, description=description) |
| | | parser.add_option('-s', '--scaffold', |
| | | dest='scaffold_name', |
| | | action='append', |
| | |
| | | dest='list', |
| | | action='store_true', |
| | | help="List all available scaffold names") |
| | | parser.add_option('--list-templates', |
| | | dest='list', |
| | | action='store_true', |
| | | help=("A backwards compatibility alias for -l/--list. " |
| | | "List all available scaffold names.")) |
| | | parser.add_option('--simulate', |
| | | dest='simulate', |
| | | action='store_true', |
| | |
| | | return self.show_scaffolds() |
| | | if not self.options.scaffold_name: |
| | | self.out('You must provide at least one scaffold name') |
| | | return |
| | | return 2 |
| | | if not self.args: |
| | | self.out('You must provide a project name') |
| | | return |
| | | return 2 |
| | | available = [x.name for x in self.scaffolds] |
| | | diff = set(self.options.scaffold_name).difference(available) |
| | | if diff: |
| | | self.out('Unavailable scaffolds: %s' % list(diff)) |
| | | return |
| | | return 2 |
| | | return self.render_scaffolds() |
| | | |
| | | def render_scaffolds(self): |
| | |
| | | for scaffold in self.scaffolds: |
| | | if scaffold.name == scaffold_name: |
| | | scaffold.run(self, output_dir, vars) |
| | | return True |
| | | return 0 |
| | | |
| | | def show_scaffolds(self): |
| | | scaffolds = sorted(self.scaffolds, key=lambda x: x.name) |
| | |
| | | ' '*(max_name-len(scaffold.name)), scaffold.summary)) |
| | | else: |
| | | self.out('No scaffolds available') |
| | | return True |
| | | return 0 |
| | | |
| | | def all_scaffolds(self): |
| | | scaffolds = [] |
New file |
| | |
| | | import optparse |
| | | import sys |
| | | import textwrap |
| | | |
| | | from pyramid.compat import url_quote |
| | | from pyramid.request import Request |
| | | from pyramid.paster import get_app |
| | | |
| | | def main(argv=sys.argv, quiet=False): |
| | | command = PRequestCommand(argv, quiet) |
| | | return command.run() |
| | | |
| | | class PRequestCommand(object): |
| | | description = """\ |
| | | Run a request for the described application. |
| | | |
| | | This command makes an artifical request to a web application that uses a |
| | | PasteDeploy (.ini) configuration file for the server and application. |
| | | |
| | | Use "prequest config.ini /path" to request "/path". Use "prequest |
| | | --method=POST config.ini /path < data" to do a POST with the given |
| | | request body. |
| | | |
| | | If the path is relative (doesn't begin with "/") it is interpreted as |
| | | relative to "/". |
| | | |
| | | The variable "environ['paste.command_request']" will be set to "True" in |
| | | the request's WSGI environment, so your application can distinguish these |
| | | calls from normal requests. |
| | | |
| | | Note that you can pass arguments besides the options listed here; any |
| | | unknown arguments will be passed to the application in |
| | | "environ['QUERY_STRING']" |
| | | """ |
| | | usage = "usage: %prog config_uri path_info [args/options]" |
| | | parser = optparse.OptionParser( |
| | | usage=usage, |
| | | description=textwrap.dedent(description) |
| | | ) |
| | | parser.add_option( |
| | | '-n', '--app-name', |
| | | dest='app_name', |
| | | metavar= 'NAME', |
| | | help="Load the named application from the config file (default 'main')", |
| | | type="string", |
| | | ) |
| | | parser.add_option( |
| | | '--header', |
| | | dest='headers', |
| | | metavar='NAME:VALUE', |
| | | type='string', |
| | | action='append', |
| | | help="Header to add to request (you can use this option multiple times)" |
| | | ) |
| | | parser.add_option( |
| | | '-d', '--display-headers', |
| | | dest='display_headers', |
| | | action='store_true', |
| | | help='Display status and headers before the response body' |
| | | ) |
| | | parser.add_option( |
| | | '-m', '--method', |
| | | dest='method', |
| | | choices=['GET', 'HEAD', 'POST', 'DELETE'], |
| | | type='choice', |
| | | help='Request method type (GET, POST, DELETE)', |
| | | ) |
| | | |
| | | get_app = staticmethod(get_app) |
| | | stdin = sys.stdin |
| | | |
| | | def __init__(self, argv, quiet=False): |
| | | self.quiet = quiet |
| | | self.options, self.args = self.parser.parse_args(argv[1:]) |
| | | |
| | | def out(self, msg): # pragma: no cover |
| | | if not self.quiet: |
| | | print(msg) |
| | | |
| | | def run(self): |
| | | if not len(self.args) >= 2: |
| | | self.out('You must provide at least two arguments') |
| | | return 2 |
| | | app_spec = self.args[0] |
| | | path = self.args[1] |
| | | if not path.startswith('/'): |
| | | path = '/' + path |
| | | |
| | | headers = {} |
| | | if self.options.headers: |
| | | for item in self.options.headers: |
| | | if ':' not in item: |
| | | self.out( |
| | | "Bad --header=%s option, value must be in the form " |
| | | "'name:value'" % item) |
| | | return 2 |
| | | name, value = item.split(':', 1) |
| | | headers[name] = value.strip() |
| | | |
| | | app = self.get_app(app_spec, self.options.app_name) |
| | | request_method = (self.options.method or 'GET').upper() |
| | | |
| | | qs = [] |
| | | for item in self.args[2:]: |
| | | if '=' in item: |
| | | k, v = item.split('=', 1) |
| | | item = url_quote(k) + '=' + url_quote(v) |
| | | else: |
| | | item = url_quote(item) |
| | | qs.append(item) |
| | | qs = '&'.join(qs) |
| | | |
| | | environ = { |
| | | 'REQUEST_METHOD': request_method, |
| | | 'SCRIPT_NAME': '', # may be empty if app is at the root |
| | | 'PATH_INFO': path, # may be empty if at root of app |
| | | 'SERVER_NAME': 'localhost', # always mandatory |
| | | 'SERVER_PORT': '80', # always mandatory |
| | | 'SERVER_PROTOCOL': 'HTTP/1.0', |
| | | 'CONTENT_TYPE': 'text/plain', |
| | | 'wsgi.run_once': True, |
| | | 'wsgi.multithread': False, |
| | | 'wsgi.multiprocess': False, |
| | | 'wsgi.errors': sys.stderr, |
| | | 'wsgi.url_scheme': 'http', |
| | | 'wsgi.version': (1, 0), |
| | | 'QUERY_STRING': qs, |
| | | 'HTTP_ACCEPT': 'text/plain;q=1.0, */*;q=0.1', |
| | | 'paste.command_request': True, |
| | | } |
| | | |
| | | if request_method == 'POST': |
| | | environ['wsgi.input'] = self.stdin |
| | | environ['CONTENT_LENGTH'] = '-1' |
| | | |
| | | for name, value in headers.items(): |
| | | if name.lower() == 'content-type': |
| | | name = 'CONTENT_TYPE' |
| | | else: |
| | | name = 'HTTP_'+name.upper().replace('-', '_') |
| | | environ[name] = value |
| | | |
| | | request = Request.blank(path, environ=environ) |
| | | response = request.get_response(app) |
| | | if self.options.display_headers: |
| | | self.out(response.status) |
| | | for name, value in response.headerlist: |
| | | self.out('%s: %s' % (name, value)) |
| | | self.out(response.ubody) |
| | | return 0 |
| | |
| | | import optparse |
| | | import sys |
| | | import textwrap |
| | | |
| | | from pyramid.paster import bootstrap |
| | | |
| | | def main(argv=sys.argv, quiet=False): |
| | | command = PRoutesCommand(argv, quiet) |
| | | command.run() |
| | | return command.run() |
| | | |
| | | class PRoutesCommand(object): |
| | | """Print all URL dispatch routes used by a Pyramid application in the |
| | | description = """\ |
| | | Print all URL dispatch routes used by a Pyramid application in the |
| | | order in which they are evaluated. Each route includes the name of the |
| | | route, the pattern of the route, and the view callable which will be |
| | | invoked when the route is matched. |
| | | |
| | | This command accepts one positional argument: |
| | | |
| | | ``config_uri`` -- specifies the PasteDeploy config file to use for the |
| | | interactive shell. The format is ``inifile#name``. If the name is left |
| | | off, ``main`` will be assumed. |
| | | |
| | | Example:: |
| | | |
| | | $ proutes myapp.ini#main |
| | | This command accepts one positional argument named "config_uri". It |
| | | specifies the PasteDeploy config file to use for the interactive |
| | | shell. The format is "inifile#name". If the name is left off, "main" |
| | | will be assumed. Example: "proutes myapp.ini". |
| | | |
| | | """ |
| | | bootstrap = (bootstrap,) |
| | | summary = "Print all URL dispatch routes related to a Pyramid application" |
| | | stdout = sys.stdout |
| | | usage = '%prog config_uri' |
| | | |
| | | parser = optparse.OptionParser() |
| | | parser = optparse.OptionParser( |
| | | usage, |
| | | description=textwrap.dedent(description) |
| | | ) |
| | | |
| | | def __init__(self, argv, quiet=False): |
| | | self.options, self.args = self.parser.parse_args(argv[1:]) |
| | |
| | | def run(self, quiet=False): |
| | | if not self.args: |
| | | self.out('requires a config file argument') |
| | | return |
| | | return 2 |
| | | from pyramid.interfaces import IRouteRequest |
| | | from pyramid.interfaces import IViewClassifier |
| | | from pyramid.interfaces import IView |
| | |
| | | routes = mapper.get_routes() |
| | | fmt = '%-15s %-30s %-25s' |
| | | if not routes: |
| | | return |
| | | return 0 |
| | | self.out(fmt % ('Name', 'Pattern', 'View')) |
| | | self.out( |
| | | fmt % ('-'*len('Name'), '-'*len('Pattern'), '-'*len('View'))) |
| | |
| | | (IViewClassifier, request_iface, Interface), |
| | | IView, name='', default=None) |
| | | self.out(fmt % (route.name, pattern, view_callable)) |
| | | return 0 |
| | | |
| | |
| | | import re |
| | | import subprocess |
| | | import sys |
| | | import textwrap |
| | | import threading |
| | | import time |
| | | import traceback |
| | |
| | | |
| | | def main(argv=sys.argv, quiet=False): |
| | | command = PServeCommand(argv, quiet=quiet) |
| | | command.run() |
| | | return command.run() |
| | | |
| | | class DaemonizeException(Exception): |
| | | pass |
| | | |
| | | class PServeCommand(object): |
| | | |
| | | usage = 'CONFIG_FILE [start|stop|restart|status] [var=value]' |
| | | takes_config_file = 1 |
| | | summary = ("Serve the application described in CONFIG_FILE or control " |
| | | "daemon status"), |
| | | usage = '%prog config_uri [start|stop|restart|status] [var=value]' |
| | | description = """\ |
| | | This command serves a web application that uses a PasteDeploy |
| | | configuration file for the server and application. |
| | |
| | | """ |
| | | verbose = 1 |
| | | |
| | | parser = optparse.OptionParser() |
| | | parser = optparse.OptionParser( |
| | | usage, |
| | | description=textwrap.dedent(description) |
| | | ) |
| | | parser.add_option( |
| | | '-n', '--app-name', |
| | | dest='app_name', |
| | |
| | | |
| | | if not self.args: |
| | | self.out('You must give a config file') |
| | | return |
| | | return 2 |
| | | app_spec = self.args[0] |
| | | if (len(self.args) > 1 |
| | | and self.args[1] in self.possible_subcommands): |
| | |
| | | if cmd not in (None, 'start', 'stop', 'restart', 'status'): |
| | | self.out( |
| | | 'Error: must give start|stop|restart (not %s)' % cmd) |
| | | return |
| | | return 2 |
| | | |
| | | if cmd == 'status' or self.options.show_status: |
| | | return self.show_status() |
| | |
| | | except DaemonizeException as ex: |
| | | if self.verbose > 0: |
| | | self.out(str(ex)) |
| | | return |
| | | return 2 |
| | | |
| | | if (self.options.monitor_restart |
| | | and not os.environ.get(self._monitor_environ_key)): |
| | |
| | | from code import interact |
| | | import optparse |
| | | import sys |
| | | import textwrap |
| | | |
| | | from pyramid.compat import configparser |
| | | from pyramid.util import DottedNameResolver |
| | |
| | | |
| | | def main(argv=sys.argv, quiet=False): |
| | | command = PShellCommand(argv, quiet) |
| | | command.run() |
| | | return command.run() |
| | | |
| | | class PShellCommand(object): |
| | | """Open an interactive shell with a :app:`Pyramid` app loaded. |
| | | usage = '%prog config_uri' |
| | | description = """\ |
| | | Open an interactive shell with a Pyramid app loaded. This command |
| | | accepts one positional argument named "config_uri" which specifies the |
| | | PasteDeploy config file to use for the interactive shell. The format is |
| | | "inifile#name". If the name is left off, the Pyramid default application |
| | | will be assumed. Example: "pshell myapp.ini#main" |
| | | |
| | | This command accepts one positional argument: |
| | | |
| | | ``config_uri`` -- specifies the PasteDeploy config file to use for the |
| | | interactive shell. The format is ``inifile#name``. If the name is left |
| | | off, ``main`` will be assumed. |
| | | |
| | | Example:: |
| | | |
| | | $ pshell myapp.ini#main |
| | | |
| | | .. note:: If you do not point the loader directly at the section of the |
| | | ini file containing your :app:`Pyramid` application, the |
| | | command will attempt to find the app for you. If you are |
| | | loading a pipeline that contains more than one :app:`Pyramid` |
| | | application within it, the loader will use the last one. |
| | | |
| | | If you do not point the loader directly at the section of the ini file |
| | | containing your Pyramid application, the command will attempt to |
| | | find the app for you. If you are loading a pipeline that contains more |
| | | than one Pyramid application within it, the loader will use the |
| | | last one. |
| | | """ |
| | | bootstrap = (bootstrap,) # for testing |
| | | summary = "Open an interactive shell with a Pyramid application loaded" |
| | | |
| | | parser = optparse.OptionParser() |
| | | parser = optparse.OptionParser( |
| | | usage, |
| | | description=textwrap.dedent(description) |
| | | ) |
| | | parser.add_option('-p', '--python-shell', |
| | | action='store', type='string', dest='python_shell', |
| | | default='', help='ipython | bpython | python') |
| | |
| | | def run(self, shell=None): |
| | | if not self.args: |
| | | self.out('Requires a config file argument') |
| | | return |
| | | return 2 |
| | | config_uri = self.args[0] |
| | | config_file = config_uri.split('#', 1)[0] |
| | | setup_logging(config_file) |
| | |
| | | import optparse |
| | | import sys |
| | | import textwrap |
| | | |
| | | from pyramid.interfaces import ITweens |
| | | |
| | |
| | | |
| | | def main(argv=sys.argv, quiet=False): |
| | | command = PTweensCommand(argv, quiet) |
| | | command.run() |
| | | return command.run() |
| | | |
| | | class PTweensCommand(object): |
| | | """Print all implicit and explicit :term:`tween` objects used by a |
| | | Pyramid application. The handler output includes whether the system is |
| | | using an explicit tweens ordering (will be true when the |
| | | ``pyramid.tweens`` setting is used) or an implicit tweens ordering (will |
| | | be true when the ``pyramid.tweens`` setting is *not* used). |
| | | usage = '%prog config_uri' |
| | | description = """\ |
| | | Print all implicit and explicit tween objects used by a Pyramid |
| | | application. The handler output includes whether the system is using an |
| | | explicit tweens ordering (will be true when the "pyramid.tweens" |
| | | deployment setting is used) or an implicit tweens ordering (will be true |
| | | when the "pyramid.tweens" deployment setting is *not* used). |
| | | |
| | | This command accepts one positional argument: |
| | | |
| | | ``config_uri`` -- specifies the PasteDeploy config file to use for the |
| | | interactive shell. The format is ``inifile#name``. If the name is left |
| | | off, ``main`` will be assumed. |
| | | |
| | | Example:: |
| | | |
| | | $ ptweens myapp.ini#main |
| | | This command accepts one positional argument named "config_uri" which |
| | | specifies the PasteDeploy config file to use for the interactive |
| | | shell. The format is "inifile#name". If the name is left off, "main" |
| | | will be assumed. Example: "ptweens myapp.ini#main". |
| | | |
| | | """ |
| | | summary = "Print all tweens related to a Pyramid application" |
| | | parser = optparse.OptionParser( |
| | | usage, |
| | | description=textwrap.dedent(description), |
| | | ) |
| | | |
| | | stdout = sys.stdout |
| | | |
| | | parser = optparse.OptionParser() |
| | | |
| | | bootstrap = (bootstrap,) # testing |
| | | |
| | | def __init__(self, argv, quiet=False): |
| | |
| | | def run(self): |
| | | if not self.args: |
| | | self.out('Requires a config file argument') |
| | | return |
| | | return 2 |
| | | config_uri = self.args[0] |
| | | env = self.bootstrap[0](config_uri) |
| | | registry = env['registry'] |
| | |
| | | self.out('Implicit Tween Chain') |
| | | self.out('') |
| | | self.show_chain(tweens.implicit()) |
| | | return 0 |
| | |
| | | import optparse |
| | | import sys |
| | | import textwrap |
| | | |
| | | from pyramid.interfaces import IMultiView |
| | | from pyramid.paster import bootstrap |
| | | |
| | | def main(argv=sys.argv, quiet=False): |
| | | command = PViewsCommand(argv, quiet) |
| | | command.run() |
| | | return command.run() |
| | | |
| | | class PViewsCommand(object): |
| | | """Print, for a given URL, the views that might match. Underneath each |
| | | usage = '%prog config_uri url' |
| | | description = """\ |
| | | Print, for a given URL, the views that might match. Underneath each |
| | | potentially matching route, list the predicates required. Underneath |
| | | each route+predicate set, print each view that might match and its |
| | | predicates. |
| | | |
| | | This command accepts two positional arguments: |
| | | |
| | | ``config_uri`` -- specifies the PasteDeploy config file to use for the |
| | | interactive shell. The format is ``inifile#name``. If the name is left |
| | | off, ``main`` will be assumed. |
| | | |
| | | ``url`` -- specifies the URL that will be used to find matching views. |
| | | |
| | | Example:: |
| | | |
| | | $ proutes myapp.ini#main url |
| | | |
| | | This command accepts two positional arguments: "config_uri" specifies the |
| | | PasteDeploy config file to use for the interactive shell. The format is |
| | | "inifile#name". If the name is left off, "main" will be assumed. "url" |
| | | specifies the path info portion of a URL that will be used to find |
| | | matching views. Example: "proutes myapp.ini#main /url" |
| | | """ |
| | | summary = "Print all views in an application that might match a URL" |
| | | stdout = sys.stdout |
| | | |
| | | parser = optparse.OptionParser() |
| | | parser = optparse.OptionParser( |
| | | usage, |
| | | description=textwrap.dedent(description) |
| | | ) |
| | | |
| | | bootstrap = (bootstrap,) # testing |
| | | |
| | |
| | | def run(self): |
| | | if len(self.args) < 2: |
| | | self.out('Command requires a config file arg and a url arg') |
| | | return |
| | | return 2 |
| | | config_uri, url = self.args |
| | | if not url.startswith('/'): |
| | | url = '/%s' % url |
| | |
| | | else: |
| | | self.out(" Not found.") |
| | | self.out('') |
| | | return 0 |
| | | |
| | |
| | | from pyramid.scaffolds.template import Template |
| | | return Template(name) |
| | | |
| | | def test_template_renderer_success(self): |
| | | def test_render_template_success(self): |
| | | inst = self._makeOne() |
| | | result = inst.template_renderer('{{a}} {{b}}', {'a':'1', 'b':'2'}) |
| | | result = inst.render_template('{{a}} {{b}}', {'a':'1', 'b':'2'}) |
| | | self.assertEqual(result, bytes_('1 2')) |
| | | |
| | | def test_template_renderer_expr_failure(self): |
| | | def test_render_template_expr_failure(self): |
| | | inst = self._makeOne() |
| | | self.assertRaises(AttributeError, inst.template_renderer, |
| | | self.assertRaises(AttributeError, inst.render_template, |
| | | '{{a.foo}}', {'a':'1', 'b':'2'}) |
| | | |
| | | def test_template_renderer_expr_success(self): |
| | | def test_render_template_expr_success(self): |
| | | inst = self._makeOne() |
| | | result = inst.template_renderer('{{a.lower()}}', {'a':'A'}) |
| | | result = inst.render_template('{{a.lower()}}', {'a':'A'}) |
| | | self.assertEqual(result, b'a') |
| | | |
| | | def test_template_renderer_expr_success_via_pipe(self): |
| | | def test_render_template_expr_success_via_pipe(self): |
| | | inst = self._makeOne() |
| | | result = inst.template_renderer('{{b|c|a.lower()}}', {'a':'A'}) |
| | | result = inst.render_template('{{b|c|a.lower()}}', {'a':'A'}) |
| | | self.assertEqual(result, b'a') |
| | | |
| | | def test_template_renderer_expr_success_via_pipe2(self): |
| | | def test_render_template_expr_success_via_pipe2(self): |
| | | inst = self._makeOne() |
| | | result = inst.template_renderer('{{b|a.lower()|c}}', {'a':'A'}) |
| | | result = inst.render_template('{{b|a.lower()|c}}', {'a':'A'}) |
| | | self.assertEqual(result, b'a') |
| | | |
| | | def test_template_renderer_expr_value_is_None(self): |
| | | def test_render_template_expr_value_is_None(self): |
| | | inst = self._makeOne() |
| | | result = inst.template_renderer('{{a}}', {'a':None}) |
| | | result = inst.render_template('{{a}}', {'a':None}) |
| | | self.assertEqual(result, b'') |
| | | |
| | | def test_module_dir(self): |
| | |
| | | self.assertEqual(copydir.output_dir, 'output dir') |
| | | self.assertEqual(copydir.vars, {'a':1}) |
| | | self.assertEqual(copydir.kw, |
| | | {'template_renderer':inst.template_renderer, |
| | | {'template_renderer':inst.render_template, |
| | | 'indent':1, |
| | | 'verbosity':1, |
| | | 'simulate':False, |
| | |
| | | inst.run(command, 'output dir', {'a':1}) |
| | | self.assertEqual(L, ['output dir']) |
| | | |
| | | def test_check_vars(self): |
| | | inst = self._makeOne() |
| | | self.assertRaises(RuntimeError, inst.check_vars, 'one', 'two') |
| | | |
| | | class DummyCopydir(object): |
| | | def copy_dir(self, template_dir, output_dir, vars, **kw): |
| | | self.template_dir = template_dir |
| | |
| | | def test_run_show_scaffolds_exist(self): |
| | | cmd = self._makeOne('-l') |
| | | result = cmd.run() |
| | | self.assertEqual(result, True) |
| | | self.assertEqual(result, 0) |
| | | out = self.out_.getvalue() |
| | | self.assertTrue(out.startswith('Available scaffolds')) |
| | | |
| | |
| | | cmd = self._makeOne('-l') |
| | | cmd.scaffolds = [] |
| | | result = cmd.run() |
| | | self.assertEqual(result, True) |
| | | self.assertEqual(result, 0) |
| | | out = self.out_.getvalue() |
| | | self.assertTrue(out.startswith('No scaffolds available')) |
| | | |
| | | def test_run_no_scaffold_name(self): |
| | | cmd = self._makeOne() |
| | | result = cmd.run() |
| | | self.assertEqual(result, None) |
| | | self.assertEqual(result, 2) |
| | | out = self.out_.getvalue() |
| | | self.assertTrue(out.startswith( |
| | | 'You must provide at least one scaffold name')) |
| | |
| | | def test_no_project_name(self): |
| | | cmd = self._makeOne('-s', 'dummy') |
| | | result = cmd.run() |
| | | self.assertEqual(result, None) |
| | | self.assertEqual(result, 2) |
| | | out = self.out_.getvalue() |
| | | self.assertTrue(out.startswith('You must provide a project name')) |
| | | |
| | | def test_unknown_scaffold_name(self): |
| | | cmd = self._makeOne('-s', 'dummyXX', 'distro') |
| | | result = cmd.run() |
| | | self.assertEqual(result, None) |
| | | self.assertEqual(result, 2) |
| | | out = self.out_.getvalue() |
| | | self.assertTrue(out.startswith('Unavailable scaffolds')) |
| | | |
| | |
| | | scaffold = DummyScaffold('dummy') |
| | | cmd.scaffolds = [scaffold] |
| | | result = cmd.run() |
| | | self.assertEqual(result, True) |
| | | self.assertEqual(result, 0) |
| | | self.assertEqual( |
| | | scaffold.output_dir, |
| | | os.path.normpath(os.path.join(os.getcwd(), 'Distro')) |
| | |
| | | scaffold = DummyScaffold('dummy') |
| | | cmd.scaffolds = [scaffold] |
| | | result = cmd.run() |
| | | self.assertEqual(result, True) |
| | | self.assertEqual(result, 0) |
| | | self.assertEqual( |
| | | scaffold.output_dir, |
| | | os.path.normpath(os.path.join(os.getcwd(), 'Distro')) |
| | |
| | | scaffold2 = DummyScaffold('dummy2') |
| | | cmd.scaffolds = [scaffold1, scaffold2] |
| | | result = cmd.run() |
| | | self.assertEqual(result, True) |
| | | self.assertEqual(result, 0) |
| | | self.assertEqual( |
| | | scaffold1.output_dir, |
| | | os.path.normpath(os.path.join(os.getcwd(), 'Distro')) |
| | |
| | | |
| | | def test_it(self): |
| | | result = self._callFUT(['pcreate']) |
| | | self.assertEqual(result, None) |
| | | self.assertEqual(result, 2) |
| | | |
| | | class DummyScaffold(object): |
| | | def __init__(self, name): |
New file |
| | |
| | | import unittest |
| | | |
| | | class TestPRequestCommand(unittest.TestCase): |
| | | def _getTargetClass(self): |
| | | from pyramid.scripts.prequest import PRequestCommand |
| | | return PRequestCommand |
| | | |
| | | def _makeOne(self, argv): |
| | | cmd = self._getTargetClass()(argv) |
| | | cmd.get_app = self.get_app |
| | | self._out = [] |
| | | cmd.out = self.out |
| | | return cmd |
| | | |
| | | def get_app(self, spec, app_name=None): |
| | | self._spec = spec |
| | | self._app_name = app_name |
| | | def helloworld(environ, start_request): |
| | | self._environ = environ |
| | | self._path_info = environ['PATH_INFO'] |
| | | start_request('200 OK', []) |
| | | return [b'abc'] |
| | | return helloworld |
| | | |
| | | def out(self, msg): |
| | | self._out.append(msg) |
| | | |
| | | def test_command_not_enough_args(self): |
| | | command = self._makeOne([]) |
| | | command.run() |
| | | self.assertEqual(self._out, ['You must provide at least two arguments']) |
| | | |
| | | def test_command_two_args(self): |
| | | command = self._makeOne(['', 'development.ini', '/']) |
| | | command.run() |
| | | self.assertEqual(self._path_info, '/') |
| | | self.assertEqual(self._spec, 'development.ini') |
| | | self.assertEqual(self._app_name, None) |
| | | self.assertEqual(self._out, ['abc']) |
| | | |
| | | def test_command_path_doesnt_start_with_slash(self): |
| | | command = self._makeOne(['', 'development.ini', 'abc']) |
| | | command.run() |
| | | self.assertEqual(self._path_info, '/abc') |
| | | self.assertEqual(self._spec, 'development.ini') |
| | | self.assertEqual(self._app_name, None) |
| | | self.assertEqual(self._out, ['abc']) |
| | | |
| | | def test_command_has_bad_config_header(self): |
| | | command = self._makeOne( |
| | | ['', '--header=name','development.ini', '/']) |
| | | command.run() |
| | | self.assertEqual( |
| | | self._out[0], |
| | | ("Bad --header=name option, value must be in the form " |
| | | "'name:value'")) |
| | | |
| | | def test_command_has_good_header_var(self): |
| | | command = self._makeOne( |
| | | ['', '--header=name:value','development.ini', '/']) |
| | | command.run() |
| | | self.assertEqual(self._environ['HTTP_NAME'], 'value') |
| | | self.assertEqual(self._path_info, '/') |
| | | self.assertEqual(self._spec, 'development.ini') |
| | | self.assertEqual(self._app_name, None) |
| | | self.assertEqual(self._out, ['abc']) |
| | | |
| | | def test_command_has_content_type_header_var(self): |
| | | command = self._makeOne( |
| | | ['', '--header=content-type:app/foo','development.ini', '/']) |
| | | command.run() |
| | | self.assertEqual(self._environ['CONTENT_TYPE'], 'app/foo') |
| | | self.assertEqual(self._path_info, '/') |
| | | self.assertEqual(self._spec, 'development.ini') |
| | | self.assertEqual(self._app_name, None) |
| | | self.assertEqual(self._out, ['abc']) |
| | | |
| | | def test_command_has_multiple_header_vars(self): |
| | | command = self._makeOne( |
| | | ['', |
| | | '--header=name:value', |
| | | '--header=name2:value2', |
| | | 'development.ini', |
| | | '/']) |
| | | command.run() |
| | | self.assertEqual(self._environ['HTTP_NAME'], 'value') |
| | | self.assertEqual(self._environ['HTTP_NAME2'], 'value2') |
| | | self.assertEqual(self._path_info, '/') |
| | | self.assertEqual(self._spec, 'development.ini') |
| | | self.assertEqual(self._app_name, None) |
| | | self.assertEqual(self._out, ['abc']) |
| | | |
| | | def test_command_method_get(self): |
| | | command = self._makeOne(['', '--method=GET', 'development.ini', '/']) |
| | | command.run() |
| | | self.assertEqual(self._path_info, '/') |
| | | self.assertEqual(self._spec, 'development.ini') |
| | | self.assertEqual(self._app_name, None) |
| | | self.assertEqual(self._out, ['abc']) |
| | | |
| | | def test_command_method_post(self): |
| | | from pyramid.compat import NativeIO |
| | | command = self._makeOne(['', '--method=POST', 'development.ini', '/']) |
| | | stdin = NativeIO() |
| | | command.stdin = stdin |
| | | command.run() |
| | | self.assertEqual(self._environ['CONTENT_LENGTH'], '-1') |
| | | self.assertEqual(self._environ['wsgi.input'], stdin) |
| | | self.assertEqual(self._path_info, '/') |
| | | self.assertEqual(self._spec, 'development.ini') |
| | | self.assertEqual(self._app_name, None) |
| | | self.assertEqual(self._out, ['abc']) |
| | | |
| | | def test_command_extra_args_used_in_query_string(self): |
| | | command = self._makeOne(['', 'development.ini', '/', 'a=1%','b=2','c']) |
| | | command.run() |
| | | self.assertEqual(self._environ['QUERY_STRING'], 'a=1%25&b=2&c') |
| | | self.assertEqual(self._path_info, '/') |
| | | self.assertEqual(self._spec, 'development.ini') |
| | | self.assertEqual(self._app_name, None) |
| | | self.assertEqual(self._out, ['abc']) |
| | | |
| | | def test_command_display_headers(self): |
| | | command = self._makeOne( |
| | | ['', '--display-headers', 'development.ini', '/']) |
| | | command.run() |
| | | self.assertEqual(self._path_info, '/') |
| | | self.assertEqual(self._spec, 'development.ini') |
| | | self.assertEqual(self._app_name, None) |
| | | self.assertEqual( |
| | | self._out, |
| | | ['200 OK', 'Content-Type: text/html; charset=UTF-8', 'abc']) |
| | | |
| | | class Test_main(unittest.TestCase): |
| | | def _callFUT(self, argv): |
| | | from pyramid.scripts.prequest import main |
| | | return main(argv, True) |
| | | |
| | | def test_it(self): |
| | | result = self._callFUT(['prequest']) |
| | | self.assertEqual(result, 2) |
| | |
| | | L = [] |
| | | command.out = L.append |
| | | result = command.run() |
| | | self.assertEqual(result, None) |
| | | self.assertEqual(result, 0) |
| | | self.assertEqual(L, []) |
| | | |
| | | def test_no_mapper(self): |
| | |
| | | L = [] |
| | | command.out = L.append |
| | | result = command.run() |
| | | self.assertEqual(result, None) |
| | | self.assertEqual(result, 0) |
| | | self.assertEqual(L, []) |
| | | |
| | | def test_single_route_no_route_registered(self): |
| | |
| | | L = [] |
| | | command.out = L.append |
| | | result = command.run() |
| | | self.assertEqual(result, None) |
| | | self.assertEqual(result, 0) |
| | | self.assertEqual(len(L), 3) |
| | | self.assertEqual(L[-1].split(), ['a', '/a', '<unknown>']) |
| | | |
| | |
| | | L = [] |
| | | command.out = L.append |
| | | result = command.run() |
| | | self.assertEqual(result, None) |
| | | self.assertEqual(result, 0) |
| | | self.assertEqual(len(L), 3) |
| | | self.assertEqual(L[-1].split(), ['a', '/a', '<unknown>']) |
| | | |
| | |
| | | command.out = L.append |
| | | command.bootstrap = (dummy.DummyBootstrap(registry=registry),) |
| | | result = command.run() |
| | | self.assertEqual(result, None) |
| | | self.assertEqual(result, 0) |
| | | self.assertEqual(len(L), 3) |
| | | self.assertEqual(L[-1].split()[:3], ['a', '/a', 'None']) |
| | | |
| | |
| | | command.out = L.append |
| | | command.bootstrap = (dummy.DummyBootstrap(registry=registry),) |
| | | result = command.run() |
| | | self.assertEqual(result, None) |
| | | self.assertEqual(result, 0) |
| | | self.assertEqual(len(L), 3) |
| | | self.assertEqual(L[-1].split()[:4], ['a', '/a', '<function', 'view']) |
| | | |
| | |
| | | command.out = L.append |
| | | command.bootstrap = (dummy.DummyBootstrap(registry=registry),) |
| | | result = command.run() |
| | | self.assertEqual(result, None) |
| | | self.assertEqual(result, 0) |
| | | self.assertEqual(len(L), 3) |
| | | self.assertEqual(L[-1].split()[:3], ['a', '/a', '<unknown>']) |
| | | |
| | |
| | | |
| | | def test_it(self): |
| | | result = self._callFUT(['proutes']) |
| | | self.assertEqual(result, None) |
| | | self.assertEqual(result, 2) |
| | | |
| | |
| | | def test_run_no_args(self): |
| | | inst = self._makeOne() |
| | | result = inst.run() |
| | | self.assertEqual(result, None) |
| | | self.assertEqual(result, 2) |
| | | self.assertEqual(self.out_.getvalue(), 'You must give a config file') |
| | | |
| | | def test_run_stop_daemon_no_such_pid_file(self): |
| | |
| | | |
| | | def test_it(self): |
| | | result = self._callFUT(['pserve']) |
| | | self.assertEqual(result, None) |
| | | self.assertEqual(result, 2) |
| | | |
| | | class TestLazyWriter(unittest.TestCase): |
| | | def _makeOne(self, filename, mode='w'): |
| | |
| | | |
| | | def test_it(self): |
| | | result = self._callFUT(['pshell']) |
| | | self.assertEqual(result, None) |
| | | self.assertEqual(result, 2) |
| | | |
| | |
| | | L = [] |
| | | command.out = L.append |
| | | result = command.run() |
| | | self.assertEqual(result, None) |
| | | self.assertEqual(result, 0) |
| | | self.assertEqual(L, []) |
| | | |
| | | def test_command_implicit_tweens_only(self): |
| | |
| | | L = [] |
| | | command.out = L.append |
| | | result = command.run() |
| | | self.assertEqual(result, None) |
| | | self.assertEqual(result, 0) |
| | | self.assertEqual( |
| | | L[0], |
| | | '"pyramid.tweens" config value NOT set (implicitly ordered tweens ' |
| | |
| | | L = [] |
| | | command.out = L.append |
| | | result = command.run() |
| | | self.assertEqual(result, None) |
| | | self.assertEqual(result, 0) |
| | | self.assertEqual( |
| | | L[0], |
| | | '"pyramid.tweens" config value set (explicitly ordered tweens used)') |
| | |
| | | |
| | | def test_it(self): |
| | | result = self._callFUT(['ptweens']) |
| | | self.assertEqual(result, None) |
| | | self.assertEqual(result, 2) |
| | |
| | | command._find_view = lambda arg1, arg2: None |
| | | command.args = ('/foo/bar/myapp.ini#myapp', '/a') |
| | | result = command.run() |
| | | self.assertEqual(result, None) |
| | | self.assertEqual(result, 0) |
| | | self.assertEqual(L[1], 'URL = /a') |
| | | self.assertEqual(L[3], ' Not found.') |
| | | |
| | |
| | | command._find_view = lambda arg1, arg2: None |
| | | command.args = ('/foo/bar/myapp.ini#myapp', 'a') |
| | | result = command.run() |
| | | self.assertEqual(result, None) |
| | | self.assertEqual(result, 0) |
| | | self.assertEqual(L[1], 'URL = /a') |
| | | self.assertEqual(L[3], ' Not found.') |
| | | |
| | |
| | | command._find_view = lambda arg1, arg2: view |
| | | command.args = ('/foo/bar/myapp.ini#myapp', '/a') |
| | | result = command.run() |
| | | self.assertEqual(result, None) |
| | | self.assertEqual(result, 0) |
| | | self.assertEqual(L[1], 'URL = /a') |
| | | self.assertEqual(L[3], ' context: context') |
| | | self.assertEqual(L[4], ' view name: a') |
| | |
| | | command._find_view = lambda arg1, arg2: view |
| | | command.args = ('/foo/bar/myapp.ini#myapp', '/a') |
| | | result = command.run() |
| | | self.assertEqual(result, None) |
| | | self.assertEqual(result, 0) |
| | | self.assertEqual(L[1], 'URL = /a') |
| | | self.assertEqual(L[3], ' context: context') |
| | | self.assertEqual(L[4], ' view name: a') |
| | |
| | | command._find_view = lambda arg1, arg2: view |
| | | command.args = ('/foo/bar/myapp.ini#myapp', '/a') |
| | | result = command.run() |
| | | self.assertEqual(result, None) |
| | | self.assertEqual(result, 0) |
| | | self.assertEqual(L[1], 'URL = /a') |
| | | self.assertEqual(L[3], ' context: context') |
| | | self.assertEqual(L[4], ' view name: a') |
| | |
| | | command._find_view = lambda arg1, arg2: view |
| | | command.args = ('/foo/bar/myapp.ini#myapp', '/a') |
| | | result = command.run() |
| | | self.assertEqual(result, None) |
| | | self.assertEqual(result, 0) |
| | | self.assertEqual(L[1], 'URL = /a') |
| | | self.assertEqual(L[3], ' context: context') |
| | | self.assertEqual(L[4], ' view name: a') |
| | |
| | | command._find_view = lambda arg1, arg2: view |
| | | command.args = ('/foo/bar/myapp.ini#myapp', '/a') |
| | | result = command.run() |
| | | self.assertEqual(result, None) |
| | | self.assertEqual(result, 0) |
| | | self.assertEqual(L[1], 'URL = /a') |
| | | self.assertEqual(L[3], ' context: context') |
| | | self.assertEqual(L[4], ' view name: a') |
| | |
| | | command._find_view = lambda arg1, arg2: multiview2 |
| | | command.args = ('/foo/bar/myapp.ini#myapp', '/a') |
| | | result = command.run() |
| | | self.assertEqual(result, None) |
| | | self.assertEqual(result, 0) |
| | | self.assertEqual(L[1], 'URL = /a') |
| | | self.assertEqual(L[3], ' context: context') |
| | | self.assertEqual(L[4], ' view name: a') |
| | |
| | | command._find_view = lambda arg1, arg2: view |
| | | command.args = ('/foo/bar/myapp.ini#myapp', '/a') |
| | | result = command.run() |
| | | self.assertEqual(result, None) |
| | | self.assertEqual(result, 0) |
| | | self.assertEqual(L[1], 'URL = /a') |
| | | self.assertEqual(L[3], ' context: context') |
| | | self.assertEqual(L[4], ' view name: a') |
| | |
| | | command._find_view = lambda arg1, arg2: multiview |
| | | command.args = ('/foo/bar/myapp.ini#myapp', '/a') |
| | | result = command.run() |
| | | self.assertEqual(result, None) |
| | | self.assertEqual(result, 0) |
| | | self.assertEqual(L[1], 'URL = /a') |
| | | self.assertEqual(L[3], ' context: context') |
| | | self.assertEqual(L[4], ' view name: a') |
| | |
| | | command._find_view = lambda arg1, arg2: multiview |
| | | command.args = ('/foo/bar/myapp.ini#myapp', '/a') |
| | | result = command.run() |
| | | self.assertEqual(result, None) |
| | | self.assertEqual(result, 0) |
| | | self.assertEqual(L[1], 'URL = /a') |
| | | self.assertEqual(L[3], ' context: context') |
| | | self.assertEqual(L[4], ' view name: a') |
| | |
| | | command._find_view = lambda arg1, arg2: multiview |
| | | command.args = ('/foo/bar/myapp.ini#myapp', '/a') |
| | | result = command.run() |
| | | self.assertEqual(result, None) |
| | | self.assertEqual(result, 0) |
| | | self.assertEqual(L[1], 'URL = /a') |
| | | self.assertEqual(L[3], ' context: context') |
| | | self.assertEqual(L[4], ' view name: a') |
| | |
| | | |
| | | def test_it(self): |
| | | result = self._callFUT(['pviews']) |
| | | self.assertEqual(result, None) |
| | | self.assertEqual(result, 2) |
| | |
| | | ]) |
| | | |
| | | setup(name='pyramid', |
| | | version='1.4dev', |
| | | version='1.3a2', |
| | | description=('The Pyramid web application development framework, a ' |
| | | 'Pylons project'), |
| | | long_description=README + '\n\n' + CHANGES, |
| | |
| | | proutes = pyramid.scripts.proutes:main |
| | | pviews = pyramid.scripts.pviews:main |
| | | ptweens = pyramid.scripts.ptweens:main |
| | | prequest = pyramid.scripts.prequest:main |
| | | [paste.server_runner] |
| | | wsgiref = pyramid.scripts.pserve:wsgiref_server_runner |
| | | cherrypy = pyramid.scripts.pserve:cherrypy_server_runner |