Package: goodconf
A thin wrapper overPydantic’s settings management.
Allows you to define configuration variables and load them from environment or JSON/YAML
file. Also generates initial configuration files and documentation for your
defined configuration.Installationpip install goodconforpip install goodconf[yaml]/pip install goodconf[toml]if parsing/generating YAML/TOML
files is required.Quick StartLet’s use configurable Django settings as an example.First, create aconf.pyfile in your project’s directory, next tosettings.py:importbase64importosfromgoodconfimportGoodConf,FieldfrompydanticimportPostgresDsnclassAppConfig(GoodConf):"Configuration for My App"DEBUG:boolDATABASE_URL:PostgresDsn="postgres://localhost:5432/mydb"SECRET_KEY:str=Field(initial=lambda:base64.b64encode(os.urandom(60)).decode(),description="Used for cryptographic signing. ""https://docs.djangoproject.com/en/2.0/ref/settings/#secret-key")classConfig:default_files=["/etc/myproject/myproject.yaml","myproject.yaml"]config=AppConfig()Next, use the config in yoursettings.pyfile:importdj_database_urlfrom.confimportconfigconfig.load()DEBUG=config.DEBUGSECRET_KEY=config.SECRET_KEYDATABASES={"default":dj_database_url.parse(config.DATABASE_URL)}In your initial developer installation instructions, give some advice such as:python-c"import myproject; print(myproject.conf.config.generate_yaml(DEBUG=True))">myproject.yamlBetter yet, make it a function andentry pointso you can install
your project and run something likegenerate-config> myproject.yaml.UsageGoodConfYour subclassedGoodConfobject can include aConfigclass with the following
attributes:file_env_varThe name of an environment variable which can be used for
the name of the configuration file to load.default_filesIf no file is passed to theloadmethod, try to load a
configuration from these files in order.It also has one method:loadTrigger the load method during instantiation. Defaults to False.Use plain-text docstring for use as a header when generating a configuration
file.Environment variables always take precedence over variables in the configuration files.See Pydantic’s docs for examples of loading:Dotenv (.env) filesDocker secretsFieldsDeclare configuration values by subclassingGoodConfand defining class
attributes which are standard Python type definitions or PydanticFieldInfoinstances generated by theFieldfunction.Goodconf can use one extra argument provided to theFieldto define an function
which can generate an initial value for the field:initialCallable to use for initial value when generating a configDjango UsageA helper is provided which monkey-patches Django’s management commands to
accept a--configargument. Replace yourmanage.pywith the following:# Define your GoodConf in `myproject/conf.py`frommyproject.confimportconfigif__name__=='__main__':config.django_manage()Why?I took inspiration fromlogan(used by
Sentry) andderpconf(used by
Thumbor). Both, however used Python files for configuration. I wanted a safer
format and one that was easier to serialize data into from a configuration
management system.Environment VariablesI don’t like working with environment variables. First, there are potential
security issues:Accidental leaks via logging or error reporting services.Child process inheritance (seeImageTragickfor an idea why this could be bad).Second, in practice on deployment environments, environment variables end up
getting written to a number of files (cron, bash profile, service definitions,
web server config, etc.). Not only is it cumbersome, but also increases the
possibility of leaks via incorrect file permissions.I prefer a single structured file which is explicitly read by the application.
I also want it to be easy to run my applications on services like Heroku
where environment variables are the preferred configuration method.This module let’s me do things the way I prefer in environments I control, but
still run them with environment variables on environments I don’t control with
minimal fuss.ContributeCreate virtual environment and install package and dependencies.pipinstall-e".[tests]"Run testspytestReleasing a new version to PyPI:exportVERSION=X.Y.Zgittag-sv$VERSION-mv$VERSIONgitpush--tagsrm-rf./disthatchbuildhatchpublish--user__token__ghreleasecreatev$VERSIONdist/goodconf-$VERSION*--generate-notes--verify-tag