API

Gate

class poort.Gate

Gate is a local storage container (DI of some sorts).

You should extend this class and provide extra methods and properties that you use throughout your application.

import poort

gate = poort.Gate()

def application(environ, start_response):
    with gate(environ):
        request = gate.request

        if request.path == '/':
            response = poort.Response('Hallo world!')
        else:
            response = poort.Response('Not found.', status_code=404)

        return response(request, start_response)

How to extend poort.Gate

import poort


class Gate(poort.Gate):
    def setup(self, environ, *args, **kwargs):
        super(Gate, self).setup(environ, *args, **kwargs)

        dbname = 'test-app'
        self.attach('database', Database(dbname))

    @property
    def database(self):
        ''':rtype: Database'''
        return self.retrieve('database')


gate = Gate()


def application(environ, start_response):
    with gate(environ):
        request = gate.request
        database = gate.database

        if request.path == '/':
            response = poort.Response('Hallo world!')
        else:
            response = poort.Response('Not found.', status_code=404)

        return response(request, start_response)
setup(environ, *args, **kwargs)

Override this method when extending poort.Gate.

Parameters:environ (dict) – Environment dict of the WSGI request.

Request

class poort.Request(environ)

A request wrapper.

Parameters:
  • host (str) – Hostname of the request.
  • path (str) – Request part of the URI.
  • method (str) – Request method (like GET, POST, PUT).
  • ssl (bool) – Check if the request was made over HTTPS.
  • ip_address (str | None) – IPAddress of the remote user.
  • accept_type (str) – Accept header (eg. application/json).
  • content_type (str) – Content-Type header (eg. multipart/form-data).
  • query (dict) – Query part of the URI (?foo=bar).
  • form (dict) – Form part of the Request (foo=bar).
  • files (dict[str, poort.utils.FileStorage]) – Files part of the Request, removed from form.
  • cookies (dict) – Cookies of the Request.
  • json (dict | None) – JSON part of the Request (content_type is application/json).
  • params (dict) – All params (query, form, files, cookies, json) combined.
  • environ (dict) – The original environ.
import poort

def application(environ, start_response):
    request = poort.Request(environ)

    if request.path == '/':
        response = poort.Response('Hallo world!')
    else:
        response = poort.Response('Not found.', status_code=404)

    return response(request, start_response)
as_dict()

Return the full request as a dict

Return type:dict

Retrieve cookie from the request.

This matches with the api of poort.Response, this provides response.set_cookie and response.del_cookie.

Parameters:
  • name (str) – Name of the cookie.
  • default (str | None) – Default when the cookie is not set.
Return type:

str | None

Response

class poort.Response(body='', headers=None, status_code=200)

A response wrapper.

Parameters:
  • body (str) – Body of the response.
  • headers (werkzeug.datastructures.Headers | list) – Headers to respond with.
  • status_code (int) – Status-code of the response [default 200].
import poort

def application(environ, start_response):
    request = poort.Request(environ)
    response = poort.Response('Hallo world!')

    return response(request, start_response)

Add a cookie to the response.

Parameters:
  • name (str) – Name of the cookie.
  • value (str) – Value of the cookie (should always be a string).
  • max_age (int | None) – Maximum age (leave None for “browser session”).
  • path (str) – Path to bind the cookie to [default ‘/’].
  • domain (str | None) – Domain to bind the cookie to [default None].
  • secure (bool) – Secure the cookie [default False], handy: request.ssl.
  • httponly (bool) – Cookie not accessable by JavaScript [default true].

Delete a cookie from the browser.

Parameters:
  • name (str) – Name of the cookie.
  • path (str) – Path to bind the cookie to [default ‘/’].
  • domain (str | None) – Domain to bind the cookie to [default None].
  • secure (bool) – Secure the cookie [default False], handy: request.ssl.
  • httponly (bool) – Cookie not accessable by JavaScript [default true].

Note

Take note that you must match the original settings of the cookie. Deleting a cookie with a non-matching path will not work.

__call__(request, start_response)

Respond to WSGI with the current settings.

Parameters:
  • request (poort.Request) – Request that was made, None is allowed.
  • start_response (callable) – Handler provided by WSGI.
get_status()

Get the status of the response as HTTP code.

Return type:str
get_body()

Retrieve the body of the response.

You can override this method to serialize JSON, for example, and return this as the body.

Return type:str
prepare_response(request=None)

Prepare the response.

This prepares (encodes) the body, you can override this method to add/override headers when the response is being prepared.

To yield other content, you should look at get_body.

Parameters:request (poort.Request) – Request that was made, None is allowed.
Return type:str
respond(request)

Prepare a tuple to respond with.

