rororo

Collection of utilities, helpers, and principles for building Python backend applications. Supports aiohttp.web, Flask, and your web-framework.

  • Works on Python 3.5+
  • BSD licensed
  • Source, issues, and pull requests on GitHub

Installation

pip install rororo

License

rororo is licensed under the terms of BSD License.

Schemas API

rororo.schemas

Validate request and response data using JSON Schema.

rororo.schemas.schema

Implement class for validating request and response data against JSON Schema.

class rororo.schemas.schema.Schema(module: module, *, response_factory: typing.Callable[..., typing.Any] = None, error_class: typing.Any = None, validator_class: typing.Any = <class 'jsonschema.validators.create.<locals>.Validator'>, validation_error_class: typing.Type[Exception] = <class 'jsonschema.exceptions.ValidationError'>, validate_func: typing.Callable[[typing.Mapping[typing.Any, typing.Any], typing.Mapping[typing.Any, typing.Any]], typing.Mapping[typing.Any, typing.Any]] = None) → None[source]

Validate request and response data against JSON Schema.

make_error(message, *, error=None, error_class=None)[source]

Return error instantiated from given message.

Parameters:
  • message (str) – Message to wrap.
  • error (Optional[Exception]) – Validation error.
  • error_class (Any) – Special class to wrap error message into. When omitted self.error_class will be used.
Return type:

Exception

make_response(data=None, **kwargs)[source]

Validate response data and wrap it inside response factory.

Parameters:
  • data (Any) – Response data. Could be ommited.
  • **kwargs – Keyword arguments to be passed to response factory.
Return type:

Any

validate_request(data, *additional, merged_class=<class 'dict'>)[source]

Validate request data against request schema from module.

Parameters:
  • data (Any) – Request data.
  • *additional – Additional data dicts to be merged with base request data.
  • merged_class (Type[dict]) – When additional data dicts supplied method by default will return merged dict with all data, but you can customize things to use read-only dict or any other additional class or callable.
Return type:

Any

rororo.schemas.validators

Customize default JSON Schema Draft 4 validator.

class rororo.schemas.validators.Validator(schema, types=(), resolver=None, format_checker=None)[source]

Customize default JSON Schema validator.

This customization allows:

  • Use tuples for “array” data type
rororo.schemas.validators.extend_with_default(validator_class)[source]

Append defaults from schema to instance need to be validated.

Parameters:validator_class (Any) – Apply the change for given validator class.
Return type:Any

rororo.schemas.utils

Utilities for Schema package.

rororo.schemas.utils.defaults(current, *args)[source]

Override current dict with defaults values.

Parameters:
  • current (dict) – Current dict.
  • *args – Sequence with default data dicts.
Return type:

dict

rororo.schemas.utils.validate_func_factory(validator_class)[source]

Provide default function for Schema validation.

Parameters:validator_class (Any) – JSONSchema suitable validator class.
Return type:Callable[[Mapping[Any, Any], Mapping[Any, Any]], Mapping[Any, Any]]

Utilities API

rororo.settings

Immutable Settings dictionary and various utilities to read settings values from environment.

Module helps you to prepare and read settings inside your web application.

rororo.settings.immutable_settings(defaults, **optionals)[source]

Initialize and return immutable Settings dictionary.

Settings dictionary allows you to setup settings values from multiple sources and make sure that values cannot be changed, updated by anyone else after initialization. This helps keep things clear and not worry about hidden settings change somewhere around your web application.

Parameters:
  • defaults (Union[module, Dict[str, Any]]) – Read settings values from module or dict-like instance.
  • **optionals

    Update base settings with optional values.

    In common additional values shouldn’t be passed, if settings values already populated from local settings or environment. But in case of using application factories this makes sense:

    from . import settings
    
    def create_app(**options):
        app = ...
        app.settings = immutable_settings(settings, **options)
        return app
    

    And yes each additional key overwrite default setting value.

Return type:

mappingproxy

rororo.settings.is_setting_key(key)[source]

Check whether given key is valid setting key or not.

Only public uppercase constants are valid settings keys, all other keys are invalid and shouldn’t present in Settings dict.

Valid settings keys

DEBUG
SECRET_KEY

Invalid settings keys

_PRIVATE_SECRET_KEY
camelCasedSetting
rel
secret_key
Parameters:key (str) – Key to check.
Return type:bool
rororo.settings.inject_settings(mixed, context, fail_silently=False)[source]

Inject settings values to given context.

Parameters:
  • mixed (Union[str, module, Dict[str, Any]]) – Settings can be a string (that it will be read from Python path), Python module or dict-like instance.
  • context (MutableMapping[str, Any]) – Context to assign settings key values. It should support dict-like item assingment.
  • fail_silently (bool) – When enabled and reading settings from Python path ignore errors if given Python path couldn’t be loaded.
Return type:

None

rororo.settings.iter_settings(mixed)[source]

Iterate over settings values from settings module or dict-like instance.

Parameters:mixed (Union[module, Dict[str, Any]]) – Settings instance to iterate.
Return type:Iterator[Tuple[str, Any]]
rororo.settings.from_env(key, default=None)[source]

Shortcut for safely reading environment variable.

Parameters:
  • key (str) – Environment var key.
  • default (Any) – Return default value if environment var not found by given key. By default: None
Return type:

Any

rororo.settings.to_bool(value)[source]

Convert string or other Python object to boolean.

Rationalle

