PECAN(1) Pecan PECAN(1) (NAME) pecan - Pecan Pecan CherryPy TurboGears Pylons . Pecan ShootQ Pictage . Pecan Python - object-dispatch . Pecan "full stack" (sessions) ( ). Pecan HTTP . Pecan HTTP : o Object-dispatch o REST o o (template language) o JSON o Python (INSTALLATION) (Stable Version) Pecan pip easy_install . Pecan . Pecan virtualenv : $ virtualenv pecan-env $ cd pecan-env $ source bin/activate . Pecan . Pecan : $ pip install pecan Pecan git GitHub : $ git clone https://github.com/pecan/pecan.git setup.py : $ cd pecan $ python setup.py develop : master . GitHub pip : $ pip install -e git://github.com/pecan/pecan.git#egg=pecan PECAN (CREATING YOUR FIRST PECAN APPLICATION) Pecan . : Pecan . Pecan <#installation> . (Base Application Template) Pecan . : $ pecan create test_project test_project Python . : $ cd test_project " " (development mode) sys.path : $ python setup.py develop : $ ls MANIFEST.in config.py public | css | | style.css | images setup.cfg setup.py test_project __init__.py app.py controllers | __init__.py | root.py model | __init__.py templates | error.html | index.html layout.html tests __init__.py config.py test_functional.py test_units.py Pecan . : public ( CSS Javascript ) . Pecan . Pecan MVC . test_project . test_project/controllers (controller) . test_project/templates (templates) . test_project/model (model) . (unit) (integration): test_project/tests . test_project/app.py Pecan . setup_app() WSGI . app.py . (Python-Based Configuration) . Pecan ORM ( - ) . model/__init__.py ORM ..SS Pecan config.py . (static). pecan serve config.py : $ pecan serve config.py Starting server in PID 000. serving on 0.0.0.0:8080, view at http://127.0.0.1:8080 - . Pecan -- .py . () : # Server Specific Configurations server = { 'port': '8080', 'host': '0.0.0.0' } # Pecan Application Configurations app = { 'root': '${package}.controllers.root.RootController', 'modules': ['${package}'], 'static_root': '%(confdir)s/public', 'template_path': '%(confdir)s/${package}/templates', 'debug': True, 'errors': { '404': '/error/404', '__force_dict__': True } } logging = { 'loggers': { 'root' : {'level': 'INFO', 'handlers': ['console']}, '${package}': {'level': 'DEBUG', 'handlers': ['console']} }, 'handlers': { 'console': { 'level': 'DEBUG', 'class': 'logging.StreamHandler', 'formatter': 'simple' } }, 'formatters': { 'simple': { 'format': ('%(asctime)s %(levelname)-5.5s [%(name)s]' '[%(threadName)s] %(message)s') } } } # Custom Configurations must be in Python dictionary format:: # # foo = {'bar':'baz'} # # All configurations are accessible at:: # pecan.conf . (Configuring Pecan Applications <#configuration>)..SS (The Application Root) Root Controller . URL ( http://localhost:8080) . (test_project.controllers.root.RootController) : from pecan import expose from webob.exc import status_map class RootController(object): @expose(generic=True, template='index.html') def index(self): return dict() @index.when(method='POST') def index_post(self, q): redirect('https://pecan.readthedocs.io/en/latest/search.html?q=%s' % q) @expose('error.html') def error(self, status): try: status = int(status) except ValueError: status = 0 message = getattr(status_map.get(status), 'explanation', '') return dict(status=status, message=message) : @expose(generic=True, template='index.html') def index(self): return dict() index() expose() <#pecan.decorators.expose> ( index.html ) () HTTP GET (/) . index() . (index.html) HTML . @index.when(method='POST') def index_post(self, q): redirect('https://pecan.readthedocs.io/en/latest/search.html?q=%s' % q) index_post() HTTP POST (q). method @index.when() 'POST' HTTP POST ( ) . @expose('error.html') def error(self, status): try: status = int(status) except ValueError: status = 0 message = getattr(status_map.get(status), 'explanation', '') return dict(status=status, message=message) error() HTTP (404 ...)..SS " (Running the Tests For Your Application)" . : $ pip install tox && tox -e py tests . (Deploying to a Web Server) Pecan Deploying Pecan in Production <#deployment> . (CONTROLLERS AND ROUTING) Pecan object-dispatch HTTP . object-dispatch . ( URL ). : from pecan import expose class BooksController(object): @expose() def index(self): return "Welcome to book section." @expose() def bestsellers(self): return "We have 5 books in the top 10." class CatalogController(object): @expose() def index(self): return "Welcome to the catalog." books = BooksController() class RootController(object): @expose() def index(self): return "Welcome to store.example.com!" @expose() def hours(self): return "Open 24/7 on the web." catalog = CatalogController() /catalog/books/bestsellers catalog books bestsellers Pecan . Pecan catalog . catalog Pecan books bestsellers . URL Pecan index . : / /hours /catalog /catalog/books /catalog/books/bestsellers : RootController.index RootController.hours CatalogController.index BooksController.index BooksController.bestsellers expose() <#pecan.decorators.expose> Pecan . expose() <#pecan.decorators.expose> Pecan . expose() <#pecan.decorators.expose> . . HTML . from pecan import expose class RootController(object): @expose() def hello(self): return 'Hello World' (namespace) <# templates>: from pecan import expose class RootController(object): @expose('html_template.mako') def hello(self): return {'msg': 'Hello!'} ${msg} Pecan JSON <#expose-json> JSON : from pecan import expose class RootController(object): @expose('json') def hello(self): return {'msg': 'Hello!'} expose() <#pecan.decorators .expose> ( ) : from pecan import expose class RootController(object): @expose('json') @expose('text_template.mako', content_type='text/plain') @expose('html_template.mako') def hello(self): return {'msg': 'Hello!'} expose() <# pecan.decorators.expose> . @expose('json') Pecan /hello.json Accept: application/json JSON . @expose('text_template.mako', content_type='text/plain') Pecan /hello.txt Accept text/plain text_template.mako . @expose('html_template.mako') Pecan /hello.html html_template.mako . /hello Pecan text/html Pecan HTML . : o pecan.decorators -- Pecan <#pecan-decorators> Python Pecan . /some-path/ Python : class RootController(object): @pecan.expose() def some-path(self): return dict() pecan expose() <#pecan.decorators.expose> : class RootController(object): @pecan.expose(route='some-path') def some_path(self): return dict() pecan /some-path/ HTTP 200 /some_path/ HTTP 404 . route() <#pecan.routing .route> route expose() <#pecan.decorators.expose> : class RootController(object): @pecan.expose() def some_path(self): return dict() pecan.route('some-path', RootController.some_path) (child controllers) route() <#pecan.routing.route> : class ChildController(object): @pecan.expose() def child(self): return dict() class RootController(object): pass pecan.route(RootController, 'child-path', ChildController()) pecan /child-path/child/ HTTP 200 . (Routing Based on Request Method) generic expose() <#pecan.decorators .expose> (overloading) URL . URL (generic controllers) ( HTTP GET HTTP POST): from pecan import expose class RootController(object): # HTTP GET / @expose(generic=True, template='json') def index(self): return dict() # HTTP POST / @index.when(method='POST', template='json') def index_POST(self, **kw): uuid = create_something() return dict(uuid=uuid) (object-dispatch) URL . Pecan URL _lookup() _default() _route(). URL . _lookup _lookup() URL . _lookup() URL ( /). _lookup() . *remainder (object-dispatch) . _lookup() URL _default() . from pecan import expose, abort from somelib import get_student_by_name class StudentController(object): def __init__(self, student): self.student = student @expose() def name(self): return self.student.name class RootController(object): @expose() def _lookup(self, primary_key, *remainder): student = get_student_by_primary_key(primary_key) if student: return StudentController(student), remainder else: abort(404) HTTP GET /8/name primary_key == 8 . _default _default() URL . from pecan import expose class RootController(object): @expose() def english(self): return 'hello' @expose() def french(self): return 'bonjour' @expose() def _default(self): return 'I cannot say hello in that language' /spanish RootController._default() ..SS _route _route() Pecan . Pecan _route() RestController <# pecan.rest.RestController> . Pecan _route() . (INTERACTING WITH THE REQUEST AND RESPONSE OBJECT) HTTP Pecan (thread-local) <#contextlocals> pecan.request pecan.response . pecan.Request pecan.Response Pecan : @pecan.expose() def login(self): assert pecan.request.path == '/login' username = pecan.request.POST.get('username') password = pecan.request.POST.get('password') pecan.response.status = 403 pecan.response.text = 'Bad Login!' Pecan : o URI o IP referer o o status HTTP ( 203 Non-Authoritative Information) . from pecan import expose, response class RootController(object): @expose('json') def hello(self): response.status = 203 return {'foo': 'bar'} HTTP abort() <#pecan.core.abort> . from pecan import expose, abort class RootController(object): @expose('json') def hello(self): abort(404) abort() <#pecan.core.abort> WSGIHTTPException Pecan HTTP . WSGI (environ) pecan.original_exception ( Custom Error Documents <#errors>) . Response <#pecan.core.Response> : from pecan import expose, Response class RootController(object): @expose() def hello(self): return Response('Hello, World!', 202) (request) (response) WebOb ( ). pecan.Request pecan.Response : class MyRequest(pecan.Request): pass class MyResponse(pecan.Response): pass : from myproject import MyRequest, MyResponse app = { 'root' : 'project.controllers.root.RootController', 'modules' : ['project'], 'static_root' : '%(confdir)s/public', 'template_path' : '%(confdir)s/project/templates', 'request_cls': MyRequest, 'response_cls': MyResponse } (Controller) Pecan GET POST HTTP (routing) . (signature) : from pecan import expose class RootController(object): @expose() def index(self, arg): return arg @expose() def kwargs(self, **kwargs): return str(kwargs) $ curl http://localhost:8080/?arg=foo foo $ curl http://localhost:8080/kwargs?a=1&b=2&c=3 {u'a': u'1', u'c': u'3', u'b': u'2'} (positionally) : from pecan import expose class RootController(object): @expose() def args(self, *args): return ','.join(args) $ curl http://localhost:8080/args/one/two/three one,two,three HTTP POST : from pecan import expose class RootController(object): @expose() def index(self, arg): return arg $ curl -X POST "http://localhost:8080/" -H "Content-Type: application/x-www-form-urlencoded" -d "arg=foo" foo Pecan Request app_iter WSGI : import os from random import choice from webob.static import FileIter from pecan import expose, response class RootController(object): @expose(content_type='image/gif') def gifs(self): filepath = choice(( "/path/to/funny/gifs/catdance.gif", "/path/to/funny/gifs/babydance.gif", "/path/to/funny/gifs/putindance.gif" )) f = open(filepath, 'rb') response.app_iter = FileIter(f) response.headers[ 'Content-Disposition' ] = 'attachment; filename="%s"' % os.path.basename(f.name) ( ) response.headers expose() <# pecan.decorators.expose> : import os from mimetypes import guess_type from webob.static import FileIter from pecan import expose, response class RootController(object): @expose() def download(self): f = open('/path/to/some/file', 'rb') response.app_iter = FileIter(f) response.headers['Content-Type'] = guess_type(f.name) response.headers[ 'Content-Disposition' ] = 'attachment; filename="%s"' % os.path.basename(f.name) (Handling File Uploads) Pecan multipart . :
request (controller) : from pecan import expose, request class RootController(object): @expose() def upload(self): assert isinstance(request.POST['file'], cgi.FieldStorage) data = request.POST['file'].file.read() Pecan Python (thread-safe) : pecan.request.context['current_user'] = some_user print pecan.request.context.items() / (metadata/context) ( per-routing) ( ). WSGI Pecan pecan.request.environ . (Helper Functions) Pecan . redirect() <#pecan.core.redirect> HTTP 302 . : redirect() pecan.core -- Pecan Core <#pecan- core> . (Determining the URL for a Controller) (URL) . _lookup() : from pecan import expose, abort from somelib import get_user_region class DefaultRegionController(object): @expose() def name(self): return "Default Region" class USRegionController(object): @expose() def name(self): return "US Region" class RootController(object): @expose() def _lookup(self, user_id, *remainder): if get_user_region(user_id) == 'us': return USRegionController(), remainder else: return DefaultRegionController(), remainder . USRegionController.name . PECAN (TEMPLATING IN PECAN) Pecan . Pecan : +--------------------------------+-----------------------------+ | | | | | | +--------------------------------+-----------------------------+ |Mako | | +--------------------------------+-----------------------------+ |Genshi | | +--------------------------------+-----------------------------+ |Kajiki | | +--------------------------------+-----------------------------+ |Jinja2 | jinja | +--------------------------------+-----------------------------+ |JSON | json | +--------------------------------+-----------------------------+ mako default_renderer : app = { 'default_renderer' : 'kajiki', # ... } pecan.decorators <#module-pecan.decorators> expose() <#pecan .decorators.expose> (public controller) . expose() <#pecan.decorators.expose> template . class MyController(object): @expose('path/to/mako/template.html') def index(self): return dict(message='I am a mako template') expose() <#pecan.decorators.expose> . @expose('kajiki:path/to/kajiki/template.html') def my_controller(self): return dict(message='I am a kajiki template') : o pecan.decorators -- Pecan (Pecan Decorators) <#pecan-decorators> o pecan.core -- Pecan (Pecan Core) <#pecan-core> o (Controllers and Routing) <#routing> (Overriding Templates) override_template() <#pecan.core.override_template> . override_template() <#pecan .core.override_template> . class MyController(object): @expose('template_one.html') def index(self): # ... override_template('template_two.html') return dict(message='I will now render with template_two.html') (Manual Rendering) render() <#pecan.core.render> Pecan . render() <#pecan.core.render> . @expose() def controller(self): return render('my_template.html', dict(message='I am the namespace')) Pecan JSON @expose('json') . : o JSON <#jsonify> o pecan.jsonify -- Pecan JSON <# pecan-jsonify> (Defining Custom Renderers) : class MyRenderer(object): def __init__(self, path, extra_vars): ''' Your renderer is provided with a path to templates, as configured by your application, and any extra template variables, also as configured ''' pass def render(self, template_path, namespace): ''' Lookup the template based on the path, and render your output based upon the supplied namespace dictionary, as returned from the controller. ''' return str(namespace) custom_renderers : app = { 'custom_renderers' : { 'my_renderer' : MyRenderer }, # ... } ... expose() <# pecan.decorators.expose> : class RootController(object): @expose('my_renderer:template.html') def index(self): return dict(name='Bob') RESTful (WRITING RESTFUL WEB SERVICES WITH GENERIC CONTROLLERS) Pecan URL RESTful . API (generic controller) RESTful ( RESTful Pecan ): from pecan import abort, expose # Note: this is *not* thread-safe. In real life, use a persistent data store. BOOKS = { '0': 'The Last of the Mohicans', '1': 'Catch-22' } class BookController(object): def __init__(self, id_): self.id_ = id_ assert self.book @property def book(self): if self.id_ in BOOKS: return dict(id=self.id_, name=BOOKS[self.id_]) abort(404) # HTTP GET // @expose(generic=True, template='json') def index(self): return self.book # HTTP PUT // @index.when(method='PUT', template='json') def index_PUT(self, **kw): BOOKS[self.id_] = kw['name'] return self.book # HTTP DELETE // @index.when(method='DELETE', template='json') def index_DELETE(self): del BOOKS[self.id_] return dict() class RootController(object): @expose() def _lookup(self, id_, *remainder): return BookController(id_), remainder # HTTP GET / @expose(generic=True, template='json') def index(self): return [dict(id=k, name=v) for k, v in BOOKS.items()] # HTTP POST / @index.when(method='POST', template='json') def index_POST(self, **kw): id_ = str(len(BOOKS)) BOOKS[id_] = kw['name'] return dict(id=id_, name=kw['name']) TurboGears2 Pecan RESTful RestController <# pecan.rest.RestController> : from pecan import expose from pecan.rest import RestController from mymodel import Book class BooksController(RestController): @expose() def get(self, id): book = Book.get(id) if not book: abort(404) return book.title URL (URL Mapping) RestController <#pecan.rest .RestController> : +----------------+-----------------------------------+-------------------------+ | | | () / | | | | URL() | | | | | +----------------+-----------------------------------+-------------------------+ |get_one | | GET /books/1 | | | . | | +----------------+-----------------------------------+-------------------------+ |get_all | | GET /books/ | | | | | | | . | | +----------------+-----------------------------------+-------------------------+ |get | get_one | GET /books/ | | | get_all. | | +----------------+-----------------------------------+-------------------------+ |GET /books/1 | | | +----------------+-----------------------------------+-------------------------+ |new | | GET /books/new | | | | | | | | | | | . | | +----------------+-----------------------------------+-------------------------+ |edit | | GET /books/1/edit | | | | | | | | | | | | | | | . | | +----------------+-----------------------------------+-------------------------+ |post | | POST /books/ | | | . | | +----------------+-----------------------------------+-------------------------+ |put | | POST | | | | /books/1?_method=put | | | . | | +----------------+-----------------------------------+-------------------------+ |PUT /books/1 | | | +----------------+-----------------------------------+-------------------------+ |get_delete | | GET /books/1/delete | | | . | | +----------------+-----------------------------------+-------------------------+ |delete | | POST | | | . | /books/1?_method=delete | +----------------+-----------------------------------+-------------------------+ |DELETE /books/1 | | | +----------------+-----------------------------------+-------------------------+ RestController <#pecan.rest.RestController> Pecan ?_method= PUT DELETE . REST RestController <#pecan.rest.RestController> index() _default() _lookup() . : _route() RestController._route() REST . RestController <#pecan.rest .RestController> . : from pecan import expose from pecan.rest import RestController from mymodel import Author, Book class BooksController(RestController): @expose() def get(self, author_id, id): author = Author.get(author_id) if not author_id: abort(404) book = author.get_book(id) if not book: abort(404) return book.title class AuthorsController(RestController): books = BooksController() @expose() def get(self, id): author = Author.get(id) if not author: abort(404) return author.name class RootController(object): authors = AuthorsController() /authors/1/books/2 BooksController.get() author_id 1 id 2 . Pecan get_one() get() . Pecan ( books ) . _custom_actions RestController <#pecan.rest.RestController> . : from pecan import expose from pecan.rest import RestController from mymodel import Book class BooksController(RestController): _custom_actions = { 'checkout': ['POST'] } @expose() def checkout(self, id): book = Book.get(id) if not book: abort(404) book.checkout() _custom_actions HTTP . checkout() POST ..SH " PECAN (CONFIGURING PECAN APPLICATIONS)" Pecan . . Pecan . "" (section) . (Default Values) : server = { 'port' : '8080', 'host' : '0.0.0.0' } app = { 'root' : None, 'modules' : [], 'static_root' : 'public', 'template_path' : '' } (Application Configuration) app Pecan WSGI . app (root controller) . : app = { 'root' : 'project.controllers.root.RootController', 'modules' : ['project'], 'static_root' : '%(confdir)s/public', 'template_path' : '%(confdir)s/project/templates', 'debug' : True } : modules Pecan . . app.setup_app WSGI . app.py setup_app . root . (callable) ( "yourapp.controllers.root.RootController"). static_root (static) ( ). Pecan (middleware) ( CSS Javascript) . template_path ( ). debug (traceback) . : app . : debug False . : o <#app-template> Pecan . WSGI . server = { 'port' : '8080', 'host' : '0.0.0.0' } (Additional Configuration) ( API ) . . twitter = { 'api_key' : 'FOO', 'api_secret' : 'SECRET' } (Accessing Configuration at Runtime) pecan.conf . . (administrator) : administrator = 'foo_bar_user' pecan.conf : >>> from pecan import conf >>> conf.administrator 'foo_bar_user' (Dictionary Conversion) . Config <#pecan.configuration .Config> . to_dict() <#pecan.configuration.Config.to_dict> ( ) : >>> from pecan import conf >>> conf Config({'app': Config({'errors': {}, 'template_path': '', 'static_root': 'public', [...] >>> conf.to_dict() {'app': {'errors': {}, 'template_path': '', 'static_root': 'public', [...] to_dict() <#pecan.configuration.Config.to_dict> . >>> from pecan import conf >>> conf Config({'app': Config({'errors': {}, 'template_path': '', 'static_root': 'public', [...] >>> conf.to_dict('prefixed_') {'prefixed_app': {'prefixed_errors': {}, 'prefixed_template_path': '', 'prefixed_static_root': 'prefixed_public', [...] (Dotted Keys, Non-Python Identifiers, and Native Dictionaries) Python (). logging Python . __force_dict__ . logging = { 'root': {'level': 'INFO', 'handlers': ['console']}, 'loggers': { 'sqlalchemy.engine': {'level': 'INFO', 'handlers': ['console']}, '__force_dict__': True }, 'formatters': { 'custom': { '()': 'my.package.customFormatter' } } } from myapp import conf assert isinstance(conf.logging.loggers, dict) assert isinstance(conf.logging.loggers['sqlalchemy.engine'], dict) (SECURITY AND AUTHENTICATION) Pecan . secure (secure Decorator Basics) secure() <#pecan.secure.secure> . : secure('') : secure(object_instance, '') from pecan import expose from pecan.secure import secure class HighlyClassifiedController(object): pass class UnclassifiedController(object): pass class RootController(object): @classmethod def check_permissions(cls): if user_is_admin(): return True return False @expose() def index(self): # # This controller is unlocked to everyone, # and will not run any security checks. # return dict() @secure('check_permissions') @expose() def topsecret(self): # # This controller is top-secret, and should # only be reachable by administrators. # return dict() highly_classified = secure(HighlyClassifiedController(), 'check_permissions') unclassified = UnclassifiedController() SecureController <#pecan.secure.SecureController> Pecan . SecureController <#pecan .secure.SecureController> check_permissions() <#pecan.secure.SecureControllerBase .check_permissions> True False . from pecan import expose from pecan.secure import SecureController, unlocked class HighlyClassifiedController(object): pass class UnclassifiedController(object): pass class RootController(SecureController): @classmethod def check_permissions(cls): if user_is_admin(): return True return False @expose() @unlocked def index(self): # # This controller is unlocked to everyone, # and will not run any security checks. # return dict() @expose() def topsecret(self): # # This controller is top-secret, and should # only be reachable by administrators. # return dict() highly_classified = HighlyClassifiedController() unclassified = unlocked(UnclassifiedController()) unlocked() <#pecan.secure.unlocked> . / (Writing Authentication/Authorization Methods) check_permissions() <#pecan.secure.SecureControllerBase .check_permissions> . ( ) LDAP . secure (More on secure) secure() <#pecan.secure.secure> . check_permissions() <#pecan.secure.SecureControllerBase .check_permissions> . . . from pecan import expose from pecan.secure import secure from myapp.session import get_current_user from myapp.model import FileObject class FileController(object): def __init__(self, name): self.file_object = FileObject(name) def read_access(self): self.file_object.read_access(get_current_user()) def write_access(self): self.file_object.write_access(get_current_user()) @secure('write_access') @expose() def upload_file(self): pass @secure('read_access') @expose() def download_file(self): pass class RootController(object): @expose() def _lookup(self, name, *remainder): return FileController(name), remainder secure() <#pecan.secure.secure> . . from pecan import expose from pecan.secure import secure from myapp.auth import user_authenitcated class RootController(object): @secure(user_authenticated) @expose() def index(self): return 'Logged in' secure() <#pecan.secure.secure> SecureController <#pecan.secure .SecureController> . (wrap) Pecan . . from pecan import expose from pecan.secure import SecureController, secure from myapp.auth import user_authenticated, admin_user class ApiController(object): pass class RootController(SecureController): @classmethod def check_permissions(cls): return user_authenticated() @classmethod def check_api_permissions(cls): return admin_user() @expose() def index(self): return 'logged in user' api = secure(ApiController(), 'check_api_permissions') Pecan admin_user() /api/ ..SS " (Multiple Secure Controllers)" . /admin/index/ Pecan check_permissions() <#pecan.secure.SecureControllerBase .check_permissions> RootController check_permissions() <#pecan.secure.SecureControllerBase .check_permissions> AdminController . from pecan import expose from pecan.secure import SecureController from myapp.auth import user_logged_in, is_admin class AdminController(SecureController): @classmethod def check_permissions(cls): return is_admin() @expose() def index(self): return 'admin dashboard' class RootController(SecureController): @classmethod def check_permissions(cls): return user_logged_in @expose() def index(self): return 'user dashboard' PECAN (PECAN HOOKS) WSGI Pecan Pecan ( ) . Pecan . : o on_route() <#pecan.hooks.PecanHook.on_route>: Pecan o before() <#pecan.hooks.PecanHook.before>: o after() <#pecan.hooks.PecanHook.after>: o on_error() <#pecan.hooks.PecanHook.on_error>: PECAN (Implementating a Pecan Hook) stdout . PecanHook <#pecan.hooks.PecanHook> (import) . on_route() <#pecan.hooks.PecanHook.on_route> before() <#pecan.hooks .PecanHook.before> after() <#pecan.hooks.PecanHook.after> on_error() <#pecan.hooks.PecanHook.on_error> . from pecan.hooks import PecanHook class SimpleHook(PecanHook): def before(self, state): print "\nabout to enter the controller..." def after(self, state): print "\nmethod: \t %s" % state.request.method print "\nresponse: \t %s" % state.response.status on_route() <#pecan.hooks .PecanHook.on_route> before() <#pecan.hooks.PecanHook.before> after() <#pecan.hooks.PecanHook.after> request response Pecan : class SimpleHook(PecanHook): def on_route(self, state): print "\nabout to map the URL to a Python method (controller)..." assert state.controller is None # Routing hasn't occurred yet assert isinstance(state.request, webob.Request) assert isinstance(state.response, webob.Response) assert isinstance(state.hooks, list) # A list of hooks to apply def before(self, state): print "\nabout to enter the controller..." if state.request.path == '/': # # `state.controller` is a reference to the actual # `@pecan.expose()`-ed controller that will be routed to # and used to generate the response body # assert state.controller.__func__ is RootController.index.__func__ assert isinstance(state.arguments, inspect.Arguments) print state.arguments.args print state.arguments.varargs print state.arguments.keywords assert isinstance(state.request, webob.Request) assert isinstance(state.response, webob.Response) assert isinstance(state.hooks, list) on_error() <#pecan.hooks.PecanHook.on_error> . on_error() <#pecan.hooks.PecanHook.on_error> Response on_error() <#pecan.hooks.PecanHook.on_error> : class CustomErrorHook(PecanHook): def on_error(self, state, exc): if isinstance(exc, SomeExceptionType): return webob.Response('Custom Error!', status=500) . app = { 'root' : '...' # ... 'hooks': lambda: [SimpleHook()] } __hooks__ HookController <# pecan.hooks.HookController> . from pecan import expose from pecan.hooks import HookController from my_hooks import SimpleHook class SimpleController(HookController): __hooks__ = [SimpleHook()] @expose('json') def index(self): print "DO SOMETHING!" return dict() SimpleHook . pecan serve config.py serving on 0.0.0.0:8080 view at http://127.0.0.1:8080 about to enter the controller... DO SOMETHING! method: GET response: 200 OK mixin . HookController <#pecan.hooks.HookController> . from pecan import expose from pecan.hooks import PecanHook, HookController class ParentHook(PecanHook): priority = 1 def before(self, state): print "\nabout to enter the parent controller..." class CommonHook(PecanHook): priority = 2 def before(self, state): print "\njust a common hook..." class SubHook(PecanHook): def before(self, state): print "\nabout to enter the subcontroller..." class SubMixin(object): __hooks__ = [SubHook()] # We'll use the same instance for both controllers, # to avoid double calls common = CommonHook() class SubController(HookController, SubMixin): __hooks__ = [common] @expose('json') def index(self): print "\nI AM THE SUB!" return dict() class RootController(HookController): __hooks__ = [common, ParentHook()] @expose('json') def index(self): print "\nI AM THE ROOT!" return dict() sub = SubController() . : pecan serve config.py serving on 0.0.0.0:8080 view at http://127.0.0.1:8080 GET / HTTP/1.1" 200 about to enter the parent controller... just a common hook I AM THE ROOT! : pecan serve config.py serving on 0.0.0.0:8080 view at http://127.0.0.1:8080 GET /sub HTTP/1.1" 200 about to enter the parent controller... just a common hook about to enter the subcontroller... I AM THE SUB! : (priority) . : / . - . Pecan . . RequestViewerHook . response . : 1. ( stdout) 2. . . : o pecan.hooks -- Pecan <#pecan-hooks> RequestViewerHook . . : o path : url o status : ( '200 OK') o method : ( 'GET' 'POST' 'PUT 'DELETE') o controller : Pecan o params : o hooks : . stdout ( X-Pecan-item_name) . /favicon.ico : path - /favicon.ico status - 404 Not Found method - GET controller - The resource could not be found. params - [] hooks - ['RequestViewerHook'] stdout . HTTP : X-Pecan-path /favicon.ico X-Pecan-status 404 Not Found X-Pecan-method GET X-Pecan-controller The resource could not be found. X-Pecan-params [] X-Pecan-hooks ['RequestViewerHook'] ( ) : items blacklist. ( ): ... 'hooks': lambda: [ RequestViewerHook({'items':['path']}) ] items . . : (override) . (request object) . ( webob): +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+ | | | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+ |accept | make_tempfile | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+ |accept_charset | max_forwards | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+ |accept_encoding | method | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+ |accept_language | params | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+ |application_url | path | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+ |as_string | path_info | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+ |authorization | path_info_peek | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+ |blank | path_info_pop | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+ |body | path_qs | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+ |body_file | path_url | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+ |body_file_raw | postvars | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+ |body_file_seekable | pragma | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+ |cache_control | query_string | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+ |call_application | queryvars | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+ |charset | range | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+ |content_length | referer | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+ |content_type | referrer | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+ |cookies | relative_url | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+ |copy | remote_addr | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+ |copy_body | remote_user | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+ |copy_get | remove_conditional_headers | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+ |date | request_body_tempfile_limit | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+ |decode_param_names | scheme | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+ |environ | script_name | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+ |from_file | server_name | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+ |from_string | server_port | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+ |get_response | str_GET | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+ |headers | str_POST | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+ |host | str_cookies | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+ |host_url | str_params | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+ |http_version | str_postvars | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+ |if_match | str_queryvars | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+ |if_modified_since | unicode_errors | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+ |if_none_match | upath_info | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+ |if_range | url | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+ |if_unmodified_since | urlargs | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+ |is_body_readable | urlvars | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+ |is_body_seekable | uscript_name | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+ |is_xhr | user_agent | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+ |make_body_seekable | | | | | | Pecan hook : | | |0.0 | | |3.5 | | |0.0 | | |o 2 | | |controller | | |o 2 | | |hooks | | |o 2 | | |params ( params webob hook ) | | | | | |168u | | | | | |168u | | | | | |168u | | |" (Blacklisting Certain Paths)" | | | . URL blacklist . | | | URL . : | | |0.0 | | |3.5 | | | | | |{ 'blacklist': ['/f'] } | | | | | | | | |168u | | | | | |168u | | | URL f (globbing) ( ). | | | : | | |0.0 | | |3.5 | | | | | |{ 'blacklist' : ['/favicon.ico', '/javascript', '/images'] } | | | | | | | | |168u | | | | | |168u | | | blacklist items ( ). | | |" JSON (JSON SERIALIZATION)" | | |Pecan JSON . json.py app.py (import) . | | | json JSON . | | | Pecan JSON User : | | |0.0 | | |3.5 | | | | | |from myproject.lib import get_current_user | | | | | |class UsersController(object): | | | @expose('json') | | | def current_user(self): | | | ''' | | | return an instance of myproject.model.User which represents | | | the current authenticated user | | | ''' | | | return get_current_user() | | | | | | | | |168u | | | | | |168u | | | Pecan User JSON . JSON Pecan json.py : | | |0.0 | | |3.5 | | | | | |from pecan.jsonify import jsonify | | |from myproject import model | | | | | |@jsonify.register(model.User) | | |def jsonify_user(user): | | | return dict( | | | name = user.name, | | | email = user.email, | | | birthday = user.birthday.isoformat() | | | ) | | | | | | | | |168u | | | | | |168u | | | model.User JSON jsonify_user() JSON . JSON JSON . | | | __json__() : | | |0.0 | | |3.5 | | | | | |class User(object): | | | def __init__(self, name, email, birthday): | | | self.name = name | | | self.email = email | | | self.birthday = birthday | | | | | | def __json__(self): | | | return dict( | | | name = self.name, | | | email = self.email, | | | birthday = self.birthday.isoformat() | | | ) | | | | | | | | |168u | | | | | |168u | | | json.py JSON JSON ..SH " / (CONTEXT/THREAD-LOCALS VS. EXPLICIT ARGUMENT PASSING)" | | | pecan pecan.request | | |pecan.response | | | . | | | (thread locality) (multi-threaded) | | | | | | pecan | | | . | | | | | | . | | | pecan | | |threading.local() | | | . (asynchronous) | | |- - | | | (monkeypatching) | | |threading.local() greenlet . | | |" (Disabling Thread-Local Proxies)" | | | / | | | | | |use_context_locals=False : | | |0.0 | | |3.5 | | | | | |app = { | | | 'root': 'project.controllers.root.RootController', | | | 'modules': ['project'], | | | 'static_root': '%(confdir)s/public', | | | 'template_path': '%(confdir)s/project/templates', | | | 'debug': True, | | | 'use_context_locals': False | | |} | | | | | | | | |168u | | | | | |168u | | | pecan | | | : | | |0.0 | | |3.5 | | | | | |class RootController(object): | | | | | | @pecan.expose('json') | | | def index(self, req, resp): | | | return dict(method=req.method) # path: / | | | | | | @pecan.expose() | | | def greet(self, req, resp, name): | | | return name # path: /greet/joe | | | | | | | | |168u | | | | | |168u | | | | | |self . | | |"PECAN (COMMAND LINE PECAN)" | | | Pecan pecan | | | . pecan | | | . | | |" Pecan (Serving a Pecan App For Development)" | | | Pecan WSGI | | | wsgiref.simple_server . | | | Pecan pecan serve : | | |0.0 | | |3.5 | | | | | |$ pecan serve config.py | | |Starting server in PID 000. | | |serving on 0.0.0.0:8080, view at http://127.0.0.1:8080 | | | | | | | | |168u | | | | | |168u | | | . | | |host port | | | Server Configuration <#server-configuration> ..SS | | | | | |pecan serve --reload . | | | Pecan | | |watchdog . | | | : | | |0.0 | | |3.5 | | | | | |$ pip install watchdog | | |Downloading/unpacking watchdog | | |... | | |Successfully installed watchdog | | | | | | | | |168u | | | | | |168u | | |0.0 | | |3.5 | | | | | |$ pecan serve --reload config.py | | |Monitoring for changes... | | |Starting server in PID 000. | | |serving on 0.0.0.0:8080, view at http://127.0.0.1:8080 | | | | | | | | |168u | | | | | |168u | | | Pecan | | | . | | | | | | Pecan | | | . | | | pecan shell : | | |0.0 | | |3.5 | | | | | |$ pecan shell config.py | | |Pecan Interactive Shell | | |Python 2.7.1 (r271:86832, Jul 31 2011, 19:30:53) | | |[GCC 4.2.1 (Based on Apple Inc. build 5658) | | | | | | The following objects are available: | | | wsgiapp - This project's WSGI App instance | | | conf - The current configuration | | | app - webtest.TestApp wrapped around wsgiapp | | | | | |>>> conf | | |Config({ | | | 'app': Config({ | | | 'root': 'myapp.controllers.root.RootController', | | | 'modules': ['myapp'], | | | 'static_root': '/Users/somebody/myapp/public', | | | 'template_path': '/Users/somebody/myapp/project/templates', | | | 'errors': {'404': '/error/404'}, | | | 'debug': True | | | }), | | | 'server': Config({ | | | 'host': '0.0.0.0', | | | 'port': '8080' | | | }) | | |}) | | |>>> app | | | | | |>>> app.get('/') | | |<200 OK text/html body='\n ...\n\n'/936> | | | | | | | | |168u | | | | | |168u | | | Ctrl-D ( Ctrl-Z) . | | | | | | pecan shell IPython | | | bpython | | |--shell ( -s) : | | |0.0 | | |3.5 | | | | | |$ pecan shell --shell=ipython config.py | | |$ pecan shell -s bpython config.py | | | | | | | | |168u | | | pecan | | | . | | | (PECAN_CONFIG) . | | | Pecan | | | . | | | (serve) Pecan export | | | . | | |0.0 | | |3.5 | | | | | |$ export PECAN_CONFIG=/path/to/app/config.py | | |$ pecan serve | | |Starting server in PID 000. | | |serving on 0.0.0.0:8080, view at http://127.0.0.1:8080 | | | | | | | | |168u | | | | | |168u | | | pecan | | | ( | | | ) . | | | PECAN_CONFIG | | | . | | | pecan | | | Pecan | | | . | | | << Pecan>> | | | ( | | | pecan shell) . | | | Pecan | | | | | |HTTP GET . | | | : | | |0.0 | | |3.5 | | | | | |$ pecan wget config.py /path/to/some/resource | | | | | | | | |168u | | | | | |168u | | | myapp | | | wget.py : | | |0.0 | | |3.5 | | | | | |# myapp/myapp/wget.py | | |import pecan | | |from webtest import TestApp | | | | | |class GetCommand(pecan.commands.BaseCommand): | | | ''' | | | Issues a (simulated) HTTP GET and returns the request body. | | | ''' | | | | | | arguments = pecan.commands.BaseCommand.arguments + ({ | | | 'name': 'path', | | | 'help': 'the URI path of the resource to request' | | | },) | | | | | | def run(self, args): | | | super(GetCommand, self).run(args) | | | app = TestApp(self.load_app()) | | | print app.get(args.path).body | | | | | | | | |168u | | | | | |168u | | | ..SS run | | | BaseCommand <#pecan.commands.base.BaseCommand> | | |run() <#pecan.commands.base.BaseCommandParent.run> : | | |0.0 | | |o 2 | | | Pecan - load_app() <#pecan.core.load_app> | | |o 2 | | | WSGI - TestApp | | |o 2 | | | HTTP GET - get() | | | | | |168u | | | | | | arguments | | | . | | | BaseCommand <#pecan.commands.base.BaseCommand> | | |( config_file ) . | | | arguments tuple | | | | | |argparse ( | | |add_argument() ). | | | pecan | | | (usage) . | | |0.0 | | |3.5 | | | | | |$ pecan -h | | |usage: pecan [-h] command ... | | | | | |positional arguments: | | | command | | | wget Issues a (simulated) HTTP GET and returns the request body | | | serve Open an interactive shell with the Pecan app loaded | | | ... | | | | | |$ pecan wget -h | | |usage: pecan wget [-h] config_file path | | |$ pecan wget config.py /path/to/some/resource | | | | | | | | |168u | | | | | |168u | | | docstring | | |GetCommand -- Issues a (simulated) HTTP GET and returns the | | |request body -- wget | | |$ pecan -h . | | | Pecan . | | | | | | setup.py | | | . setup.py | | | setup() . | | |0.0 | | |3.5 | | | | | |# myapp/setup.py | | |... | | |setup( | | | name='myapp', | | | version='0.1', | | | author='Joe Somebody', | | | ... | | |) | | | | | | | | |168u | | | | | |168u | | | entry_points | | | setup() [pecan.command] | | | : | | |0.0 | | |3.5 | | | | | |# myapp/setup.py | | |... | | |setup( | | | name='myapp', | | | version='0.1', | | | author='Joe Somebody', | | | ... | | | entry_points=""" | | | [pecan.command] | | | wget = myapp.wget:GetCommand | | | """ | | |) | | | | | | | | |168u | | | | | |168u | | | (development) | | | . | | |0.0 | | |3.5 | | | | | |$ python setup.py develop | | | | | | | | |168u | | | | | |168u | | | . | | |0.0 | | |3.5 | | | | | |$ pecan wget config.py /path/to/some/resource | | | | | | | | |168u | | |" (Reloading Automatically as Files Change)" | | | | | |pecan serve --reload . | | | Pecan | | |watchdog . | | | : | | |0.0 | | |3.5 | | | | | |$ pip install watchdog | | |Downloading/unpacking watchdog | | |... | | |Successfully installed watchdog | | | | | | | | |168u | | | | | |168u | | |0.0 | | |3.5 | | | | | |$ pecan serve --reload config.py | | |Monitoring for changes... | | |Starting server in PID 000. | | |serving on 0.0.0.0:8080, view at http://127.0.0.1:8080 | | | | | | | | |168u | | | | | |168u | | | Pecan | | | . | | |" Pecan (Debugging Pecan Applications)" | | | Pecan | | | . | | |debug True : | | |0.0 | | |3.5 | | | | | |app = { | | | ... | | | 'debug': True, | | | ... | | |} | | | | | | | | |168u | | | | | |168u | | | | | | WSGI | | | . | | | Pecan | | | backlash | | | . | | | : | | |0.0 | | |3.5 | | | | | |$ pip install backlash | | |Downloading/unpacking backlash | | |... | | |Successfully installed backlash | | | | | | | | |168u | | | | | |168u | | |" (Serving Static Files)" | | | Pecan CSS Javascript | | | . | | | : | | |0.0 | | |3.5 | | | | | |app = { | | | ... | | | 'debug': True, | | | 'static_root': '%(confdir)/public | | |} | | | | | | | | |168u | | | | | |168u | | | static_root | | | . %(confdir) | | | Pecan . | | |: | | |0.0 | | |3.5 | | | (production) app.debug True | | | . | | | | | |168u | | | Pecan . . | | |: | | |0.0 | | |3.5 | | | Pecan (pecan serve) (production-ready) . | | | | | |168u | | | | | |168u | | | Pecan | | | Pecan : | | |0.0 | | |o 2 | | | setuptools . Pecan setup.py ( python /path/to/project/setup.py install). Pecan Creating Your First Pecan Application <#quick-start> Pecan . | | |o 2 | | | pip . | | | pip freeze pip install requirements.txt . | | |o 2 | | | Installation <#installation>. | | | | | |168u | | |: | | |0.0 | | |3.5 | | | (virtualenv) . | | | | | |168u | | | | | |168u | | | (Debug Mode) | | |: | | |0.0 | | |3.5 | | | Pecan Debug Mode (tracebacks) . . debug False . | | |0.0 | | |3.5 | | | | | |# myapp/production_config.py | | |app = { | | | ... | | | 'debug': False | | |} | | | | | | | | |168u | | | | | |168u | | | | | |168u | | | | | |168u | | |Pecan WSGI | | | WSGI . Pecan "WSGI application" WSGI WSGI ("WSGI compatible") . : | | |0.0 | | |o 2 | | |mod_wsgi | | |o 2 | | |uWSGI | | |o 2 | | |Gunicorn | | |o 2 | | |waitress | | |o 2 | | |CherryPy | | | | | |168u | | | WSGI Pecan deploy() <#pecan.deploy.deploy> : | | |0.0 | | |3.5 | | | | | |from pecan.deploy import deploy | | |application = deploy('/path/to/some/app/config.py') | | | | | | | | |168u | | |Pecan ( CSS Javascript ) . | | | Pecan . | | | WSGI ( ). : | | |0.0 | | |1. 3 | | | ( nginx cherokee CherryPy lighttpd ) WSGI : | | |3.0 | | |3.5 | | | | | | , e.g., Apache, nginx, cherokee (0.0.0.0:80) | | | | | | | Instance e.g., mod_wsgi, Gunicorn, uWSGI (127.0.0.1:5000 or /tmp/some.sock) | | | Instance e.g., mod_wsgi, Gunicorn, uWSGI (127.0.0.1:5001 or /tmp/some.sock) | | | Instance e.g., mod_wsgi, Gunicorn, uWSGI (127.0.0.1:5002 or /tmp/some.sock) | | | Instance e.g., mod_wsgi, Gunicorn, uWSGI (127.0.0.1:5003 or /tmp/some.sock) | | | | | | | | |168u | | | | | |168u | | |2. 3 | | | CDN . | | | | | |168u | | |" " | | |Apache + mod_wsgi | | | mod_wsgi Apache WSGI ( Pecan ) . | | | mod_wsgi . | | | simpleapp /var/www/simpleapp virtualenv /var/www/venv ( Pecan) . user1 group1 . | | | .wsgi mod_wsgi : | | |0.0 | | |3.5 | | | | | |# /var/www/simpleapp/app.wsgi | | |from pecan.deploy import deploy | | |application = deploy('/var/www/simpleapp/config.py') | | | | | | | | |168u | | | | | |168u | | | Apache . : | | |0.0 | | |3.5 | | | | | | | | | ServerName example.com | | | | | | WSGIDaemonProcess simpleapp user=user1 group=group1 threads=5 python-path=/var/www/venv/lib/python2.7/site-packages | | | WSGIScriptAlias / /var/www/simpleapp/app.wsgi | | | | | | | | | WSGIProcessGroup simpleapp | | | WSGIApplicationGroup %{GLOBAL} | | | Order deny,allow | | | Allow from all | | | | | | | | | | | | | | |168u | | | | | |168u | | | WSGI mod_wsgi mod_wsgi . | | | Apache ..SS uWSGI | | | uWSGI C . uwsgi (http fastcgi...). | | | Pecan uWSGI : | | |0.0 | | |3.5 | | | | | |$ pip install uwsgi | | |$ pecan create simpleapp && cd simpleapp | | |$ python setup.py develop | | |$ uwsgi --http-socket :8080 --venv /path/to/virtualenv --pecan config.py | | | | | | | | |168u | | | | | |168u | | | Unix ( nginx ): | | |0.0 | | |3.5 | | | | | |$ uwsgi -s /tmp/uwsgi.sock --venv /path/to/virtualenv --pecan config.py | | | | | | | | |168u | | | | | |168u | | |Gunicorn | | | Gunicorn "Green Unicorn" HTTP WSGI UNIX . pre-fork Unicorn Ruby . eventlet greenlet . | | | Pecan Gunicorn . Pecan : | | |0.0 | | |3.5 | | | | | |$ pip install gunicorn | | |$ pecan create simpleapp && cd simpleapp | | |$ python setup.py develop | | |$ gunicorn_pecan config.py | | | | | | | | |168u | | | | | |168u | | |CherryPy | | | CherryPy (thread-pooled) HTTP/1.1 WSGI . Pecan (static) . | | | CherryPy Pecan . | | |0.0 | | |3.5 | | | | | |$ pip install cherrypy | | |$ pecan create simpleapp && cd simpleapp | | |$ python setup.py develop | | | | | | | | |168u | | | | | |168u | | | CherryPy ( setup.py) . ( run.py) : | | |0.0 | | |3.5 | | | | | |import os | | | | | |import cherrypy | | |from cheroot import wsgi | | |from cheroot.wsgi import PathInfoDispatcher | | |from pecan.deploy import deploy | | | | | |simpleapp_wsgi_app = deploy('/path/to/production_config.py') | | | | | |public_path = os.path.abspath(os.path.join(os.path.dirname(__file__), 'public')) | | | | | |# A dummy class for our Root object | | |# necessary for some CherryPy machinery | | |class Root(object): | | | pass | | | | | |def make_static_config(static_dir_name): | | | """ | | | All custom static configurations are set here, since most are common, it | | | makes sense to generate them just once. | | | """ | | | static_path = os.path.join('/', static_dir_name) | | | path = os.path.join(public_path, static_dir_name) | | | configuration = { | | | static_path: { | | | 'tools.staticdir.on': True, | | | 'tools.staticdir.dir': path | | | } | | | } | | | return cherrypy.tree.mount(Root(), '/', config=configuration) | | | | | |# Assuming your app has media on different paths, like 'css', and 'images' | | |application = PathInfoDispatcher({ | | | '/': simpleapp_wsgi_app, | | | '/css': make_static_config('css'), | | | '/images': make_static_config('images') | | |}) | | | | | |server = wsgi.Server(('0.0.0.0', 8080), application, server_name='simpleapp') | | | | | |try: | | | server.start() | | |except KeyboardInterrupt: | | | print("Terminating server...") | | | server.stop() | | | | | | | | |168u | | | | | |168u | | | Python : | | |0.0 | | |3.5 | | | | | |$ python run.py | | | | | | | | |168u | | |Pecan logging.config.dictConfig | | | logging . | | | dictConfig() | | | . | | | | | | quickstart << Pecan>> <#quick-start> : | | |0.0 | | |3.5 | | | | | |$ pecan create myapp | | | | | | | | |168u | | | | | |168u | | | handler logger . | | |0.0 | | |3.5 | | | | | |# myapp/config.py | | | | | |app = { ... } | | |server = { ... } | | | | | |logging = { | | | 'root' : {'level': 'INFO', 'handlers': ['console']}, | | | 'loggers': { | | | 'myapp': {'level': 'DEBUG', 'handlers': ['console']} | | | }, | | | 'handlers': { | | | 'console': { | | | 'level': 'DEBUG', | | | 'class': 'logging.StreamHandler', | | | 'formatter': 'simple' | | | } | | | }, | | | 'formatters': { | | | 'simple': { | | | 'format': ('%(asctime)s %(levelname)-5.5s [%(name)s]' | | | '[%(threadName)s] %(message)s') | | | } | | | } | | |} | | | | | | | | |168u | | | | | |168u | | |0.0 | | |o 2 | | |console simple stderr . | | |o 2 | | |myapp DEBUG handler console | | | | | |o 2 | | |root INFO handler console | | | | | | | | |168u | | | | | | (logger) myapp Pecan . | | | . | | | . | | |0.0 | | |3.5 | | | | | |# myapp/myapp/controllers/root.py | | |from pecan import expose | | |import logging | | | | | |logger = logging.getLogger(__name__) | | | | | |class RootController(object): | | | | | | @expose() | | | def index(self): | | | if bad_stuff(): | | | logger.error('Uh-oh!') | | | return dict() | | | | | | | | |168u | | | logging . : | | |0.0 | | |o 2 | | |FileHandler - | | |o 2 | | |RotatingFileHandler - | | |FileHandler (rotate) | | |o 2 | | |SysLogHandler - syslog | | |o 2 | | |SMTPHandler - SMTP | | | | | |168u | | | logging . | | | Paste Translogger | | | Paste ( Pecan ) | | |TransLogger Apache Combined Log Format . TransLogger access.log Apache . | | | setup_app app.py : | | |0.0 | | |3.5 | | | | | |# myapp/myapp/app.py | | |from pecan import make_app | | |from paste.translogger import TransLogger | | | | | |def setup_app(config): | | | # ... | | | app = make_app( | | | config.app.root | | | # ... | | | ) | | | app = TransLogger(app, setup_console_handler=False) | | | return app | | | | | | | | |168u | | | | | |168u | | | TransLogger | | |wsgi Pecan ( ) : | | |0.0 | | |3.5 | | | | | |# myapp/config.py | | | | | |app = { ... } | | |server = { ... } | | | | | |logging = { | | | 'loggers': { | | | # ... | | | 'wsgi': {'level': 'INFO', 'handlers': ['logfile'], 'qualname': 'wsgi'} | | | }, | | | 'handlers': { | | | # ... | | | 'logfile': { | | | 'class': 'logging.FileHandler', | | | 'filename': '/etc/access.log', | | | 'level': 'INFO', | | | 'formatter': 'messageonly' | | | } | | | }, | | | 'formatters': { | | | # ... | | | 'messageonly': {'format': '%(message)s'} | | | } | | |} | | | | | | | | |168u | | | (test runner) Pecan . myapp.tests . | | | (unit testing) (integration testing) Pecan unittest . | | |" (Test Discovery and Other Tools)" | | | Pecan python setup.py test . Pecan | | |nose pytest | | | tox . | | |" WebTest (Writing Functional Tests with WebTest)" | | | " (mock)" " (fake)" . . | | | . Pecan webtest . HTTP HTTP . (quickstart) Pecan . | | |0.0 | | |3.5 | | | | | |# myapp/myapp/tests/__init__.py | | | | | |import os | | |from unittest import TestCase | | |from pecan import set_config | | |from pecan.testing import load_test_app | | | | | |class FunctionalTest(TestCase): | | | """ | | | Used for functional tests where you need to test your | | | literal application and its integration with the framework. | | | """ | | | | | | def setUp(self): | | | self.app = load_test_app(os.path.join( | | | os.path.dirname(__file__), | | | 'config.py' | | | )) | | | | | | def tearDown(self): | | | set_config({}, overwrite=True) | | | | | | | | |168u | | | | | |168u | | | Pecan pecan.testing.load_test_app() <#pecan.testing.load_test_app> Pecan TestApp . | | | FunctionalTest HTTP . | | |0.0 | | |3.5 | | | | | |class TestIndex(FunctionalTest): | | | | | | def test_index(self): | | | resp = self.app.get('/') | | | assert resp.status_int == 200 | | | assert 'Hello, World' in resp.body | | | | | | | | |168u | | | | | |168u | | | : | | |0.0 | | |3.5 | | | | | |TestApp | | | webtest . | | | | | |168u | | | (assertions) . | | | Pecan | | |" " TestResponse . | | | Pecan | | |name URL . | | |0.0 | | |3.5 | | | | | |# myapp/myapp/controllers/root.py | | |from pecan import expose | | | | | |class RootController(object): | | | | | | @expose('index.html') | | | def index(self, name='Joe'): | | | """A request to / will access this controller""" | | | return dict(name=name) | | | | | | | | |168u | | | | | |168u | | | ( ) . | | |0.0 | | |3.5 | | | | | |# myapp/myapp/templates/index.html | | |Hello, ${name}! | | | | | | | | |168u | | | | | |168u | | | (functional test) : | | |0.0 | | |3.5 | | | | | |class TestIndex(FunctionalTest): | | | | | | def test_index(self): | | | resp = self.app.get('/') | | | assert resp.status_int == 200 | | | assert 'Hello, Joe!' in resp.body | | | | | | | | |168u | | | | | |168u | | | webtest.TestResponse.body Pecan | | |webtest.TestResponse.namespace ( | | | ) webtest.TestResponse.template_name ( | | |) . | | |0.0 | | |3.5 | | | | | |class TestIndex(FunctionalTest): | | | | | | def test_index(self): | | | resp = self.app.get('/') | | | assert resp.status_int == 200 | | | assert resp.namespace == {'name': 'Joe'} | | | assert resp.template_name == 'index.html' | | | | | | | | |168u | | | | | |168u | | | | | | . | | |" (GENERATING AND VALIDATING FORMS)" | | | Pecan (opinionated) | | | | | | . | | | | | |WTForms Pecan ..SS | | | first_name | | | last_name . | | |0.0 | | |3.5 | | | | | |from wtforms import Form, TextField, validators | | | | | |class MyForm(Form): | | | first_name = TextField(u'First Name', validators=[validators.required()]) | | | last_name = TextField(u'Last Name', validators=[validators.optional()]) | | | | | |class SomeController(object): | | | pass | | | | | | | | |168u | | | | | |168u | | | | | | . | | |0.0 | | |3.5 | | | | | |from pecan import expose | | |from wtforms import Form, TextField, validators | | | | | |class MyForm(Form): | | | first_name = TextField(u'First Name', validators=[validators.required()]) | | | last_name = TextField(u'Last Name', validators=[validators.optional()]) | | | | | |class SomeController(object): | | | | | | @expose(template='index.html') | | | def index(self): | | | return dict(form=MyForm()) | | | | | | | | |168u | | | | | |168u | | | Mako : | | |0.0 | | |3.5 | | | | | |
| | |
| | | ${form.first_name.label}: | | | ${form.first_name} | | |
| | |
| | | ${form.last_name.label}: | | | ${form.last_name} | | |
| | | | | |
| | | | | | | | |168u | | | | | |168u | | | POST | | | MyForm | | | . | | |0.0 | | |3.5 | | | | | |from pecan import expose, request | | |from wtforms import Form, TextField, validators | | | | | |class MyForm(Form): | | | first_name = TextField(u'First Name', validators=[validators.required()]) | | | last_name = TextField(u'Last Name', validators=[validators.optional()]) | | | | | |class SomeController(object): | | | | | | @expose(template='index.html') | | | def index(self): | | | my_form = MyForm(request.POST) | | | if request.method == 'POST' and my_form.validate(): | | | # save_values() | | | redirect('/success') | | | else: | | | return dict(form=my_form) | | | | | | | | |168u | | | (Pecan) (opinionated) . | | | (best practices) Beaker Pecan . | | |" (Setting up Session Management)" | | | . (middleware) WSGI . (Pecan Hooks) <#hooks> . | | | WSGI SessionMiddleware Beaker app.py . | | |0.0 | | |3.5 | | | | | |from pecan import conf, make_app | | |from beaker.middleware import SessionMiddleware | | |from test_project import model | | | | | |app = make_app( | | | ... | | |) | | |app = SessionMiddleware(app, conf.beaker) | | | | | | | | |168u | | | | | |168u | | | : | | |0.0 | | |3.5 | | | | | |beaker = { | | | 'session.key' : 'sessionkey', | | | 'session.type' : 'cookie', | | | 'session.validate_key' : '05d2175d1090e31f42fa36e63b8d2aad', | | | '__force_dict__' : True | | |} | | | | | | | | |168u | | | | | |168u | | |" ORM (WORKING WITH DATABASES, TRANSACTIONS, AND ORM'S)" | | | (Pecan) ORM . ORM SQLAlchemy Pecan . | | |"init_model (init_model and Preparing Your Model)" | | | quickstart Pecan (stub) . | | |0.0 | | |3.5 | | | | | |. | | | test_project | | | app.py | | | __init__.py | | | controllers | | | model | | | | __init__.py | | | templates | | | | | | | | |168u | | | | | |168u | | | init_model() . | | |0.0 | | |3.5 | | | | | |from pecan import conf | | | | | |def init_model(): | | | """ | | | This is a stub method which is called at application startup time. | | | | | | If you need to bind to a parsed database configuration, set up tables | | | or ORM classes, or perform any database initialization, this is the | | | recommended place to do it. | | | | | | For more information working with databases, and some common recipes, | | | see https://pecan.readthedocs.io/en/latest/databases.html | | | """ | | | pass | | | | | | | | |168u | | | | | |168u | | | (bindings) (engines) (pools) ORM . | | | model (commit) (rollback) (session) . (relations) . Pecan . | | |0.0 | | |3.5 | | | | | |# Server Specific Configurations | | |server = { | | | ... | | |} | | | | | |# Pecan Application Configurations | | |app = { | | | ... | | |} | | | | | |# Bindings and options to pass to SQLAlchemy's ``create_engine`` | | |sqlalchemy = { | | | 'url' : 'mysql://root:@localhost/dbname?charset=utf8&use_unicode=0', | | | 'echo' : False, | | | 'echo_pool' : False, | | | 'pool_recycle' : 3600, | | | 'encoding' : 'utf-8' | | |} | | | | | | | | |168u | | | | | |168u | | | SQLAlchemy : | | |0.0 | | |3.5 | | | | | |from pecan import conf | | |from sqlalchemy import create_engine, MetaData | | |from sqlalchemy.orm import scoped_session, sessionmaker | | | | | |Session = scoped_session(sessionmaker()) | | |metadata = MetaData() | | | | | |def _engine_from_config(configuration): | | | configuration = dict(configuration) | | | url = configuration.pop('url') | | | return create_engine(url, **configuration) | | | | | |def init_model(): | | | conf.sqlalchemy.engine = _engine_from_config(conf.sqlalchemy) | | | | | |def start(): | | | Session.bind = conf.sqlalchemy.engine | | | metadata.bind = Session.bind | | | | | |def commit(): | | | Session.commit() | | | | | |def rollback(): | | | Session.rollback() | | | | | |def clear(): | | | Session.remove() | | | | | | | | |168u | | | . WSGI . (Pecan Hooks) <#hooks> . TransactionHook <#pecan.hooks.TransactionHook> . app.py . | | |0.0 | | |3.5 | | | | | |from pecan import conf, make_app | | |from pecan.hooks import TransactionHook | | |from test_project import model | | | | | |app = make_app( | | | conf.app.root, | | | static_root = conf.app.static_root, | | | template_path = conf.app.template_path, | | | debug = conf.app.debug, | | | hooks = [ | | | TransactionHook( | | | model.start, | | | model.start_read_only, | | | model.commit, | | | model.rollback, | | | model.clear | | | ) | | | ] | | |) | | | | | | | | |168u | | | | | |168u | | | HTTP POST PUT DELETE TransactionHook <#pecan.hooks.TransactionHook> : | | |0.0 | | |1. 3 | | | model.start() . SQLAlchemy . | | |2. 3 | | | . | | |3. 3 | | | model.rollback() (re-raised). (rollback) . | | |4. 3 | | | model.commit() model.clear() . | | | | | |168u | | | ( HTTP GET HEAD) TransactionHook <#pecan.hooks.TransactionHook> . | | |0.0 | | |1. 3 | | | model.start_read_only() . SQLAlchemy . | | |2. 3 | | | . | | |3. 3 | | | model.clear() . | | | | | |168u | | | after_commit() <#pecan.decorators.after_commit> pecan.decorators -- <#pecan-decorators> . | | | (Splitting Reads and Writes) | | | TransactionHook <#pecan.hooks.TransactionHook> HTTP ( GET/HEAD (slave) POST/PUT/DELETE (master) / ). TransactionHook <#pecan.hooks.TransactionHook> . | | | master/standby master standby Pecan sqlalchemy : | | |0.0 | | |3.5 | | | | | |# Server Specific Configurations | | |server = { | | | ... | | |} | | | | | |# Pecan Application Configurations | | |app = { | | | ... | | |} | | | | | |# Master database | | |sqlalchemy_w = { | | | 'url': 'postgresql+psycopg2://root:@master_host/dbname', | | | 'pool_recycle': 3600, | | | 'encoding': 'utf-8' | | |} | | | | | |# Read Only database | | |sqlalchemy_ro = { | | | 'url': 'postgresql+psycopg2://root:@standby_host/dbname', | | | 'pool_recycle': 3600, | | | 'encoding': 'utf-8' | | |} | | | | | | | | |168u | | | | | |168u | | | quickstart Pecan ( init_model Preparing Your Model ) : | | |0.0 | | |3.5 | | | | | |from pecan import conf | | |from sqlalchemy import create_engine, MetaData | | |from sqlalchemy.orm import scoped_session, sessionmaker | | | | | |Session = scoped_session(sessionmaker()) | | |metadata = MetaData() | | | | | | | | |def init_model(): | | | conf.sqlalchemy_w.engine = _engine_from_config(conf.sqlalchemy_w) | | | conf.sqlalchemy_ro.engine = _engine_from_config(conf.sqlalchemy_ro) | | | | | |def _engine_from_config(configuration): | | | configuration = dict(configuration) | | | url = configuration.pop('url') | | | return create_engine(url, **configuration) | | | | | | | | |def start(): | | | Session.bind = conf.sqlalchemy_w.engine | | | metadata.bind = conf.sqlalchemy_w.engine | | | | | | | | |def start_read_only(): | | | Session.bind = conf.sqlalchemy_ro.engine | | | metadata.bind = conf.sqlalchemy_ro.engine | | | | | | | | |def commit(): | | | Session.commit() | | | | | | | | |def rollback(): | | | Session.rollback() | | | | | | | | |def clear(): | | | Session.close() | | | | | | | | |def flush(): | | | Session.flush() | | | | | | | | |168u | | | Pecan 404 Page Not Found . | | | << Pecan>> <#quick-start> . | | |: | | |0.0 | | |3.5 | | | HTTP 404 HTTP . . | | | | | |168u | | | | | |168u | | |" (Overview)" | | |Pecan : | | |0.0 | | |3.5 | | |0.0 | | |o 2 | | | (Routing) HTTP config.py | | |o 2 | | | (Custom Controllers) | | | | | |168u | | | | | |168u | | | | | |168u | | |" (Configure Routing)" | | | test_project HTTP 404 Page Not Found . | | | test_project/config.py error-handler . | | |0.0 | | |3.5 | | | | | |# Pecan Application Configurations | | |app = { | | | 'root' : 'test_project.controllers.root.RootController', | | | 'modules' : ['test_project'], | | | 'static_root' : '%(confdir)s/public', | | | 'template_path' : '%(confdir)s/test_project/templates', | | | 'reload' : True, | | | 'debug' : True, | | | | | | # modify the 'errors' key to direct HTTP status codes to a custom | | | # controller | | | 'errors' : { | | | #404 : '/error/404', | | | 404 : '/notfound', | | | '__force_dict__' : True | | | } | | |} | | | | | | | | |168u | | | | | |168u | | | Pecan 404 notfound . | | |" (Write Custom Controllers)" | | | test_project.root.RootController ( test_project/controllers/root.py). | | |0.0 | | |3.5 | | | | | |from pecan import expose | | |from webob.exc import status_map | | | | | | | | |class RootController(object): | | | | | | @expose(generic=True, template='index.html') | | | def index(self): | | | return dict() | | | | | | @index.when(method='POST') | | | def index_post(self, q): | | | redirect('https://pecan.readthedocs.io/en/latest/search.html?q=%s' % q) | | | | | | | | | ## custom handling of '404 Page Not Found' messages | | | @expose('error.html') | | | def notfound(self): | | | return dict(status=404, message="test_project does not have this page") | | | | | | | | | @expose('error.html') | | | def error(self, status): | | | try: | | | status = int(status) | | | except ValueError: | | | status = 0 | | | message = getattr(status_map.get(status), 'explanation', '') | | | return dict(status=status, message=message) | | | | | | | | |168u | | | | | |168u | | | ! | | | RootController : | | |0.0 | | |3.5 | | | | | |## custom handling of '404 Page Not Found' messages | | |@expose('error.html') | | |def notfound(self): | | | return dict(status=404, message="test_project does not have this page") | | | | | | | | |168u | | | | | |168u | | | notfound expose() <#pecan.decorators.expose> error.html ( test_project test_project/templates/ ). Pecan . | | | 404 test_project ..SH " : (EXAMPLE APPLICATION: SIMPLE FORMS PROCESSING)" | | | Pecan . | | |" (Project Setup)" | | | Pecan : | | |0.0 | | |3.5 | | | | | |$ pip install pecan | | | | | | | | |168u | | | | | |168u | | | Pecan : | | |0.0 | | |3.5 | | | | | |$ pecan create mywebsite | | |$ cd mywebsite | | | | | | | | |168u | | | | | |168u | | | (development mode) : | | |0.0 | | |3.5 | | | | | |$ python setup.py develop | | | | | | | | |168u | | | | | |168u | | | templates index.html . : | | |0.0 | | |3.5 | | | | | |<%inherit file="layout.html" /> | | | | | |<%def name="title()"> | | | Welcome to Pecan! | | | | | |
| | |

