Configuration library for Python applications
.. NOTE: Make sure to edit the template for this file in docs_tmpl/ and .. not the cog-generated version.
Everett is a Python configuration library for your app.
:Code: https://github.com/willkg/everett :Issues: https://github.com/willkg/everett/issues :License: MPL v2 :Documentation: https://everett.readthedocs.io/
Goals of Everett:
From that, Everett has the following features:
autocomponentconfig
and automoduleconfig
directives for
automatically generating configuration documentationEverett is inspired by python-decouple <https://github.com/henriquebastos/python-decouple>
_ and configman <https://configman.readthedocs.io/en/latest/>
_.
Run::
$ pip install everett
Some configuration environments require additional dependencies::
# For INI support
$ pip install 'everett[ini]'
# for YAML support
$ pip install 'everett[yaml]'
Additionally, if you want to use the Sphinx extension to document your configuration, you need to add Sphinx::
# to use the Sphinx extension
$ pip install 'everett[sphinx]'
Example::
# myserver.py
"""
Minimal example showing how to use configuration for a web app.
"""
from everett.manager import ConfigManager
config = ConfigManager.basic_config(
doc="Check https://example.com/configuration for documentation."
)
host = config("host", default="localhost")
port = config("port", default="8000", parser=int)
debug_mode = config(
"debug",
default="False",
parser=bool,
doc="Set to True for debugmode; False for regular mode",
)
print(f"host: {host}")
print(f"port: {port}")
print(f"debug_mode: {debug_mode}")
Then you can run it::
$ python myserver.py
host: localhost
port: 8000
debug_mode: False
You can set environment variables to affect configuration::
$ PORT=7000 python myserver.py
host: localhost
port: 7000
debug_mode: False
It checks a .env
file in the current directory::
$ echo "HOST=127.0.0.1" > .env
$ python myserver.py
host: 127.0.0.1
port: 8000
debug_mode: False
It spits out useful error information if configuration is wrong::
$ DEBUG=foo python myserver.py
<traceback>
everett.InvalidValueError: ValueError: 'foo' is not a valid bool value
DEBUG requires a value parseable by everett.manager.parse_bool
DEBUG docs: Set to True for debugmode; False for regular mode
Project docs: Check https://example.com/configuration for documentation.
You can test your code using config_override
in your tests to test various
configuration values::
# testdebug.py
"""
Minimal example showing how to override configuration values when testing.
"""
import unittest
from everett.manager import ConfigManager, config_override
class App:
def __init__(self):
config = ConfigManager.basic_config()
self.debug = config("debug", default="False", parser=bool)
class TestDebug(unittest.TestCase):
def test_debug_on(self):
with config_override(DEBUG="on"):
app = App()
self.assertTrue(app.debug)
def test_debug_off(self):
with config_override(DEBUG="off"):
app = App()
self.assertFalse(app.debug)
if __name__ == "__main__":
unittest.main()
Run that::
..
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
That's perfectly fine for a 12-Factor <https://12factor.net/>
_ app.
When you outgrow that or need different variations of it, you can switch to
creating a ConfigManager
instance that meets your needs.
Most other libraries I looked at had one or more of the following issues:
Backwards incompatible changes:
Fixes and features:
Added support for Python 3.12 (#221)
Fix env file parsing in regards to quotes. (#230)
Fixes and features:
Implement default_if_empty
argument which will return the default value
(if specified) if the value is the empty string. (#205)
Implement parse_time_period
parser for converting time periods like "10m4s"
into the total number of seconds that represents.
::
>>> from everett.manager import parse_time_period
>>> parse_time_period("4m")
240
(#203)
Implement parse_data_size
parser for converting values like "40gb" into
the total number of bytes that represents.
::
>>> from everett.manager import parse_data_size
>>> parse_time_period("40gb")
40000000000
(#204)
Fix an UnboundLocalError
when using automoduleconfig
and providing a
Python dotted path to a thing that either kicks up an ImportError
or
doesn't exist. Now it raises a more helpful error. (#201)
Fixes and features:
Add support for Python 3.11. (#187)
Add raise_configuration_error
method on ConfigManager
. (#185)
Improve automoduleconfig
to walk the whole AST and document configuration
set by assign::
SOMEVAR = _config("somevar")
and dict::
SOMEGROUP = {
"SOMEVAR": _config("somevar"),
}
(#184)
Fix options not showing up on ReadTheDocs. (#186)
Backwards incompatible changes:
Dropped support for Python 3.6. (#176)
Dropped autocomponent
Sphinx directive in favor of
autocomponentconfig
.
Fixes and features:
Add support for Python 3.10. (#173)
Rework namespaces so that you can apply a namespace (with_namespace()
)
after binding a component (with_options()
) (#175)
Overhauled, simplified, and improved documentation. Files with example output
are now generated using cog <https://pypi.org/project/cogapp/>
_.
Rewrite Sphinx extension.
This now supports manually documenting configuration using
everett:component
and everett:option
directives.
This adds :everett:component:
and :everett:option:
roles for linking
to specific configuration in the docs.
It also addsh autocomponentconfig
and automoduleconfig
directives for
automatically generating documentation.
When using these directives, items are added to the index and everything is linkable making it easier to find and talk to users about specific configuration items. (#172)
Fixes:
Fix Sphinx warning about roles in Everett sphinxext. (#165)
Fix get_runtime_config
to work with slots (#166)
Backwards incompatible changes:
This radically reduces the boilerplate required to define components. It also improves the connections between things so it's easier to:
Previously, components needed to subclass RequiredConfigMixin and provide a "required_config" class attribute. Something like this::
from everett.component import RequiredConfigMixin, ConfigOptions
class SomeClass(RequiredConfigMixin):
required_config = ConfigOptions()
required_config.add_option(
"some_option",
default="42",
)
That's been slimmed down and now looks like this::
from everett.manager import Option
class SomeClass:
class Config:
some_option = Option(default="42")
That's much simpler and the underlying implementation code is less tangled and complex, too.
If you used everett.component.RequiredConfigMixin
or
everett.component.ConfigOptions
, you'll need to update your classes.
If you didn't use those things, then you don't have to make any changes.
See the documentation on components for how it all works now.
Changed the way configuration variables are referred to in configuration error messages. Previously, I tried to use a general way "namespace=something key=somethingelse" but that's confusing and won't match up with project documentation.
I changed it to the convention used in the process environment and
env files. For example, FOO_BAR
.
If you use INI or YAML for configuration, you can specify a msg_builder
argument when you build the ConfigManager
and build error messages
tailored to your users.
Fixes:
Switch to src/
repository layout.
Added type annotations and type checking during CI. (#155)
Standardized on f-strings across the codebase.
Switched Sphinx theme.
Update of documentation, fleshed out and simplified examples, cleaned up language, reworked structure of API section (previously called Library or some unhelpful thing like that), etc.
Backwards incompatible changes:
Dropped support for Python 3.4. (#96)
Dropped support for Python 3.5. (#116)
Fixes:
Add support for Python 3.7. (#68)
Add support for Python 3.8. (#102)
Add support for Python 3.9. (#117)
Reformatted code with Black, added Makefile, switched to GitHub Actions.
Fix get_runtime_config()
to infer namespaces. (#118)
Fix RemovedInSphinx50Warning
. (#115)
Documentation fixes and clarifications.
Fixes:
Improve documentation.
Fix problems when there are nested BoundConfigs
. Now they work
correctly. (#90)
Add "meta" to options letting you declare additional data on the option when you're adding it.
For example, this lets you do things like mark options as "secrets"
so that you know which ones to ******
out when logging your
configuration. (#88)
Fixes:
Fix documentation issues.
Package missing everett.ext
. Thank you, dsblank! (#84)
Backwards incompatible changes:
Dropped support for Python 2.7. Everett no longer supports Python 2. (#73)
Dropped support for Python 3.3 and added support for Python 3.7. Thank you, pjz! (#68)
Moved ConfigIniEnv
to a different module. Now you need to import it
like this::
from everett.ext.inifile import ConfigIniEnv
(#79)
Features:
Everett now logs configuration discovery in the everett
logger at the
logging.DEBUG
level. This is helpful for trouble-shooting some kinds of
issues. (#74)
Everett now has a YAML configuration environment. In order to use it, you need to install its requirements::
$ pip install everett[yaml]
Then you can import it like this::
from everett.ext.yamlfile import ConfigYamlEnv
(#72)
Fixes:
Everett no longer requires configobj
--it's now optional. If you use
ConfigIniEnv
, you can install it with::
$ pip install everett[ini]
(#79)
Fixed list parsing and file discovery in ConfigIniEnv so they match the docs and are more consistent with other envs. Thank you, apollo13! (#71)
Added a .basic_config()
for fast opinionated setup that uses the
process environment and a .env
file in the current working directory.
Switching to semver.
Changed:
Rewrite Sphinx extension. The extension is now in the everett.sphinxext
module and the directive is now .. autocomponent::
. It generates better
documentation and it now indexes Everett components and options.
This is backwards-incompatible. You will need to update your Sphinx configuration and documentation.
Changed the HISTORY.rst
structure.
Changed the repr for everett.NO_VALUE
to "NO_VALUE"
.
InvalidValueError
and ConfigurationMissingError
now have
namespace
, key
, and parser
attributes allowing you to build your
own messages.
Fixed:
Documentation fixes and updates.
Added:
Add :namespace:
and :case:
arguments to autoconfig directive. These
make it easier to cater your documentation to your project's needs.
Add support for Python 3.6.
Minor documentation fixes and updates.
Added:
ConfigManager
objects and config options. This will make it easier for
your users to debug configuration errors they're having with your software.Fixed:
ListOf
so it returns empty lists rather than a list with a single
empty string.Documentation fixes and updates.
Added:
Add RequiredConfigMixin.get_runtime_config()
which returns the runtime
configuration for a component or tree of components. This lets you print
runtime configuration at startup, generate INI files, etc.
Add ConfigObjEnv
which lets you use an object for configuration. This
works with argparse's Namespace amongst other things.
Changed:
Change :show-docstring:
to take an optional value which is the attribute
to pull docstring content from. This means you don't have to mix programming
documentation with user documentation--they can be in different attributes.
Improve configuration-related exceptions. With Python 3, configuration errors
all derive from ConfigurationError
and have helpful error messages that
should make it clear what's wrong with the configuration value. With Python 2,
you can get other kinds of Exceptions thrown depending on the parser used, but
configuration error messages should still be helpful.
Documentation fixes and updates.
Added:
Add :show-docstring:
flag to autoconfig
directive.
Add :hide-classname:
flag to autoconfig
directive.
Changed:
ConfigIniEnv
to use configobj which allows for nested sections in
INI files. This also allows you to specify multiple INI files and have later
ones override earlier ones.Fixed:
autoconfig
Sphinx directive and add tests--it was all kinds of broken.Documentation fixes and updates.
Added:
raw_value
argument to config calls. This makes it easier to write code
that prints configuration.Fixed:
listify(None)
to return []
.Documentation fixes and updates.
Fixed:
alternate_keys
with components. Previously it worked for everything
but components. Now it works with components, too.Documentation fixes and updates.
Added:
Add ConfigManager.from_dict()
shorthand for building configuration
instances.
Add .get_namespace()
to ConfigManager
and friends for getting
the complete namespace for a given config instance as a list of strings.
Add alternate_keys
to config call. This lets you specify a list of keys in
order to try if the primary key doesn't find a value. This is helpful for
deprecating keys that you used to use in a backwards-compatible way.
Add root:
prefix to keys allowing you to look outside of the current
namespace and at the configuration root for configuration values.
Changed:
ConfigDictEnv
case-insensitive to keys and namespaces.Documentation fixes and updates.
Added:
Add ConfigEnvFileEnv
for supporting .env
files. Thank you, Paul!
Add "on" and "off" as valid boolean values. This makes it easier to use config for feature flippers. Thank you, Paul!
Changed:
Change ConfigIniEnv
to take a single path or list of paths. Thank you,
Paul!
Make NO_VALUE
falsy.
Fixed:
__call__
returning None--it should return NO_VALUE
.Lots of docs updates: finished the section about making your own parsers, added a section on using dj-database-url, added a section on django-cache-url and expanded on existing examples.
Initial writing.