API Reference

Application Classes

class BaseApplication(version=None)

Base application for Application and Rewrite

cliarguments = None

A list of easycli.Argument or easycli.SubCommand.

climain(argv=None)

Provide a callable to call as the CLI entry point.

import sys


if __name__ == '__main__':
    sys.exit(app.climain(sys.argv))

You can use this method as the setuptools entry point for Automatic Script Creation

setup.py

from setuptools import setup


setup(
    name='foo',
    ...
    entry_points={
        'console_scripts': [
            'foo = foo:app.climain'
        ]
    }
)
events = None

A dictionary to hold registered functions to specific hooks.

hook(name, *a, **kw)

Only way to fire registered hooks.

Hooks can registered by when() with the name.

app.hook('endresponse')

Extra parameters: *a, **kw will be passed to event handlers.

Normally, users no need to call this method.

ready()

Call the ready hook().

You need to call this method before using the instance as the WSGI application.

Typical usage:

from yhttp.core import Application, text


app = Application()

@app.route()
@text
def get(req):
    return 'Hello World!'

if __name__ != '__main__':
    app.ready()
settings = None

Instance of pymlconf.Root as the global configuration instance.

shutdown()

Call the shutdown hook().

when(func)

Return decorator to registers the func into events by its name.

Currently these hooks are suuported:

  • ready

  • shutdown

  • endresponse

The hook name will be choosed by the func.__name__, so if you need to aware when ready() is called write something like this:

@app.when
def ready(app):
    ...

@app.when
def shutdown(app):
    ...

@app.when
def endresponse(response):
    ...
class Application(version=None)

Bases: BaseApplication

WSGI Web Application.

Instance of this class can be used as a WSGI application.

Variables:
  • bodyguard_factory – A factory of Guard and or it’s subclasses to be used in Application.bodyguard() to instantiate a new guard for a handler. default: Guard.

  • queryguard_factory – A factory of Guard and or it’s subclasses to be used in Application.queryguard() to instantiate a new guard for a handler. default: Guard.

  • routes – A dictionionary to hold the regext routes handler mappings.

bodyguard(fields=None, strict=False)

A decorator factory to validate HTTP request’s body.

Added in version 5.1.

from yhttp.core import guard as g

@app.route()
@app.bodyguard(fields=(
    g.String('foo', length=(1, 8), pattern=r'\d+', optional=True),
    g.Integer('bar', range=(0, 9), optional=True),
), strict=True)
@json()
def post(req):
    ...

This method calls the bodyguard_factory to intantiate a Guard class or it’s subclasses.

Parameters:
  • fields – A tuple of Gurad.Field subclass instances to define the allowed fields and field attributes.

  • strict – If True, it raises Guard.statuscode_unknownfields when one or more fields are not in the given fields argument.

bodyguard_factory

alias of Guard

delete_route(pattern, verb, flags=0)

Delete a route

Parameters:
  • pattern – Regular expression to match the routing table.

  • flags – Regular expression flags. see re.compile().

  • verb – The HTTP verb to match the routing table.

queryguard(fields=None, strict=False)

A decorator factory to validate the URL’s query string.

Added in version 5.1.

from yhttp.core import guard as g
from yhttp.core.multidict import MultiDict

def bar(req, field: g.Field, values: MultiDict):
    return 'bar default value'

@app.route()
@app.queryguard(fields=(
    g.String(
        'foo',
        length=(1, 8),
        pattern=r'\d+',
        optional=True,
        default='foo default value',
    ),
    g.Integer(
        'bar',
        range=(0, 9),
        optional=True,
        default=bar
   ),
), strict=True)
@json()
def post(req):
    ...

This method calls the queryguard_factory to intantiate a Guard class or it’s subclasses.

Parameters:
  • fields – A tuple of Gurad.Field subclass instances to define the allowed fields and field attributes.

  • strict – If True, it raises Guard.statuscode_unknownfields when one or more fields are not in the given fields argument.

queryguard_factory

alias of Guard

route(pattern='/', flags=0, verb=None, insert=None, exists='error')

Return a decorator to register a handler for given regex pattern.

if verb is None then the function name will used instead.

@app.route(r'/.*')
def get(req):
    ...