| | |
| | |
| | |
| | |
| | |

Enter a message:

| | |

Enter your first name:

| | | | | |
| | |
| | | % if not form_post_data is UNDEFINED: | | |

${form_post_data['first_name']}, your message is: ${form_post_data['message']}

| | | % endif | | |
| | | | | | | | |168u | | | | | |168u | | | | | |0.0 | | |1. 3 | | | form input . message first_name . | | |2. 3 | | | form_post_data . | | |3. 3 | | | POST . | | | | | |168u | | | controllers root.py . RootController '/' index.html . . | | | root.py : | | |0.0 | | |3.5 | | | | | |from pecan import expose | | | | | | | | |class RootController(object): | | | | | | @expose(generic=True, template='index.html') | | | def index(self): | | | return dict() | | | | | | @index.when(method='POST', template='index.html') | | | def index_post(self, **kwargs): | | | return dict(form_post_data=kwargs) | | | | | | | | |168u | | | | | |168u | | | | | |0.0 | | |1. 3 | | | index index.html . | | |2. 3 | | | index_post . | | | | | |168u | | | : | | |0.0 | | |3.5 | | | | | |$ pecan serve config.py | | | | | | | | |168u | | | | | |168u | | | : .SS | | | submit . (post back) . | | | . . WTForms . | | | WTForms : | | |0.0 | | |3.5 | | | | | |$ pip install wtforms | | | | | | | | |168u | | | | | |168u | | |: | | |0.0 | | |3.5 | | | Pecan . Pecan . . | | | | | |168u | | | | | |168u | | | root.py : | | |0.0 | | |3.5 | | | | | |from pecan import expose, request | | |from wtforms import Form, TextField, validators | | | | | | | | |class PersonalizedMessageForm(Form): | | | message = TextField(u'Enter a message', | | | validators=[validators.required()]) | | | first_name = TextField(u'Enter your first name', | | | validators=[validators.required()]) | | | | | | | | |class RootController(object): | | | | | | @expose(generic=True, template='index.html') | | | def index(self): | | | return dict(form=PersonalizedMessageForm()) | | | | | | @index.when(method='POST', template='index.html') | | | def index_post(self): | | | form = PersonalizedMessageForm(request.POST) | | | if form.validate(): | | | return dict(message=form.message.data, | | | first_name=form.first_name.data) | | | else: | | | return dict(form=form) | | | | | | | | |168u | | | | | |168u | | | | | |0.0 | | |1. 3 | | | PersonalizedMessageForm | | |2. 3 | | | index PersonalizedMessageForm | | |3. 3 | | | index_post (POST) . . () | | | | | |168u | | | index.html : | | |0.0 | | |3.5 | | | | | |<%inherit file="layout.html" /> | | | | | |## provide definitions for blocks we want to redefine | | |<%def name="title()"> | | | Welcome to Pecan! | | | | | |
| | |

