{"id":24288173,"url":"https://github.com/bjoluc/appcfg","last_synced_at":"2025-06-24T08:33:36.678Z","repository":{"id":57411005,"uuid":"268549107","full_name":"bjoluc/appcfg","owner":"bjoluc","description":"Simple hierarchic Python application configuration","archived":false,"fork":false,"pushed_at":"2023-02-06T16:34:50.000Z","size":95,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-02-18T23:03:49.550Z","etag":null,"topics":["app","application","config","configuration","env","environment","node-config","python"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bjoluc.png","metadata":{"files":{"readme":"readme.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"license","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-06-01T14:43:59.000Z","updated_at":"2023-02-06T14:47:46.000Z","dependencies_parsed_at":"2022-09-09T16:01:45.031Z","dependency_job_id":null,"html_url":"https://github.com/bjoluc/appcfg","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bjoluc%2Fappcfg","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bjoluc%2Fappcfg/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bjoluc%2Fappcfg/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bjoluc%2Fappcfg/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bjoluc","download_url":"https://codeload.github.com/bjoluc/appcfg/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":242123200,"owners_count":20075344,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["app","application","config","configuration","env","environment","node-config","python"],"created_at":"2025-01-16T09:53:43.526Z","updated_at":"2025-03-05T23:42:48.168Z","avatar_url":"https://github.com/bjoluc.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# appcfg\n\n[![PyPI](https://img.shields.io/pypi/v/appcfg)](https://pypi.python.org/pypi/appcfg/)\n[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/bjoluc/appcfg/build.yml)](https://github.com/bjoluc/appcfg/actions)\n[![codecov](https://codecov.io/gh/bjoluc/appcfg/branch/main/graph/badge.svg)](https://codecov.io/gh/bjoluc/appcfg)\n[![PyPI pyversions](https://img.shields.io/pypi/pyversions/appcfg.svg)](https://pypi.python.org/pypi/appcfg/)\n[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)\n[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079)](https://github.com/bjoluc/semantic-release-config-poetry)\n\nSimple hierarchic Python application configuration inspired by [node-config](https://github.com/lorenwest/node-config)\n\n## Motivation\n\nApplications (especially web services) often require certain configuration options to depend on the environment an application runs in (development, testing, production, etc.).\nFor instance, a database address config option may default to a local database server during development, a mock database server during testing, and yet another database server during production.\nIt may also need to be customizable via an environment variable.\n`appcfg` approaches scenarios like this and, similar to [node-config](https://github.com/lorenwest/node-config) for Node.js, allows to specify default configuration options for various environments and optionally override them by custom environment variables.\n\n## Getting Started\n\nLet's start by installing `appcfg` with `pip install appcfg[yaml]`, or simply `pip install appcfg` if you want to use the JSON format instead of YAML for config files.\n\nIn the top-level directory of your application (where the topmost `__init__.py` file is located), create a `config` directory.\nIf your application consists of a single Python file, just locate the `config` directory next to it.\nHere's an example project tree that we will refer to in the rest of this section:\n\n```diff\n ├── myproject\n │   ├── __init__.py\n+│   ├── config\n+|   |   └── ...\n |   ├── anothermodule.py\n │   └── myproject.py\n ├── tests\n │   ├── __init__.py\n │   └── test_myproject.py\n```\n\nWithin the `config` directory, create a `default.yml` file (or `default.json`, if you prefer that).\nThis file will hold your default configuration.\nIn the database example from the previous section, `default.yml` might look like this:\n\n```yaml\ndatabases:\n  mongo:\n    host: localhost\n    port: 27017\n    user: myuser\n    pass: mypassword\nsecrets:\n  mysecret: secret\n```\n\nWithin any module in the `myproject` package, we can now simply access that configuration as a `dict` object:\n\n```python\nfrom appcfg import get_config\n\nconfig = get_config(__name__)\nprint(config[\"databases\"][\"mongo\"][\"host\"])\n```\n\n`__name__` is passed to `get_config` so that it can infer the project root path where the `config` directory is located.\nThis way, `appcfg` can be used independently in multiple projects loaded at the same time, and projects can also retrieve one another's configuration.\nFor instance, in `test_myproject.py`, the configuration of `myproject` could be retrieved with `get_config(\"myproject\")`.\n\n## Environments\n\nLet's add an override config file for production, `production.yml`:\n\n```yaml\ndatabases:\n  mongo:\n    host: mongodb\n```\n\nAnd one for testing, `test.yml`:\n\n```yaml\ndatabases:\n  mongo:\n    host: mock\nsecrets:\n  mysecret: wellknown\n```\n\nBy default, none of these config files will be used.\nHowever, an environment can be specified by setting the `ENV` environment variable (alternatively, `PY_ENV` or `ENVIRONMENT` are also supported).\nIn this case, the configuration options from the corresponding config file will be merged into the ones from `default.yml`.\nIf, for instance, `ENV` is set to `production`, the config dict returned from `get_config()` will contain all the values from `default.yml`, but `config[\"databases\"][\"mongo\"][\"host\"]` will be set to `mongodb` instead of `localhost`.\nSimilarly, with `ENV=test`, `config[\"databases\"][\"mongo\"][\"host\"]` would be `mock` and, `config[\"secret\"][\"mysecret\"]` would be `wellknown`.\nIn case `ENV` is set but no corresponding config file is found, `get_config()` returns the options from the `default` config file.\n\n## Custom Environment Variables\n\nLet's say, we want the database host, user, and password, and the secret to be customizable via additional environment variables.\nThis can be achieved by adding an `env-vars.yml` config file with the following contents:\n\n```yaml\ndatabases:\n  mongo:\n    host: MONGO_HOST\n    user: MONGO_USER\n    pass: MONGO_PASS\nsecrets:\n  mysecret: MY_SECRET\n```\n\nThis way, if one of the specified environment variables is set, it will override the corresponding field's value from any other configuration file.\nOtherwise, that value is left untouched.\nFor instance, setting `MONGO_HOST=myhost` would result in `config[\"databases\"][\"mongo\"][\"host\"]` to be `myhost`, ignoring `localhost` from `default.yml` or `mongodb` from `production.yml`.\nNote that config values set via environment variables are always of type `str`, regardless of the overridden value's type.\n\n## Tips and Tricks\n\n### Environment Specification with pytest\n\nYou may wish to set `ENV=test` during unit tests without manually specifying it for every `pytest` invocation.\n[pytest-env](https://github.com/MobileDynasty/pytest-env) can do the job for you if you specify\n\n```ini\n[pytest]\nenv =\n    ENV=test\n```\n\nin your pytest configuration.\n\n\u003c!-- BEING API DOC --\u003e\n\n## API\n\n### get_config\n\nReturns a dict that contains the content of `default.json` or `default.yml` in the `config` directory within the root module's directory, inferred from `module_name`.\n\nIf an `ENV`, `PY_ENV`, or `ENVIRONMENT` variable is set (listed in the order of\nprecedence), and a config file with a base name corresponding to that variable's\nvalue is found, the contents of that config file are merged into the default\nconfiguration. Additionally, the environment variables specified in `env-vars.json`\nor `env-vars.yml` override any other configuration when they are set.\n\nIf none of `ENV`, `PY_ENV`, or `ENVIRONMENT` is set, only the `default` config file\nwill be loaded and optionally be overridden by custom environment variables as\nspecified in the `env-vars` config file. The `ENV` values \"dev\" and \"develop\" map to\nthe `development.json` or `development.yml` config file.\n\n**Arguments**:\n\n- `module_name` (`str`): The name of the module (or any of its submodules) for which\n  the configuration should be loaded. `__name__` can be used when `get_config()` is\n  called from the Python project that contains the `config` directory. Note that\n  `appcfg` requires the `config` directory to be a direct child of the top-level\n  package directory, or, if not a package, the directory that contains the specified\n  module.\n\n- `cached` (`bool`): If `True` (the default), the configuration for each `config`\n  directory will only be loaded once and the same dict object will be returned by\n  every subsequent call to `get_config()`.\n\n### get_env\n\nIf an `ENV`, `PY_ENV`, or `ENVIRONMENT` (listed in the order of precedence) environment variable is set, return the value of it. Otherwise, return \"default\".\n\nSpecial cases:\n\n- \"dev\" and \"develop\" are mapped to \"development\"\n\n\u003c!-- END API DOC --\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbjoluc%2Fappcfg","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbjoluc%2Fappcfg","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbjoluc%2Fappcfg/lists"}