config-as-json 0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- config_as_json-0.1/LICENSE.txt +22 -0
- config_as_json-0.1/PKG-INFO +98 -0
- config_as_json-0.1/README.md +139 -0
- config_as_json-0.1/README_pypi.md +77 -0
- config_as_json-0.1/config_as_json.egg-info/PKG-INFO +98 -0
- config_as_json-0.1/config_as_json.egg-info/SOURCES.txt +27 -0
- config_as_json-0.1/config_as_json.egg-info/dependency_links.txt +1 -0
- config_as_json-0.1/config_as_json.egg-info/requires.txt +3 -0
- config_as_json-0.1/config_as_json.egg-info/top_level.txt +1 -0
- config_as_json-0.1/pyproject.toml +24 -0
- config_as_json-0.1/setup.cfg +4 -0
- config_as_json-0.1/setup.py +21 -0
- config_as_json-0.1/src/config_as_json/__init__.py +74 -0
- config_as_json-0.1/src/config_as_json/assert_dict_equal.py +82 -0
- config_as_json-0.1/src/config_as_json/commontypes.py +21 -0
- config_as_json-0.1/src/config_as_json/config.py +959 -0
- config_as_json-0.1/src/config_as_json/config_auto_change_hook.py +73 -0
- config_as_json-0.1/src/config_as_json/config_factory.py +201 -0
- config_as_json-0.1/src/config_as_json/dict_validators.py +330 -0
- config_as_json-0.1/src/config_as_json/discriminated_dict_validators.py +292 -0
- config_as_json-0.1/src/config_as_json/file_extension.py +42 -0
- config_as_json-0.1/src/config_as_json/file_must_exist.py +37 -0
- config_as_json-0.1/src/config_as_json/list_validators.py +782 -0
- config_as_json-0.1/src/config_as_json/migrate_cfg.py +55 -0
- config_as_json-0.1/src/config_as_json/migrate_cfg_warn_hook.py +43 -0
- config_as_json-0.1/src/config_as_json/projected_validators.py +162 -0
- config_as_json-0.1/src/config_as_json/py.typed +0 -0
- config_as_json-0.1/src/config_as_json/str_to_enum.py +50 -0
- config_as_json-0.1/src/config_as_json/validator.py +565 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Tom Björkholm
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: config-as-json
|
|
3
|
+
Version: 0.1
|
|
4
|
+
Summary: Read, write, validate, and migrate JSON-backed config classes.
|
|
5
|
+
Author: Tom Björkholm
|
|
6
|
+
Author-email: Tom Björkholm <klausuler_linnet0q@icloud.com>
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
Project-URL: Source code, https://bitbucket.org/tom-bjorkholm/config_as_json/
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Requires-Python: >=3.12
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE.txt
|
|
14
|
+
Requires-Dist: setuptools>=82.0.1
|
|
15
|
+
Requires-Dist: build>=1.4.2
|
|
16
|
+
Requires-Dist: wheel>=0.46.3
|
|
17
|
+
Dynamic: author
|
|
18
|
+
Dynamic: license-file
|
|
19
|
+
Dynamic: requires-dist
|
|
20
|
+
Dynamic: requires-python
|
|
21
|
+
|
|
22
|
+
# config-as-json
|
|
23
|
+
|
|
24
|
+
`config-as-json` helps an application keep its configuration schema in a
|
|
25
|
+
Python class while storing actual configuration data in JSON files.
|
|
26
|
+
|
|
27
|
+
The intended usage model is:
|
|
28
|
+
|
|
29
|
+
- Derive an application-specific class from `config_as_json.Config`.
|
|
30
|
+
- Add one instance attribute per supported configuration parameter. An
|
|
31
|
+
instance attribute can also be a dict or list, optionally with nested
|
|
32
|
+
dicts and lists.
|
|
33
|
+
- Let the values assigned in the derived constructor act as the default
|
|
34
|
+
configuration.
|
|
35
|
+
- Use the library to write those defaults as JSON and to read JSON back into
|
|
36
|
+
the derived configuration object.
|
|
37
|
+
|
|
38
|
+
The library is designed to support evolving configuration formats by letting
|
|
39
|
+
applications define:
|
|
40
|
+
|
|
41
|
+
- custom parsers for values that should become richer Python types
|
|
42
|
+
- optional keys that receive default values when omitted
|
|
43
|
+
- backward-compatible key renames for older configuration files
|
|
44
|
+
- hooks that can warn or report when automatic compatibility changes were
|
|
45
|
+
needed
|
|
46
|
+
|
|
47
|
+
## Installation
|
|
48
|
+
|
|
49
|
+
`config-as-json` requires Python 3.12 or newer.
|
|
50
|
+
|
|
51
|
+
```sh
|
|
52
|
+
pip install --upgrade config-as-json
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Main entry points
|
|
56
|
+
|
|
57
|
+
- `config_as_json.Config`
|
|
58
|
+
Base class for JSON-backed configuration objects.
|
|
59
|
+
- `config_as_json.config_factory_from_json`
|
|
60
|
+
Select the correct configuration class by inspecting JSON input.
|
|
61
|
+
- `config_as_json.ConfigAutoChangeHook`
|
|
62
|
+
Receive notifications about automatic changes during parsing.
|
|
63
|
+
- `config_as_json.MigrateCfgWarnHook`
|
|
64
|
+
Warn when backward compatibility was used.
|
|
65
|
+
- `config_as_json.migrate_cfg`
|
|
66
|
+
Read an older configuration file and write it back in the newest supported
|
|
67
|
+
format.
|
|
68
|
+
|
|
69
|
+
The generated API reference also shows the implementation modules where these
|
|
70
|
+
public objects are defined.
|
|
71
|
+
|
|
72
|
+
## Documentation and examples
|
|
73
|
+
|
|
74
|
+
- Example directory: [example/src/example/README.md](https://bitbucket.org/tom-bjorkholm/config_as_json/src/master/example/src/example/README.md)
|
|
75
|
+
- Public API notes: [doc/api.md](https://bitbucket.org/tom-bjorkholm/config_as_json/src/master/doc/api.md)
|
|
76
|
+
- Protected/internal API notes: [doc/protected_api.md](https://bitbucket.org/tom-bjorkholm/config_as_json/src/master/doc/protected_api.md)
|
|
77
|
+
- Source repository: [config_as_json](https://bitbucket.org/tom-bjorkholm/config_as_json/)
|
|
78
|
+
|
|
79
|
+
The example directory contains worked examples for new users. It is not
|
|
80
|
+
included in the package installed from PyPI.
|
|
81
|
+
|
|
82
|
+
## Project status
|
|
83
|
+
|
|
84
|
+
This package originated as configuration code from a larger application and
|
|
85
|
+
has been refactored into a stand-alone reusable library. The public API
|
|
86
|
+
reference and worked examples are maintained in the source repository.
|
|
87
|
+
|
|
88
|
+
## License
|
|
89
|
+
|
|
90
|
+
MIT
|
|
91
|
+
|
|
92
|
+
## Test summary
|
|
93
|
+
|
|
94
|
+
- Test result: 3397 passed in 9s
|
|
95
|
+
- No flake8 warnings.
|
|
96
|
+
- No mypy errors found.
|
|
97
|
+
- Built version(s): 0.1
|
|
98
|
+
- Build and test using Python 3.14.3
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# config-as-json
|
|
2
|
+
|
|
3
|
+
> Looking for installation and user-facing package information?
|
|
4
|
+
> See [README_pypi.md](README_pypi.md) or the
|
|
5
|
+
> [PyPI project page](https://pypi.org/project/config-as-json).
|
|
6
|
+
|
|
7
|
+
## Repository purpose
|
|
8
|
+
|
|
9
|
+
`config-as-json` is a reusable library that grew out of configuration code
|
|
10
|
+
from an application.
|
|
11
|
+
|
|
12
|
+
The intended library model is:
|
|
13
|
+
|
|
14
|
+
- An application derives its own configuration class from
|
|
15
|
+
`config_as_json.Config`.
|
|
16
|
+
- The derived class creates one instance attribute per supported
|
|
17
|
+
configuration parameter. Supported configuration parameters can also
|
|
18
|
+
be dicts and lists.
|
|
19
|
+
- The values assigned in the derived class constructor are the default
|
|
20
|
+
configuration values.
|
|
21
|
+
- The library writes those values as JSON, reads JSON back into the object,
|
|
22
|
+
and helps users with clear diagnostics when configuration data is missing,
|
|
23
|
+
misspelled, outdated, or of the wrong type.
|
|
24
|
+
|
|
25
|
+
The source docstrings are used to generate the API reference in `doc/`, and
|
|
26
|
+
the examples in `example/src/example/` are the main worked documentation for
|
|
27
|
+
new users. User-facing documentation names public classes and functions as
|
|
28
|
+
exports from `config_as_json`; the generated API reference may also show the
|
|
29
|
+
implementation modules where those objects are defined.
|
|
30
|
+
|
|
31
|
+
## Product vision and boundaries
|
|
32
|
+
|
|
33
|
+
This package is about representing an application's configuration as a Python
|
|
34
|
+
object with an explicit schema and a JSON representation.
|
|
35
|
+
|
|
36
|
+
The library is intended to:
|
|
37
|
+
|
|
38
|
+
- Keep the application's configuration schema visible in normal Python code.
|
|
39
|
+
- Use the derived class itself as the source of default values.
|
|
40
|
+
- Read and write human-editable JSON configuration files.
|
|
41
|
+
- Support evolution of the configuration format through optional keys,
|
|
42
|
+
converters, and backward-compatible key renames.
|
|
43
|
+
- Help end users with actionable error messages instead of silent fallback.
|
|
44
|
+
|
|
45
|
+
The library is not intended to invent configuration structure dynamically or
|
|
46
|
+
to hide the application's schema behind a large generic framework.
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
## Main building blocks
|
|
50
|
+
|
|
51
|
+
- `config_as_json.Config`
|
|
52
|
+
The base class for derived configuration classes.
|
|
53
|
+
- `config_as_json.config_factory_from_json`
|
|
54
|
+
Select among several configuration classes by inspecting JSON input.
|
|
55
|
+
- `config_as_json.ConfigAutoChangeHook`
|
|
56
|
+
Hook interface for reporting automatic changes applied during parsing.
|
|
57
|
+
- `config_as_json.migrate_cfg`
|
|
58
|
+
Helper for reading an older configuration file and writing it back in the
|
|
59
|
+
newest supported format.
|
|
60
|
+
- `config_as_json.MigrateCfgWarnHook`
|
|
61
|
+
Standard hook that warns users when backward compatibility was needed.
|
|
62
|
+
- Utility modules such as `str_to_enum`, `file_extension`,
|
|
63
|
+
`file_must_exist`, `commontypes`, and `assert_dict_equal`
|
|
64
|
+
These are part of the current public surface and are documented as such.
|
|
65
|
+
|
|
66
|
+
## Related documentation
|
|
67
|
+
|
|
68
|
+
- User-facing package overview: [README_pypi.md](README_pypi.md)
|
|
69
|
+
- Example directory: [example/src/example/README.md](example/src/example/README.md)
|
|
70
|
+
- Public API notes: [doc/api.md](doc/api.md)
|
|
71
|
+
- Protected/internal API notes: [doc/protected_api.md](doc/protected_api.md)
|
|
72
|
+
- Build system design: [common_build_tools/README.md](common_build_tools/README.md)
|
|
73
|
+
|
|
74
|
+
The example directory contains worked examples for new users and is also
|
|
75
|
+
useful for maintainers who want to see intended API usage in context.
|
|
76
|
+
|
|
77
|
+
## Cloning
|
|
78
|
+
|
|
79
|
+
This repository uses submodules. Clone it with:
|
|
80
|
+
|
|
81
|
+
```sh
|
|
82
|
+
git clone --recurse-submodules \
|
|
83
|
+
git@bitbucket.org:tom-bjorkholm/config_as_json.git
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
If you already cloned without submodules, initialize them with:
|
|
87
|
+
|
|
88
|
+
```sh
|
|
89
|
+
git submodule update --init --recursive
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
To update the checked-out submodule revisions:
|
|
93
|
+
|
|
94
|
+
```sh
|
|
95
|
+
git submodule update --remote --merge
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Supported Python versions
|
|
99
|
+
|
|
100
|
+
- Package runtime baseline: Python 3.12 or newer
|
|
101
|
+
- Maintainer validation target: Python 3.12, 3.13, and 3.14
|
|
102
|
+
- Main day-to-day development: usually the newest supported Python version
|
|
103
|
+
|
|
104
|
+
## Development workflow
|
|
105
|
+
|
|
106
|
+
On macOS and Linux, the normal workflow is:
|
|
107
|
+
|
|
108
|
+
1. Run `./run_setup_build_environment.py` once after cloning or when the
|
|
109
|
+
build environment needs to be recreated.
|
|
110
|
+
2. Run `./run_build.py` for the normal build-and-test cycle.
|
|
111
|
+
3. Run `./run_clean_build.py` before review or release work that needs a
|
|
112
|
+
completely fresh build.
|
|
113
|
+
|
|
114
|
+
The helper scripts are:
|
|
115
|
+
|
|
116
|
+
- `run_setup_build_environment.py`
|
|
117
|
+
Create or refresh the build environment.
|
|
118
|
+
- `run_build.py`
|
|
119
|
+
Build the package and run the configured checks in the project virtual
|
|
120
|
+
environment.
|
|
121
|
+
- `run_clean.py`
|
|
122
|
+
Remove files generated by the build system.
|
|
123
|
+
- `run_clean_build.py`
|
|
124
|
+
Perform a clean build from scratch. This is especially useful because some
|
|
125
|
+
duplicate-code diagnostics only appear on a clean build.
|
|
126
|
+
- `run_pypi_build.py`
|
|
127
|
+
Create the distribution artifacts intended for PyPI publishing.
|
|
128
|
+
|
|
129
|
+
The standard verification suite includes pytest, pylint, flake8, and mypy.
|
|
130
|
+
After a build, the generated reports can be browsed through
|
|
131
|
+
`reports/index.html`.
|
|
132
|
+
|
|
133
|
+
## Test summary
|
|
134
|
+
|
|
135
|
+
- Test result: 3397 passed in 9s
|
|
136
|
+
- No flake8 warnings.
|
|
137
|
+
- No mypy errors found.
|
|
138
|
+
- Built version(s): 0.1
|
|
139
|
+
- Build and test using Python 3.14.3
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# config-as-json
|
|
2
|
+
|
|
3
|
+
`config-as-json` helps an application keep its configuration schema in a
|
|
4
|
+
Python class while storing actual configuration data in JSON files.
|
|
5
|
+
|
|
6
|
+
The intended usage model is:
|
|
7
|
+
|
|
8
|
+
- Derive an application-specific class from `config_as_json.Config`.
|
|
9
|
+
- Add one instance attribute per supported configuration parameter. An
|
|
10
|
+
instance attribute can also be a dict or list, optionally with nested
|
|
11
|
+
dicts and lists.
|
|
12
|
+
- Let the values assigned in the derived constructor act as the default
|
|
13
|
+
configuration.
|
|
14
|
+
- Use the library to write those defaults as JSON and to read JSON back into
|
|
15
|
+
the derived configuration object.
|
|
16
|
+
|
|
17
|
+
The library is designed to support evolving configuration formats by letting
|
|
18
|
+
applications define:
|
|
19
|
+
|
|
20
|
+
- custom parsers for values that should become richer Python types
|
|
21
|
+
- optional keys that receive default values when omitted
|
|
22
|
+
- backward-compatible key renames for older configuration files
|
|
23
|
+
- hooks that can warn or report when automatic compatibility changes were
|
|
24
|
+
needed
|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
`config-as-json` requires Python 3.12 or newer.
|
|
29
|
+
|
|
30
|
+
```sh
|
|
31
|
+
pip install --upgrade config-as-json
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Main entry points
|
|
35
|
+
|
|
36
|
+
- `config_as_json.Config`
|
|
37
|
+
Base class for JSON-backed configuration objects.
|
|
38
|
+
- `config_as_json.config_factory_from_json`
|
|
39
|
+
Select the correct configuration class by inspecting JSON input.
|
|
40
|
+
- `config_as_json.ConfigAutoChangeHook`
|
|
41
|
+
Receive notifications about automatic changes during parsing.
|
|
42
|
+
- `config_as_json.MigrateCfgWarnHook`
|
|
43
|
+
Warn when backward compatibility was used.
|
|
44
|
+
- `config_as_json.migrate_cfg`
|
|
45
|
+
Read an older configuration file and write it back in the newest supported
|
|
46
|
+
format.
|
|
47
|
+
|
|
48
|
+
The generated API reference also shows the implementation modules where these
|
|
49
|
+
public objects are defined.
|
|
50
|
+
|
|
51
|
+
## Documentation and examples
|
|
52
|
+
|
|
53
|
+
- Example directory: [example/src/example/README.md](https://bitbucket.org/tom-bjorkholm/config_as_json/src/master/example/src/example/README.md)
|
|
54
|
+
- Public API notes: [doc/api.md](https://bitbucket.org/tom-bjorkholm/config_as_json/src/master/doc/api.md)
|
|
55
|
+
- Protected/internal API notes: [doc/protected_api.md](https://bitbucket.org/tom-bjorkholm/config_as_json/src/master/doc/protected_api.md)
|
|
56
|
+
- Source repository: [config_as_json](https://bitbucket.org/tom-bjorkholm/config_as_json/)
|
|
57
|
+
|
|
58
|
+
The example directory contains worked examples for new users. It is not
|
|
59
|
+
included in the package installed from PyPI.
|
|
60
|
+
|
|
61
|
+
## Project status
|
|
62
|
+
|
|
63
|
+
This package originated as configuration code from a larger application and
|
|
64
|
+
has been refactored into a stand-alone reusable library. The public API
|
|
65
|
+
reference and worked examples are maintained in the source repository.
|
|
66
|
+
|
|
67
|
+
## License
|
|
68
|
+
|
|
69
|
+
MIT
|
|
70
|
+
|
|
71
|
+
## Test summary
|
|
72
|
+
|
|
73
|
+
- Test result: 3397 passed in 9s
|
|
74
|
+
- No flake8 warnings.
|
|
75
|
+
- No mypy errors found.
|
|
76
|
+
- Built version(s): 0.1
|
|
77
|
+
- Build and test using Python 3.14.3
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: config-as-json
|
|
3
|
+
Version: 0.1
|
|
4
|
+
Summary: Read, write, validate, and migrate JSON-backed config classes.
|
|
5
|
+
Author: Tom Björkholm
|
|
6
|
+
Author-email: Tom Björkholm <klausuler_linnet0q@icloud.com>
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
Project-URL: Source code, https://bitbucket.org/tom-bjorkholm/config_as_json/
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Requires-Python: >=3.12
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE.txt
|
|
14
|
+
Requires-Dist: setuptools>=82.0.1
|
|
15
|
+
Requires-Dist: build>=1.4.2
|
|
16
|
+
Requires-Dist: wheel>=0.46.3
|
|
17
|
+
Dynamic: author
|
|
18
|
+
Dynamic: license-file
|
|
19
|
+
Dynamic: requires-dist
|
|
20
|
+
Dynamic: requires-python
|
|
21
|
+
|
|
22
|
+
# config-as-json
|
|
23
|
+
|
|
24
|
+
`config-as-json` helps an application keep its configuration schema in a
|
|
25
|
+
Python class while storing actual configuration data in JSON files.
|
|
26
|
+
|
|
27
|
+
The intended usage model is:
|
|
28
|
+
|
|
29
|
+
- Derive an application-specific class from `config_as_json.Config`.
|
|
30
|
+
- Add one instance attribute per supported configuration parameter. An
|
|
31
|
+
instance attribute can also be a dict or list, optionally with nested
|
|
32
|
+
dicts and lists.
|
|
33
|
+
- Let the values assigned in the derived constructor act as the default
|
|
34
|
+
configuration.
|
|
35
|
+
- Use the library to write those defaults as JSON and to read JSON back into
|
|
36
|
+
the derived configuration object.
|
|
37
|
+
|
|
38
|
+
The library is designed to support evolving configuration formats by letting
|
|
39
|
+
applications define:
|
|
40
|
+
|
|
41
|
+
- custom parsers for values that should become richer Python types
|
|
42
|
+
- optional keys that receive default values when omitted
|
|
43
|
+
- backward-compatible key renames for older configuration files
|
|
44
|
+
- hooks that can warn or report when automatic compatibility changes were
|
|
45
|
+
needed
|
|
46
|
+
|
|
47
|
+
## Installation
|
|
48
|
+
|
|
49
|
+
`config-as-json` requires Python 3.12 or newer.
|
|
50
|
+
|
|
51
|
+
```sh
|
|
52
|
+
pip install --upgrade config-as-json
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Main entry points
|
|
56
|
+
|
|
57
|
+
- `config_as_json.Config`
|
|
58
|
+
Base class for JSON-backed configuration objects.
|
|
59
|
+
- `config_as_json.config_factory_from_json`
|
|
60
|
+
Select the correct configuration class by inspecting JSON input.
|
|
61
|
+
- `config_as_json.ConfigAutoChangeHook`
|
|
62
|
+
Receive notifications about automatic changes during parsing.
|
|
63
|
+
- `config_as_json.MigrateCfgWarnHook`
|
|
64
|
+
Warn when backward compatibility was used.
|
|
65
|
+
- `config_as_json.migrate_cfg`
|
|
66
|
+
Read an older configuration file and write it back in the newest supported
|
|
67
|
+
format.
|
|
68
|
+
|
|
69
|
+
The generated API reference also shows the implementation modules where these
|
|
70
|
+
public objects are defined.
|
|
71
|
+
|
|
72
|
+
## Documentation and examples
|
|
73
|
+
|
|
74
|
+
- Example directory: [example/src/example/README.md](https://bitbucket.org/tom-bjorkholm/config_as_json/src/master/example/src/example/README.md)
|
|
75
|
+
- Public API notes: [doc/api.md](https://bitbucket.org/tom-bjorkholm/config_as_json/src/master/doc/api.md)
|
|
76
|
+
- Protected/internal API notes: [doc/protected_api.md](https://bitbucket.org/tom-bjorkholm/config_as_json/src/master/doc/protected_api.md)
|
|
77
|
+
- Source repository: [config_as_json](https://bitbucket.org/tom-bjorkholm/config_as_json/)
|
|
78
|
+
|
|
79
|
+
The example directory contains worked examples for new users. It is not
|
|
80
|
+
included in the package installed from PyPI.
|
|
81
|
+
|
|
82
|
+
## Project status
|
|
83
|
+
|
|
84
|
+
This package originated as configuration code from a larger application and
|
|
85
|
+
has been refactored into a stand-alone reusable library. The public API
|
|
86
|
+
reference and worked examples are maintained in the source repository.
|
|
87
|
+
|
|
88
|
+
## License
|
|
89
|
+
|
|
90
|
+
MIT
|
|
91
|
+
|
|
92
|
+
## Test summary
|
|
93
|
+
|
|
94
|
+
- Test result: 3397 passed in 9s
|
|
95
|
+
- No flake8 warnings.
|
|
96
|
+
- No mypy errors found.
|
|
97
|
+
- Built version(s): 0.1
|
|
98
|
+
- Build and test using Python 3.14.3
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
LICENSE.txt
|
|
2
|
+
README.md
|
|
3
|
+
README_pypi.md
|
|
4
|
+
pyproject.toml
|
|
5
|
+
setup.py
|
|
6
|
+
config_as_json.egg-info/PKG-INFO
|
|
7
|
+
config_as_json.egg-info/SOURCES.txt
|
|
8
|
+
config_as_json.egg-info/dependency_links.txt
|
|
9
|
+
config_as_json.egg-info/requires.txt
|
|
10
|
+
config_as_json.egg-info/top_level.txt
|
|
11
|
+
src/config_as_json/__init__.py
|
|
12
|
+
src/config_as_json/assert_dict_equal.py
|
|
13
|
+
src/config_as_json/commontypes.py
|
|
14
|
+
src/config_as_json/config.py
|
|
15
|
+
src/config_as_json/config_auto_change_hook.py
|
|
16
|
+
src/config_as_json/config_factory.py
|
|
17
|
+
src/config_as_json/dict_validators.py
|
|
18
|
+
src/config_as_json/discriminated_dict_validators.py
|
|
19
|
+
src/config_as_json/file_extension.py
|
|
20
|
+
src/config_as_json/file_must_exist.py
|
|
21
|
+
src/config_as_json/list_validators.py
|
|
22
|
+
src/config_as_json/migrate_cfg.py
|
|
23
|
+
src/config_as_json/migrate_cfg_warn_hook.py
|
|
24
|
+
src/config_as_json/projected_validators.py
|
|
25
|
+
src/config_as_json/py.typed
|
|
26
|
+
src/config_as_json/str_to_enum.py
|
|
27
|
+
src/config_as_json/validator.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
config_as_json
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "config-as-json"
|
|
7
|
+
version = "0.1"
|
|
8
|
+
authors = [
|
|
9
|
+
{ name="Tom Björkholm", email="klausuler_linnet0q@icloud.com" },
|
|
10
|
+
]
|
|
11
|
+
description = "Read, write, validate, and migrate JSON-backed config classes."
|
|
12
|
+
readme = "README_pypi.md"
|
|
13
|
+
requires-python = ">=3.12"
|
|
14
|
+
license = "MIT"
|
|
15
|
+
license-files = ["LICENSE.txt"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Operating System :: OS Independent"
|
|
19
|
+
]
|
|
20
|
+
dynamic = ["dependencies"]
|
|
21
|
+
|
|
22
|
+
[project.urls]
|
|
23
|
+
"Source code" = "https://bitbucket.org/tom-bjorkholm/config_as_json/"
|
|
24
|
+
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#! /usr/local/bin/python3
|
|
2
|
+
"""Setup file specifying build of .whl."""
|
|
3
|
+
|
|
4
|
+
from setuptools import setup # type: ignore[import-untyped]
|
|
5
|
+
|
|
6
|
+
setup(
|
|
7
|
+
name='config-as-json',
|
|
8
|
+
version='0.1',
|
|
9
|
+
description='Read, write, validate, and migrate JSON-backed config classes.',
|
|
10
|
+
author='Tom Björkholm',
|
|
11
|
+
author_email='klausuler_linnet0q@icloud.com',
|
|
12
|
+
python_requires='>=3.12',
|
|
13
|
+
packages=['config_as_json'],
|
|
14
|
+
package_dir={'config_as_json': 'src/config_as_json'},
|
|
15
|
+
package_data={'config_as_json': ['py.typed']},
|
|
16
|
+
install_requires=[
|
|
17
|
+
'setuptools >= 82.0.1',
|
|
18
|
+
'build >= 1.4.2',
|
|
19
|
+
'wheel >= 0.46.3',
|
|
20
|
+
]
|
|
21
|
+
)
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#! /usr/local/bin/python3
|
|
2
|
+
"""Define application configuration classes that serialize to JSON.
|
|
3
|
+
|
|
4
|
+
The package centers on :class:`config_as_json.config.Config`. Applications
|
|
5
|
+
derive their own configuration classes, declare supported settings as
|
|
6
|
+
instance attributes, and use the library to read, validate, migrate, and
|
|
7
|
+
write JSON configuration files.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
# Copyright (c) 2026 Tom Björkholm
|
|
11
|
+
# MIT License
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
from config_as_json.config import Config, BackwardCompatible, ConfigBadJson, \
|
|
15
|
+
ParseConverter
|
|
16
|
+
from config_as_json.commontypes import JsonType, PathOrStr
|
|
17
|
+
from config_as_json.config_factory import config_factory_from_json, \
|
|
18
|
+
MatchConfig, MatchConfigSeq, JsonValueMatcher
|
|
19
|
+
from config_as_json.config_auto_change_hook import ConfigAutoChangeHook
|
|
20
|
+
from config_as_json.migrate_cfg_warn_hook import MigrateCfgWarnHook
|
|
21
|
+
from config_as_json.migrate_cfg import migrate_cfg
|
|
22
|
+
from config_as_json.validator import ValidationPlan, ValidationStep, \
|
|
23
|
+
WholeConfigValidationStep, MemberValidationStep, WholeConfigValidator, \
|
|
24
|
+
MemberValidator, StrValidator, IntFloatValidator, string_best_match, \
|
|
25
|
+
InvalidConfiguration, InvalidConfigurationValue
|
|
26
|
+
from config_as_json.list_validators import ListValueValidator, \
|
|
27
|
+
ListSizeValidator, ListIsOrderedValidator, ListOrderingValidator, \
|
|
28
|
+
ListForEachValidator
|
|
29
|
+
from config_as_json.dict_validators import DictKeysValidator, DictRule, \
|
|
30
|
+
DictForEachValidator
|
|
31
|
+
from config_as_json.discriminated_dict_validators import DictVariant, \
|
|
32
|
+
DiscriminatedDictValidator
|
|
33
|
+
from config_as_json.projected_validators import ProjectedMemberValidator
|
|
34
|
+
from config_as_json.str_to_enum import string_to_enum_best_match
|
|
35
|
+
from config_as_json.assert_dict_equal import assert_dict_equal
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
__all__ = ['Config',
|
|
39
|
+
'BackwardCompatible',
|
|
40
|
+
'ConfigBadJson',
|
|
41
|
+
'JsonType',
|
|
42
|
+
'PathOrStr',
|
|
43
|
+
'ParseConverter',
|
|
44
|
+
'ConfigAutoChangeHook',
|
|
45
|
+
'MigrateCfgWarnHook',
|
|
46
|
+
'migrate_cfg',
|
|
47
|
+
'config_factory_from_json',
|
|
48
|
+
'MatchConfig',
|
|
49
|
+
'MatchConfigSeq',
|
|
50
|
+
'JsonValueMatcher',
|
|
51
|
+
'ValidationPlan',
|
|
52
|
+
'ValidationStep',
|
|
53
|
+
'WholeConfigValidationStep',
|
|
54
|
+
'MemberValidationStep',
|
|
55
|
+
'WholeConfigValidator',
|
|
56
|
+
'MemberValidator',
|
|
57
|
+
'StrValidator',
|
|
58
|
+
'IntFloatValidator',
|
|
59
|
+
'string_best_match',
|
|
60
|
+
'string_to_enum_best_match',
|
|
61
|
+
'InvalidConfiguration',
|
|
62
|
+
'InvalidConfigurationValue',
|
|
63
|
+
'ListValueValidator',
|
|
64
|
+
'ListSizeValidator',
|
|
65
|
+
'ListIsOrderedValidator',
|
|
66
|
+
'ListOrderingValidator',
|
|
67
|
+
'ListForEachValidator',
|
|
68
|
+
'DictKeysValidator',
|
|
69
|
+
'DictRule',
|
|
70
|
+
'DictForEachValidator',
|
|
71
|
+
'DictVariant',
|
|
72
|
+
'DiscriminatedDictValidator',
|
|
73
|
+
'ProjectedMemberValidator',
|
|
74
|
+
'assert_dict_equal']
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
#! /usr/local/bin/python3
|
|
2
|
+
"""Compare mapping objects while ignoring selected keys.
|
|
3
|
+
|
|
4
|
+
This primarily exists as a tool for developers of applications that use
|
|
5
|
+
configuration classes derived from ``Config``.
|
|
6
|
+
It is also useful in test code that wants a readable failure message
|
|
7
|
+
before asserting equality of configuration objects in applications that
|
|
8
|
+
use the library.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
# Copyright (c) 2024-2026 Tom Björkholm
|
|
12
|
+
# MIT License
|
|
13
|
+
|
|
14
|
+
from typing import Mapping, TextIO
|
|
15
|
+
import sys
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _print_dict_differs(msg: str, lhs: Mapping[str, object],
|
|
19
|
+
rhs: Mapping[str, object],
|
|
20
|
+
stderr_file: TextIO = sys.stderr) -> None:
|
|
21
|
+
"""Print a detailed mismatch report to standard error.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
msg: Summary of the mismatch that was detected.
|
|
25
|
+
lhs: Left-hand mapping after any ignored keys were removed.
|
|
26
|
+
rhs: Right-hand mapping after any ignored keys were removed.
|
|
27
|
+
stderr_file: Stream used for diagnostics. Defaults to ``sys.stderr``.
|
|
28
|
+
"""
|
|
29
|
+
print(f'{msg}\n' +
|
|
30
|
+
f'Number of keys in left dict: {len(lhs)}\n' +
|
|
31
|
+
f'Number of keys in right dict: {len(rhs)}\n' +
|
|
32
|
+
f' left dict: {str(lhs)}\nright dict: {str(rhs)}',
|
|
33
|
+
file=stderr_file)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def assert_dict_equal(lhs: Mapping[str, object], rhs: Mapping[str, object],
|
|
37
|
+
ignorekeys: list[str],
|
|
38
|
+
stderr_file: TextIO = sys.stderr) -> None:
|
|
39
|
+
"""Assert that two mappings are equal after ignoring selected keys.
|
|
40
|
+
|
|
41
|
+
The function makes defensive copies, removes any keys listed in
|
|
42
|
+
``ignorekeys`` from both sides, prints a readable difference report when
|
|
43
|
+
a mismatch is detected, and finally raises ``AssertionError`` through the
|
|
44
|
+
normal ``assert`` statements.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
lhs: Left-hand mapping to compare.
|
|
48
|
+
rhs: Right-hand mapping to compare.
|
|
49
|
+
ignorekeys: Keys to drop from both mappings before comparison.
|
|
50
|
+
stderr_file: Stream used for diagnostics. Defaults to ``sys.stderr``.
|
|
51
|
+
|
|
52
|
+
Raises:
|
|
53
|
+
AssertionError: The mappings do not match after ignored keys have been
|
|
54
|
+
removed.
|
|
55
|
+
"""
|
|
56
|
+
lhs_val = dict(lhs)
|
|
57
|
+
rhs_val = dict(rhs)
|
|
58
|
+
assert isinstance(lhs_val, dict)
|
|
59
|
+
assert isinstance(rhs_val, dict)
|
|
60
|
+
for key in ignorekeys:
|
|
61
|
+
if key in lhs_val:
|
|
62
|
+
del lhs_val[key]
|
|
63
|
+
if key in rhs_val:
|
|
64
|
+
del rhs_val[key]
|
|
65
|
+
if len(lhs_val) != len(rhs_val):
|
|
66
|
+
_print_dict_differs('Different number of keys in dicts',
|
|
67
|
+
lhs_val, rhs_val, stderr_file)
|
|
68
|
+
assert len(lhs_val) == len(rhs_val)
|
|
69
|
+
for key, value in lhs_val.items():
|
|
70
|
+
if key not in rhs_val:
|
|
71
|
+
_print_dict_differs(f'Key "{key}" exist only in left dict.',
|
|
72
|
+
lhs_val, rhs_val, stderr_file)
|
|
73
|
+
assert key in rhs_val
|
|
74
|
+
if value != rhs_val[key]:
|
|
75
|
+
txt = f'Key "{key}" has different values in left and right\n'
|
|
76
|
+
txt += f' left[{key}] = {value}\n'
|
|
77
|
+
txt += f'right[{key}] = {rhs_val[key]}\n'
|
|
78
|
+
_print_dict_differs(txt, lhs_val, rhs_val, stderr_file)
|
|
79
|
+
assert value == rhs_val[key]
|
|
80
|
+
if lhs_val != rhs_val: # pragma: no cover
|
|
81
|
+
_print_dict_differs('Dicts differ', lhs_val, rhs_val, stderr_file)
|
|
82
|
+
assert lhs_val == rhs_val
|