User Guide¶
Flask extension to dynamically assemble your Flask application from packages.
Flask-Registry is initialized like this:
>>> from flask import Flask
>>> from flask_registry import Registry, ListRegistry
>>> app = Flask('myapp')
>>> r = Registry(app=app)
A simple usage example of ListRegistry
looks like this:
>>> app.extensions['registry']['my.namespace'] = ListRegistry()
>>> len(app.extensions['registry'])
1
>>> app.extensions['registry']['my.namespace'].register("something")
>>> app.extensions['registry']['my.namespace'].register("something else")
>>> len(app.extensions['registry']['my.namespace'])
2
>>> for obj in app.extensions['registry']['my.namespace']:
... print(obj)
something
something else
Module Discovery¶
The module discovery registries.
They provide discovery functionality useful for searching a list of Python
packages for a specific module name, and afterwards registering the module.
This is used to e.g. load and register Flask blueprints by
BlueprintAutoDiscoveryRegistry
.
Assume e.g. we want to discover the helpers
module from the tests
package. First we initialize the registry:
>>> from flask import Flask
>>> from flask_registry import Registry, ModuleDiscoveryRegistry
>>> from flask_registry import ImportPathRegistry
>>> app = Flask('myapp')
>>> r = Registry(app=app)
We then create the list of packages to search through using an
ImportPathRegistry
:
>>> r['mypackages'] = ImportPathRegistry(initial=['registry_module'])
Then, initialize the ModuleDiscoveryRegistry
and run the discovery:
>>> r['mydiscoveredmodules'] = ModuleDiscoveryRegistry(
... 'helpers', registry_namespace='mypackages')
>>> len(r['mydiscoveredmodules'])
0
>>> r['mydiscoveredmodules'].discover(app=app)
>>> len(r['mydiscoveredmodules'])
1
Lazy discovery¶
Using RegistryProxy
you may lazily discover modules. Above example using
lazy loading looks like this:
>>> from flask_registry import RegistryProxy
>>> app = Flask('myapp')
>>> r = Registry(app=app)
>>> pkg_proxy = RegistryProxy('mypackages', ImportPathRegistry,
... initial=['registry_module'])
>>> mod_proxy = RegistryProxy('mydiscoveredmodules',
... ModuleDiscoveryRegistry,
... 'helpers',
... registry_namespace=pkg_proxy)
>>> 'mypackages' in r
False
>>> 'mydiscoveredmodules' in r
False
>>> with app.app_context():
... mod_proxy.discover(app=app)
>>> 'mypackages' in r
True
>>> 'mydiscoveredmodules' in r
True
Application Discovery¶
Application discovery registries.
They provide discovery functionality useful for dynamically constructing Flask applications based on configuration variables. This allows a developer to package config, blueprints and extensions into isolated and reusable packages which a framework can dynamically install into a Flask application.
Such a package (named registry_module
) could look like and it is located
in tests
directory:
registry_module.views
– contains blueprints which should be registered on the application object.registry_module.mockext
– contains asetup_app()
method which be used to install any Flask extensions on the application object.registry_module.config
– contains configuration variables specific for this module.
Following is a simplified example of a Flask application factory, that will load config, extensions and blueprints:
>>> from flask import Flask, Blueprint
>>> from flask_registry import Registry, PackageRegistry
>>> from flask_registry import ExtensionRegistry
>>> from flask_registry import ConfigurationRegistry
>>> from flask_registry import BlueprintAutoDiscoveryRegistry
>>> class Config(object):
... PACKAGES = ['registry_module']
... EXTENSIONS = ['registry_module.mockext']
... USER_CFG = True
>>> def create_app(config):
... app = Flask('myapp')
... app.config.from_object(config)
... r = Registry(app=app)
... r['packages'] = PackageRegistry(app)
... r['extensions'] = ExtensionRegistry(app)
... r['config'] = ConfigurationRegistry(app)
... r['blueprints'] = BlueprintAutoDiscoveryRegistry(app=app)
... return app
>>> config = Config()
>>> app = create_app(config)
Packages¶
The config variable PACKAGES
specifies the list of Python packages, which
ConfigurationRegistry
and BlueprintAutoDiscoveryRegistry
will search for config.py
and views.py
modules inside.
>>> for pkg in app.extensions['registry']['packages']:
... print(pkg)
registry_module
Extensions¶
The config variable EXTENSIONS
specifies the list of Python packages,
which the ExtensionRegistry
will load and call setup_app(app)
on,
to dynamically initialize Flask extensions.
>>> for pkg in app.extensions['registry']['extensions']:
... print(pkg)
registry_module.mockext
Configuration¶
The ConfigurationRegistry
will merge any package defined config, with the
application config without overwriting already set variables in the application
config:
>>> config.USER_CFG
True
>>> import registry_module.config
>>> registry_module.config.USER_CFG
False
>>> app.config['USER_CFG']
True
Blueprints¶
The BlueprintAutoDiscoveryRegistry
will search for blueprints defined
inside a views
module in each package defined in PACKAGES
. It will
also register the discovered blueprints on the Flask application.
Each views
module should define either a single blueprint in the variable
blueprint
and/or multiple blueprints in the variable blueprints
:
>>> from registry_module import views
>>> isinstance(views.blueprint, Blueprint)
True
>>> len(views.blueprints)
2
>>> for k in sorted(app.blueprints.keys()):
... print(k)
test
test1
test2
Package Resources¶
Package Resources¶
Package resource registries may be used to discover e.g. package resources as well as loading entry points.
Entry points¶
setuptools
entry points are a simple way for packages to “advertise”
Python objects, so that frameworks can search for these entry points.
setup.py
files for instance allows you to specify console_scripts
entry points, which will install scripts into system path for you.
The EntryPointRegistry
allows you to easily register these entry points
into your Flask application:
>>> from flask import Flask
>>> from flask_registry import Registry, EntryPointRegistry
>>> app = Flask('myapp')
>>> r = Registry(app=app)
>>> r['scripts'] = EntryPointRegistry('console_scripts')
>>> 'easy_install' in r['scripts']
True
Entry points are specified in you setup.py
, e.g.:
setup(
# ...
entry_points={
'flask_registry.test_entry': [
'testcase = flask_registry:RegistryBase',
]
},
# ...
)
>>> r['entrypoints'] = EntryPointRegistry(
... 'flask_registry.test_entry', load=True)
>>> 'testcase' in r['entrypoints']
True
>>> from flask_registry import RegistryBase
>>> r['entrypoints']['testcase'][0] == RegistryBase
True
See http://pythonhosted.org/setuptools/pkg_resources.html#entry-points for more information on entry points.
Resource files¶
The PkgResourcesDirDiscoveryRegistry
will search a list of Python
packages for a specific resource directory and register all files found in the
directories.
Assume e.g. a package tests
have a directory resources
with one file
in it called testresource.cfg
. This file can be discovered in the following
manner:
>>> import os
>>> app = Flask('myapp')
>>> r = Registry(app=app)
>>> from flask_registry import ImportPathRegistry
>>> from flask_registry import PkgResourcesDirDiscoveryRegistry
>>> r['packages'] = ImportPathRegistry(initial=['registry_module'])
>>> r['res'] = PkgResourcesDirDiscoveryRegistry('resources', app=app)
>>> os.path.basename(r['res'][0]) == 'testresource.cfg'
True
Extending Flask-Registry¶
Flask-Registry extensions.
Extending Flask-Registry¶
You can easily create your own type of registries by subclassing one of the
existing registries found in the modules under flask_registry.registries
.
If you for instance want to create a list registry that only accepts integers, you could create it like this:
>>> from flask import Flask
>>> from flask_registry import Registry, RegistryError, ListRegistry
>>> class IntListRegistry(ListRegistry):
... def register(self, item):
... if not isinstance(item, int):
... raise ValueError("Object must be of type int")
>>> app = Flask('myapp')
>>> r = Registry(app=app)
>>> r['myns'] = IntListRegistry()
>>> r['myns'].register(1)
>>> r['myns'].register("some string")
Traceback (most recent call last):
File "/usr/lib/python2.7/doctest.py", line 1289, in __run
compileflags, 1) in test.globs
File "<doctest default[7]>", line 1, in <module>
r['myns'].register("some string")
File "<doctest default[2]>", line 4, in register
raise ValueError("Object must be of type int")
ValueError: Object must be of type int