Add docs for handlers, app handler
This commit is contained in:
parent
6b110e567a
commit
4a7729a702
|
@ -25,9 +25,9 @@ Glossary
|
||||||
virtual environment.
|
virtual environment.
|
||||||
|
|
||||||
app handler
|
app handler
|
||||||
Python object representing the core of the :term:`app`. There is
|
Python object representing the core :term:`handler` for the
|
||||||
normally just one "global" app handler, which is an instance of
|
:term:`app`. There is normally just one "global" app handler;
|
||||||
:class:`~wuttjamaican.app.AppHandler`.
|
see also :doc:`narr/handlers/app`.
|
||||||
|
|
||||||
app name
|
app name
|
||||||
Code-friendly name for the underlying app/config system
|
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/
|
.. _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
|
settings table
|
||||||
Table in the :term:`app database` which is used to store
|
Table in the :term:`app database` which is used to store
|
||||||
:term:`config settings<config setting>`.
|
:term:`config settings<config setting>`.
|
||||||
|
|
|
@ -2,7 +2,12 @@
|
||||||
WuttJamaican
|
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
|
It mostly is a distillation of certain patterns developed within the
|
||||||
`Rattail Project`_, which are deemed generally useful. (At least,
|
`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 configuration, using config files and/or DB settings table
|
||||||
* flexible command line interface, with arbitrary top-level and
|
* flexible command line interface, with arbitrary top-level and
|
||||||
subcommands
|
subcommands
|
||||||
|
* flexible architecture, abstracting various portions of the overall app
|
||||||
|
|
||||||
|
|
||||||
Contents
|
Contents
|
||||||
|
|
|
@ -110,8 +110,8 @@ are really aliases) or can use different functions:
|
||||||
poser = poser.commands:poser_main
|
poser = poser.commands:poser_main
|
||||||
wutta-poser = poser.commands:wutta_poser_main
|
wutta-poser = poser.commands:wutta_poser_main
|
||||||
|
|
||||||
Next time your ``poser`` package is installed, the command will be
|
Next time your ``poser`` :term:`package` is installed, the command
|
||||||
available:
|
will be available:
|
||||||
|
|
||||||
.. code-block:: sh
|
.. 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:
|
may be thought of in a couple ways:
|
||||||
|
|
||||||
First there is the :term:`ad hoc script` which is a single file and
|
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.
|
can be placed anywhere, but is not installed as part of a
|
||||||
See :doc:`scripts`.
|
:term:`package`. See :doc:`scripts`.
|
||||||
|
|
||||||
But the "real" command line interface uses :term:`commands<command>`
|
But the "real" command line interface uses :term:`commands<command>`
|
||||||
and :term:`subcommands<subcommand>`; these are installed as part of a
|
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
|
generally must invoke the Python interpreter somehow and explicitly
|
||||||
tell it the path to your script.
|
tell it the path to your script.
|
||||||
|
|
||||||
Note that a script is (usually) not installed as part of a package.
|
Note that a script is (usually) not installed as part of a
|
||||||
They can live anywhere.
|
:term:`package`. They can live anywhere.
|
||||||
|
|
||||||
Below we'll walk through creating a script.
|
Below we'll walk through creating a script.
|
||||||
|
|
||||||
|
|
|
@ -82,8 +82,8 @@ with underscore for sake of the subcommand entry point:
|
||||||
wutta_poser.subcommands =
|
wutta_poser.subcommands =
|
||||||
hello = poser.commands:Hello
|
hello = poser.commands:Hello
|
||||||
|
|
||||||
Next time your ``poser`` package is installed, the subcommand will be
|
Next time your ``poser`` :term:`package` is installed, the subcommand
|
||||||
available, so you can e.g.:
|
will be available, so you can e.g.:
|
||||||
|
|
||||||
.. code-block:: sh
|
.. 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
|
install/index
|
||||||
config/index
|
config/index
|
||||||
cli/index
|
cli/index
|
||||||
|
handlers/index
|
||||||
|
|
|
@ -31,15 +31,18 @@ from wuttjamaican.util import load_entry_points, load_object, parse_bool
|
||||||
|
|
||||||
class AppHandler:
|
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. "the handler to handle all handlers"
|
||||||
|
|
||||||
aka. "one handler to bind them all"
|
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
|
There is normally no need to create one of these yourself; rather
|
||||||
you should call :meth:`~wuttjamaican.conf.WuttaConfig.get_app()`
|
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
|
:param config: Config object for the app. This should be an
|
||||||
instance of :class:`~wuttjamaican.conf.WuttaConfig`.
|
instance of :class:`~wuttjamaican.conf.WuttaConfig`.
|
||||||
|
|
|
@ -562,6 +562,8 @@ class WuttaConfig:
|
||||||
"""
|
"""
|
||||||
Returns the global :class:`~wuttjamaican.app.AppHandler`
|
Returns the global :class:`~wuttjamaican.app.AppHandler`
|
||||||
instance, creating it if necessary.
|
instance, creating it if necessary.
|
||||||
|
|
||||||
|
See also :doc:`/narr/handlers/app`.
|
||||||
"""
|
"""
|
||||||
if not hasattr(self, 'app'):
|
if not hasattr(self, 'app'):
|
||||||
spec = self.get(f'{self.appname}.app.handler', usedb=False,
|
spec = self.get(f'{self.appname}.app.handler', usedb=False,
|
||||||
|
|
Loading…
Reference in a new issue