API Reference¶
Application Classes¶
- class BaseApplication(version=None)¶
Base application for
Application
andRewrite
- cliarguments = None¶
A list of
easycli.Argument
oreasycli.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' ] } )
See also
- 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.
- when(func)¶
Return decorator to registers the
func
intoevents
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 inApplication.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 inApplication.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 aGuard
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 raisesGuard.statuscode_unknownfields
when one or more fields are not in the givenfields
argument.
- 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 aGuard
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 raisesGuard.statuscode_unknownfields
when one or more fields are not in the givenfields
argument.
- route(pattern='/', flags=0, verb=None, insert=None, exists='error')¶
Return a decorator to register a handler for given regex pattern.
if
verb
isNone
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): ...
See also
- 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 intoroutes
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
- Parameters:
pattern – Regular expression to match the requests.
directory – Static files are here.
default – if None, the
app.settings.staticdir.default
(which default isindex.html
) will be used as the default document.autoindex – Automatic directory indexing, default True.
fallback – if
True
, theapp.settings.staticdir.fallback
(which default isindex.html
) will be used as the fallback document if the requested resource was not found. ifstr
, the value will be used instead ofapp.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
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 aboutpattern
andrepl
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 themultipart/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 raisesstatuses.lengthrequired
andstatuses.unprocessablecontent
instead of programmatic exceptions ifrelax=False
(the default behaviour).if
relax=True
, it returnsNone
on any failure.
- getform(relax=False)¶
Return the request body as a
MultiDict
object.This is actualy a wrapper around the
Request.form
. but raisesstatuses.lengthrequired
andstatuses.unprocessablecontent
instead of programmatic exceptions ifrelax=False
(the default behaviour).if
relax=True
, it returnsNone
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 raisesstatuses.lengthrequired
andstatuses.unprocessablecontent
instead of programmaticujson
exceptions ifrelax=False
(the default behaviour).if
relax=True
, it returnsNone
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 beaplication/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.
- 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.
- 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
toapplication/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
toapplication/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
totext/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
totext/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
, theField.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 withoptional
. 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 raisesGuard.statuscode_unknownfields
when one or more fields are not in the givenfields
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.
- 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 raisesValueError
. 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
HTTP 503 Service Unavailable exception factory
- status¶
Alias for
HTTPStatus
- statuscode(code)¶
Set the
Response.status
tocode
.@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