You can bypass this behavior by passing verb keyword argument:

@app.route(r'/', verb='get')
def somethingelse(req):
    ...

To catch any verb by the handler use *.

@app.route(r'/', verb='*')
def any(req):
    ...

Regular expression groups will be capture and dispatched as the positional arguments of the handler after req:

@app.route(r'/(\\d+)/(\\w*)')
def get(req, id, name):
    ...

This method returns a decorator for handler fucntions. So, you can use it like:

books = app.route(r'/books/(.*)')

@books
def get(req, id):
    ...

@books
def post(req, id):
    ...
Parameters:
  • pattern – Regular expression to match the request.

  • flags – Regular expression flags. see re.compile().

  • verb – If not given then handler.__name__ will be used to match HTYP verb, Use * to catch all verbs.

  • insert – If not given, route will be appended to the end of the routes. Otherwise it must be an integer indicating the place to insert the new route into routes attribute.

  • exists – Tell what to do if route already exists, possible values: error``(default) and ``remove to remove the existing route before appending and or inserting the new one.

Added in version 2.9: insert

Added in version 6.1: exists

staticdirectory(pattern, directory, default=None, autoindex=True, fallback=None, **kw)

Register a directory with a regular expression pattern.

So the files inside the directory are accessible by their names:

app.staticdirectory(r'/foo/', 'physical/path/to/foo')

You you can do:

curl localhost:8080/foo/a.txt

See also

Static Contents

Parameters:
  • pattern – Regular expression to match the requests.

  • directory – Static files are here.

  • default – if None, the app.settings.staticdir.default (which default is index.html) will be used as the default document.

  • autoindex – Automatic directory indexing, default True.

  • fallback – if True, the app.settings.staticdir.fallback (which default is index.html) will be used as the fallback document if the requested resource was not found. if str, the value will be used instead of app.settings.staticdir.fallback.

Added in version 2.13: The default and fallback keyword arguments.

Added in version 3.8: The autoindex keyword argument.

staticfile(pattern, filename, **kw)

Register a filename with a regular expression pattern to be served.

app.staticfile(r'/a\.txt', 'physical/path/to/a.txt')

See also

Static Contents

Rewrite Class

class Rewrite(default=None)

Bases: BaseApplication

Useful to route specific requests to other WSGI application.

Added in version 3.2.

import yhttp.core as y

root = y.Application()
foo = y.Application()
bar = y.Application()

app = y.Rewrite(default=root)
app.route(r'/foo/?', r'/', foo)
app.route(r'/bar/?(.*)', r'/b/\1', bar)
app.ready()

@root.route()
def get(req):
    return 'root'

@foo.route()
def get(req):
    return 'foo'

@bar.route(r'/b')
def get(req):
    return 'bar'
Parameters:

default – Fallback application.

ready()

Call the ready hook().

You need to call this method before using the instance as the WSGI application.

Typical usage:

from yhttp.core import Application, text


app = Application()

@app.route()
@text
def get(req):
    return 'Hello World!'

if __name__ != '__main__':
    app.ready()
route(pattern, repl, handler)

Register an application for specific url.

import yhttp.core as y

root = y.Application()
foo = y.Application()
bar = y.Application()

app = y.Rewrite(default=root)
app.route(r'/foo/([a-z]+)/(\d+)', r'/books/\2/\1', foo)
# Add other applications
app.ready()

See re.sub() for more info about pattern and repl arguments.

Parameters:
  • pattern – A regex pattern to match the environ['PATH_INFO'].

  • repl – URL Rewrite rule, See re.sub()

  • handler – An instance of BaseApplication.

shutdown()

Call the shutdown hook().

Request Class

class Request(app, environ, response)

Represent an HTTP request.

Application.__call__() instantiates this class on each call.

body()

Reads the request body.

contentlength()

HTTP Request Content-Length header value.

contenttype()

HTTP Request Content-Type header value without encoding.

cookies()

Return a dictionary representing the HTTP cookie data.

environ = None

WSIG environ dictionary

files()

Return a dictionary representing the submitted files.

Parse multipart form data from the environ dict and return a dictionary with the form-field name as a key(unicode) and multipart.MultipartPart instances as value, because the form-field was a file-upload or the value is too big to fit into memory limits.

