Skip to content

Commit

Permalink
feat: backport v2.2.2
Browse files Browse the repository at this point in the history
  • Loading branch information
zifeo committed Sep 24, 2023
2 parents 6c8130c + fe0148c commit e15ad06
Show file tree
Hide file tree
Showing 21 changed files with 902 additions and 309 deletions.
3 changes: 0 additions & 3 deletions .flake8

This file was deleted.

10 changes: 10 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
version: 2
updates:
- package-ecosystem: github-actions
directory: /
schedule:
interval: monthly
- package-ecosystem: pip
directory: /
schedule:
interval: monthly
2 changes: 1 addition & 1 deletion .github/workflows/pr-title-check.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
name: Validate PR title
runs-on: ubuntu-latest
steps:
- uses: amannn/action-semantic-pull-request@v4
- uses: amannn/action-semantic-pull-request@v5
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/test-release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ jobs:
test-release:
uses: zifeo/workflows/.github/workflows/py-test-release.yml@main
with:
python-matrix: '["3.8", "3.9", "3.10"]'
poetry-version: "1.1.12"
python-version: "3.10"
python-matrix: '["3.8", "3.9", "3.10", "3.11"]'
poetry-version: "1.3.2"
python-version: "3.11"
publish-pypi: true
secrets:
pypi-token: ${{ secrets.PYPI_TOKEN }}
30 changes: 13 additions & 17 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
repos:
- repo: https://github.com/sqlalchemyorg/zimports/
rev: v0.6.0
hooks:
- id: zimports
- repo: https://github.com/psf/black
rev: 22.3.0
hooks:
- id: black
- repo: https://gitlab.com/pycqa/flake8
rev: 3.9.2
hooks:
- id: flake8
- repo: https://github.com/commitizen-tools/commitizen
rev: v2.27.1
hooks:
- id: commitizen
stages: [commit-msg]
- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: "v0.0.291"
hooks:
- id: ruff
- repo: https://github.com/psf/black
rev: 23.9.1
hooks:
- id: black
- repo: https://github.com/commitizen-tools/commitizen
rev: 3.9.1
hooks:
- id: commitizen
stages: [commit-msg]
51 changes: 51 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,54 @@
## v2.2.2 (2023-09-24)

### Fix

- union alternative syntax #112 (#113)

## v2.2.1 (2023-05-26)

### Fix

- for issue with nested dataclasses that have default values #98

## v2.2.0 (2023-05-23)

### Feat