Parameters:request (poort.Request) – Request that was made, None is allowed.
Return type:tuple[str, list[str], str]
class poort.JsonResponse(data, headers=None, status_code=200)

A response wrapper for JSON results.

Automaticly sets the Content-Type to application/json and transforms your data when the response is prepared. Override json_default to provide your own default transformations.

It automaticly handles datetime, date,, Decimal, FileStorage, items with .to_dict(), items that can be iterated and items with __str__. When this fails, it simple calls repr on the item, it will not raise an Exception when it cannot handle formatting the item.

Parameters:
  • data (dict) – Data to convert to JSON.
  • headers – A list of extra headers, be warned that some headers may be overridden.
  • status_code (int) – Status-Code of the response [default 200].
import poort

def get_some_information():
    return poort.JsonResponse({
        'status': 'ok',
        'data': {
            'some': 'Data here.'
        }
    })
class poort.HtmlResponse(body, headers=None, status_code=200)

A response wrapper for HTML results.

Automaticly sets the Content-Type to text/html

Parameters:
  • body (str) – Your HTML data.
  • headers – A list of extra headers, be warned that some headers may be overridden.
  • status_code (int) – Status-Code of the response [default 200].
import poort

def get_some_information():
    return poort.HtmlResponse('''
        <html>
            <head>
                <title>Hello</title>
            </head>
            <body>
                <p>Hello, this is some HTML.</p>
            </body>
        </html>
    ''')
class poort.TemplateResponse(filename, context, headers=None, status_code=200)

A templated wrapper for HTML results.

Automaticly sets the Content-Type to text/html. This uses the staticly bound renderer (a Jinja2 environment by default) to render your HTML.

Parameters:
  • filename (str) – Filename of the template.
  • context (dict) – Context passed into the template.
  • headers – A list of extra headers, be warned that some headers may be overridden.
  • status_code (int) – Status-Code of the response [default 200].
Variables:

renderer (jinja2.Environment) – Template renderer.

import poort

poort.TemplateResponse.configure('./templates')

def get_some_information():
    return poort.TemplateResponse('index.html', {'name': 'World'})
<!-- templates/index.html -->
<html>
    <head>
        <title>Hallo</title>
    </head>
    <body>
        <p>Hallo {{ name }}!</p>
    </body>
</html>
class poort.WrappedTemplateResponse(template, context, headers=None, status_code=200, base_template=None)

A wrapping templated wrapper for HTML results.

Automaticly sets the Content-Type to text/html. You can use this class to have a wrapper around your template. It extends TemplateResponse and works in the same manner, except it also renders a base_template and injects the rendered template into it as the body.

Parameters:
  • filename (str) – Filename of the template.
  • context – Context passed into the template.
  • headers (werkzeug.datastructures.Headers | list) – A list of extra headers, be warned that some headers may be overridden.
  • status_code (int) – Status-Code of the response [default 200].
  • base_template
import poort

poort.WrappedTemplateResponse.configure('./templates')
poort.WrappedTemplateResponse.BASE_TEMPLATE = 'base.html'

def get_some_information():
    return poort.TemplateResponse('index.html', {
        'name': 'World',
        'scripts': ['/assets/scripts/jquery.min.js',
                    '/assets/scripts/bootstrap.min.js'],
        'styles': ['/assets/styles/bootstrap.min.css'],
    })
<!-- templates/index.html -->
{% do scripts.append('/assets/scripts/index.js') %}
<p>Hallo {{ name }}!</p>
<!-- templates/base.html -->
<html>
    <head>
        <title>Hallo</title>

        {% for style in context.styles %}
          <link href="{{ style }}" rel="stylesheet">
        {% endfor %}
    </head>
    <body>
        {{ body }}
        {% for script in context.scripts %}
            <script src="{{ script }}">
        {% endfor %}
    </body>
</html>

Note

This is a work-around for mutating scripts and styles (among other things) while rendering a page. By mutating the original context, the base template can use the updated variables. If you simply want to render templates without this functionality, simply use TemplateResponse as the simple extending result can be achieved using {% extend ‘base.html’ %}.

class poort.FileResponse(filename, as_attachment=False, cache_timeout=43200, headers=None, status_code=200)

A file wrapper response.

This will send a file to the requester. The Content-Type will be guessed, it will also set the Content-Length and Last-Modified information based on the file.

You can enable caching by providing the request when delivering the response and by setting the cache_timeout.

Parameters:
  • filename (str) – Filename you want to sent, absolute is preferred.
  • as_attachment (bool | str) – Send the file as an attachment, True will use the basename of filename, set it to a str (‘download.csv’) to determine the attachment name yourself.
  • cache_timeout (int) – How long should the result be cached [default 43200, 12 hours).
  • headers (werkzeug.datastructures.Headers | list) – A list of extra headers, be warned that some headers may be overridden.
  • status_code (int) – Status-Code of the response [default 200].