Note

On the first access to this attribute, the Request.form() attribute will be initialized if any not-file fields are submitted.

Added in version 4.0.

form()

Return a MultiDict representing the submitted HTTP from.

Parse form data from the environ dict and return a dictionary with the form-field name as a key(unicode) and lists as values (multiple values per key are possible).

Note

Both urlencoded and multipart are supported.

Note

On the first access to this attribute, the Request.files() attribute will be initialized. if any file fields are submitted using the multipart/form content header.

Added in version 2.6: An easy way to get form values is: .. code-block::

req[‘field-name’]

The above expression is the same as: .. code-block:

req.form['field-name']

Changed in version 4.0: The multipart files are not represented by this attribute and will be accessible by Request.files() instead.

Changed in version 4.0: You may get all values for an identical field using:

req.form.getall('field-name')
fullpath()

Request full URI including query string.

getfiles(relax=False)

Return the request body as a MultiDict object.

This is actualy a wrapper around the Request.files. but raises statuses.lengthrequired and statuses.unprocessablecontent instead of programmatic exceptions if relax=False (the default behaviour).

if relax=True, it returns None on any failure.

getform(relax=False)

Return the request body as a MultiDict object.

This is actualy a wrapper around the Request.form. but raises statuses.lengthrequired and statuses.unprocessablecontent instead of programmatic exceptions if relax=False (the default behaviour).

if relax=True, it returns None on any failure.

getjson(relax=False)

Return the request body as a decoded JSON object.

This is actualy a wrapper around the Request.json. but raises statuses.lengthrequired and statuses.unprocessablecontent instead of programmatic ujson exceptions if relax=False (the default behaviour).

if relax=True, it returns None on any failure.

headers()

HTTP Request headers set.

see HeadersMask class to figure out how it works.

json()

Return a dictionary representing the submitted JSON document.

Note

Content-Type header must be aplication/json.

Added in version 4.0.

path()

Request URL without query string and scheme://domain.ext.

query()

Return A dictionary representing the submitted query string.

response = None

The Response instance associated to this request.

scheme()

Return HTTP Request Scheme (http|https).

verb()

HTTP method.

HeadersMask Class

class HeadersMask(environ)

A simple proxy over Request.environ.

Useful to get headers by their original name without the HTTP_ prefix, which is the python’s WSGI servers default behavior.

@app.route()
def get(req):
    foo = req.headers['foo']
    bar = req.headers.get('bar')
    if 'baz' in req.headers:
        baz = True

     ...

Response Class

class Response(app, environ, startresponse)

Represent the HTTP response.

Which accessible by Request.response inside handlers.

body = None

Response body

charset = None

Response encoding, None for binary

conclude()

Conclude the response.

Calls WSGI start_response callback and encode response body to transfer to the client.

Returns:

response body

property contenttype

Response content type incuding charset.

headers = None

An instance of HeaderSet class.

length = None

Response content length

start()

Start the response.

Usualy Application calls this method when response is ready to transfered to user.

startstream()

Start streaming the response.

Transfer data chunk by chunk instead of what conclude() does.

status = '200 OK'

HTTP Status code

type = None

Response content type without charset.

HeaderSet Class

class HeaderSet(items=None)

A mutable case-insensitive ordered dictionary to keep HTTP headers.

@app.route()
def get(req):
    req.response.headers.add('x-foo', 'a', 'b')
    req.response.headers['x-bar'] = 'bar'
    req.response.headers += ['x-baz: qux']

MultiDict

class MultiDict(backend=None, *args, **kwargs)

A dict that remembers old values for each key.

HTTP headers and query strings may repeat with differing values, such as Set-Cookie. We need to remember all values.

get(k[, d]) D[k] if k in D, else d.  d defaults to None.
keys() a set-like object providing a view on D's keys

HTTPStatus Class

class HTTPStatus(code, text, keepheaders=False, headers=None, nobody=False)

Base class for all HTTP Exceptions.

Parameters:
  • code – HTTP status code.

  • text – HTTP status text.

  • keepheaders – If set, appliation keeps the Response.headers when exception is occured.

  • headers – Some extra HTTP headers to be added to the Response.headers when exception is raised.

contenttype decorators