| | |
| | |
| | | % if not form: | | |

${first_name}, your message is: ${message}

| | | % else: | | |
| | |
| | | ${form.message.label}: | | | ${form.message} | | | % if form.message.errors: | | | ${form.message.errors[0]} | | | % endif | | |
| | |
| | | ${form.first_name.label}: | | | ${form.first_name} | | | % if form.first_name.errors: | | | ${form.first_name.errors[0]} | | | % endif | | |
| | | | | |
| | | % endif | | |
| | | | | | | | |168u | | | | | |168u | | |: | | |0.0 | | |3.5 | | | WTForms . . . | | | | | |168u | | | | | |168u | | | : | | |0.0 | | |3.5 | | | | | |$ pecan serve config.py | | | | | | | | |168u | | | | | |168u | | | : | | | ..SH " : AJAX (EXAMPLE APPLICATION: SIMPLE AJAX)" | | | Pecan AJAX JSON . | | |" (Project Setup)" | | | Pecan : | | |0.0 | | |3.5 | | | | | |$ pip install pecan | | | | | | | | |168u | | | | | |168u | | | Pecan : | | |0.0 | | |3.5 | | | | | |$ pecan create myajax | | |$ cd myajax | | | | | | | | |168u | | | | | |168u | | | : | | |0.0 | | |3.5 | | | | | |$ python setup.py develop | | | | | | | | |168u | | | | | |168u | | |" AJAX (Adding JavaScript AJAX Support)" | | | jQuery . jQuery templates layout.html . | | | jQuery : | | |0.0 | | |3.5 | | | | | | | | | | | | | | |168u | | | | | |168u | | | AJAX jQuery . | | | layout.html : | | |0.0 | | |3.5 | | | | | | | | | | | | ${self.title()} | | | ${self.style()} | | | ${self.javascript()} | | | | | | | | | ${self.body()} | | | | | | | | | | | |<%def name="title()"> | | | Default Title | | | | | | | | |<%def name="style()"> | | | | | | | | | | | |<%def name="javascript()"> | | | | | | | | | | | | | | | | | | | | | | | |168u | | | | | |168u | | | | | |0.0 | | |1. 3 | | | head jQuery CDN | | |2. 3 | | | AJAX HTTP GET id | | |3. 3 | | | onSuccess | | | index.html . AJAX Pecan HTML . index.html : | | |0.0 | | |3.5 | | | | | |<%inherit file="layout.html" /> | | | | | |<%def name="title()"> | | |Welcome to Pecan! | | | | | | | | |
| | |