- support StrEnum from python 3.11 (#91)
- add support fro string enum (#88)
- dependabot (#69)
- upgrade deps and switch to ruff (#68)

### Fix

- union and yaml loader fixes (#92)
- license

## v2.1.3 (2022-12-05)

### Fix

- typing for dict, close #64 (#65)

## v2.1.2 (2022-10-22)

### Fix

- readme
- remote loading error, close #57

## v2.1.1 (2022-09-16)

### Fix

- dumps close #54 (#55)

## v2.1.0 (2022-07-31)

### Feat

- add yaml source support (#51)

## v2.0.0 (2022-06-28)

### Feat
Expand Down
27 changes: 17 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
[![Actions Status](https://github.com/zifeo/dataconf/workflows/CI/badge.svg)](https://github.com/zifeo/dataconf/actions)
[![PyPI version](https://badge.fury.io/py/dataconf.svg)](https://badge.fury.io/py/dataconf)

Simple dataclasses configuration management for Python with hocon/json/yaml/properties/env-vars/dict/cli support, based on awesome and lightweight [pyhocon](https://github.com/chimpler/pyhocon) parsing library.
Simple dataclasses configuration management for Python with
hocon/json/yaml/properties/env-vars/dict/cli support.

## Getting started

Expand Down Expand Up @@ -114,15 +115,16 @@ print(dataconf.string(conf, Config))

@dataclass
class Example:
hello: string
world: string
hello: str
world: str
foo: List[str]

os.environ['DC_WORLD'] = 'monde'

print(
dataconf
.multi
.url('https://raw.githubusercontent.com/zifeo/dataconf/master/confs/simple.hocon')
.url('https://raw.githubusercontent.com/zifeo/dataconf/main/confs/simple.hocon')
.env('DC')
.on(Example)
)
Expand All @@ -135,24 +137,27 @@ print(
import dataconf

conf = dataconf.string('{ name: Test }', Config)
conf = dataconf.string('name:\n\tvalue: Test', Config, loader=dataconf.YAML) # dataconf.HOCON by default
conf = dataconf.env('PREFIX_', Config)
conf = dataconf.dict({'name': 'Test'}, Config)
conf = dataconf.url('https://raw.githubusercontent.com/zifeo/dataconf/master/confs/test.hocon', Config)
conf = dataconf.file('confs/test.{hocon,json,yaml,properties}', Config)
conf = dataconf.url('https://raw.githubusercontent.com/zifeo/dataconf/master/confs/test.hocon', Config) # hocon, json, yaml, properties
conf = dataconf.file('confs/test.hocon', Config) # hocon, json, yaml, properties
conf = dataconf.cli(sys.argv, Config)

# Aggregation
conf = dataconf.multi.string(...).env(...).url(...).file(...).dict(...).cli(...).on(Config)

# Same api as Python json/yaml packages (e.g. `load`, `loads`, `dump`, `dumps`)
conf = dataconf.load('confs/test.{hocon,json,yaml,properties}', Config)
conf = dataconf.load('confs/test.hocon', Config) # hocon, json, yaml, properties
conf = dataconf.load('confs/test.yaml', Config, loader=dataconf.YAML) # dataconf.HOCON by default
dataconf.dump('confs/test.hocon', conf, out='hocon')
dataconf.dump('confs/test.json', conf, out='json')
dataconf.dump('confs/test.yaml', conf, out='yaml')
dataconf.dump('confs/test.properties', conf, out='properties')
```

For full HOCON capabilities see [here](https://github.com/chimpler/pyhocon/#example-of-hocon-file).
For full HOCON capabilities see
[here](https://github.com/chimpler/pyhocon/#example-of-hocon-file).

## Parse env vars

Expand Down Expand Up @@ -202,11 +207,13 @@ is equivalent to
}
```

Note that when using `.env` source, the strict mode is disabled and value might be casted.
Note that when using `.env` source, the strict mode is disabled and value might
be casted.

## Parse CLI arguments

Same as env vars parse (dashes are converted to underscore, e.g. `TEST_A``--test-a`).
Same as env vars parse (dashes are converted to underscore, e.g. `TEST_A`
`--test-a`).

## CLI usage

Expand Down
4 changes: 4 additions & 0 deletions confs/simple.hocon
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
hello = bonjour
foo = [
bar
]
5 changes: 3 additions & 2 deletions confs/simple.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{
"hello": "bonjour"
}
"hello": "bonjour",
"foo": ["bar"]
}
3 changes: 3 additions & 0 deletions confs/simple.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
hello: bonjour
foo:
- bar
4 changes: 4 additions & 0 deletions dataconf/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@
from dataconf.main import dumps
from dataconf.main import env
from dataconf.main import file
from dataconf.main import HOCON
from dataconf.main import load
from dataconf.main import loads
from dataconf.main import multi
from dataconf.main import parse
from dataconf.main import string
from dataconf.main import url
from dataconf.main import YAML
from dataconf.version import __version__

__all__ = [
Expand All @@ -25,5 +27,7 @@
"cli",
"multi",
"parse",
"YAML",
"HOCON",
"__version__",
]
58 changes: 41 additions & 17 deletions dataconf/main.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
import inspect
import contextlib
import os
from typing import Any, Optional
from typing import Dict
from typing import List
from typing import Type
from urllib.parse import urlparse
from urllib.request import urlopen

from dataconf import utils
from dataconf.exceptions import MalformedConfigException
from pyhocon import ConfigFactory
from pyhocon import HOCONConverter
from pyhocon.config_parser import ConfigTree
import pyparsing
from yaml import safe_load

HOCON = 1
YAML = 2


def inject_callee_scope(func):
Expand Down Expand Up @@ -41,7 +50,6 @@ def parse(
globalns=None,
localns=None,
):

try:
return utils.__parse(
conf, clazz, "", strict, ignore_unexpected, globalns, localns
Expand All @@ -66,23 +74,39 @@ def __init__(self, confs: List[ConfigTree], strict: bool = True) -> None:
self.strict = strict

def env(self, prefix: str) -> "Multi":
self.strict = False
data = env_vars_parse(prefix, os.environ)
return self.dict(data)
return Multi(self.confs, strict=False).dict(data)

def dict(self, obj: str) -> "Multi":
conf = ConfigFactory.from_dict(obj)
return Multi(self.confs + [conf], self.strict)

def string(self, s: str) -> "Multi":
def string(self, s: str, loader: str = HOCON) -> "Multi":
if loader == YAML:
data = safe_load(s)
return self.dict(data)

conf = ConfigFactory.parse_string(s)
return Multi(self.confs + [conf], self.strict)

def url(self, uri: str) -> "Multi":
conf = ConfigFactory.parse_URL(uri)
def url(self, uri: str, timeout: int = 10) -> "Multi":
path = urlparse(uri).path
if path.endswith(".yaml") or path.endswith(".yml"):
with contextlib.closing(urlopen(uri, timeout=timeout)) as fd:
s = fd.read().decode("utf-8")
return self.string(s, loader=YAML)

conf = ConfigFactory.parse_URL(uri, timeout=timeout, required=True)
return Multi(self.confs + [conf], self.strict)

def file(self, path: str) -> "Multi":
def file(self, path: str, loader: Optional[str] = None) -> "Multi":
if loader == YAML or (
loader is None and (path.endswith(".yaml") or path.endswith(".yml"))
):
with open(path, "r") as f:
data = safe_load(f)
return self.dict(data)

conf = ConfigFactory.parse_file(path)
return Multi(self.confs + [conf], self.strict)

Expand All @@ -107,13 +131,13 @@ def env(prefix: str, clazz: Type, **kwargs):


@inject_callee_scope
def dict(obj: str, clazz: Type, **kwargs):
def dict(obj: Dict[str, Any], clazz: Type, **kwargs):
return multi.dict(obj).on(clazz, **kwargs)


@inject_callee_scope
def string(s: str, clazz: Type, **kwargs):
return multi.string(s).on(clazz, **kwargs)
def string(s: str, clazz: Type, loader: str = HOCON, **kwargs):
return multi.string(s, loader).on(clazz, **kwargs)


@inject_callee_scope
Expand All @@ -122,8 +146,8 @@ def url(uri: str, clazz: Type, **kwargs):


@inject_callee_scope
def file(path: str, clazz: Type, **kwargs):
return multi.file(path).on(clazz, **kwargs)
def file(path: str, clazz: Type, loader: Optional[str] = None, **kwargs):
return multi.file(path, loader).on(clazz, **kwargs)


@inject_callee_scope
Expand All @@ -132,13 +156,13 @@ def cli(argv: List[str], clazz: Type, **kwargs):


@inject_callee_scope
def load(path: str, clazz: Type, **kwargs):
return file(path, clazz, **kwargs)
def load(path: str, clazz: Type, loader: Optional[str] = None, **kwargs):
return file(path, clazz, loader, **kwargs)


@inject_callee_scope
def loads(s: str, clazz: Type, **kwargs):
return string(s, clazz, **kwargs)
def loads(s: str, clazz: Type, loader: str = HOCON, **kwargs):
return string(s, clazz, loader, **kwargs)


def dump(file: str, instance: object, out: str):
Expand All @@ -147,7 +171,7 @@ def dump(file: str, instance: object, out: str):


def dumps(instance: object, out: str):
conf = utils.generate(instance, "")
conf = utils.__generate(instance, "")

if out:
if out.lower() == "hocon":
Expand Down
Loading

0 comments on commit e15ad06

Please sign in to comment.