Variables:

attachment_filename (str) – Name of the attachment.

import poort

def get_some_information():
    return poort.FileResponse('cached-123456789-download.csv',
                              'download-name-here.csv')

def application(environ, start_response):
    request = poort.Request(environ)
    response = get_some_information()

    return response(request, start_response)

See also

For passing the request variable: Response.__call__()

size

Size of the file in bytes.

Return type:int
mtime

Modified datetime of the file.

Return type:datetime.datetime
etag

Get an Etag based on the file.

Return type:str
poort.template_or_json_response(request, template, context, headers=None, status_code=200, template_response_class=None, json_response_class=None)

Return a JSON or HTML response, based on the request.

When called, it checks the Request.want_json variable. Based on this outcome a template_response_class or a json_response_class is spawned.

Parameters:
  • request (poort.Request) – Request of the caller.
  • template (str) – The filename of the template.
  • context (dict) – Context that should be passed.
  • headers (werkzeug.datastructures.Headers | list) – A list of extra headers, be warned that some headers may be overridden.
  • status_code (int) – Status-Code of the response [default 200].
  • template_response_class (callable | None) – Which template response class should be used [default TemplateResponse].
  • json_response_class (callable | None) – Which JSON response class should be used [default JsonResponse].
import poort
import poort.template_or_json_response as toj

def get_some_information(request):
    return toj(request, 'user.html', {
        'id': 44,
        'email': 'j.doe@example.com',
        'first': 'John',
        'last': 'Doe',
    })

def application(environ, start_response):
    request = poort.Request(environ)
    response = get_some_information(request)

    return response(request, start_response)
poort.wrapped_template_or_json_response(request, template, context, headers=None, status_code=200, template_response_class=None, json_response_class=None)

Return a JSON or HTML response, based on the request.

When called, it checks the Request.want_json variable. Based on this outcome a template_response_class or a json_response_class is spawned.

Parameters:
  • request (poort.Request) – Request of the caller.
  • template (str) – The filename of the template.
  • context (dict) – Context that should be passed.
  • headers (werkzeug.datastructures.Headers | list) – A list of extra headers, be warned that some headers may be overridden.
  • status_code (int) – Status-Code of the response [default 200].
  • template_response_class (callable | None) – Which template response class should be used [default WrappedTemplateResponse].
  • json_response_class (callable | None) – Which JSON response class should be used [default JsonResponse].
import poort
import poort.wrapper_template_or_json_response as wtoj

def get_some_information(request):
    return wtoj(request, 'user.html', {
        'id': 44,
        'email': 'j.doe@example.com',
        'first': 'John',
        'last': 'Doe',
    })

def application(environ, start_response):
    request = poort.Request(environ)
    response = get_some_information(request)

    return response(request, start_response)

CLI

poort.cli.start()

Start a server for your app.

Parameters:
  • package (str) – Package/module containing your app.
  • runnable (str) – Entrypoint of the server for requests.
  • environ (str) – Which environment to start (production, staging, development [default]).
  • check (bool) – Check if the package is importable and the entrypoint is runnable.
poort start --environ production
poort status
poort.cli.stop()

Stop the server.

Parameters:graceful (bool) – Graceful or forceful (–quick).
poort stop
poort.cli.reload()

Reload the server.

poort reload
poort.cli.scale()

Scale the workers of server up or down.

Parameters:
  • way (str) – Which way to scale (–way up | –way down)
  • amount (int) – The amount of workers to scale.
poort scale --way up --amount 2
poort.cli.status()

Show a status screen (refreshing) of the server.

The status screen shows information about the workers and gives you some shortcut keys to handle the server (quit, upscale, download, reload). It also shows the last couple of lines from the server error log.

Parameters:
  • watch – Keep watching
  • amount (int) – The amount of workers to scale.
poort status

Output example:

test-poort-two


Running with 2 workers (default is 2)

Name         PID     CPU      Mem
----------------------------------------
Master     27309    0.0%     8.1M
Worker 1   27316    0.3%    36.8M
Worker 2   27319    0.3%    36.6M


Waiting...           -- (q)uit (u)pscale (d)ownscale (r)eload


[2016-06-30 13:54:13] [26806] [INFO] Worker exiting (pid: 26806)
[2016-06-30 13:54:13] [26805] [INFO] Worker exiting (pid: 26805)
[2016-06-30 13:54:13] [26831] [INFO] Booting worker with pid: 26831
[2016-06-30 13:54:13] [26832] [INFO] Booting worker with pid: 26832

Warning

This is a very curde program, do not mash a key!