| | |
| | | | | |
| | |

Select a project to get details:

| | | | | | | | | | | |
| | | | | |
| | | | | | | | |168u | | | | | |168u | | | | | |0.0 | | |1. 3 | | | (submit) . . | | | | | |168u | | | JSON | | | HTML JavaScript . model . projects.py : | | |0.0 | | |3.5 | | | | | |class Project(object): | | | def __init__(self, name, licensing, repository, documentation): | | | self.name = name | | | self.licensing = licensing | | | self.repository = repository | | | self.documentation = documentation | | | | | | def __json__(self): | | | return dict( | | | name=self.name, | | | licensing=self.licensing, | | | repository=self.repository, | | | documentation=self.documentation | | | ) | | | | | | | | |168u | | | | | |168u | | | | | |0.0 | | |1. 3 | | | Project . | | |2. 3 | | | __json__ Project class JSON . JSON . | | | | | |168u | | |: | | |0.0 | | |3.5 | | | JSON Pecan JSON <#jsonify> . | | | | | |168u | | | | | |168u | | | | | | root.py controllers ProjectsController . root.py : | | |0.0 | | |3.5 | | | | | |from pecan import expose | | | | | |from myajax.controllers.projects import ProjectsController | | | | | | | | |class RootController(object): | | | | | | projects = ProjectsController() | | | | | | @expose(generic=True, template='index.html') | | | def index(self): | | | return dict() | | | | | | | | |168u | | | | | |168u | | | | | |0.0 | | |1. 3 | | | (boilerplate) . | | |2. 3 | | | ProjectsController . | | | | | |168u | | | projects.py controllers . ProjectsController AJAX GET ( ) JSON . | | | projects.py : | | |0.0 | | |3.5 | | | | | |from pecan import expose, response | | |from pecan.rest import RestController | | | | | |from myajax.model.projects import Project | | | | | | | | |class ProjectsController(RestController): | | | | | | # Note: You would probably store this information in a database | | | # This is just for simplicity and demonstration purposes | | | def __init__(self): | | | self.projects = [ | | | Project(name='OpenStack', | | | licensing='Apache 2', | | | repository='http://github.com/openstack', | | | documentation='http://docs.openstack.org'), | | | Project(name='Pecan', | | | licensing='BSD', | | | repository='http://github.com/pecan/pecan', | | | documentation='https://pecan.readthedocs.io'), | | | Project(name='stevedore', | | | licensing='Apache 2', | | | repository='http://github.com/dreamhost/pecan', | | | documentation='http://docs.openstack.org/developer/stevedore/') | | | ] | | | | | | | | | @expose('json', content_type='application/json') | | | def get(self, id): | | | response.status = 200 | | | return self.projects[int(id)] | | | | | | | | |168u | | | | | |168u | | | | | |0.0 | | |1. 3 | | | projects . . | | |2. 3 | | | (endpoint) projects id JSON . | | | | | |168u | | | : | | |0.0 | | |3.5 | | | | | |$ pecan serve config.py | | | | | | | | |168u | | | | | |168u | | | : | | | . id HTTP 404 . ProjectsController . | | | get : | | |0.0 | | |3.5 | | | | | |@expose('json', content_type='application/json') | | |def get(self, id): | | | try: | | | response.status = 200 | | | return self.projects[int(id)] | | | except (IndexError, ValueError) as ex: | | | abort(404) | | | | | | | | |168u | | | | | | id ProjectsController . index.html option id - . | | |0.0 | | |3.5 | | | | | |