contenttype(contenttype=None, charset=None, dump=None)

Yield a decorator to set response content type and encoding.

import json

from yhttp.core import contenttype

@app.route()
@contenttype('application/json', 'utf8', json.dumps)
def get(req):
    return {'foo': 'bar'}

There are ready to use contenttype decorators which can importes from yhttp.core package, like: json().

You may create your very own content type decorator by calling this function with desired arguments, for example:

invoice = contenttype('application/pdf', None, dump=makeinvoicepdf)

@app.route('/invoices/(\d+)')
@invoice
def get(req, id):
    ...

The json() decorator is created with something like:

json = contenttype('application/json', 'utf8', dump=json.dumps)
Parameters:
  • contenttype – HTTP Content-Type, example: application/json

  • charset – Character set, example: utf8

  • dump – A callable(body) -> body to transform the body to appropriate content type.

Returns:

decorator for HTTP handlers.

binary(handler)

Sets the Response.contenttype to application/octet-stream.

Handlers must return bytes when this decorator is used.

from yhttp.core import binary


@app.route()
@binary
def get(req):
    return b'binarydata'
json(handler)

Sets the Response.contenttype to application/json;charset=utf-8 and encode the returned value by handler to json byte-string format.

Handlers must return dict when this decorator is used.

from yhttp.core import json


@app.route()
@json
def get(req):
    return {'foo': 'bar'}
text(handler)

Sets the Response.contenttype to text/text; charset=utf-8.

Handlers must return str when this decorator is used.

Added in version 2.8.

from yhttp.core import text


@app.route()
@text
def get(req):
    return 'Unicode String'
html(handler)

Sets the Response.contenttype to text/html; charset=utf-8.

Handlers must return str when this decorator is used.

Added in version 2.8.

from yhttp.core import html


@app.route()
@html
def get(req):
    return 'Unicode String'

gurad Module

class Field(name, optional=False, default=None, callback=None)

Base class for all fields such as String

Parameters:
  • optional – If True, the Field.statuscode_missing is not raised when the field is not submitted by the client. default: False.

  • default – A scalar or callable(req, field, valuesdict) as the default value for field if not submitted. this argument cannot passed with optional. default: None.

Variables:

statuscode_missing – int, the status code to raise when the field is not submitted by the user when strict=True. default: 400.

Added in version 5.2: default argument.

__call__(*, optional=None, default=None, callback=None, **kwargs)

Copy and override the field.

bar = guard.String('bar')

@app.route
@app.queryguard((
    bar,
    bar(name='baz', optional=True)
))
def get(req, *, bar=None, baz=None):
    ...
class Guard(fields=None, strict=False)

The guard.Guard class is used to validate the HTTP requests.

see: Application.bodyguard() for more info.

Added in version 5.1.

Parameters:
  • strict – If True, it raises Guard.statuscode_unknownfields when one or more fields are not in the given fields argument.

  • fields – A tuple of Gurad.Field subclass instances to define the allowed fields and field attributes.

Variables:

statuscode_unknownfields – int, the status code to raise when an unknown field(s) is/are found.

validate(req, values)

Validates the submitted data

Parameters:
  • req – Current yhttp Request object.

  • values – A MultiDict representing the submitted data.

class Integer(name, range=None, **kwargs)

Represent the guard for integer field.

Parameters:
  • name – str, the field name.

  • range(int, int), a tuple of (min, max) to specify the minimum and maximum allowed value.

Variables:
  • statuscode_badtype – int, the status code to raise when the type cast to integer int(value) is raises ValueError. default: 400.

  • statuscode_outofrange – int, the status code to raise when value is not in specified range.

__call__(*, range=None, **kwargs)

Copy and override the field.

bar = guard.String('bar')

@app.route
@app.queryguard((
    bar,
    bar(name='baz', optional=True)
))
def get(req, *, bar=None, baz=None):
    ...
class String(name, length=None, pattern=None, **kwargs)

Represent the guard for string field.

Parameters:
  • name – str, the field name.

  • length(int, int), a tuple of (min, max) to specify the minimum and maximum allowed length for the value.

  • pattern – A regex pattern to specify the data format for the field.

