Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
d174817
run some formatting
ArachnidAbby Mar 24, 2026
2967a4a
fix bug with trailing spaces on toml
ArachnidAbby Mar 24, 2026
00b59e0
fix global instance setting issue + add some basic tests pt1
ArachnidAbby Mar 25, 2026
73ab44b
fix validation of lists + more tests
ArachnidAbby Mar 25, 2026
3103b51
All basic test + another bugfix
ArachnidAbby Mar 25, 2026
2af7ee5
reorder some of the class definitions to try to be more organized
ArachnidAbby Mar 25, 2026
9f437bc
add new item for feature list
ArachnidAbby Mar 25, 2026
a923e7b
add sphinx to dev dependencies
ArachnidAbby Mar 25, 2026
11df8e7
docs quickstart
ArachnidAbby Mar 25, 2026
9747e3b
basic config start
ArachnidAbby Mar 25, 2026
f585477
restructure
ArachnidAbby Mar 25, 2026
3ed0460
setup rtd
ArachnidAbby Mar 25, 2026
8ceeb9c
document large swaths of the spec
ArachnidAbby Mar 25, 2026
b876744
fix configuration conf.py
ArachnidAbby Mar 25, 2026
631dac2
add documentation requirements
ArachnidAbby Mar 25, 2026
89b78be
increase toc depth
ArachnidAbby Mar 25, 2026
15d7e22
automatic versioning to make `uv bump` more useful
ArachnidAbby Mar 25, 2026
d4ee7d1
Finish docs for spec module
ArachnidAbby Mar 25, 2026
fdcb7ab
writer documentation
ArachnidAbby Mar 25, 2026
d822faa
Finish Documentation
ArachnidAbby Mar 25, 2026
f4c7590
add Section docs
ArachnidAbby Mar 25, 2026
20bc6d0
Fix formatting
ArachnidAbby Mar 25, 2026
5697390
fix typos
ArachnidAbby Mar 25, 2026
0f96fcf
fix typo
ArachnidAbby Mar 25, 2026
6487454
Merge pull request #8 from Summersweet-Software/documentation
ArachnidAbby Mar 25, 2026
d13df6c
Add documentation url to toml
ArachnidAbby Mar 26, 2026
f6c4394
be a little smarter next time, Abby
ArachnidAbby Mar 26, 2026
96b38bc
Merge branch 'staging' of https://github.com/ArachnidAbby/Comprehensi…
ArachnidAbby Apr 7, 2026
62b8b68
make tests use all available config writers + add more tests
ArachnidAbby Apr 7, 2026
38b5247
fix trailing whitespace
ArachnidAbby Apr 7, 2026
8c0d8fd
attempt using gitlab ci
ArachnidAbby Apr 7, 2026
f87efe5
Merge pull request #7 from Summersweet-Software/tests
ArachnidAbby Apr 7, 2026
94822a6
Allow for arbitrary object writing
ArachnidAbby Apr 7, 2026
1d5b0ce
Document new objects feature
ArachnidAbby Apr 7, 2026
2ad06f1
document new utility module
ArachnidAbby Apr 7, 2026
ac13714
fix type goofiness
ArachnidAbby Apr 8, 2026
6d66ccd
Merge pull request #9 from Summersweet-Software/parser_system_rewrite
ArachnidAbby Apr 8, 2026
ecd0a41
publish to testpypi
ArachnidAbby Apr 8, 2026
976262e
Merge branch 'staging' of https://github.com/ArachnidAbby/Comprehensi…
ArachnidAbby Apr 8, 2026
3b3e3a4
fix things
ArachnidAbby Apr 8, 2026
ca6b2fa
rename workflow
ArachnidAbby Apr 8, 2026
7cea8a8
attempt using testpypi secret key
ArachnidAbby Apr 8, 2026
957d8bb
try to correctly use github secret
ArachnidAbby Apr 8, 2026
45748ae
Random version ID's for testpypi pushes
ArachnidAbby Apr 15, 2026
a6e3a25
Remove useless line
ArachnidAbby Apr 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .github/workflows/pytest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: Run Python Tests

on:
push:
branches: [ "main", "staging"]
pull_request:
branches: [ "main", "staging" ]

permissions:
contents: read

jobs:
build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v5

- name: Install the latest version of uv
uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57
with:
enable-cache: true

- name: run tests
run: uv run pytest
36 changes: 36 additions & 0 deletions .github/workflows/test_publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: "Test Publish"

on:
push:
branches: [ "main", "staging"]
pull_request:
branches: [ "main", "staging" ]

