Add docs for handlers, app handler
This commit is contained in:
parent
6b110e567a
commit
4a7729a702
|
@ -25,9 +25,9 @@ Glossary
|
|||
virtual environment.
|
||||
|
||||
app handler
|
||||
Python object representing the core of the :term:`app`. There is
|
||||
normally just one "global" app handler, which is an instance of
|
||||
:class:`~wuttjamaican.app.AppHandler`.
|
||||
Python object representing the core :term:`handler` for the
|
||||
:term:`app`. There is normally just one "global" app handler;
|
||||
see also :doc:`narr/handlers/app`.
|
||||
|
||||
app name
|
||||
Code-friendly name for the underlying app/config system
|
||||
|
@ -85,6 +85,14 @@ Glossary
|
|||
|
||||
.. _Python Packaging User Guide: https://packaging.python.org/en/latest/specifications/entry-points/
|
||||
|
||||
handler
|
||||
Similar to a "plugin" concept but only *one* handler may be used
|
||||
for a given purpose. See also :doc:`narr/handlers/index`.
|
||||
|
||||
package
|
||||
Generally refers to a proper Python package, i.e. a collection of
|
||||
modules etc. which is installed via ``pip``.
|
||||
|
||||
settings table
|
||||
Table in the :term:`app database` which is used to store
|
||||
:term:`config settings<config setting>`.
|
||||
|
|
|
@ -2,7 +2,12 @@
|
|||
WuttJamaican
|
||||
============
|
||||
|
||||
This package provides a "base layer" for custom apps.
|
||||
This package provides a "base layer" for custom apps, regardless of
|
||||
environment/platform:
|
||||
|
||||
* console
|
||||
* web
|
||||
* GUI
|
||||
|
||||
It mostly is a distillation of certain patterns developed within the
|
||||
`Rattail Project`_, which are deemed generally useful. (At least,
|
||||
|
@ -24,6 +29,7 @@ Features
|
|||
* flexible configuration, using config files and/or DB settings table
|
||||
* flexible command line interface, with arbitrary top-level and
|
||||
subcommands
|
||||
* flexible architecture, abstracting various portions of the overall app
|
||||
|
||||
|
||||
Contents
|
||||
|
|
|
@ -110,8 +110,8 @@ are really aliases) or can use different functions:
|
|||
poser = poser.commands:poser_main
|
||||
wutta-poser = poser.commands:wutta_poser_main
|
||||
|
||||
Next time your ``poser`` package is installed, the command will be
|
||||
available:
|
||||
Next time your ``poser`` :term:`package` is installed, the command
|
||||
will be available:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
|
|
|
@ -6,8 +6,8 @@ The command line interface is an important part of app automation and
|
|||
may be thought of in a couple ways:
|
||||
|
||||
First there is the :term:`ad hoc script` which is a single file and
|
||||
can be placed anywhere, but is not installed as part of a package.
|
||||
See :doc:`scripts`.
|
||||
can be placed anywhere, but is not installed as part of a
|
||||
:term:`package`. See :doc:`scripts`.
|
||||
|
||||
But the "real" command line interface uses :term:`commands<command>`
|
||||
and :term:`subcommands<subcommand>`; these are installed as part of a
|
||||
|
|
|
@ -10,8 +10,8 @@ A script is just a text file with Python code. To run it you
|
|||
generally must invoke the Python interpreter somehow and explicitly
|
||||
tell it the path to your script.
|
||||
|
||||
Note that a script is (usually) not installed as part of a package.
|
||||
They can live anywhere.
|
||||
Note that a script is (usually) not installed as part of a
|
||||
:term:`package`. They can live anywhere.
|
||||
|
||||
Below we'll walk through creating a script.
|
||||
|
||||
|
|
|
@ -82,8 +82,8 @@ with underscore for sake of the subcommand entry point:
|
|||
wutta_poser.subcommands =
|
||||
hello = poser.commands:Hello
|
||||
|
||||
Next time your ``poser`` package is installed, the subcommand will be
|
||||
available, so you can e.g.:
|
||||
Next time your ``poser`` :term:`package` is installed, the subcommand
|
||||
will be available, so you can e.g.:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
|
|
68
docs/narr/handlers/app.rst
Normal file
68
docs/narr/handlers/app.rst
Normal file
|
@ -0,0 +1,68 @@
|
|||
|
||||
App Handler
|
||||
===========
|
||||
|
||||
There is one special "global" type of :term:`handler` which
|
||||
corresponds to the :term:`app` itself, whereas all other handlers
|
||||
correspond to some "portion" of the app.
|
||||
|
||||
The :term:`app handler` provides:
|
||||
|
||||
* various "global" utilities
|
||||
* primary interface for obtaining all other handlers
|
||||
|
||||
The base class and default app handler is
|
||||
:class:`wuttjamaican.app.AppHandler`.
|
||||
|
||||
The :term:`config object` is responsible for creating the app handler
|
||||
via :meth:`~wuttjamaican.conf.WuttaConfig.get_app()`::
|
||||
|
||||
from wuttjamaican.conf import make_config
|
||||
|
||||
config = make_config()
|
||||
app = config.get_app()
|
||||
|
||||
|
||||
Overriding the App Handler
|
||||
--------------------------
|
||||
|
||||
It is expected that many apps will want a more customized app handler.
|
||||
To do this, first create your app handler class e.g. in
|
||||
``poser/app.py``::
|
||||
|
||||
from wuttjamaican.app import AppHandler
|
||||
|
||||
class PoserAppHandler(AppHandler):
|
||||
"""
|
||||
Custom app handler for the Poser system.
|
||||
"""
|
||||
|
||||
def make_session(self, **kwargs):
|
||||
"""
|
||||
Override this method to specify extra/default params etc.
|
||||
"""
|
||||
#kwargs.setdefault('foo', 'bar')
|
||||
session = super().make_session(**kwargs)
|
||||
return session
|
||||
|
||||
def hello(self):
|
||||
"""
|
||||
Extra method to print a hello message.
|
||||
"""
|
||||
print("hello from", self.appname)
|
||||
|
||||
|
||||
Then in your config file, specify that your app handler should be used
|
||||
instead of the default. Note that the config section will need to
|
||||
match whatever the :term:`app name` is. (And note that the app name
|
||||
is not necessarily the same as your :term:`package` name!)
|
||||
|
||||
.. code-block:: ini
|
||||
|
||||
# nb. this is the default
|
||||
[wutta]
|
||||
app.handler = poser.app:PoserAppHandler
|
||||
|
||||
# but if appname is 'foobar' then it should be this
|
||||
[foobar]
|
||||
app.handler = poser.app:PoserAppHandler
|
31
docs/narr/handlers/arch.rst
Normal file
31
docs/narr/handlers/arch.rst
Normal file
|
@ -0,0 +1,31 @@
|
|||
|
||||
Architecture
|
||||
============
|
||||
|
||||
Handlers are similar to a "plugin" concept in that multiple handlers
|
||||
may be installed e.g. by different packages. But whereas one might
|
||||
"enable" multiple plugins, only *one* handler may be used, for a given
|
||||
purpose.
|
||||
|
||||
There can be many "types" of handlers; each is responsible for a
|
||||
certain aspect of the overall app. So it can be thought of as,
|
||||
"*Which* plugin should *handle* this aspect of the app?"
|
||||
|
||||
|
||||
What a Handler Does
|
||||
-------------------
|
||||
|
||||
Each type of handler does something different. For instance there
|
||||
might be an "auth handler" responsible for authenticating user
|
||||
credentials.
|
||||
|
||||
The app itself will define the need for a handler. For instance if a
|
||||
user login mechanism is needed, then the app might define the "auth
|
||||
handler" (e.g. ``AuthHandler``) base class, and add a way to locate
|
||||
and use it at runtime.
|
||||
|
||||
Other packages might then also define "auth handlers" derived from the
|
||||
base class, and perhaps a way for the app to locate them as well.
|
||||
|
||||
The app should probably have a way for the "choice" of auth handler to
|
||||
be configurable, and possibly expose this choice via admin UI.
|
10
docs/narr/handlers/index.rst
Normal file
10
docs/narr/handlers/index.rst
Normal file
|
@ -0,0 +1,10 @@
|
|||
|
||||
Handlers
|
||||
========
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
overview
|
||||
arch
|
||||
app
|
10
docs/narr/handlers/overview.rst
Normal file
10
docs/narr/handlers/overview.rst
Normal file
|
@ -0,0 +1,10 @@
|
|||
|
||||
Overview
|
||||
========
|
||||
|
||||
The :term:`handler` concept is central to the :term:`app` architecture.
|
||||
|
||||
They are analogous to "plugins" but only *one* handler is used for a
|
||||
given purpose. See :doc:`arch`.
|
||||
|
||||
So far there is only one handler type defined; see :doc:`app`.
|
|
@ -8,3 +8,4 @@ Documentation
|
|||
install/index
|
||||
config/index
|
||||
cli/index
|
||||
handlers/index
|
||||
|
|
|
@ -31,15 +31,18 @@ from wuttjamaican.util import load_entry_points, load_object, parse_bool
|
|||
|
||||
class AppHandler:
|
||||
"""
|
||||
Base class and default implementation for top-level app handler.
|
||||
Base class and default implementation for top-level :term:`app
|
||||
handler`.
|
||||
|
||||
aka. "the handler to handle all handlers"
|
||||
|
||||
aka. "one handler to bind them all"
|
||||
|
||||
For more info see :doc:`/narr/handlers/app`.
|
||||
|
||||
There is normally no need to create one of these yourself; rather
|
||||
you should call :meth:`~wuttjamaican.conf.WuttaConfig.get_app()`
|
||||
on the config object if you need the app handler.
|
||||
on the :term:`config object` if you need the app handler.
|
||||
|
||||
:param config: Config object for the app. This should be an
|
||||
instance of :class:`~wuttjamaican.conf.WuttaConfig`.
|
||||
|
|
|
@ -562,6 +562,8 @@ class WuttaConfig:
|
|||
"""
|
||||
Returns the global :class:`~wuttjamaican.app.AppHandler`
|
||||
instance, creating it if necessary.
|
||||
|
||||
See also :doc:`/narr/handlers/app`.
|
||||
"""
|
||||
if not hasattr(self, 'app'):
|
||||
spec = self.get(f'{self.appname}.app.handler', usedb=False,
|
||||
|
|
Loading…
Reference in a new issue