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.
@@ -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,3 @@
1
+ github: phil65
2
+ custom:
3
+ - https://www.paypal.me/phil65
@@ -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,9 @@
1
+ # Set update schedule for GitHub Actions
2
+
3
+ version: 2
4
+ updates:
5
+ - package-ecosystem: "github-actions"
6
+ directory: "/"
7
+ schedule:
8
+ # Check for updates to GitHub Actions every week
9
+ interval: "weekly"
@@ -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
@@ -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
+ [![PyPI License](https://img.shields.io/pypi/l/schemez.svg)](https://pypi.org/project/schemez/)
56
+ [![Package status](https://img.shields.io/pypi/status/schemez.svg)](https://pypi.org/project/schemez/)
57
+ [![Daily downloads](https://img.shields.io/pypi/dd/schemez.svg)](https://pypi.org/project/schemez/)
58
+ [![Weekly downloads](https://img.shields.io/pypi/dw/schemez.svg)](https://pypi.org/project/schemez/)
59
+ [![Monthly downloads](https://img.shields.io/pypi/dm/schemez.svg)](https://pypi.org/project/schemez/)
60
+ [![Distribution format](https://img.shields.io/pypi/format/schemez.svg)](https://pypi.org/project/schemez/)
61
+ [![Wheel availability](https://img.shields.io/pypi/wheel/schemez.svg)](https://pypi.org/project/schemez/)
62
+ [![Python version](https://img.shields.io/pypi/pyversions/schemez.svg)](https://pypi.org/project/schemez/)
63
+ [![Implementation](https://img.shields.io/pypi/implementation/schemez.svg)](https://pypi.org/project/schemez/)
64
+ [![Releases](https://img.shields.io/github/downloads/phil65/schemez/total.svg)](https://github.com/phil65/schemez/releases)
65
+ [![Github Contributors](https://img.shields.io/github/contributors/phil65/schemez)](https://github.com/phil65/schemez/graphs/contributors)
66
+ [![Github Discussions](https://img.shields.io/github/discussions/phil65/schemez)](https://github.com/phil65/schemez/discussions)
67
+ [![Github Forks](https://img.shields.io/github/forks/phil65/schemez)](https://github.com/phil65/schemez/forks)
68
+ [![Github Issues](https://img.shields.io/github/issues/phil65/schemez)](https://github.com/phil65/schemez/issues)
69
+ [![Github Issues](https://img.shields.io/github/issues-pr/phil65/schemez)](https://github.com/phil65/schemez/pulls)
70
+ [![Github Watchers](https://img.shields.io/github/watchers/phil65/schemez)](https://github.com/phil65/schemez/watchers)
71
+ [![Github Stars](https://img.shields.io/github/stars/phil65/schemez)](https://github.com/phil65/schemez/stars)
72
+ [![Github Repository size](https://img.shields.io/github/repo-size/phil65/schemez)](https://github.com/phil65/schemez)
73
+ [![Github last commit](https://img.shields.io/github/last-commit/phil65/schemez)](https://github.com/phil65/schemez/commits)
74
+ [![Github release date](https://img.shields.io/github/release-date/phil65/schemez)](https://github.com/phil65/schemez/releases)
75
+ [![Github language count](https://img.shields.io/github/languages/count/phil65/schemez)](https://github.com/phil65/schemez)
76
+ [![Github commits this week](https://img.shields.io/github/commit-activity/w/phil65/schemez)](https://github.com/phil65/schemez)
77
+ [![Github commits this month](https://img.shields.io/github/commit-activity/m/phil65/schemez)](https://github.com/phil65/schemez)
78
+ [![Github commits this year](https://img.shields.io/github/commit-activity/y/phil65/schemez)](https://github.com/phil65/schemez)
79
+ [![Package status](https://codecov.io/gh/phil65/schemez/branch/main/graph/badge.svg)](https://codecov.io/gh/phil65/schemez/)
80
+ [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
81
+ [![PyUp](https://pyup.io/repos/github/phil65/schemez/shield.svg)](https://pyup.io/repos/github/phil65/schemez/)
82
+
83
+ [Read the documentation!](https://phil65.github.io/schemez/)
84
+
@@ -0,0 +1,32 @@
1
+ # Schemez
2
+
3
+ [![PyPI License](https://img.shields.io/pypi/l/schemez.svg)](https://pypi.org/project/schemez/)
4
+ [![Package status](https://img.shields.io/pypi/status/schemez.svg)](https://pypi.org/project/schemez/)
5
+ [![Daily downloads](https://img.shields.io/pypi/dd/schemez.svg)](https://pypi.org/project/schemez/)
6
+ [![Weekly downloads](https://img.shields.io/pypi/dw/schemez.svg)](https://pypi.org/project/schemez/)
7
+ [![Monthly downloads](https://img.shields.io/pypi/dm/schemez.svg)](https://pypi.org/project/schemez/)
8
+ [![Distribution format](https://img.shields.io/pypi/format/schemez.svg)](https://pypi.org/project/schemez/)
9
+ [![Wheel availability](https://img.shields.io/pypi/wheel/schemez.svg)](https://pypi.org/project/schemez/)
10
+ [![Python version](https://img.shields.io/pypi/pyversions/schemez.svg)](https://pypi.org/project/schemez/)
11
+ [![Implementation](https://img.shields.io/pypi/implementation/schemez.svg)](https://pypi.org/project/schemez/)
12
+ [![Releases](https://img.shields.io/github/downloads/phil65/schemez/total.svg)](https://github.com/phil65/schemez/releases)
13
+ [![Github Contributors](https://img.shields.io/github/contributors/phil65/schemez)](https://github.com/phil65/schemez/graphs/contributors)
14
+ [![Github Discussions](https://img.shields.io/github/discussions/phil65/schemez)](https://github.com/phil65/schemez/discussions)
15
+ [![Github Forks](https://img.shields.io/github/forks/phil65/schemez)](https://github.com/phil65/schemez/forks)
16
+ [![Github Issues](https://img.shields.io/github/issues/phil65/schemez)](https://github.com/phil65/schemez/issues)
17
+ [![Github Issues](https://img.shields.io/github/issues-pr/phil65/schemez)](https://github.com/phil65/schemez/pulls)
18
+ [![Github Watchers](https://img.shields.io/github/watchers/phil65/schemez)](https://github.com/phil65/schemez/watchers)
19
+ [![Github Stars](https://img.shields.io/github/stars/phil65/schemez)](https://github.com/phil65/schemez/stars)
20
+ [![Github Repository size](https://img.shields.io/github/repo-size/phil65/schemez)](https://github.com/phil65/schemez)
21
+ [![Github last commit](https://img.shields.io/github/last-commit/phil65/schemez)](https://github.com/phil65/schemez/commits)
22
+ [![Github release date](https://img.shields.io/github/release-date/phil65/schemez)](https://github.com/phil65/schemez/releases)
23
+ [![Github language count](https://img.shields.io/github/languages/count/phil65/schemez)](https://github.com/phil65/schemez)
24
+ [![Github commits this week](https://img.shields.io/github/commit-activity/w/phil65/schemez)](https://github.com/phil65/schemez)
25
+ [![Github commits this month](https://img.shields.io/github/commit-activity/m/phil65/schemez)](https://github.com/phil65/schemez)
26
+ [![Github commits this year](https://img.shields.io/github/commit-activity/y/phil65/schemez)](https://github.com/phil65/schemez)
27
+ [![Package status](https://codecov.io/gh/phil65/schemez/branch/main/graph/badge.svg)](https://codecov.io/gh/phil65/schemez/)
28
+ [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
29
+ [![PyUp](https://pyup.io/repos/github/phil65/schemez/shield.svg)](https://pyup.io/repos/github/phil65/schemez/)
30
+
31
+ [Read the documentation!](https://phil65.github.io/schemez/)
32
+
File without changes
@@ -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}")
@@ -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 &copy; 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,6 @@
1
+ __version__ = "0.0.1"
2
+
3
+
4
+ from schemez.schema import Schema
5
+
6
+ __all__ = ["Schema"]
@@ -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,3 @@
1
+ from pathlib import Path
2
+
3
+ TESTS_DIR = Path(__file__).parent
@@ -0,0 +1 @@
1
+ from __future__ import annotations
@@ -0,0 +1,5 @@
1
+ from __future__ import annotations
2
+
3
+
4
+ def test_nothing():
5
+ pass