jobs:
run:
runs-on: ubuntu-latest
environment:
name: pypi
permissions:
id-token: write
contents: read
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Install uv
uses: astral-sh/setup-uv@v7
- name: Install Python 3.13
run: uv python install 3.13
- name: Build
run: |
uv version --bump patch --bump dev=$RANDOM # random version id
uv build
# Check that basic features work and we didn't miss to include crucial files
- name: Smoke test (wheel)
run: uv run --isolated --no-project --with dist/*.whl testing.py
- name: Smoke test (source distribution)
run: uv run --isolated --no-project --with dist/*.tar.gz testing.py
- name: Publish
env:
TEST_PYPI_SECRET_KEY: ${{ secrets.TEST_PYPI_SECRET_KEY }}
run: uv publish --index testpypi --token $TEST_PYPI_SECRET_KEY
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ env/
**/__pycache__/
dist/
comprehensiveconfig.egg-info/
docs/build/

# Testing files
test.json
Expand Down
22 changes: 22 additions & 0 deletions .readthedocs.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details

# Required
version: 2

# Set the OS, Python version, and other tools you might need
build:
os: ubuntu-24.04
tools:
python: "3.13"

# Build documentation in the "docs/" directory with Sphinx
sphinx:
configuration: docs/source/conf.py

# Optionally, but recommended,
# declare the Python requirements required to build your documentation
# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
python:
install:
- requirements: docs/requirements.txt
4 changes: 2 additions & 2 deletions comprehensiveconfig/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,11 @@ def __getattribute__(self, name):

return super().__getattribute__(name)

def __setattribute__(self, name, value):
def __setattr__(self, name, value):
"""set attributes from active instance if available"""
inst = object.__getattribute__(self, "_INST")
if inst is not None and name in inst._ALL_FIELDS.keys():
return inst.__setattribute__(name, value)
return inst.__setattr__(name, value)

return super().__setattr__(name, value)

Expand Down
4 changes: 2 additions & 2 deletions comprehensiveconfig/configio.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ def dump(cls, file, node: spec.AnyConfigField):

@classmethod
@abstractmethod
def loads(cls, file) -> dict[str, Any]:
"""load a file by name"""
def loads(cls, data: str) -> dict[str, Any]:
"""load configuration string"""
pass

@classmethod
Expand Down
42 changes: 32 additions & 10 deletions comprehensiveconfig/json.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
from datetime import datetime
import json
from typing import Any
from . import configio
from . import spec

Expand All @@ -7,31 +9,50 @@ class JsonWriter(configio.ConfigurationWriter):
@classmethod
def dump_section(cls, node: spec.Section):
return {
node._FIELD_VAR_MAP[name]: (
cls.dump_value(node.get_field(name), value)
)
node._FIELD_VAR_MAP[name]: (cls.dump_value(node.get_field(name), value))
for name, value in node._value.items()
}

@classmethod
def dump_value(cls, node: spec.AnyConfigField, value):
"""convert value into json_serializable object that can be used as a key or value"""
match node:
case type() | spec.Section():
case spec.ConfigurationFieldABCMeta() | spec.Section():
return cls.dump_section(value)
case spec.Table(_, type() | spec.Section() | spec.ConfigUnion()):
return {cls.dump_value(key, key): cls.dump_value(val, val) for key, val in value.items()}
case spec.Table(
_,
spec.ConfigurationFieldABCMeta() | spec.Section() | spec.ConfigUnion(),
):
return {
cls.dump_value(key, key): cls.dump_value(val, val)
for key, val in value.items()
}
case spec.ConfigEnum(_, True):
return value.name
case spec.ConfigEnum(_, False):
return value.value
case _:
case str() | int() | float() | datetime() | dict() | None:
return value
case _:
# magic method to make writing new field types possible
if hasattr(node, "__write_json_value__"):
return value.__write_json_value__(
node, value
) # return a json serializable object

@classmethod
def dumps(cls, node) -> str:
match node:
case spec.Section():
return json.dumps(cls.dump_section(node), indent=4)
case spec.ConfigurationField():
if not node._has_default:
raise ValueError("Field has no default value")

dumped_value = cls.dump_value(node, node._default_value)
if isinstance(dumped_value, dict):
return json.dumps(dumped_value)
return str(dumped_value)
case _:
raise ValueError(node)

Expand All @@ -46,5 +67,6 @@ def load(cls, file):
return json.load(f)
return json.load(file)

# just alias the name
loads = json.loads
@classmethod
def loads(cls, data: str) -> dict[str, Any]:
return json.loads(data)
Loading
Loading