# Configs in Python made smooth and simple
Betterconf (**better config**) is a Python library for project configuration
management. It allows you define your config like a regular Python class.
Features:
* Easy to hack.
* Less boilerplate.
* Minimal code to do big things.
* Zero dependencies. Only vanilla Python >=3.11
Betterconf is heavily typed, so your editors and typecheckers will be happy with it.
It's not that huge as Pydantic, so takes like 5 minutes to dive into.
Betterconf is highly customizable, so you can do anything with it.
## Installation
I recommend you to use poetry:
```sh
poetry add betterconf
```
However, you can use pip:
```sh
pip install betterconf
```
## How to?
Betterconf is very intuitive, so you don't need special knowledge to use it. We'll cover the basics.
The most simple config will look like this:
```python
from betterconf import betterconf
@betterconf
class Config:
LOGIN: str
PASSWORD: str
cfg = Config()
print(config.LOGIN)
```
Let's dive into what it does. By default, betterconf uses `EnvironmentProvider`, getting values with `os.getenv`,
so you can run this example with `LOGIN=vasya PASSWORD=admin python config.py` and simply get your login.
There is a very usable thing in our fancy-web-world, called `.env`s. Betterconf, since 4.5.0 automatically supports them out-of-the-box! See it:
```python
from betterconf import betterconf, DotenvProvider
# here betterconf gets values from `.env` file, you can change name or the path passing it as the first
# argument to provider.
# also, auto_load lets you not to write `provider.load_into_env` (loading variables to os.environ)
# or `provider.load_into_provider()` (loading them into the provider's inner storage).
@betterconf(provider=DotenvProvider(auto_load=True))
class Config:
val1: int
val2: str
name: str
cfg = Config()
print(cfg.val1, cfg.val2, cfg.name)
```
Your `.env` then looks like this:
```
name="John Wicked"
val1=12
val2="testing value"
```
But what if you need a different provider? Betterconf lets you set providers as for config itself and for each field respectively.
```python
import json
from betterconf import Alias
from betterconf import betterconf, field
from betterconf import JSONProvider, AbstractProvider
sample_json_config = json.dumps({"field": {"from": {"json": 123}}})
# our provider, that just gives the name of field back
class NameProvider(AbstractProvider):
def get(self, name: str) -> str:
return name
@betterconf(provider=NameProvider())
class Config:
# value will be got from NameProvider and will simply be `my_fancy_name`
my_fancy_name: str
# here we get value from JSONProvider; the default nested_access is '.'
field_from_json: Alias[int, "field::from::json"] = field(provider=JSONProvider(sample_json_config, nested_access="::"))
```
Betterconf casts primitive types itself, they include list, float, str, int. But if you need specific caster, say for complex object, you can write your own.
```python
from betterconf import betterconf
from betterconf import AbstractCaster, field
class DashesToDotsCaster(AbstractCaster):
def cast(self, val: str) -> str:
return val.replace("_", ".")
@betterconf
class Config:
simple_int: int
value: str = field(caster=DashesToDotsCaster())
print(Config(value="privet_mir", simple_int="55666").value)
```
Subconfigs and referencing one field in another declaration is also available. Check out examples folder.
## License
This project is licensed under MIT License.
See [LICENSE](LICENSE) for details.
Made with :heart: by [prostomarkeloff](https://github.com/prostomarkeloff) and our contributors.
Raw data
{
"_id": null,
"home_page": "https://github.com/prostomarkeloff/betterconf",
"name": "betterconf",
"maintainer": null,
"docs_url": null,
"requires_python": "<4.0,>=3.11",
"maintainer_email": null,
"keywords": "configs, config, env, .env",
"author": "prostomarkeloff",
"author_email": null,
"download_url": "https://files.pythonhosted.org/packages/e5/30/71b6a8d16547db3003265dc03a7a677660bc1c244c46b1a8640e53f3bd87/betterconf-4.5.0.tar.gz",
"platform": null,
"description": "# Configs in Python made smooth and simple\n\nBetterconf (**better config**) is a Python library for project configuration\nmanagement. It allows you define your config like a regular Python class.\n\nFeatures:\n\n* Easy to hack.\n* Less boilerplate.\n* Minimal code to do big things.\n* Zero dependencies. Only vanilla Python >=3.11\n\nBetterconf is heavily typed, so your editors and typecheckers will be happy with it.\n\nIt's not that huge as Pydantic, so takes like 5 minutes to dive into.\n\nBetterconf is highly customizable, so you can do anything with it.\n\n## Installation\n\nI recommend you to use poetry:\n\n```sh\npoetry add betterconf\n```\n\nHowever, you can use pip:\n\n```sh\npip install betterconf\n```\n\n## How to?\n\nBetterconf is very intuitive, so you don't need special knowledge to use it. We'll cover the basics.\n\nThe most simple config will look like this:\n```python\nfrom betterconf import betterconf\n\n@betterconf\nclass Config:\n LOGIN: str\n PASSWORD: str\n\ncfg = Config()\nprint(config.LOGIN)\n```\n\nLet's dive into what it does. By default, betterconf uses `EnvironmentProvider`, getting values with `os.getenv`,\nso you can run this example with `LOGIN=vasya PASSWORD=admin python config.py` and simply get your login.\n\n\nThere is a very usable thing in our fancy-web-world, called `.env`s. Betterconf, since 4.5.0 automatically supports them out-of-the-box! See it:\n\n```python\nfrom betterconf import betterconf, DotenvProvider\n\n# here betterconf gets values from `.env` file, you can change name or the path passing it as the first\n# argument to provider.\n# also, auto_load lets you not to write `provider.load_into_env` (loading variables to os.environ)\n# or `provider.load_into_provider()` (loading them into the provider's inner storage).\n@betterconf(provider=DotenvProvider(auto_load=True))\nclass Config:\n val1: int\n val2: str\n name: str\n\ncfg = Config()\nprint(cfg.val1, cfg.val2, cfg.name)\n```\n\nYour `.env` then looks like this:\n\n```\nname=\"John Wicked\"\nval1=12\nval2=\"testing value\"\n```\n\n\nBut what if you need a different provider? Betterconf lets you set providers as for config itself and for each field respectively.\n\n```python\nimport json\nfrom betterconf import Alias\nfrom betterconf import betterconf, field\nfrom betterconf import JSONProvider, AbstractProvider\n\nsample_json_config = json.dumps({\"field\": {\"from\": {\"json\": 123}}})\n\n# our provider, that just gives the name of field back\nclass NameProvider(AbstractProvider):\n def get(self, name: str) -> str:\n return name\n\n@betterconf(provider=NameProvider())\nclass Config:\n # value will be got from NameProvider and will simply be `my_fancy_name`\n my_fancy_name: str\n # here we get value from JSONProvider; the default nested_access is '.'\n field_from_json: Alias[int, \"field::from::json\"] = field(provider=JSONProvider(sample_json_config, nested_access=\"::\"))\n\n```\n\nBetterconf casts primitive types itself, they include list, float, str, int. But if you need specific caster, say for complex object, you can write your own.\n\n```python\nfrom betterconf import betterconf\nfrom betterconf import AbstractCaster, field\n\nclass DashesToDotsCaster(AbstractCaster):\n def cast(self, val: str) -> str:\n return val.replace(\"_\", \".\")\n\n@betterconf\nclass Config:\n simple_int: int\n value: str = field(caster=DashesToDotsCaster())\n\nprint(Config(value=\"privet_mir\", simple_int=\"55666\").value)\n```\n\nSubconfigs and referencing one field in another declaration is also available. Check out examples folder.\n\n## License\nThis project is licensed under MIT License.\n\nSee [LICENSE](LICENSE) for details.\n\n\nMade with :heart: by [prostomarkeloff](https://github.com/prostomarkeloff) and our contributors.\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Configs in Python made smooth and simple",
"version": "4.5.0",
"project_urls": {
"Documentation": "https://github.com/prostomarkeloff/betterconf",
"Homepage": "https://github.com/prostomarkeloff/betterconf",
"Repository": "https://github.com/prostomarkeloff/betterconf"
},
"split_keywords": [
"configs",
" config",
" env",
" .env"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "183c86921e4e407f25413819e04471606c32377f47887af7873e0613f5036946",
"md5": "4d2995eb4432918a28d814f9fa4c63e9",
"sha256": "ee6ad8ae4c49a7f977555dcb435eb258eb044e10a2f43fdd77bb67b8ff682118"
},
"downloads": -1,
"filename": "betterconf-4.5.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "4d2995eb4432918a28d814f9fa4c63e9",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": "<4.0,>=3.11",
"size": 11769,
"upload_time": "2025-01-21T12:36:41",
"upload_time_iso_8601": "2025-01-21T12:36:41.064035Z",
"url": "https://files.pythonhosted.org/packages/18/3c/86921e4e407f25413819e04471606c32377f47887af7873e0613f5036946/betterconf-4.5.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "e53071b6a8d16547db3003265dc03a7a677660bc1c244c46b1a8640e53f3bd87",
"md5": "acbbcfd6171f1a7b2e95382afe8ee764",
"sha256": "aebc050d24cf8fdf837b204411c57afcbc837158a7fa21713d31b240b2a1f1d3"
},
"downloads": -1,
"filename": "betterconf-4.5.0.tar.gz",
"has_sig": false,
"md5_digest": "acbbcfd6171f1a7b2e95382afe8ee764",
"packagetype": "sdist",
"python_version": "source",
"requires_python": "<4.0,>=3.11",
"size": 10561,
"upload_time": "2025-01-21T12:36:43",
"upload_time_iso_8601": "2025-01-21T12:36:43.526792Z",
"url": "https://files.pythonhosted.org/packages/e5/30/71b6a8d16547db3003265dc03a7a677660bc1c244c46b1a8640e53f3bd87/betterconf-4.5.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-01-21 12:36:43",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "prostomarkeloff",
"github_project": "betterconf",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "betterconf"
}