Passing flags is one of the most common cases of using environment vars and as values are strings we need to have an easy way to convert them to boolean Python value.

Without this function int or float string values can be converted as false positives, e.g. bool('0') => True, but using this function ensure that digit flag be properly converted to boolean value.

Parameters:value (Any) – String or other value.
Return type:bool
rororo.settings.setup_locale(locale, first_weekday=None)[source]

Shortcut helper to setup locale for backend application.

Parameters:
  • locale (str) – Locale to use.
  • first_weekday (Optional[int]) – Weekday for start week. 0 for Monday, 6 for Sunday. By default: None
Return type:

str

rororo.settings.setup_timezone(timezone)[source]

Shortcut helper to configure timezone for backend application.

Parameters:timezone (str) – Timezone to use, e.g. “UTC”, “Europe/Kiev”.
Return type:None

rororo.logger

Logging utilities.

Module provides easy way to setup logging for your web application.

rororo.logger.default_logging_dict(*loggers, **kwargs)[source]

Prepare logging dict suitable with logging.config.dictConfig.

Usage:

from logging.config import dictConfig
dictConfig(default_logging_dict('yourlogger'))
Parameters:
  • *loggers – Enable logging for each logger in sequence.
  • **kwargs – Setup additional logger params via keyword arguments.
Return type:

Dict[str, Any]

rororo.logger.update_sentry_logging(logging_dict, sentry_dsn, *loggers, **kwargs)[source]

Enable Sentry logging if Sentry DSN passed.

Note

Sentry logging requires raven library to be installed.

Usage:

from logging.config import dictConfig

LOGGING = default_logging_dict()
SENTRY_DSN = '...'

update_sentry_logging(LOGGING, SENTRY_DSN)
dictConfig(LOGGING)

Using AioHttpTransport for SentryHandler

This will allow to use aiohttp.client for pushing data to Sentry in your aiohttp.web app, which means elimination of sync calls to Sentry.

from raven_aiohttp import AioHttpTransport
update_sentry_logging(LOGGING, SENTRY_DSN, transport=AioHttpTransport)
Parameters:
  • logging_dict (Dict[str, Any]) – Logging dict.
  • sentry_dsn (Optional[str]) – Sentry DSN value. If None do not update logging dict at all.
  • *loggers – Use Sentry logging for each logger in the sequence. If the sequence is empty use Sentry logging to each available logger.
  • **kwargs – Additional kwargs to be passed to SentryHandler.
Return type:

None

class rororo.logger.IgnoreErrorsFilter[source]

Ignore all warnings and errors from stdout handler.

filter(record)[source]

Allow only debug and info log messages to stdout handler.

Return type:bool

rororo.aio

Various utilities for aiohttp and other aio-libs.

rororo.aio.add_resource_context(router, url_prefix=None, name_prefix=None)[source]

Context manager for adding resources for given router.

Main goal of context manager to easify process of adding resources with routes to the router. This also allow to reduce amount of repeats, when supplying new resources by reusing URL & name prefixes for all routes inside context manager.

Behind the scene, context manager returns a function which calls:

resource = router.add_resource(url, name)
resource.add_route(method, handler)

Usage:

with add_resource_context(app.router, '/api', 'api') as add_resource:
    add_resource('/', get=views.index)
    add_resource('/news', get=views.list_news, post=views.create_news)
Parameters:
  • router (Any) – Route to add resources to.
  • url_prefix (Optional[str]) – If supplied prepend this prefix to each resource URL.
  • name_prefix (Optional[str]) – If supplied prepend this prefix to each resource name.
Return type:

Iterator[Any]

rororo.aio.is_xhr_request(request)[source]

Check whether current request is XHR one or not.

Basically it just checks that request contains X-Requested-With header and that the header equals to XMLHttpRequest.

Parameters:request (Any) – Request instance.
Return type:bool
rororo.aio.parse_aioredis_url(url)[source]

Convert Redis URL string to dict suitable to pass to aioredis.create_redis(...) call.

Usage:

async def connect_redis(url=None):
    url = url or 'redis://localhost:6379/0'
    return await create_redis(**get_aioredis_parts(url))
Parameters:url (str) – URL to access Redis instance, started with redis://.
Return type:Dict[str, Any]

Changelog

1.1.1 (2017-10-09)

  • Do not attempt to convert empty list to dict for request/response data

1.1.0 (2017-10-09)

  • Allow to supply non-dicts in request/response data

1.0.0 (2017-05-14)

  • Publish 1.0 release, even proper docs are not ready yet

1.0.0b1 (2017-05-13)

  • Annotate all code in rororo
  • Use mypy on linting source code
  • Require Python 3.5 or higher due to changes above

1.0.0a5 (2016-10-23)

1.0.0a4 (2016-09-01)

  • Pass kwargs to SentryHandler on configuring Sentry logging

1.0.0a3 (2016-08-08)

  • Add rororo.aio module with:
    • add_resource_context context manager
    • is_xhr_request, parse_aioredis_url utility functions
  • Update flake8 config & bump aiohttp version for tests
  • Added ChangeLog & modified GitHub Releases Page

1.0.0a2 (2015-12-18)

  • Adds ability to supply custom error class while making manual errors by schema.make_error method
  • Default validator class preset default values from schema to instance for validation
  • Several improvements to test process

1.0.0a1 (2015-11-26)

  • New beginning for rororo project. Now it is a bunch of helper methods instead of yet another web-framework.