schemez 0.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.
- schemez-0.0.1/.copier-answers.yml +21 -0
- schemez-0.0.1/.github/FUNDING.yml +3 -0
- schemez-0.0.1/.github/copilot-instructions.md +19 -0
- schemez-0.0.1/.github/dependabot.yml +9 -0
- schemez-0.0.1/.github/workflows/build.yml +88 -0
- schemez-0.0.1/.github/workflows/documentation.yml +57 -0
- schemez-0.0.1/.gitignore +32 -0
- schemez-0.0.1/.pre-commit-config.yaml +48 -0
- schemez-0.0.1/LICENSE +22 -0
- schemez-0.0.1/PKG-INFO +84 -0
- schemez-0.0.1/README.md +32 -0
- schemez-0.0.1/docs/.empty +0 -0
- schemez-0.0.1/duties.py +60 -0
- schemez-0.0.1/mkdocs.yml +92 -0
- schemez-0.0.1/overrides/_dummy.txt +1 -0
- schemez-0.0.1/pyproject.toml +250 -0
- schemez-0.0.1/src/schemez/__init__.py +6 -0
- schemez-0.0.1/src/schemez/helpers.py +35 -0
- schemez-0.0.1/src/schemez/py.typed +0 -0
- schemez-0.0.1/src/schemez/schema.py +67 -0
- schemez-0.0.1/tests/__init__.py +3 -0
- schemez-0.0.1/tests/conftest.py +1 -0
- schemez-0.0.1/tests/test_schema.py +5 -0
@@ -0,0 +1,21 @@
|
|
1
|
+
# Changes here will be overwritten by Copier
|
2
|
+
_commit: v1.8.4
|
3
|
+
_src_path: .\copier-phil65\
|
4
|
+
author_email: philipptemminghoff@googlemail.com
|
5
|
+
author_fullname: Philipp Temminghoff
|
6
|
+
author_username: phil65
|
7
|
+
copyright_date: '2025'
|
8
|
+
copyright_holder: Philipp Temminghoff
|
9
|
+
copyright_holder_email: philipptemminghoff@googlemail.com
|
10
|
+
libraries_use_pydantic: true
|
11
|
+
libraries_use_qt: false
|
12
|
+
project_description: Pydantic shim for config stuff
|
13
|
+
project_name: Schemez
|
14
|
+
python_minimum_version: '3.12'
|
15
|
+
python_package_command_line_name: schemez
|
16
|
+
python_package_distribution_name: schemez
|
17
|
+
python_package_import_name: schemez
|
18
|
+
repository_name: schemez
|
19
|
+
repository_namespace: phil65
|
20
|
+
repository_provider: github.com
|
21
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
## Code style
|
2
|
+
|
3
|
+
You can assume Python 3.12.
|
4
|
+
Use newest language features if possible
|
5
|
+
Consider using pattern matching, walrus operators and other new syntax features.
|
6
|
+
Adhere to pep8.
|
7
|
+
|
8
|
+
## Tests
|
9
|
+
|
10
|
+
Tests are written using PyTest. Dont put tests into a class.
|
11
|
+
|
12
|
+
## DocStrings
|
13
|
+
|
14
|
+
DocStrings are written in google-style.
|
15
|
+
Dont add the types to the "Args" section.
|
16
|
+
Only add a Return section if a value is returned and the meaning of the returned value
|
17
|
+
is not obvious.
|
18
|
+
You can use markdown admonitions with python-markdown syntax if neccessary (!!! info, !!! note, !!! warning).
|
19
|
+
You can use markdown tables and markdown lists if neccessary.
|
@@ -0,0 +1,88 @@
|
|
1
|
+
name: Build
|
2
|
+
|
3
|
+
on: [push, pull_request]
|
4
|
+
|
5
|
+
jobs:
|
6
|
+
test:
|
7
|
+
runs-on: ${{ matrix.os }}
|
8
|
+
continue-on-error: ${{ matrix.python_version == '3.14' }}
|
9
|
+
strategy:
|
10
|
+
matrix:
|
11
|
+
python_version: ["3.12", "3.13", "3.14"]
|
12
|
+
os: ["ubuntu-latest", "macos-latest", "windows-latest"]
|
13
|
+
steps:
|
14
|
+
- name: Check out repository
|
15
|
+
uses: actions/checkout@v4
|
16
|
+
|
17
|
+
- name: Set up Python ${{ matrix.python_version }}
|
18
|
+
uses: actions/setup-python@v5
|
19
|
+
with:
|
20
|
+
python-version: ${{ matrix.python_version }}
|
21
|
+
allow-prereleases: true
|
22
|
+
|
23
|
+
- name: Install uv
|
24
|
+
uses: astral-sh/setup-uv@v5
|
25
|
+
with:
|
26
|
+
enable-cache: true
|
27
|
+
cache-dependency-glob: pyproject.toml
|
28
|
+
cache-suffix: py${{ matrix.python_version }}
|
29
|
+
|
30
|
+
- name: Install dependencies (uv sync)
|
31
|
+
run: uv sync --all-extras --no-group docs
|
32
|
+
|
33
|
+
- name: Check for code issues (ruff check)
|
34
|
+
uses: astral-sh/ruff-action@v3
|
35
|
+
|
36
|
+
- name: Check code format (ruff format)
|
37
|
+
uses: astral-sh/ruff-action@v3
|
38
|
+
with:
|
39
|
+
args: "format --check"
|
40
|
+
|
41
|
+
- name: Static type checking (MyPy)
|
42
|
+
run: uv run --no-group docs mypy src/schemez/
|
43
|
+
|
44
|
+
- name: Run tests
|
45
|
+
run: uv run --no-group docs pytest --cov-report=xml --cov=src/schemez/ --cov-report=term-missing
|
46
|
+
|
47
|
+
- name: Upload test results to Codecov
|
48
|
+
uses: codecov/codecov-action@v5
|
49
|
+
with:
|
50
|
+
fail_ci_if_error: false
|
51
|
+
verbose: true
|
52
|
+
|
53
|
+
release:
|
54
|
+
runs-on: ubuntu-latest
|
55
|
+
needs: test
|
56
|
+
if: startsWith(github.ref, 'refs/tags/')
|
57
|
+
permissions:
|
58
|
+
# this permission is mandatory for trusted publishing
|
59
|
+
id-token: write
|
60
|
+
contents: write
|
61
|
+
steps:
|
62
|
+
- name: Check out repository
|
63
|
+
uses: actions/checkout@v4
|
64
|
+
|
65
|
+
- name: Set up Python
|
66
|
+
uses: actions/setup-python@v5
|
67
|
+
with:
|
68
|
+
python-version: "3.12"
|
69
|
+
|
70
|
+
- name: Install uv
|
71
|
+
uses: astral-sh/setup-uv@v5
|
72
|
+
with:
|
73
|
+
enable-cache: true
|
74
|
+
cache-dependency-glob: pyproject.toml
|
75
|
+
cache-suffix: py${{ matrix.python_version }}
|
76
|
+
|
77
|
+
- name: Build package
|
78
|
+
run: uv build
|
79
|
+
|
80
|
+
- name: Publish package distributions to PyPI
|
81
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
82
|
+
|
83
|
+
- name: Release package on GitHub
|
84
|
+
uses: ncipollo/release-action@v1
|
85
|
+
with:
|
86
|
+
body: ${{ github.event.head_commit.message }}
|
87
|
+
artifacts: dist/*.whl,dist/*.tar.gz
|
88
|
+
token: ${{ secrets.GITHUB_TOKEN }}
|
@@ -0,0 +1,57 @@
|
|
1
|
+
name: Build documentation
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches:
|
6
|
+
- main
|
7
|
+
|
8
|
+
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
|
9
|
+
permissions:
|
10
|
+
contents: read
|
11
|
+
pages: write
|
12
|
+
id-token: write
|
13
|
+
|
14
|
+
# Allow one concurrent deployment
|
15
|
+
concurrency:
|
16
|
+
group: "pages"
|
17
|
+
cancel-in-progress: true
|
18
|
+
|
19
|
+
# Default to bash
|
20
|
+
defaults:
|
21
|
+
run:
|
22
|
+
shell: bash
|
23
|
+
|
24
|
+
jobs:
|
25
|
+
build:
|
26
|
+
runs-on: ubuntu-latest
|
27
|
+
|
28
|
+
steps:
|
29
|
+
- uses: actions/checkout@v4
|
30
|
+
with:
|
31
|
+
fetch-depth: 0
|
32
|
+
- name: Set up Python
|
33
|
+
uses: actions/setup-python@v5
|
34
|
+
with:
|
35
|
+
python-version: "3.12"
|
36
|
+
- name: Install uv
|
37
|
+
uses: astral-sh/setup-uv@v5
|
38
|
+
- name: Install dependencies
|
39
|
+
run: |
|
40
|
+
uv sync --all-extras
|
41
|
+
- name: Build
|
42
|
+
run: uv run mknodes build
|
43
|
+
- name: Upload artifact
|
44
|
+
uses: actions/upload-pages-artifact@v3
|
45
|
+
with:
|
46
|
+
path: ./site
|
47
|
+
|
48
|
+
deploy:
|
49
|
+
environment:
|
50
|
+
name: github-pages
|
51
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
52
|
+
runs-on: ubuntu-latest
|
53
|
+
needs: build
|
54
|
+
steps:
|
55
|
+
- name: Deploy to GitHub Pages
|
56
|
+
id: deployment
|
57
|
+
uses: actions/deploy-pages@v4
|
schemez-0.0.1/.gitignore
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
2
|
+
__pycache__/
|
3
|
+
*.py[cod]
|
4
|
+
# Distribution / packaging
|
5
|
+
*.sublime-workspace
|
6
|
+
# Unit test / coverage reports
|
7
|
+
.coverage
|
8
|
+
coverage.xml
|
9
|
+
.cache
|
10
|
+
.hatch
|
11
|
+
.pytest_cache/
|
12
|
+
junit.xml
|
13
|
+
# Jupyter Notebook
|
14
|
+
.ipynb_checkpoints
|
15
|
+
# pyenv
|
16
|
+
.python-version
|
17
|
+
# dotenv
|
18
|
+
.env
|
19
|
+
# virtualenv
|
20
|
+
.venv
|
21
|
+
# mkdocs documentation
|
22
|
+
/site
|
23
|
+
# mypy
|
24
|
+
.mypy_cache/
|
25
|
+
# .vscode
|
26
|
+
.vscode/
|
27
|
+
# OS files
|
28
|
+
.DS_Store
|
29
|
+
# uv
|
30
|
+
uv.lock
|
31
|
+
# DiskCache cache file
|
32
|
+
./model_cache
|
@@ -0,0 +1,48 @@
|
|
1
|
+
default_language_version:
|
2
|
+
python: python3.12
|
3
|
+
default_stages: [pre-commit]
|
4
|
+
repos:
|
5
|
+
- repo: local
|
6
|
+
hooks:
|
7
|
+
- id: pytest-check
|
8
|
+
name: pytest-check
|
9
|
+
entry: uv run pytest
|
10
|
+
language: system
|
11
|
+
# stages: [push]
|
12
|
+
types: [python]
|
13
|
+
pass_filenames: false
|
14
|
+
always_run: true
|
15
|
+
|
16
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
17
|
+
# https://pre-commit.com/hooks.html
|
18
|
+
rev: v5.0.0
|
19
|
+
hooks:
|
20
|
+
- id: check-added-large-files
|
21
|
+
- id: check-case-conflict
|
22
|
+
- id: check-merge-conflict
|
23
|
+
- id: check-toml
|
24
|
+
- id: check-json
|
25
|
+
- id: check-xml
|
26
|
+
- id: check-yaml
|
27
|
+
args: [--allow-multiple-documents, --unsafe]
|
28
|
+
- id: debug-statements
|
29
|
+
- id: detect-private-key
|
30
|
+
|
31
|
+
- repo: https://github.com/pre-commit/mirrors-mypy
|
32
|
+
rev: v1.13.0
|
33
|
+
hooks:
|
34
|
+
- id: mypy
|
35
|
+
additional_dependencies: [orjson, pydantic]
|
36
|
+
|
37
|
+
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
38
|
+
rev: v0.7.2
|
39
|
+
hooks:
|
40
|
+
- id: ruff
|
41
|
+
- id: ruff-format
|
42
|
+
|
43
|
+
- repo: https://github.com/commitizen-tools/commitizen
|
44
|
+
rev: v3.30.0
|
45
|
+
hooks:
|
46
|
+
- id: commitizen
|
47
|
+
stages: [commit-msg]
|
48
|
+
additional_dependencies: [typing-extensions]
|
schemez-0.0.1/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2024, Philipp Temminghoff
|
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
|
+
|
schemez-0.0.1/PKG-INFO
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: schemez
|
3
|
+
Version: 0.0.1
|
4
|
+
Summary: Pydantic shim for config stuff
|
5
|
+
Project-URL: Documentation, https://phil65.github.io/schemez/
|
6
|
+
Project-URL: Source, https://github.com/phil65/schemez
|
7
|
+
Project-URL: Issues, https://github.com/phil65/schemez/issues
|
8
|
+
Project-URL: Discussions, https://github.com/phil65/schemez/discussions
|
9
|
+
Project-URL: Code coverage, https://app.codecov.io/gh/phil65/schemez
|
10
|
+
Author-email: Philipp Temminghoff <philipptemminghoff@googlemail.com>
|
11
|
+
License: MIT License
|
12
|
+
|
13
|
+
Copyright (c) 2024, Philipp Temminghoff
|
14
|
+
|
15
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
16
|
+
of this software and associated documentation files (the "Software"), to deal
|
17
|
+
in the Software without restriction, including without limitation the rights
|
18
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
19
|
+
copies of the Software, and to permit persons to whom the Software is
|
20
|
+
furnished to do so, subject to the following conditions:
|
21
|
+
|
22
|
+
The above copyright notice and this permission notice shall be included in all
|
23
|
+
copies or substantial portions of the Software.
|
24
|
+
|
25
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
26
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
27
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
28
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
29
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
30
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
31
|
+
SOFTWARE.
|
32
|
+
|
33
|
+
License-File: LICENSE
|
34
|
+
Classifier: Development Status :: 4 - Beta
|
35
|
+
Classifier: Framework :: Pydantic
|
36
|
+
Classifier: Framework :: Pydantic :: 2
|
37
|
+
Classifier: Intended Audience :: Developers
|
38
|
+
Classifier: Operating System :: OS Independent
|
39
|
+
Classifier: Programming Language :: Python :: 3
|
40
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
41
|
+
Classifier: Programming Language :: Python :: 3.12
|
42
|
+
Classifier: Programming Language :: Python :: 3.13
|
43
|
+
Classifier: Programming Language :: Python :: 3.14
|
44
|
+
Classifier: Topic :: Documentation
|
45
|
+
Classifier: Topic :: Software Development
|
46
|
+
Classifier: Topic :: Utilities
|
47
|
+
Classifier: Typing :: Typed
|
48
|
+
Requires-Python: >=3.12
|
49
|
+
Requires-Dist: pydantic
|
50
|
+
Requires-Dist: universal-pathlib>=0.2.6
|
51
|
+
Description-Content-Type: text/markdown
|
52
|
+
|
53
|
+
# Schemez
|
54
|
+
|
55
|
+
[](https://pypi.org/project/schemez/)
|
56
|
+
[](https://pypi.org/project/schemez/)
|
57
|
+
[](https://pypi.org/project/schemez/)
|
58
|
+
[](https://pypi.org/project/schemez/)
|
59
|
+
[](https://pypi.org/project/schemez/)
|
60
|
+
[](https://pypi.org/project/schemez/)
|
61
|
+
[](https://pypi.org/project/schemez/)
|
62
|
+
[](https://pypi.org/project/schemez/)
|
63
|
+
[](https://pypi.org/project/schemez/)
|
64
|
+
[](https://github.com/phil65/schemez/releases)
|
65
|
+
[](https://github.com/phil65/schemez/graphs/contributors)
|
66
|
+
[](https://github.com/phil65/schemez/discussions)
|
67
|
+
[](https://github.com/phil65/schemez/forks)
|
68
|
+
[](https://github.com/phil65/schemez/issues)
|
69
|
+
[](https://github.com/phil65/schemez/pulls)
|
70
|
+
[](https://github.com/phil65/schemez/watchers)
|
71
|
+
[](https://github.com/phil65/schemez/stars)
|
72
|
+
[](https://github.com/phil65/schemez)
|
73
|
+
[](https://github.com/phil65/schemez/commits)
|
74
|
+
[](https://github.com/phil65/schemez/releases)
|
75
|
+
[](https://github.com/phil65/schemez)
|
76
|
+
[](https://github.com/phil65/schemez)
|
77
|
+
[](https://github.com/phil65/schemez)
|
78
|
+
[](https://github.com/phil65/schemez)
|
79
|
+
[](https://codecov.io/gh/phil65/schemez/)
|
80
|
+
[](https://github.com/psf/black)
|
81
|
+
[](https://pyup.io/repos/github/phil65/schemez/)
|
82
|
+
|
83
|
+
[Read the documentation!](https://phil65.github.io/schemez/)
|
84
|
+
|
schemez-0.0.1/README.md
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# Schemez
|
2
|
+
|
3
|
+
[](https://pypi.org/project/schemez/)
|
4
|
+
[](https://pypi.org/project/schemez/)
|
5
|
+
[](https://pypi.org/project/schemez/)
|
6
|
+
[](https://pypi.org/project/schemez/)
|
7
|
+
[](https://pypi.org/project/schemez/)
|
8
|
+
[](https://pypi.org/project/schemez/)
|
9
|
+
[](https://pypi.org/project/schemez/)
|
10
|
+
[](https://pypi.org/project/schemez/)
|
11
|
+
[](https://pypi.org/project/schemez/)
|
12
|
+
[](https://github.com/phil65/schemez/releases)
|
13
|
+
[](https://github.com/phil65/schemez/graphs/contributors)
|
14
|
+
[](https://github.com/phil65/schemez/discussions)
|
15
|
+
[](https://github.com/phil65/schemez/forks)
|
16
|
+
[](https://github.com/phil65/schemez/issues)
|
17
|
+
[](https://github.com/phil65/schemez/pulls)
|
18
|
+
[](https://github.com/phil65/schemez/watchers)
|
19
|
+
[](https://github.com/phil65/schemez/stars)
|
20
|
+
[](https://github.com/phil65/schemez)
|
21
|
+
[](https://github.com/phil65/schemez/commits)
|
22
|
+
[](https://github.com/phil65/schemez/releases)
|
23
|
+
[](https://github.com/phil65/schemez)
|
24
|
+
[](https://github.com/phil65/schemez)
|
25
|
+
[](https://github.com/phil65/schemez)
|
26
|
+
[](https://github.com/phil65/schemez)
|
27
|
+
[](https://codecov.io/gh/phil65/schemez/)
|
28
|
+
[](https://github.com/psf/black)
|
29
|
+
[](https://pyup.io/repos/github/phil65/schemez/)
|
30
|
+
|
31
|
+
[Read the documentation!](https://phil65.github.io/schemez/)
|
32
|
+
|
File without changes
|
schemez-0.0.1/duties.py
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from duty import duty
|
4
|
+
|
5
|
+
|
6
|
+
@duty(capture=False)
|
7
|
+
def build(ctx, *args: str):
|
8
|
+
"""Build a MkNodes page."""
|
9
|
+
args_str = " " + " ".join(args) if args else ""
|
10
|
+
ctx.run(f"uv run mknodes build{args_str}")
|
11
|
+
|
12
|
+
|
13
|
+
@duty(capture=False)
|
14
|
+
def serve(ctx, *args: str):
|
15
|
+
"""Serve a MkNodes page."""
|
16
|
+
args_str = " " + " ".join(args) if args else ""
|
17
|
+
ctx.run(f"uv run mknodes serve{args_str}")
|
18
|
+
|
19
|
+
|
20
|
+
@duty(capture=False)
|
21
|
+
def test(ctx, *args: str):
|
22
|
+
"""Serve a MkNodes page."""
|
23
|
+
args_str = " " + " ".join(args) if args else ""
|
24
|
+
ctx.run(f"uv run pytest{args_str}")
|
25
|
+
|
26
|
+
|
27
|
+
@duty(capture=False)
|
28
|
+
def clean(ctx):
|
29
|
+
"""Clean all files from the Git directory except checked-in files."""
|
30
|
+
ctx.run("git clean -dfX")
|
31
|
+
|
32
|
+
|
33
|
+
@duty(capture=False)
|
34
|
+
def update(ctx):
|
35
|
+
"""Update all environment packages using pip directly."""
|
36
|
+
ctx.run("uv lock --upgrade")
|
37
|
+
ctx.run("uv sync --all-extras")
|
38
|
+
|
39
|
+
|
40
|
+
@duty(capture=False)
|
41
|
+
def lint(ctx):
|
42
|
+
"""Lint the code and fix issues if possible."""
|
43
|
+
ctx.run("uv run ruff check --fix --unsafe-fixes .")
|
44
|
+
ctx.run("uv run ruff format .")
|
45
|
+
ctx.run("uv run mypy src/schemez/")
|
46
|
+
|
47
|
+
|
48
|
+
@duty(capture=False)
|
49
|
+
def lint_check(ctx):
|
50
|
+
"""Lint the code."""
|
51
|
+
ctx.run("uv run ruff check .")
|
52
|
+
ctx.run("uv run ruff format --check .")
|
53
|
+
ctx.run("uv run mypy src/schemez/")
|
54
|
+
|
55
|
+
|
56
|
+
@duty(capture=False)
|
57
|
+
def version(ctx, *args: str):
|
58
|
+
"""Bump package version."""
|
59
|
+
args_str = " " + " ".join(args) if args else ""
|
60
|
+
ctx.run(f"hatch version{args_str}")
|
schemez-0.0.1/mkdocs.yml
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
site_name: "Schemez"
|
2
|
+
site_description: "Pydantic shim for config stuff"
|
3
|
+
repo_url: "https://github.com/phil65/schemez/"
|
4
|
+
site_url: https://phil65.github.io/schemez/
|
5
|
+
site_author: "Philipp Temminghoff"
|
6
|
+
copyright: Copyright © 2025 Philipp Temminghoff
|
7
|
+
|
8
|
+
theme:
|
9
|
+
name: material
|
10
|
+
custom_dir: overrides
|
11
|
+
icon:
|
12
|
+
logo: material/graph-outline
|
13
|
+
palette:
|
14
|
+
# Palette toggle for automatic mode
|
15
|
+
- media: "(prefers-color-scheme)"
|
16
|
+
toggle:
|
17
|
+
icon: material/brightness-auto
|
18
|
+
name: Switch to light mode
|
19
|
+
|
20
|
+
# Palette toggle for light mode
|
21
|
+
- media: "(prefers-color-scheme: light)"
|
22
|
+
scheme: default
|
23
|
+
primary: red
|
24
|
+
toggle:
|
25
|
+
icon: material/brightness-7
|
26
|
+
name: Switch to dark mode
|
27
|
+
|
28
|
+
# Palette toggle for dark mode
|
29
|
+
- media: "(prefers-color-scheme: dark)"
|
30
|
+
scheme: slate
|
31
|
+
primary: red
|
32
|
+
toggle:
|
33
|
+
icon: material/brightness-4
|
34
|
+
name: Switch to system preference
|
35
|
+
features:
|
36
|
+
- announce.dismiss
|
37
|
+
- content.action.edit
|
38
|
+
- content.code.copy
|
39
|
+
- content.code.select
|
40
|
+
- content.code.annotate
|
41
|
+
- content.tooltips
|
42
|
+
# - content.tabs.link
|
43
|
+
- navigation.tracking # update URL based on current item in TOC
|
44
|
+
- navigation.path # shows breadcrumbs
|
45
|
+
- navigation.tabs # make top level tabs
|
46
|
+
- navigation.indexes # documents can be directly attached to sections (overview pages)
|
47
|
+
- navigation.footer # next/previous page buttons in footer
|
48
|
+
- navigation.top # adds back-to-top button
|
49
|
+
# - navigation.sections # top-level sections are rendered as groups
|
50
|
+
# - navigation.expand # expand all subsections in left sidebar by default
|
51
|
+
- toc.follow # makes toc follow scrolling
|
52
|
+
# - toc.integrate # integrates toc into left menu
|
53
|
+
- search.highlight
|
54
|
+
- search.suggest
|
55
|
+
# - search.share
|
56
|
+
|
57
|
+
plugins:
|
58
|
+
- search
|
59
|
+
- autorefs
|
60
|
+
- mknodes
|
61
|
+
- mkdocstrings:
|
62
|
+
default_handler: python
|
63
|
+
handlers:
|
64
|
+
python:
|
65
|
+
import:
|
66
|
+
- url: https://docs.python.org/3/objects.inv
|
67
|
+
domains: [std, py]
|
68
|
+
options:
|
69
|
+
# https://mkdocstrings.github.io/python/usage/
|
70
|
+
enable_inventory: !ENV [CI, false]
|
71
|
+
show_signature_annotations: true
|
72
|
+
show_symbol_type_toc: true
|
73
|
+
show_symbol_type_heading: true
|
74
|
+
show_root_toc_entry: false
|
75
|
+
# merge_init_into_class: true
|
76
|
+
ignore_init_summary: true
|
77
|
+
inherited_members: false
|
78
|
+
signature_crossrefs: true
|
79
|
+
separate_signature: true
|
80
|
+
line_length: 90
|
81
|
+
markdown_extensions:
|
82
|
+
- attr_list
|
83
|
+
- pymdownx.emoji
|
84
|
+
- toc:
|
85
|
+
permalink: true
|
86
|
+
|
87
|
+
extra:
|
88
|
+
social:
|
89
|
+
- icon: fontawesome/brands/github
|
90
|
+
link: https://github.com/phil65
|
91
|
+
- icon: fontawesome/brands/python
|
92
|
+
link: https://pypi.org/project/schemez/
|
@@ -0,0 +1 @@
|
|
1
|
+
File exists to make sure that folder exists for git
|
@@ -0,0 +1,250 @@
|
|
1
|
+
[tool.hatch.version]
|
2
|
+
source = "regex_commit"
|
3
|
+
commit_extra_args = ["-e"]
|
4
|
+
path = "src/schemez/__init__.py"
|
5
|
+
|
6
|
+
[build-system]
|
7
|
+
requires = ["hatchling", "hatch-regex-commit"]
|
8
|
+
build-backend = "hatchling.build"
|
9
|
+
|
10
|
+
[project]
|
11
|
+
name = "schemez"
|
12
|
+
description = "Pydantic shim for config stuff"
|
13
|
+
authors = [
|
14
|
+
{ name = "Philipp Temminghoff", email = "philipptemminghoff@googlemail.com" },
|
15
|
+
]
|
16
|
+
readme = "README.md"
|
17
|
+
dynamic = ["version"]
|
18
|
+
classifiers = [
|
19
|
+
"Development Status :: 4 - Beta",
|
20
|
+
"Intended Audience :: Developers",
|
21
|
+
"Operating System :: OS Independent",
|
22
|
+
"Programming Language :: Python :: 3",
|
23
|
+
"Programming Language :: Python :: 3 :: Only",
|
24
|
+
"Programming Language :: Python :: 3.12",
|
25
|
+
"Programming Language :: Python :: 3.13",
|
26
|
+
"Programming Language :: Python :: 3.14",
|
27
|
+
"Topic :: Documentation",
|
28
|
+
"Topic :: Software Development",
|
29
|
+
"Topic :: Utilities",
|
30
|
+
"Typing :: Typed","Framework :: Pydantic",
|
31
|
+
"Framework :: Pydantic :: 2",
|
32
|
+
|
33
|
+
]
|
34
|
+
keywords = []
|
35
|
+
requires-python = ">=3.12"
|
36
|
+
license = { file = "LICENSE" }
|
37
|
+
dependencies = [
|
38
|
+
"pydantic",
|
39
|
+
# Only add below (Copier)
|
40
|
+
"universal-pathlib>=0.2.6",
|
41
|
+
]
|
42
|
+
|
43
|
+
[project-optional-dependencies]
|
44
|
+
yaml = ["yamling"]
|
45
|
+
|
46
|
+
[tool.uv]
|
47
|
+
default-groups = ["dev", "lint", "docs"]
|
48
|
+
|
49
|
+
[dependency-groups]
|
50
|
+
dev = [
|
51
|
+
"pytest",
|
52
|
+
"pytest-cov",
|
53
|
+
"pyreadline3",
|
54
|
+
"devtools",
|
55
|
+
# Only add below (Copier)
|
56
|
+
]
|
57
|
+
benchmark = ["pyinstrument"]
|
58
|
+
lint = [
|
59
|
+
"ruff",
|
60
|
+
"mypy[faster-cache]; python_version < '3.14'",
|
61
|
+
"mypy; python_version >= '3.14'",
|
62
|
+
# Only add below (Copier)
|
63
|
+
]
|
64
|
+
docs = [
|
65
|
+
"mkdocs-mknodes",
|
66
|
+
"mkdocs-material",
|
67
|
+
# Only add below (Copier)
|
68
|
+
]
|
69
|
+
|
70
|
+
[project.urls]
|
71
|
+
Documentation = "https://phil65.github.io/schemez/"
|
72
|
+
Source = "https://github.com/phil65/schemez"
|
73
|
+
Issues = "https://github.com/phil65/schemez/issues"
|
74
|
+
Discussions = "https://github.com/phil65/schemez/discussions"
|
75
|
+
"Code coverage" = "https://app.codecov.io/gh/phil65/schemez"
|
76
|
+
|
77
|
+
[tool.pytest.ini_options]
|
78
|
+
testpaths = "tests/"
|
79
|
+
log_cli = true
|
80
|
+
log_format = "%(asctime)s %(levelname)s %(message)s"
|
81
|
+
log_date_format = "%Y-%m-%d %H:%M:%S"
|
82
|
+
|
83
|
+
[tool.coverage.report]
|
84
|
+
exclude_lines = [
|
85
|
+
"pragma: no cover",
|
86
|
+
"if TYPE_CHECKING:",
|
87
|
+
"@overload",
|
88
|
+
"except ImportError",
|
89
|
+
'if __name__ == "__main__":',
|
90
|
+
]
|
91
|
+
|
92
|
+
[tool.mypy]
|
93
|
+
python_version = "3.12"
|
94
|
+
disable_error_code = ["misc", "import"]
|
95
|
+
pretty = true
|
96
|
+
check_untyped_defs = true
|
97
|
+
exclude = ['venv/', '.venv/', 'tests/']
|
98
|
+
plugins = ["pydantic.mypy"]
|
99
|
+
|
100
|
+
[tool.ruff]
|
101
|
+
line-length = 90
|
102
|
+
extend-exclude = ['docs']
|
103
|
+
target-version = "py312"
|
104
|
+
|
105
|
+
[tool.ruff.lint]
|
106
|
+
select = [
|
107
|
+
"A", # Flake8-builtins
|
108
|
+
# "ANN", # Flake8-Annotations
|
109
|
+
# "ASYNC", # Flake8-Async
|
110
|
+
# "ARG", # # Flake8-Unused-Arguments
|
111
|
+
"B", # flake8-bugbear
|
112
|
+
"BLE", # Flake8-blind-except
|
113
|
+
"C",
|
114
|
+
"C4", # flake8-comprehensions
|
115
|
+
# "C90", # MCCabe
|
116
|
+
"COM", # Flake8-commas
|
117
|
+
# "CPY", # Copyright-related rules
|
118
|
+
"D", # PyDocStyle
|
119
|
+
# "DTZ", # Flake8- Datetimez
|
120
|
+
"E", # PyCodeStyle Error
|
121
|
+
"EM", # flake8-errmsg
|
122
|
+
# "ERA", # Eradicate
|
123
|
+
"EXE", # flake8-executable
|
124
|
+
"F", # PyFlakes
|
125
|
+
"FA", # flake8-future-annotations
|
126
|
+
# "FBT", # flake8-boolean-trap
|
127
|
+
# "FIX", # flake8-fixme
|
128
|
+
"FLY", # flynt
|
129
|
+
"G", # flake8-logging-format
|
130
|
+
"I", # ISort
|
131
|
+
"ICN", # Flake8-import-conventions
|
132
|
+
"INP", # flake8-no-pep420
|
133
|
+
"INT", # flake8-gettext
|
134
|
+
"ISC", # flake8-implicit-str-concat
|
135
|
+
"N", # pep8-naming
|
136
|
+
# "NPY", # numpy-specific rules
|
137
|
+
# "PD", # pandas-vet
|
138
|
+
"PERF", # perflint
|
139
|
+
# "PGH", # pygrep-hooks
|
140
|
+
"PIE", # flake8-pie
|
141
|
+
"PLE", # PyLint Error
|
142
|
+
"PLC", # PyLint convention
|
143
|
+
# "PLW", # PyLint Warning
|
144
|
+
"PLR", # PyLint refactor
|
145
|
+
"PT", # flake8-pytest-style
|
146
|
+
"PTH", # flake8-use-pathlib
|
147
|
+
"PYI", # flake8-pyi
|
148
|
+
"Q", # flake8-quotes
|
149
|
+
"RET", # flake8-return
|
150
|
+
"RSE", # flake8-raise
|
151
|
+
"RUF", # ruff-specific rules
|
152
|
+
# "S", # flake8-bandit
|
153
|
+
"SIM", # flake8-simplify
|
154
|
+
"SLF", # flake8-self
|
155
|
+
"SLOT", # flake8-slots
|
156
|
+
# "T",
|
157
|
+
# "TD", # flake8-todos
|
158
|
+
"T10", # flake8-debugger
|
159
|
+
# "T20", # flake8-print
|
160
|
+
"TC", # flake8-type-checking
|
161
|
+
"TID", # flake8-tidy-imports
|
162
|
+
"TRY", # tryceratops
|
163
|
+
"UP", # PyUpgrade
|
164
|
+
"W", # PyCodeStyle warning
|
165
|
+
"YTT", # flake8-2020
|
166
|
+
]
|
167
|
+
ignore = [
|
168
|
+
"C408", # Unnecessary {obj_type} call (rewrite as a literal)
|
169
|
+
"B905", # zip() without an explicit strict= parameter
|
170
|
+
"C901", # {name} is too complex ({complexity} > {max_complexity})
|
171
|
+
"COM812",
|
172
|
+
# "CPY001", # Missing copyright notice at top of file
|
173
|
+
"D100", # Missing docstring in public module
|
174
|
+
"D101", # Missing docstring in public class
|
175
|
+
"D102", # Missing docstring in public method
|
176
|
+
"D103", # Missing docstring in public function
|
177
|
+
"D104", # Missing docstring in public package
|
178
|
+
"D105", # Missing docstring in magic method
|
179
|
+
"D106", # Missing docstring in public nested class
|
180
|
+
"D107", # Missing docstring in __init__
|
181
|
+
"D203", # 1 blank line required before class docstring
|
182
|
+
"D204", # 1 blank line required after class docstring
|
183
|
+
"D213", # Multi-line docstring summary should start at the second line
|
184
|
+
"D215", # Section underline is over-indented ("{name}")
|
185
|
+
"D400", # First line should end with a period
|
186
|
+
"D401", # First line of docstring should be in imperative mood: "{first_line}"
|
187
|
+
"D404", # First word of the docstring should not be "This"
|
188
|
+
"D406", # Section name should end with a newline ("{name}")
|
189
|
+
"D407", # Missing dashed underline after section ("{name}")
|
190
|
+
"D408", # Section underline should be in the line following the section's name ("{name}")
|
191
|
+
"D409", # Section underline should match the length of its name ("{name}")
|
192
|
+
"D413", # Missing blank line after last section ("{name}")
|
193
|
+
"ISC001",
|
194
|
+
"PLR0912", # Too many branches
|
195
|
+
"PLR0913", # Too many arguments to function call
|
196
|
+
"PLR0915", # Too many statements
|
197
|
+
# "PLR2004", # Magic values instead of named consts
|
198
|
+
"SLF001", # Private member accessed
|
199
|
+
"TRY003", # Avoid specifying long messages outside the exception class
|
200
|
+
"TC006", # runtime-cast-value
|
201
|
+
]
|
202
|
+
|
203
|
+
[tool.ruff.lint.flake8-quotes]
|
204
|
+
docstring-quotes = "double"
|
205
|
+
|
206
|
+
[tool.ruff.format]
|
207
|
+
# Enable preview style formatting.
|
208
|
+
preview = true
|
209
|
+
|
210
|
+
[tool.ruff.lint.isort]
|
211
|
+
lines-after-imports = 2
|
212
|
+
# lines-between-types = 1
|
213
|
+
# atomic = true
|
214
|
+
force-sort-within-sections = true
|
215
|
+
combine-as-imports = true
|
216
|
+
|
217
|
+
[tool.ruff.lint.per-file-ignores]
|
218
|
+
"__init__.py" = ["E402", "I001"]
|
219
|
+
"scripts/*" = ["INP001"]
|
220
|
+
|
221
|
+
[tool.pyright]
|
222
|
+
venvPath = "."
|
223
|
+
venv = ".venv"
|
224
|
+
pythonVersion = "3.12"
|
225
|
+
pythonPlatform = "All"
|
226
|
+
typeCheckingMode = "basic"
|
227
|
+
deprecateTypingAliases = true
|
228
|
+
reportMissingTypeStubs = false
|
229
|
+
reportUnusedCallResult = false
|
230
|
+
reportUnknownVariableType = false
|
231
|
+
reportAny = false
|
232
|
+
reportImplicitOverride = false
|
233
|
+
reportUnusedFunction = false
|
234
|
+
reportImplicitStringConcatenation = false
|
235
|
+
reportIgnoreCommentWithoutRule = false
|
236
|
+
reportUnannotatedClassAttribute = false
|
237
|
+
reportSelfClsParameterName = false
|
238
|
+
reportPrivateImportUsage = false
|
239
|
+
|
240
|
+
[tool.mknodes]
|
241
|
+
allowed-commit-types = [
|
242
|
+
"fix",
|
243
|
+
"feat",
|
244
|
+
"refactor",
|
245
|
+
"docs",
|
246
|
+
"test",
|
247
|
+
"build",
|
248
|
+
"chore",
|
249
|
+
]
|
250
|
+
docstring-style = "google"
|
@@ -0,0 +1,35 @@
|
|
1
|
+
"""Helpers for BaseModels."""
|
2
|
+
|
3
|
+
from __future__ import annotations
|
4
|
+
|
5
|
+
import os
|
6
|
+
|
7
|
+
from pydantic import BaseModel
|
8
|
+
|
9
|
+
|
10
|
+
StrPath = str | os.PathLike[str]
|
11
|
+
|
12
|
+
|
13
|
+
def merge_models[T: BaseModel](base: T, overlay: T) -> T:
|
14
|
+
"""Deep merge two Pydantic models."""
|
15
|
+
if not isinstance(overlay, type(base)):
|
16
|
+
msg = f"Cannot merge different types: {type(base)} and {type(overlay)}"
|
17
|
+
raise TypeError(msg)
|
18
|
+
|
19
|
+
merged_data = base.model_dump()
|
20
|
+
overlay_data = overlay.model_dump(exclude_none=True)
|
21
|
+
for field_name, field_value in overlay_data.items():
|
22
|
+
base_value = merged_data.get(field_name)
|
23
|
+
|
24
|
+
match (base_value, field_value):
|
25
|
+
case (list(), list()):
|
26
|
+
merged_data[field_name] = [
|
27
|
+
*base_value,
|
28
|
+
*(item for item in field_value if item not in base_value),
|
29
|
+
]
|
30
|
+
case (dict(), dict()):
|
31
|
+
merged_data[field_name] = base_value | field_value
|
32
|
+
case _:
|
33
|
+
merged_data[field_name] = field_value
|
34
|
+
|
35
|
+
return base.__class__.model_validate(merged_data)
|
File without changes
|
@@ -0,0 +1,67 @@
|
|
1
|
+
"""Configuration models for Schemez."""
|
2
|
+
|
3
|
+
from __future__ import annotations
|
4
|
+
|
5
|
+
import os
|
6
|
+
from typing import Self
|
7
|
+
|
8
|
+
from pydantic import BaseModel, ConfigDict
|
9
|
+
import upath
|
10
|
+
|
11
|
+
|
12
|
+
StrPath = str | os.PathLike[str]
|
13
|
+
|
14
|
+
|
15
|
+
class Schema(BaseModel):
|
16
|
+
"""Base class configuration models.
|
17
|
+
|
18
|
+
Provides:
|
19
|
+
- Common Pydantic settings
|
20
|
+
- YAML serialization
|
21
|
+
- Basic merge functionality
|
22
|
+
"""
|
23
|
+
|
24
|
+
model_config = ConfigDict(extra="forbid", use_attribute_docstrings=True)
|
25
|
+
|
26
|
+
def merge(self, other: Self) -> Self:
|
27
|
+
"""Merge with another instance by overlaying its non-None values."""
|
28
|
+
from schemez.helpers import merge_models
|
29
|
+
|
30
|
+
return merge_models(self, other)
|
31
|
+
|
32
|
+
@classmethod
|
33
|
+
def from_yaml(cls, content: str, inherit_path: StrPath | None = None) -> Self:
|
34
|
+
"""Create from YAML string."""
|
35
|
+
import yamling
|
36
|
+
|
37
|
+
data = yamling.load_yaml(content, resolve_inherit=inherit_path or False)
|
38
|
+
return cls.model_validate(data)
|
39
|
+
|
40
|
+
def model_dump_yaml(self) -> str:
|
41
|
+
"""Dump configuration to YAML string."""
|
42
|
+
import yamling
|
43
|
+
|
44
|
+
return yamling.dump_yaml(self.model_dump(exclude_none=True))
|
45
|
+
|
46
|
+
def save(self, path: StrPath, overwrite: bool = False) -> None:
|
47
|
+
"""Save configuration to a YAML file.
|
48
|
+
|
49
|
+
Args:
|
50
|
+
path: Path to save the configuration to
|
51
|
+
overwrite: Whether to overwrite an existing file
|
52
|
+
|
53
|
+
Raises:
|
54
|
+
OSError: If file cannot be written
|
55
|
+
ValueError: If path is invalid
|
56
|
+
"""
|
57
|
+
yaml_str = self.model_dump_yaml()
|
58
|
+
try:
|
59
|
+
file_path = upath.UPath(path)
|
60
|
+
if file_path.exists() and not overwrite:
|
61
|
+
msg = f"File already exists: {path}"
|
62
|
+
raise FileExistsError(msg) # noqa: TRY301
|
63
|
+
file_path.parent.mkdir(parents=True, exist_ok=True)
|
64
|
+
file_path.write_text(yaml_str)
|
65
|
+
except Exception as exc:
|
66
|
+
msg = f"Failed to save configuration to {path}"
|
67
|
+
raise ValueError(msg) from exc
|
@@ -0,0 +1 @@
|
|
1
|
+
from __future__ import annotations
|