Select a project to get details:

| | | | | | | | | | | |168u | | | | | |168u | | | WSME . | | | : | | |0.0 | | |3.5 | | | | | |$ pecan serve config.py | | | | | | | | |168u | | | | | |168u | | | : | | | WSME . . | | | Pecan docstring . API docstring : | | |"PECAN.CORE -- PECAN (PECAN CORE)" | | | pecan.core Pecan . HTTP . | | |0.0 | | | | | |class pecan.core.Pecan(*args, **kw) | | | : PecanBase | | | Pecan. pecan.make_app . | | | Pecan WSGI . | | |7.0 | | | | | | (Parameters) | | |7.0 | | |o 2 | | |root -- ( "myapp.controller.root.RootController") | | |o 2 | | |default_renderer -- . mako . | | |o 2 | | |template_path -- ( ) . 'templates' . | | |o 2 | | |hooks -- pecan.hooks.PecanHook <#pecan.hooks.PecanHook> . | | |o 2 | | |custom_renderers -- . | | |o 2 | | |extra_template_vars -- (namespace) . | | |o 2 | | |force_canonical -- (canonical URLs) . | | |o 2 | | |guess_content_type_from_ext -- . | | |o 2 | | |use_context_locals -- True pecan.request pecan.response (thread-local) . | | |o 2 | | |request_cls -- pecan.request . pecan.Request . | | |o 2 | | |response_cls -- pecan.response . pecan.Response . | | | | | |168u | | | | | |168u | | |7.0 | | | | | |find_controller(_state) | | | Pecan. | | | | | |168u | | |7.0 | | | | | |handle_hooks(hooks, *args, **kw) | | | (hooks) . | | |7.0 | | | | | | (Parameters) | | |7.0 | | |o 2 | | |hook_type -- before after on_error on_route. | | |o 2 | | |*args -- | | | . | | | | | | | | |168u | | | | | |168u | | | | | |168u | | | | | |168u | | |0.0 | | | | | |class pecan.core.Request(environ, charset=None, unicode_errors=None, decode_param_names=None, **kw) | | | : Request | | | | | |168u | | |0.0 | | | | | |class pecan.core.Response(body=None, status=None, headerlist=None, app_iter=None, content_type=None, conditional_response=None, charset=, **kw) | | | : Response | | | | | |168u | | |0.0 | | | | | |pecan.core.abort(status_code, detail='', headers=None, comment=None, **kw) | | | HTTP (Raise). 401 Unauthorized 403 Forbidden . | | |7.0 | | | | | | (Parameters) | | |7.0 | | |o 2 | | |status_code -- HTTP . | | |o 2 | | |detail -- . | | |o 2 | | |headers -- . | | |o 2 | | |comment -- () . | | | | | |168u | | | | | |168u | | | | | |168u | | |0.0 | | | | | |pecan.core.load_app(config, **kwargs) | | | Pecan . | | |7.0 | | | | | | (Parameters) | | |config -- () | | | | | |168u | | | pecan.Pecan | | | | | |168u | | |0.0 | | | | | |pecan.core.override_template(template, content_type=None) | | | (override) . | | |7.0 | | | | | | (Parameters) | | |7.0 | | |o 2 | | |template -- @expose . | | |o 2 | | |content_type -- MIME response.func_closure | | | | | |168u | | | | | |168u | | | | | |168u | | |0.0 | | | | | |pecan.core.redirect(location=None, internal=False, code=None, headers=None, add_slash=False, request=None) | | | (redirect) . HTTP 302 . | | |7.0.TP | | | (Parameters) | | |7.0 | | |o 2 | | |location -- HTTP . | | |o 2 | | |internal -- . | | |o 2 | | |code -- HTTP . 302 . | | |o 2 | | |headers -- HTTP . | | |o 2 | | |request -- pecan.Request . | | | | | |168u | | | | | |168u | | | | | |168u | | |0.0 | | | | | |pecan.core.render(template, namespace, app=None) | | | Pecan . @expose . | | |7.0 | | | | | | (Parameters) | | |7.0 | | |o 2 | | |template -- @expose . | | |o 2 | | |namespace -- . | | |o 2 | | |app -- pecan.Pecan | | | | | |168u | | | | | |168u | | | | | |168u | | |PECAN.COMMANDS -- PECAN (PECAN COMMANDS) | | | pecan.commands pecan ( ) pecan serve pecan shell . | | |0.0 | | | | | |class pecan.commands.base.BaseCommand | | | : BaseCommandParent | | | Pecan. | | | pecan Pecan : | | |$ pecan my-custom-command config.py | | |7.0 | | |3.5 | | | | | |# myapp/myapp/custom_command.py | | |class CustomCommand(pecan.commands.base.BaseCommand): | | | ''' | | | (First) line of the docstring is used to summarize the command. | | | ''' | | | | | | arguments = ({ | | | 'name': '--extra_arg', | | | 'help': 'an extra command line argument', | | | 'optional': True | | | }) | | | | | | def run(self, args): | | | super(SomeCommand, self).run(args) | | | if args.extra_arg: | | | pass | | | | | | | | |168u | | | | | |168u | | | | | |168u | | |0.0 | | | | | |class pecan.commands.base.BaseCommandParent | | | : object | | | Pecan. | | | pecan Pecan : | | |$ pecan my-custom-command config.py | | |7.0 | | |3.5 | | | | | |# myapp/myapp/custom_command.py | | |class CustomCommand(pecan.commands.base.BaseCommand): | | | ''' | | | (First) line of the docstring is used to summarize the command. | | | ''' | | | | | | arguments = ({ | | | 'name': '--extra_arg', | | | 'help': 'an extra command line argument', | | | 'optional': True | | | }) | | | | | | def run(self, args): | | | super(SomeCommand, self).run(args) | | | if args.extra_arg: | | | pass | | | | | | | | |168u | | | | | |168u | | |7.0 | | | | | |run(args) | | | . | | | | | |168u | | | | | |168u | | |0.0 | | | | | |class pecan.commands.base.CommandManager | | | : object | | | (entry points) pecan.command . | | | | | |168u | | |0.0 | | | | | |class pecan.commands.base.CommandRunner | | | : object | | | pecan (dispatch) . | | | | | |168u | | |0.0 | | | | | |class pecan.commands.base.HelpfulArgumentParser(prog=None, usage=None, description=None, epilog=None, parents=[], formatter_class=, prefix_chars='-', fromfile_prefix_chars=None, argument_default=None, conflict_handler='error', add_help=True, allow_abbrev=True, exit_on_error=True, *, suggest_on_error=False, color=True) | | | : ArgumentParser | | |7.0 | | | | | |error(message: string) | | | stderr . | | | (override) -- (exception) . | | | | | |168u | | | Serve Pecan. | | |0.0 | | | | | |class pecan.commands.serve.PecanWSGIRequestHandler(*args, **kwargs) | | | : WSGIRequestHandler object | | | wsgiref . | | |7.0 | | | | | |log_message(format, *args) | | | log_message wsgiref . | | | HTTP 4XX (warning) 5XX (error) INFO . | | | | | |168u | | | | | |168u | | |0.0 | | | | | |class pecan.commands.serve.ServeCommand | | | : BaseCommand | | | Pecan . | | | Pecan . | | |7.0 | | | | | |run(args) | | | . | | | | | |168u | | |7.0 | | | | | |serve(app, conf) | | | WSGI. | | | | | |168u | | | | | |168u | | |0.0 | | | | | |pecan.commands.serve.gunicorn_run() | | | gunicorn_pecan pecan | | | | | |168u | | |pecan.commands.shell -- Pecan | | | Shell Pecan. | | |0.0 | | | | | |class pecan.commands.shell.BPythonShell | | | : object | | | bpython Pecan. | | |7.0 | | | | | |classmethod invoke(ns, banner) | | |7.0 | | | | | | | | |7.0 | | |o 2 | | |ns -- | | |o 2 | | |banner -- | | | | | |168u | | | | | |168u | | | bpython. | | | | | |168u | | | | | |168u | | |0.0 | | | | | |class pecan.commands.shell.IPythonShell | | | : object | | | ipython Pecan. | | |7.0 | | | | | |classmethod invoke(ns, banner) | | |7.0 | | | | | | | | |7.0 | | |o 2 | | |ns -- | | |o 2 | | |banner -- | | | | | |168u | | | | | |168u | | | ipython. | | | InteractiveShellEmbed IPython IPShellEmbed . | | | | | |168u | | | | | |168u | | |0.0 | | | | | |class pecan.commands.shell.NativePythonShell | | | : object | | | Pecan. | | |7.0 | | | | | |classmethod invoke(ns, banner) | | |7.0 | | | | | | | | |7.0 | | |o 2 | | |ns -- | | |o 2 | | |banner -- | | | | | |168u | | | | | |168u | | | . | | | | | |168u | | | | | |168u | | |0.0 | | | | | |class pecan.commands.shell.ShellCommand | | | : BaseCommand | | | Pecan. | | | (ipython bpython ). . | | |7.0 | | | | | |invoke_shell(locs, banner) | | | . | | | (ipython bpython ) . | | | | | |168u | | |7.0 | | | | | |load_model(config) | | | | | | | | |168u | | |7.0 | | | | | |run(args) | | | pecan (locals) . | | | | | |168u | | | pecan.configuration Pecan . | | |0.0 | | | | | |class pecan.configuration.Config(conf_dict=None, filename='') | | | : object | | | Pecan. | | | Pecan . | | |7.0 | | | | | | | | |7.0 | | |o 2 | | |conf_dict -- . | | |o 2 | | |filename -- . | | | | | |168u | | | | | |168u | | |7.0 | | | | | |to_dict(prefix=None) | | | Config . | | |7.0 | | | | | | | | |prefix -- . | | | | | |168u | | | | | |168u | | |7.0 | | | | | |update(conf_dict) | | | . | | |7.0 | | | | | | | | |conf_dict -- . | | | | | |168u | | | | | |168u | | | | | |168u | | |0.0 | | | | | |class pecan.configuration.ConfigDict | | | : dict | | | | | |168u | | |0.0 | | | | | |pecan.configuration.conf_from_dict(conf_dict) | | | . | | |7.0 | | | | | | | | |conf_dict -- . | | | | | |168u | | | | | |168u | | |0.0 | | | | | |pecan.configuration.conf_from_file(filepath) | | | . | | |7.0 | | | | | | | | |filepath -- . | | | | | |168u | | | | | |168u | | |0.0 | | | | | |pecan.configuration.get_conf_path_from_env() | | | PECAN_CONFIG RuntimeError . | | | | | |168u | | |0.0 | | | | | |pecan.configuration.initconf() | | | pecan.configuration.conf pecan.conf . | | | | | |168u | | |0.0 | | | | | |pecan.configuration.set_config(config, overwrite=False) | | | . | | |7.0 | | | | | | | | |config -- () . | | | | | |168u | | | pecan.decorators Pecan . | | |0.0 | | | | | |pecan.decorators.accept_noncanonical(func) | | | URL (non-canonical) . | | | | | |168u | | |0.0 | | | | | |pecan.decorators.after_commit(action) | | | pecan.hooks <#module-pecan.hooks> TransactionHook (commit) (callable) . | | |7.0 | | | | | | (Parameters) | | |action -- commit. | | | | | |168u | | | | | |168u | | |0.0 | | | | | |pecan.decorators.after_rollback(action) | | | pecan.hooks <#module-pecan.hooks> TransactionHook (rollback) (callable) . | | |7.0 | | | | | | (Parameters) | | |action -- rollback. | | | | | |168u | | | | | |168u | | |0.0 | | | | | |pecan.decorators.expose(template=None, generic=False, route=None, **kw) | | | <<>> ("exposed") HTTP . | | |7.0 | | | | | | (Parameters) | | |7.0 | | |o 2 | | |template -- . (renderer) 'json' JSON <#expose-json>. | | |o 2 | | |content_type -- (content-type) . | | |o 2 | | |generic -- <<>> ("generic") functools.singledispatch . HTTP . | | |o 2 | | |route -- ( /). | | |` | | |some-special-path' . | | | | | |168u | | | | | |168u | | | | | |168u | | |0.0 | | | | | |pecan.decorators.transactional(ignore_redirects=True) | | | pecan.hooks <#module-pecan.hooks> TransactionHook HTTP . | | |7.0 | | | | | | (Parameters) | | |ignore_redirects -- (hook) (redirects) . | | | | | |168u | | | pecan.deploy Pecan . | | |0.0 | | | | | |pecan.deploy.deploy(config) | | | config ( ) WSGI . | | | | | |168u | | |"PECAN.HOOKS - PECAN (PECAN HOOKS)" | | | pecan.hooks hooks () Pecan (cross-cutting) . | | |0.0 | | | | | |class pecan.hooks.HookController | | | : object | | | . __hooks__ . | | | | | |168u | | |0.0 | | | | | |class pecan.hooks.PecanHook | | | : object | | | Pecan. . priority . | | |7.0 | | | | | |after(state) | | | . | | |7.0 | | | | | | (Parameters) | | |state -- state Pecan . | | | | | |168u | | | | | |168u | | |7.0 | | | | | |before(state) | | | . | | |7.0 | | | | | | (Parameters) | | |state -- state Pecan . | | | | | |168u | | | | | |168u | | |7.0 | | | | | |on_error(state, e) | | | (exception) . | | |7.0 | | | | | | (Parameters) | | |7.0 | | |o 2 | | |state -- state Pecan . | | |o 2 | | |e -- Exception . | | | | | |168u | | | | | |168u | | | | | |168u | | |7.0 | | | | | |on_route(state) | | | . | | |7.0 | | | | | | (Parameters) | | |state -- state Pecan . | | | | | |168u | | | | | |168u | | | | | |168u | | |0.0 | | | | | |class pecan.hooks.RequestViewerHook(config=None, writer=<_io.TextIOWrapper name='' mode='w' encoding='utf-8'>, terminal=True, headers=True) | | | : PecanHook | | |7.0 | | | | | | (Parameters) | | |7.0 | | |o 2 | | |config -- () items / blacklist . | | |o 2 | | |writer -- (stream writer) . write . | | |o 2 | | |terminal -- ( ) | | |o 2 | | |headers -- X-HTTP | | | | | |168u | | | | | |168u | | | . . url . | | | ( ) . | | |items | | | . . request : | | |7.0 | | |o 2 | | |path | | |o 2 | | |status | | |o 2 | | |method | | |o 2 | | |controller | | |o 2 | | |params | | |o 2 | | |hooks | | | | | |168u | | |: | | |7.0 | | |3.5 | | | list . | | | | | |168u | | | | | |168u | | |blacklist | | | url . /javascript : | | |7.0 | | |3.5 | | | | | |'blacklist': ['/javascript'] | | | | | | | | |168u | | | | | |168u | | | . url . | | |: | | |7.0 | | |3.5 | | | list . | | | | | |168u | | | | | |168u | | | RequestViewerHook <#requestviewerhook> . | | |7.0 | | | | | |after(state) | | | . | | |7.0 | | | | | | (Parameters) | | |state -- state Pecan . | | | | | |168u | | | | | |168u | | |7.0 | | | | | |format_hooks(hooks) | | | | | | Pecan ( request ) | | | | | |168u | | |7.0.TP | | |get_controller(state) | | | (controller) | | | Pecan ( request ) | | | | | |168u | | | | | |168u | | |0.0 | | | | | |class pecan.hooks.TransactionHook(start, start_ro, commit, rollback, clear) | | | : PecanHook | | |7.0 | | | | | | | | |7.0 | | |o 2 | | |start -- callable . | | |o 2 | | |start_ro -- callable . | | |o 2 | | |commit -- callable (commit) . | | |o 2 | | |rollback -- callable (roll back) . | | |o 2 | | |clear -- callable (context) . | | | | | |168u | | | | | |168u | | | (hook) . GET HEAD . is_transactional (override) . | | |7.0 | | | | | |after(state) | | | . | | |7.0 | | | | | | | | |state -- state Pecan . | | | | | |168u | | | | | |168u | | |7.0 | | | | | |before(state) | | | . | | |7.0 | | | | | | | | |state -- state Pecan . | | | | | |168u | | | | | |168u | | |7.0 | | | | | |is_transactional(state) | | | (state) . transactional :mod:pecan.decorators GET HEAD . | | |7.0 | | | | | | | | |state -- state Pecan . | | | | | |168u | | | | | |168u | | |7.0 | | | | | |on_error(state, e) | | | (exception) . | | |7.0 | | | | | | | | |7.0 | | |o 2 | | |state -- state Pecan . | | |o 2 | | |e -- Exception . | | | | | |168u | | | | | |168u | | | | | |168u | | |7.0 | | | | | |on_route(state) | | | . | | |7.0 | | | | | | | | |state -- state Pecan . | | | | | |168u | | | | | |168u | | |"PECAN.JSONIFY -- JSON PECAN" | | | pecan.jsonify JSON . | | |0.0 | | | | | |class pecan.jsonify.GenericFunctionJSON(*, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, sort_keys=False, indent=None, separators=None, default=None) | | | : GenericJSON | | |7.0 | | | | | |default(obj) | | | JSON . | | |7.0 | | | | | | | | |obj -- | | |JSON | | | | | |168u | | | : | | |7.0 | | |o 2 | | |2.0 | | | | | | __json__() | | | __json__() | | | | | |168u | | |o 2 | | |2.0 | | | | | | date datetime | | | str | | | | | |168u | | |o 2 | | |2.0 | | | | | | Decimal | | | float | | | | | |168u | | |o 2 | | |2.0 | | | | | | SQLAlchemy | | | object.__dict__ SQLAlchemy | | | | | | | | |168u | | |o 2 | | |2.0 | | | | | | ResultProxy SQLAlchemy | | | ResultProxy | | | | | | ("row") . | | |: | | |7.0 | | |3.5 | | |{'count': 5, 'rows': [('Ed Jones',), ('Pete Jones',), | | |('Wendy Williams',), ('Mary Contrary',), ('Fred Smith',)]} | | | | | |168u | | | | | |168u | | | | | |168u | | |o 2 | | |2.0 | | | | | | RowProxy SQLAlchemy | | | RowProxy | | | | | | JSON . | | | | | |168u | | |o 2 | | |2.0 | | | | | | webob.multidict.MultiDict | | | MultiDict.mixed() | | | JSON . | | | | | |168u | | | | | |168u | | | | | |168u | | | | | |168u | | |0.0 | | | | | |class pecan.jsonify.GenericJSON(*, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, sort_keys=False, indent=None, separators=None, default=None) | | | : JSONEncoder | | | JSON. | | | JSON . | | |7.0 | | | | | |default(obj) | | | JSON . | | |7.0 | | | | | | | | |obj -- | | |JSON | | | | | |168u | | | : | | |7.0 | | |o 2 | | |2.0 | | | | | | __json__() | | | __json__() | | | | | |168u | | |o 2 | | |2.0 | | | | | | date datetime | | | str | | | | | |168u | | |o 2 | | |2.0 | | | | | | Decimal | | | float | | | | | |168u | | |o 2 | | |2.0 | | | | | | SQLAlchemy | | | object.__dict__ SQLAlchemy | | | | | | | | |168u | | |o 2 | | |2.0 | | | | | | ResultProxy SQLAlchemy | | | ResultProxy | | | | | | ("row") . | | |: | | |7.0 | | |3.5 | | |{'count': 5, 'rows': [('Ed Jones',), ('Pete Jones',), | | |('Wendy Williams',), ('Mary Contrary',), ('Fred Smith',)]} | | | | | |168u | | | | | |168u | | | | | |168u | | |o 2 | | |2.0 | | | | | | RowProxy SQLAlchemy | | | RowProxy | | | | | | JSON . | | | | | |168u | | |o 2 | | |2.0 | | | | | | webob.multidict.MultiDict | | | MultiDict.mixed() | | | JSON . | | | | | |168u | | | | | |168u | | | | | |168u | | | pecan.rest | | |RESTful Pecan . | | |0.0 | | | | | |class pecan.rest.RestController(*args, **kwargs) | | | : object | | | REST. | | | REST . | | | RestController | | | pecan RESTful | | |. (resource) | | | REST (GET POST PUT | | |DELETE) . | | | RESTful Pecan | | | Writing RESTful Web Services with Generic Controllers <#rest> . | | | | | |168u | | |"PECAN.ROUTING -- PECAN (PECAN ROUTING)" | | | pecan.routing (object-dispatch) | | | Pecan . | | |0.0 | | | | | |pecan.routing.find_object(obj, remainder, notfound_handlers, request) | | | url | | |<<>> ('walk') | | | (remainder) . | | | | | |168u | | |0.0 | | | | | |pecan.routing.lookup_controller(obj, remainder, request=None) | | | url | | | . | | | . | | | | | |168u | | |0.0 | | | | | |pecan.routing.route(*args) | | | (path segment) . | | | | | | Python . | | | : | | |/path/with-dashes/ | | |... (syntax) Python : | | |7.0 | | |3.5 | | | | | |class Controller(object): | | | | | | with-dashes = SubController() | | | | | | | | |168u | | | | | |168u | | |... : | | |7.0 | | |3.5 | | | | | |class Controller(object): | | | pass | | | | | |pecan.route(Controller, 'with-dashes', SubController()) | | | | | | | | |168u | | | | | |168u | | | | | |168u | | |"PECAN.SECURE -- PECAN (PECAN SECURE CONTROLLERS)" | | | pecan.secure | | | . | | |0.0 | | | | | |pecan.secure.secure(func_or_obj, check_permissions_for_obj=None) | | | . | | |7.0 | | | | | | : | | |@secure() | | | | | | : | | |secure(, ) | | | | | |168u | | | | | |168u | | |0.0 | | | | | |pecan.secure.unlocked(func_or_obj) | | | (attribute) SecureController . | | | (wrap) . | | | | | |168u | | |0.0 | | | | | |class pecan.secure.SecureControllerBase | | | : object | | |7.0 | | | | | |classmethod check_permissions() | | | True False . | | |SecureController . | | | | | |168u | | | | | |168u | | |0.0 | | | | | |class pecan.secure.SecureController | | | : SecureControllerBase | | | . | | |SecureController check_permissions | | |True False ( ) | | |. | | | pecan.templating . | | |0.0 | | | | | |class pecan.templating.ExtraNamespace(extras=None) | | | : object | | | . | | |7.0 | | | | | | | | |extras -- . dict . | | | | | |168u | | |7.0 | | | | | |make_ns(ns) | | | (lazily) . | | | | | |168u | | |7.0 | | | | | |update(d) | | | . | | | | | |168u | | | | | |168u | | |0.0 | | | | | |class pecan.templating.GenshiRenderer(path, extra_vars) | | | : object | | | Genshi . | | |7.0 | | | | | |render(template_path, namespace) | | | Genshi . | | | | | |168u | | | | | |168u | | |0.0 | | | | | |class pecan.templating.JinjaRenderer(path, extra_vars) | | | : object | | | Jinja . | | |7.0 | | | | | |render(template_path, namespace) | | | Jinja . | | | | | |168u | | | | | |168u | | |0.0 | | | | | |class pecan.templating.JsonRenderer(path, extra_vars) | | | : object | | | JSON . | | |7.0 | | | | | |render(template_path, namespace) | | | JSON . | | | | | |168u | | | | | |168u | | |0.0 | | | | | |class pecan.templating.KajikiRenderer(path, extra_vars) | | | : object | | | Kajiki . | | |7.0 | | | | | |render(template_path, namespace) | | | Kajiki . | | | | | |168u | | | | | |168u | | |0.0 | | | | | |class pecan.templating.MakoRenderer(path, extra_vars) | | | : object | | | Mako . | | |7.0 | | | | | |render(template_path, namespace) | | | Mako . | | | | | |168u | | | | | |168u | | |0.0 | | | | | |class pecan.templating.RendererFactory(custom_renderers=None, extra_vars=None) | | | : object | | | Renderer . | | |7.0 | | | | | | | | |7.0 | | |o 2 | | |custom_renderers -- | | |o 2 | | |extra_vars -- | | | | | |168u | | | | | |168u | | |7.0 | | | | | |add_renderers(custom_dict) | | | . | | |7.0 | | | | | | | | |custom_dict -- | | | | | |168u | | | | | |168u | | |7.0 | | | | | |available(name) | | | true . | | |7.0 | | | | | | | | |name -- | | | | | |168u | | | | | |168u | | |7.0 | | | | | |get(name, template_path) | | | . | | |7.0 | | | | | | | | |7.0 | | |o 2 | | |name -- | | |o 2 | | |template_path -- | | | | | |168u | | | | | |168u | | | | | |168u | | | | | |168u | | |0.0 | | | | | |pecan.templating.format_genshi_error(exc_value) | | | Genshi . | | | | | |168u | | |0.0 | | | | | |pecan.templating.format_jinja_error(exc_value) | | | Jinja . | | | | | |168u | | |0.0 | | | | | |pecan.templating.format_line_context(filename, lineno, context=10) | | | (line context) . | | |7.0 | | | | | | | | |7.0 | | |o 2 | | |filename -- | | |o 2 | | |lineno -- | | |o 2 | | |context -- . | | | | | |168u | | | | | |168u | | | | | |168u | | |0.0 | | | | | |pecan.templating.format_mako_error(exc_value) | | | Mako . | | | pecan.testing (fixtures) Pecan . | | |0.0 | | | | | |pecan.testing.load_test_app(config=None, **kwargs) | | | (functional tests) (framework) . | | |7.0 | | | | | | (Parameters) | | |config -- () None None PECAN_CONFIG . | | | | | |168u | | | WSGI pecan.Pecan webtest.TestApp . | | |7.0 | | | | | |:: | | |app = load_test_app('path/to/some/config.py') | | |resp = app.get('/path/to/some/resource').status_int | | |assert resp.status_int == 200 | | |resp = app.post('/path/to/some/resource', params={'param': 'value'}) | | |assert resp.status_int == 302 | | | | | |168u | | | load_test_app : | | |7.0 | | |3.5 | | | | | |app = load_test_app() | | | | | |resp = app.get('/path/to/some/resource').status_int | | |assert resp.status_int == 200 | | | | | | | | |168u | | | | | |168u | | | | | |168u | | |0.0 | | | | | |pecan.testing.reset_global_config() | | | . pecan.configuration.DEFAULT . | | | | | |168u | | |"PECAN.UTIL -- PECAN (PECAN UTILS)" | | | pecan.util Pecan . | | |0.0 | | | | | |pecan.util.getargspec(method) | | | argspec . | | | | | |168u | | |1.8.0 | | |0.0 | | |o 2 | | | pkg_resources importlib.metadata importlib.resources () | | |o 2 | | | Python . Python 3.8 3.9 () | | | | | |168u | | |1.7.0 | | |0.0 | | |o 2 | | | Python 3.8 3.13 () | | |o 2 | | | pecan pecan.ext (import) () | | | | | |168u | | |1.6.0 | | |0.0 | | |o 2 | | | pecan () | | | (CLI) pecan | | |o 2 | | | Python 3.7 | | |0.0 | | |o 2 | | | () | | | | | |168u | | |1.5.0 | | |0.0 | | |o 2 | | |pecan six () | | |o 2 | | | pecan SQLAlchemy 2.0 () | | |o 2 | | |pecan SQLAlchemy 1.3 | | | | | |168u | | |1.4.2 | | |0.0 | | |o 2 | | |pecan webtest () | | | | | |168u | | |1.4.1 | | |0.0 | | |o 2 | | | Python 3.10 | | |o 2 | | | trove Python 3.6 - 3.9 | | |o 2 | | | setuptools | | |() | | |o 2 | | | | | |SQLAlchemy pecan () | | | | | |168u | | |1.4.0 | | |0.0 | | |o 2 | | | pecan webob >= 1.8 | | |o 2 | | | Accept | | |() | | |o 2 | | | Python 3.5 | | | | | |168u | | |1.3.3 | | |0.0 | | |o 2 | | | RestController @secure | | | () | | |o 2 | | | Python 3.3 | | | | | |168u | | |1.3.2 | | |0.0 | | |o 2 | | | pecan 1.8 webob | | |() | | | | | |168u | | |1.3.1 | | |0.0 | | |o 2 | | | webob 1.8> Accept | | |() | | |() | | | | | |168u | | |1.3.0 | | |0.0 | | |o 2 | | | Python 3.6 pecan | | |o 2 | | | Python 2.6 pecan | | | | | |168u | | |1.2.1 | | |0.0 | | |o 2 | | | / API ( 1.2) | | |(). | | | . | | | | | |168u | | |1.2 | | |0.0 | | |o 2 | | | | | | pecan.expose() (). | | |o 2 | | | Pecan None HTTP 204 No | | |Content (). | | |o 2 | | | method pecan.expose() | | | (). | | |0.0 | | |o 2 | | | HTTP JSON JSON pecan | | |() | | |(). | | |o 2 | | | readthedocs | | |readthedocs.org readthedocs.io. | | | | | |168u | | |1.1.1 | | |0.0 | | |o 2 | | | Python 3.5 . | | |o 2 | | | Python 3.5 inspect.getargspec inspect.signature | | |( inspect.getargspec Python 3 ). | | |o 2 | | | | | |pecan.redirect(..., internal=True) "after" | | |(). | | | | | |168u | | |1.1.0 | | |0.0 | | |o 2 | | | pecan.middleware.debug.DebugMiddleware ERROR | | |(). | | |o 2 | | | Javascript | | |(). | | | | | |168u | | |1.0.5 | | |0.0 | | |o 2 | | | argspec | | |(). | | | | | |168u | | |1.0.4 | | |0.0 | | |o 2 | | | pecan Jinja2 | | |Genshi (). | | |o 2 | | | | | | pecan create (). | | | | | |168u | | |1.0.3 | | |0.0 | | |o 2 | | | pecan.hooks.HookController Python3.4 | | |(). | | | | | |168u | | |1.0.2 | | |0.0 | | |o 2 | | | pecan.util.getargspec Python 2.6 | | | argspec . | | |o 2 | | | threading.lock pecan serve | | |--reload . | | | | | |168u | | |1.0.1 | | |0.0 | | |o 2 | | | URL | | |(file.html file.html/) | | | Content-Type . | | |o 2 | | | / pecan.config.Configuration | | | . | | | | | |168u | | |1.0.0 | | |0.0 | | |o 2 | | | pecan () | | | backlash. (tracebacks) | | | pip install backlash . | | |o 2 | | | Content-Type: content_type | | | pecan.expose() | | | . | | |o 2 | | | RFC3986 | | | . | | |o 2 | | | pecan.abort ( | | | NewRelic ). | | |0.0 | | |o 2 | | | Python 3.2 . | | |o 2 | | | | | | . | | | Python ( | | | /some/~path~/ ). | | |o 2 | | | app.debugger | | | DebugMiddleware pecan | | | pdb ( ipdb) . | | |o 2 | | | quickstart pecan pecan | | | DEBUG . | | |o 2 | | | staticmethods . | | |o 2 | | | URL (quoted) | | | (query strings) pecan . | | |o 2 | | | Unicode pecan ( | | | pecan ). | | |o 2 | | | RestController HTTP 405 Method Not | | |Allowed HTTP 404 Not Found . | | |RestController HTTP 405 Method Not Allowed | | |Allow . | | |o 2 | | | pecan (_route _lookup | | |_default) REST . | | |o 2 | | | pecan debug=False | | |(production) . | | | | | |168u | | |0.8.3 | | |0.0 | | |o 2 | | | pecan | | | . pecan HTTP 400 ( | | |UnicodeDecodeError HTTP 500 ) : | | |- HTTP POST Unicode | | |- percent-encoded : | | |2.0 | | |3.5 | | |/some/path/%aa/ | | | | | |168u | | | | | |168u | | |o 2 | | | (verbosity) (import) | | | pecan import . | | | | | |168u | | |0.8.2 | | |0.0 | | |o 2 | | | ( | | |?check=a&check=b) . | | | | | |168u | | |0.8.1 | | |0.0 | | |o 2 | | | (infinite recursion) PecanHook pypy. | | | pecan + pypy | | |(metaclass) PecanHook . | | |o 2 | | | @staticmethod @exposed | | |. | | |o 2 | | | . | | | | | |168u | | |0.8.0 | | |0.0 | | |3.5 | | |0.0 | | |o 2 | | | HTTP POST JSON . | | |o 2 | | | argspec (wrapped controllers). | | |o 2 | | | RestController HTTP 404 400. | | |o 2 | | | HTTP 204 UnicodeDecodeError . | | |o 2 | | | (generic subcontrollers) . | | |o 2 | | | context locals . | | |o 2 | | | . | | |o 2 | | | assert python -O . | | | | | |168u | | | | | |168u | | |0.0 | | |o 2 | | | (edge case) RestController HTTP 400 ( HTTP 500 ). | | |o 2 | | | (root logger) (quickstarted) pecan. | | |o 2 | | | pecan.state.arguments . | | |o 2 | | | PecanHook. | | |rest.RestController hooks.HookController | | | ( ). | | |o 2 | | | Pecan . | | | | | |168u | | |0.6.1 | | |0.0 | | |o 2 | | | pecan HTTP 204 . | | | | | |168u | | |0.6.0 | | |0.0 | | |o 2 | | | (threadlocals) pecan.request | | | pecan.response WSGI . | | | Context/Thread-Locals vs. Explicit Argument Passing <#contextlocals> . | | |o 2 | | | (hook composition) mixin. | | | Attaching Hooks <#attaching-hooks> . | | |o 2 | | | WSGI | | | webob . | | |o 2 | | | Pecan webob.Response | | | Pecan (short-circuit). | | |o 2 | | | HTTP 405 pecan Allow | | | . | | |o 2 | | | RFC2616: ( ) | | |pecan HTTP 204 ( HTTP 200) . | | |o 2 | | | RFC2616: pecan HTTP 204 HTTP 304 | | | Content-Type ( HTTP ). | | |o 2 | | | : Accept JSON | | | HTTP webob JSON HTML . | | |o 2 | | | default_renderer = json . | | | | | |168u | | |0.5.0 | | |0.0 | | |o 2 | | | pypy . | | |o 2 | | | pecan serve. | | |o 2 | | | (scaffold) REST API . | | |o 2 | | | | | |pecan.testing.load_test_app. | | |o 2 | | | (recursion) . | | |o 2 | | | gunicorn_pecan threading.local | | | (green threads) eventlet/gevent . | | |o 2 | | | pecan. | | | | | |168u | | |0.4.5 | | |0.0 | | |o 2 | | | RestController _lookup . | | |o 2 | | | WSGI threadlocal | | |( ). | | |o 2 | | | pecan intersphinx. | | |o 2 | | |pecan Python 3.4 . | | |0.0 | | |o 2 | | | (memoization) controller controller . | | | | | |168u | | |0.4.3 | | |0.0 | | |o 2 | | | RestController. | | |o 2 | | | controller . | | |o 2 | | | _default RestController. | | |o 2 | | | pecan.request.context . | | | | | |168u | | |0.4.2 | | |0.0 | | |o 2 | | | WSME pecan . | | | | | |168u | | |0.4.1 | | |0.0 | | |o 2 | | | StackForge Gerrit Jenkins GitHub. | | |o 2 | | | pecan uwsgi . | | |o 2 | | | simplegeneric | | |functools.singledispatch Python 3.4. | | |o 2 | | | dispatch pecan . | | | | | |168u | | |0.3.2 | | |0.0 | | |o 2 | | | pecan.conf.app . | | |o 2 | | | controller _lookup. | | |o 2 | | | . | | |o 2 | | | pecan.conf.requestviewer. | | | | | |168u | | |0.3.1 | | |0.0 | | |o 2 | | | on_error Pecan Response . | | |o 2 | | | . | | | | | |168u | | |0.3.0 | | |0.0 | | |o 2 | | | Pecan Python 2.6 2.7 3.2 3.3 . | | | | | |168u | | |0.2.4 | | |0.0 | | |o 2 | | | _lookup (fallback) RestController. | | |o 2 | | | . | | | | | |168u | | |0.2.3 | | |0.0 | | |o 2 | | | pecan.core | | | dispatch . | | |o 2 | | | abort WSGI environ | | | ( pecan) | | | . | | |o 2 | | | TransactionHook | | |pecan . | | |o 2 | | | quickstart . | | |0.0 | | |o 2 | | | JavaScript debian. | | |o 2 | | | scaffold tox. | | |o 2 | | | pecan | | |PECAN_CONFIG. | | |o 2 | | | DELETE ( ) RestControllers . | | |o 2 | | | HTTP. | | | | | |168u | | |0.2.1 | | |0.0 | | |o 2 | | | readme requirements.txt . | | |o 2 | | | dir() pecan.request pecan.response. | | |o 2 | | | (mount) pecan WSGI . | | | | | |168u | | |0.2.0 | | |0.0 | | |o 2 | | | (scaffolding) . | | |o 2 | | | (content-type) URL. | | |o 2 | | | Jinja Jinja2 . | | |o 2 | | | RestController. #156 . | | |o 2 | | | CONTRIBUTING.rst. | | |o 2 | | | . | | |o 2 | | | gunicorn_pecan. | | |o 2 | | | import ( py26). | | |o 2 | | | : mimetype . | | |o 2 | | | scaffold pep8. | | |o 2 | | | $ pecan --version. | | | | | |168u | | |0.2.0B | | |0.0 | | |o 2 | | | SecureController. #131. | | |o 2 | | | (static) . | | |o 2 | | | (race condition) . | | |o 2 | | | app.py. | | |o 2 | | | Accept HTTP. | | |o 2 | | | () README. | | |o 2 | | | Hooks. | | |o 2 | | |: *args. | | | | | |168u | | |" (LICENSE)" | | | Pecan BSD : | | |0.0 | | |3.5 | | | | | |Copyright (c) <2010>, Pecan Framework | | |All rights reserved. | | | | | |Redistribution and use in source and binary forms, with or without | | |modification, are permitted provided that the following conditions are met: | | | * Redistributions of source code must retain the above copyright | | | notice, this list of conditions and the following disclaimer. | | | * Redistributions in binary form must reproduce the above copyright | | | notice, this list of conditions and the following disclaimer in the | | | documentation and/or other materials provided with the distribution. | | | * Neither the name of the nor the | | | names of its contributors may be used to endorse or promote products | | | derived from this software without specific prior written permission. | | | | | |THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | | |ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | | |WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | | |DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY | | |DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | | |(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | | |LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | | |ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | | |(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | | |SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | | | | | | | | |168u | | |Jonathan LaCour | | |" (COPYRIGHT)" | | |2010, Jonathan LaCour | | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+ 1.8.0 March 20, 2026 PECAN(1)