1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
|
Scruffy
=======
.. image:: https://img.shields.io/travis/snare/scruffy.svg
:target: https://travis-ci.org/snare/scruffy
.. image:: https://img.shields.io/pypi/format/scruffington.svg
:target: https://pypi.python.org/pypi/scruffington
.. image:: https://readthedocs.org/projects/scruffy/badge/?version=latest
:target: http://scruffy.readthedocs.org/en/latest/
*Scruffy. The Janitor.*
Scruffy is a framework for taking care of a bunch of boilerplate in Python apps. It handles the loading of configuration files, the loading and management of plugins, and the management of other filesystem resources such as temporary files and directories, log files, etc.
A typical use case for Scruffy is a command-line Python tool with some or all of the following requirements:
* Read a set of configuration defaults
* Read a local configuration file and apply it on top of the defaults
* Allow overriding some configuration options with command line flags or at runtime
* Load a core set of Python-based plugins
* Load a set of user-defined Python-based plugins
* Generate log files whose name, location and other logging settings are based on configuration
* Store application state between runs in a file or database
Scruffy is used by Voltron_ and Calculon_
.. _Voltron: https://github.com/snare/voltron
.. _Calculon: https://github.com/snare/calculon
Installation
------------
A standard python setup script is included.
$ python setup.py install
This will install the Scruffy package wherever that happens on your system.
Alternately, Scruffy can be installed with `pip` from PyPi (where it's called `scruffington`, because I didn't check for a conflict before I named it).
$ pip install scruffington
Documentation
-------------
Full documentation is hosted at readthedocs_
.. _readthedocs: http://scruffy.readthedocs.io/
Quick start
-----------
Config
~~~~~~
Load a user config file, and apply it on top of a set of defaults loaded from inside the Python package we're currently running from.
*thingy.yaml*:
.. code:: yaml
some_property: 1
other_property: a thing
*thingy.py*:
.. code:: python
from scruffy import ConfigFile
c = ConfigFile('thingy.yaml', load=True,
defaults=File('defaults.yaml', parent=PackageDirectory())
)
print("c.some_property == {c.some_property}".format(c=c))
print("c.other_property == {c.other_property}".format(c=c))
Run it:
::
$ python thingy.py
c.some_property == 1
c.other_property == a thing
Plugins
~~~~~~~
Load some plugins.
*~/.thingy/plugins/example.py*:
.. code:: python
from scruffy import Plugin
class ExamplePlugin(Plugin):
def do_a_thing(self):
print('{}.{} is doing a thing'.format(__name__, self.__class__.__name__))
*thingy.py*:
.. code:: python
from scruffy import PluginDirectory, PluginRegistry
pd = PluginDirectory('~/.thingy/plugins')
pd.load()
for p in PluginRegistry.plugins:
print("Initialising plugin {}".format(p))
p().do_a_thing()
Run it:
::
$ python thingy.py
Initialising plugin <class 'example.ExamplePlugin'>
example.ExamplePlugin is doing a thing
Logging
~~~~~~~
Scruffy's `LogFile` class will do some configuration of Python's `logging` module.
*log.py*:
.. code:: python
import logging
from scruffy import LogFile
log = logging.getLogger('main')
log.setLevel(logging.INFO)
LogFile('/tmp/thingy.log', logger='main').configure()
log.info('Hello from log.py')
*/tmp/thingy.log*:
::
Hello from log.py
Environment
~~~~~~~~~~~
Scruffy's `Environment` class ties all the other stuff together. The other classes can be instantiated as named children of an `Environment`, which will load any `Config` objects, apply the configs to the other objects, and then prepare the other objects.
*~/.thingy/config*:
.. code:: yaml
log_dir: /tmp/logs
log_file: thingy.log
*env.py*:
.. code:: python
from scruffy import *
e = Environment(
main_dir=Directory('~/.thingy', create=True,
config=ConfigFile('config', defaults=File('defaults.yaml', parent=PackageDirectory())),
lock=LockFile('lock')
user_plugins=PluginDirectory('plugins')
),
log_dir=Directory('{config:log_dir}', create=True
LogFile('{config:log_file}', logger='main')
),
pkg_plugins=PluginDirectory('plugins', parent=PackageDirectory())
)
License
-------
See LICENSE file. If you use this and don't hate it, buy me a beer at a conference some time.
Credits
-------
Props to richo_. Flat duck pride.
.. _richo: http://github.com/richo
|