1 files added
4 files modified
| | |
| | | Next release |
| | | ============ |
| | | |
| | | 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". |
| | | |
| | | 1.3a2 (2011-12-14) |
| | | ================== |
| | | |
| | |
| | | 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 |
| | |
| | | |
| | | 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: |
| | | |
| | | Writing a Script |
| | |
| | | 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 |
| | |
| | | |
| | | - Added a narrative docs chapter named :ref:`scaffolding_chapter`. |
| | | |
| | | - Added a description of the ``prequest`` command-line script at |
| | | :ref:`invoking_a_request`. |
| | | |
| | | Dependency Changes |
| | | ------------------ |
| | | |
| | |
| | | import optparse |
| | | import os |
| | | import re |
| | | import sys |
| | | import textwrap |
| | | |
| | | from pyramid.compat import url_quote |
| | | from pyramid.request import Request |
| | | from paste.deploy import loadapp |
| | | from pyramid.paster import get_app |
| | | |
| | | def main(argv=sys.argv, quiet=False): |
| | | command = PRequestCommand(argv, quiet) |
| | | command.run() |
| | | return command.run() |
| | | |
| | | class PRequestCommand(object): |
| | | description = """\ |
| | |
| | | type="string", |
| | | ) |
| | | parser.add_option( |
| | | '-c', '--config-var', |
| | | dest='config_vars', |
| | | metavar='NAME:VALUE', |
| | | action='append', |
| | | help="Variable to make available in the config for %()s substitution " |
| | | "(you can use this option multiple times)" |
| | | ) |
| | | parser.add_option( |
| | | '--header', |
| | | dest='headers', |
| | | metavar='NAME:VALUE', |
| | |
| | | parser.add_option( |
| | | '-m', '--method', |
| | | dest='method', |
| | | choices=['GET', 'POST'], |
| | | choices=['GET', 'HEAD', 'POST', 'DELETE'], |
| | | type='choice', |
| | | help='Request method type (GET or POST)', |
| | | help='Request method type (GET, POST, DELETE)', |
| | | ) |
| | | |
| | | _scheme_re = re.compile(r'^[a-z][a-z]+:', re.I) |
| | | 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, delim='\n'): # pragma: no cover |
| | | def out(self, msg): # pragma: no cover |
| | | if not self.quiet: |
| | | sys.stdout.write(msg+delim) |
| | | sys.stdout.flush() |
| | | print(msg) |
| | | |
| | | def run(self): |
| | | if not len(self.args) >= 2: |
| | | self.out('You must provide at least two arguments') |
| | | return |
| | | return 2 |
| | | app_spec = self.args[0] |
| | | path = self.args[1] |
| | | if not path.startswith('/'): |
| | | path = '/' + path |
| | | |
| | | vars = {} |
| | | if self.options.config_vars: |
| | | for item in self.options.config_vars: |
| | | if ':' not in item: |
| | | raise ValueError( |
| | | "Bad option, should be name:value " |
| | | ": --config-var=%s" % item) |
| | | name, value = item.split(':', 1) |
| | | vars[name] = value |
| | | |
| | | headers = {} |
| | | if self.options.headers: |
| | | for item in self.options.headers: |
| | | if ':' not in item: |
| | | raise ValueError( |
| | | "Bad option, should be name:value : --header=%s" % 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() |
| | | |
| | | if not self._scheme_re.search(app_spec): |
| | | app_spec = 'config:' + app_spec |
| | | |
| | | if self.options.app_name: |
| | | if '#' in app_spec: |
| | | app_spec = app_spec.split('#', 1)[0] |
| | | app_spec = app_spec + '#' + self.options.app_name |
| | | |
| | | app = loadapp(app_spec, relative_to=os.getcwd(), global_conf=vars) |
| | | app = self.get_app(app_spec, self.options.app_name) |
| | | request_method = (self.options.method or 'GET').upper() |
| | | |
| | | qs = [] |
| | |
| | | } |
| | | |
| | | if request_method == 'POST': |
| | | environ['wsgi.input'] = sys.stdin |
| | | environ['wsgi.input'] = self.stdin |
| | | environ['CONTENT_LENGTH'] = '-1' |
| | | |
| | | for name, value in headers.items(): |
| | |
| | | self.out(response.status) |
| | | for name, value in response.headerlist: |
| | | self.out('%s: %s' % (name, value)) |
| | | self.out(response.body, '') |
| | | |
| | | self.out(response.ubody) |
| | | return 0 |
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) |