Variables:
  • statuscode_badlength – int, the status code to raise when value length is not permitted. default: 400.

  • statuscode_badformat – int, the status code to raise when value format is not match with given pattern. default: 400.

__call__(*, length=None, pattern=None, **kwargs)

Copy and override the field.

bar = guard.String('bar')

@app.route
@app.queryguard((
    bar,
    bar(name='baz', optional=True)
))
def get(req, *, bar=None, baz=None):
    ...

statuses Module

exception HTTPStatus(code, text, keepheaders=False, headers=None, nobody=False)

Base class for all HTTP Exceptions.

Parameters:
  • code – HTTP status code.

  • text – HTTP status text.

  • keepheaders – If set, appliation keeps the Response.headers when exception is occured.

  • headers – Some extra HTTP headers to be added to the Response.headers when exception is raised.

badgateway = functools.partial(<class 'yhttp.core.statuses.HTTPStatus'>, 502, 'Bad Gateway')

HTTP 502 Bad Gateway exception factory

badrequest = functools.partial(<class 'yhttp.core.statuses.HTTPStatus'>, 400, 'Bad Request')

HTTP 400 Bad Request exception factory

conflict = functools.partial(<class 'yhttp.core.statuses.HTTPStatus'>, 409, 'Conflict')

HTTP 409 Conflict exception factory

created = functools.partial(<class 'yhttp.core.statuses.HTTPStatus'>, 201, 'Created', keepheaders=True)

HTTP 201 Created exception factory

forbidden = functools.partial(<class 'yhttp.core.statuses.HTTPStatus'>, 403, 'Forbidden')

HTTP 403 Forbidden exception factory

found(location, **kw)

HTTP 302 Found exception factory

gatewaytimeout = functools.partial(<class 'yhttp.core.statuses.HTTPStatus'>, 504, 'Gateway Timeout')

HTTP 504 Gateway Timeout exception factory

gone = functools.partial(<class 'yhttp.core.statuses.HTTPStatus'>, 410, 'Gone')

HTTP 410 Gone exception factory

internalservererror = functools.partial(<class 'yhttp.core.statuses.HTTPStatus'>, 500, 'Internal Server Error')

HTTP 500 Internal Server Error exception factory

lengthrequired = functools.partial(<class 'yhttp.core.statuses.HTTPStatus'>, 411, 'Length Required')

HTTP 411 Length Required

methodnotallowed = functools.partial(<class 'yhttp.core.statuses.HTTPStatus'>, 405, 'Method Not Allowed')

HTTP 405 Method Not Allowed exception factory

movedpermanently(location, **kw)

HTTP 301 Moved Permanently exception factory

nocontent = functools.partial(<class 'yhttp.core.statuses.HTTPStatus'>, 204, 'No Content', keepheaders=True, nobody=True)

HTTP 204 No Content exception factory

notfound = functools.partial(<class 'yhttp.core.statuses.HTTPStatus'>, 404, 'Not Found')

HTTP 404 Not Found exception factory

notmodified = functools.partial(<class 'yhttp.core.statuses.HTTPStatus'>, 304, 'Not Modified', nobody=True)

HTTP 304 Not Modified exception factory

ok = functools.partial(<class 'yhttp.core.statuses.HTTPStatus'>, 200, 'OK', keepheaders=True)

HTTP 200 OK

preconditionfailed = functools.partial(<class 'yhttp.core.statuses.HTTPStatus'>, 412, 'Precondition Failed')

HTTP 412 Precondition Failed exception factory

serviceunavailable = functools.partial(<class 'yhttp.core.statuses.HTTPStatus'>, 503, 'Service Unavailable')

HTTP 503 Service Unavailable exception factory

status

Alias for HTTPStatus

statuscode(code)

Set the Response.status to code.

@app.route()
@statuscode('201 Created')
def post(req):
    ...

with Given(app, verb='POST'):
    assert status == '201 Created'

Added in version 2.5.

unauthorized = functools.partial(<class 'yhttp.core.statuses.HTTPStatus'>, 401, 'Unauthorized')

HTTP 401 Unauthorized exception factory

unprocessablecontent = functools.partial(<class 'yhttp.core.statuses.HTTPStatus'>, 422, 'Unprocessable Content')

HTTP 422 Unprocessable Content