pyrmute 0.1.0__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,57 @@
1
+ name: ci
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ pull_request:
8
+ branches:
9
+ - main
10
+ release:
11
+ types:
12
+ - created
13
+ schedule:
14
+ # Run nightly to check that tests are working with latest dependencies
15
+ - cron: "0 0 * * *"
16
+
17
+ permissions:
18
+ contents: read
19
+ pull-requests: write
20
+
21
+ jobs:
22
+ check:
23
+ runs-on: ubuntu-latest
24
+ strategy:
25
+ matrix:
26
+ python-version: ["3.11", "3.12", "3.13"]
27
+
28
+ steps:
29
+ - name: Checkout
30
+ uses: actions/checkout@v5
31
+ with:
32
+ fetch-depth: 0
33
+
34
+ - name: Install uv
35
+ uses: astral-sh/setup-uv@v6
36
+
37
+ - name: Set up Python
38
+ run: uv python install ${{ matrix.python-version }}
39
+
40
+ - name: Set up Python
41
+ run: uv sync --python ${{ matrix.python-version }} --all-extras --frozen
42
+
43
+ - name: Ruff check
44
+ if: ${{ always() }}
45
+ run: uv run ruff check
46
+
47
+ - name: Ruff format
48
+ if: ${{ always() }}
49
+ run: uv run ruff format --check
50
+
51
+ - name: Check typing with mypy
52
+ if: ${{ always() }}
53
+ run: uv run mypy src tests
54
+
55
+ - name: Run tests
56
+ if: ${{ always() }}
57
+ run: uv run pytest
@@ -0,0 +1,42 @@
1
+ name: Publish Python distribution to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [created]
6
+
7
+ permissions:
8
+ contents: read
9
+ pull-requests: write
10
+
11
+ jobs:
12
+ publish-pypi-package:
13
+ name: Publish to PyPI
14
+ runs-on: ubuntu-latest
15
+
16
+ environment:
17
+ name: release
18
+ url: https://pypi.org/project/pyrmute/
19
+
20
+ permissions:
21
+ id-token: write
22
+
23
+ steps:
24
+ - uses: actions/checkout@v5
25
+ with:
26
+ fetch-depth: 0
27
+
28
+ - name: Set up Python 3.11
29
+ uses: actions/setup-python@v6
30
+ with:
31
+ python-version: "3.11"
32
+
33
+ - name: Install build dependencies
34
+ run: |
35
+ pip install -U pip
36
+ pip install build
37
+
38
+ - name: Build distributions
39
+ run: python -m build
40
+
41
+ - name: Publish package distributions to PyPI
42
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,19 @@
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+
9
+ # Virtual environments
10
+ .venv
11
+
12
+ # uv
13
+ .python-version
14
+
15
+ # cov
16
+ .coverage
17
+
18
+ # setuptools-scm version
19
+ _version.py
pyrmute-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2025 to present Matt Ferrera and individual contributors.
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.
pyrmute-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,130 @@
1
+ Metadata-Version: 2.4
2
+ Name: pyrmute
3
+ Version: 0.1.0
4
+ Summary: Pydantic model migrations and schemas
5
+ Author-email: Matt Ferrera <mattferrera@gmail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/mferrera/pyrmute
8
+ Project-URL: Repository, https://github.com/mferrera/pyrmute
9
+ Project-URL: Documentation, https://github.com/mferrera/pyrmute
10
+ Keywords: pydantic,migration,versioning,schema
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Topic :: Utilities
13
+ Classifier: Operating System :: POSIX :: Linux
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Natural Language :: English
18
+ Requires-Python: >=3.11
19
+ Description-Content-Type: text/markdown
20
+ License-File: LICENSE
21
+ Requires-Dist: pydantic
22
+ Provides-Extra: dev
23
+ Requires-Dist: mypy; extra == "dev"
24
+ Requires-Dist: pytest; extra == "dev"
25
+ Requires-Dist: pytest-cov; extra == "dev"
26
+ Requires-Dist: pytest-mock; extra == "dev"
27
+ Requires-Dist: pytest-xdist; extra == "dev"
28
+ Requires-Dist: ruff; extra == "dev"
29
+ Dynamic: license-file
30
+
31
+ # pyrmute
32
+
33
+ [![ci](https://img.shields.io/github/actions/workflow/status/mferrera/pyrmute/ci.yml?branch=main&logo=github&label=ci)](https://github.com/mferrera/pyrmute/actions?query=event%3Apush+branch%3Amain+workflow%3Aci)
34
+ [![pypi](https://img.shields.io/pypi/v/pyrmute.svg)](https://pypi.python.org/pypi/pyrmute)
35
+ [![versions](https://img.shields.io/pypi/pyversions/pyrmute.svg)](https://github.com/mferrera/pyrmute)
36
+ [![license](https://img.shields.io/github/license/pyrmute/pyrmute.svg)](https://github.com/mferrera/pyrmute/blob/main/LICENSE)
37
+
38
+ Pydantic model migrations and schema management with semantic versioning.
39
+
40
+ Pyrmute helps you evolve your data models over time without breaking changes.
41
+ Version your Pydantic models, define migrations between versions, and
42
+ automatically transform legacy data to current schemas. Export JSON schemas
43
+ for all versions to maintain API contracts.
44
+
45
+ **Key features:**
46
+ - **Version your models** - Use semantic versioning to track model evolution
47
+ - **Automatic migrations** - Chain migrations across multiple versions (1.0.0 → 2.0.0 → 3.0.0)
48
+ - **Validated transformations** - Migrations return validated Pydantic models by default
49
+ - **Schema export** - Generate JSON schemas for all versions, with support for `$ref` to external schemas and custom schema generators
50
+ - **Nested model support** - Automatically migrates nested Pydantic models
51
+
52
+ ## Help
53
+
54
+ See [documentation](https://mferrera.github.io/pyrmute/) for more details.
55
+
56
+ ## Installation
57
+
58
+ Install using `pip install -U pyrmute`.
59
+
60
+ ## Simple Example
61
+
62
+ ```python
63
+ from pydantic import BaseModel
64
+ from pyrmute import ModelManager, MigrationData
65
+
66
+ manager = ModelManager()
67
+
68
+
69
+ @manager.model("User", "1.0.0")
70
+ class UserV1(BaseModel):
71
+ """Version 1.0.0: Initial user model."""
72
+ name: str
73
+ age: int
74
+
75
+
76
+ @manager.model("User", "2.0.0")
77
+ class UserV2(BaseModel):
78
+ """Version 2.0.0: Split name into first/last."""
79
+ first_name: str
80
+ last_name: str
81
+ age: int
82
+
83
+
84
+ @manager.model("User", "3.0.0")
85
+ class UserV3(BaseModel):
86
+ """Version 3.0.0: Add email, make age optional."""
87
+ first_name: str
88
+ last_name: str
89
+ email: str
90
+ age: int | None = None
91
+
92
+
93
+ # Define migrations
94
+ @manager.migration("User", "1.0.0", "2.0.0")
95
+ def split_name(data: MigrationData) -> MigrationData:
96
+ parts = data["name"].split(" ", 1)
97
+ return {
98
+ "first_name": parts[0],
99
+ "last_name": parts[1] if len(parts) > 1 else "",
100
+ "age": data["age"],
101
+ }
102
+
103
+
104
+ @manager.migration("User", "2.0.0", "3.0.0")
105
+ def add_email(data: MigrationData) -> MigrationData:
106
+ return {**data, "email": f"{data['first_name'].lower()}@example.com"}
107
+
108
+
109
+ # Migrate old data forward, from raw data or dumped from the Pydantic model
110
+ legacy_data = {"name": "John Doe", "age": 30}
111
+ # Returns a validated Pydantic model
112
+ current_user = manager.migrate(legacy_data, "User", "1.0.0", "3.0.0")
113
+
114
+ print(current_user)
115
+ # first_name='John' last_name='Doe' email='john@example.com' age=30
116
+
117
+ # Export schemas for all versions
118
+ manager.dump_schemas("schemas/")
119
+ # Creates: schemas/User_v1.0.0.json, schemas/User_v2.0.0.json, schemas/User_v3.0.0.json
120
+ ```
121
+
122
+ ## Contributing
123
+
124
+ For guidance on setting up a development environment and how to make a
125
+ contribution to pyrmute, see
126
+ [Contributing to pyrmute](https://mferrera.github.io/pyrmute/contributing/).
127
+
128
+ ## Reporting a Security Vulnerability
129
+
130
+ See our [security policy](https://github.com/mferrera/pyrmute/security/policy).
@@ -0,0 +1,100 @@
1
+ # pyrmute
2
+
3
+ [![ci](https://img.shields.io/github/actions/workflow/status/mferrera/pyrmute/ci.yml?branch=main&logo=github&label=ci)](https://github.com/mferrera/pyrmute/actions?query=event%3Apush+branch%3Amain+workflow%3Aci)
4
+ [![pypi](https://img.shields.io/pypi/v/pyrmute.svg)](https://pypi.python.org/pypi/pyrmute)
5
+ [![versions](https://img.shields.io/pypi/pyversions/pyrmute.svg)](https://github.com/mferrera/pyrmute)
6
+ [![license](https://img.shields.io/github/license/pyrmute/pyrmute.svg)](https://github.com/mferrera/pyrmute/blob/main/LICENSE)
7
+
8
+ Pydantic model migrations and schema management with semantic versioning.
9
+
10
+ Pyrmute helps you evolve your data models over time without breaking changes.
11
+ Version your Pydantic models, define migrations between versions, and
12
+ automatically transform legacy data to current schemas. Export JSON schemas
13
+ for all versions to maintain API contracts.
14
+
15
+ **Key features:**
16
+ - **Version your models** - Use semantic versioning to track model evolution
17
+ - **Automatic migrations** - Chain migrations across multiple versions (1.0.0 → 2.0.0 → 3.0.0)
18
+ - **Validated transformations** - Migrations return validated Pydantic models by default
19
+ - **Schema export** - Generate JSON schemas for all versions, with support for `$ref` to external schemas and custom schema generators
20
+ - **Nested model support** - Automatically migrates nested Pydantic models
21
+
22
+ ## Help
23
+
24
+ See [documentation](https://mferrera.github.io/pyrmute/) for more details.
25
+
26
+ ## Installation
27
+
28
+ Install using `pip install -U pyrmute`.
29
+
30
+ ## Simple Example
31
+
32
+ ```python
33
+ from pydantic import BaseModel
34
+ from pyrmute import ModelManager, MigrationData
35
+
36
+ manager = ModelManager()
37
+
38
+
39
+ @manager.model("User", "1.0.0")
40
+ class UserV1(BaseModel):
41
+ """Version 1.0.0: Initial user model."""
42
+ name: str
43
+ age: int
44
+
45
+
46
+ @manager.model("User", "2.0.0")
47
+ class UserV2(BaseModel):
48
+ """Version 2.0.0: Split name into first/last."""
49
+ first_name: str
50
+ last_name: str
51
+ age: int
52
+
53
+
54
+ @manager.model("User", "3.0.0")
55
+ class UserV3(BaseModel):
56
+ """Version 3.0.0: Add email, make age optional."""
57
+ first_name: str
58
+ last_name: str
59
+ email: str
60
+ age: int | None = None
61
+
62
+
63
+ # Define migrations
64
+ @manager.migration("User", "1.0.0", "2.0.0")
65
+ def split_name(data: MigrationData) -> MigrationData:
66
+ parts = data["name"].split(" ", 1)
67
+ return {
68
+ "first_name": parts[0],
69
+ "last_name": parts[1] if len(parts) > 1 else "",
70
+ "age": data["age"],
71
+ }
72
+
73
+
74
+ @manager.migration("User", "2.0.0", "3.0.0")
75
+ def add_email(data: MigrationData) -> MigrationData:
76
+ return {**data, "email": f"{data['first_name'].lower()}@example.com"}
77
+
78
+
79
+ # Migrate old data forward, from raw data or dumped from the Pydantic model
80
+ legacy_data = {"name": "John Doe", "age": 30}
81
+ # Returns a validated Pydantic model
82
+ current_user = manager.migrate(legacy_data, "User", "1.0.0", "3.0.0")
83
+
84
+ print(current_user)
85
+ # first_name='John' last_name='Doe' email='john@example.com' age=30
86
+
87
+ # Export schemas for all versions
88
+ manager.dump_schemas("schemas/")
89
+ # Creates: schemas/User_v1.0.0.json, schemas/User_v2.0.0.json, schemas/User_v3.0.0.json
90
+ ```
91
+
92
+ ## Contributing
93
+
94
+ For guidance on setting up a development environment and how to make a
95
+ contribution to pyrmute, see
96
+ [Contributing to pyrmute](https://mferrera.github.io/pyrmute/contributing/).
97
+
98
+ ## Reporting a Security Vulnerability
99
+
100
+ See our [security policy](https://github.com/mferrera/pyrmute/security/policy).
@@ -0,0 +1,133 @@
1
+ [build-system]
2
+ requires = [
3
+ "setuptools",
4
+ "setuptools_scm[toml]",
5
+ ]
6
+ build-backend = "setuptools.build_meta"
7
+
8
+ [project]
9
+ name = "pyrmute"
10
+ description = "Pydantic model migrations and schemas"
11
+ readme = "README.md"
12
+ requires-python = ">=3.11"
13
+ license = { text = "MIT" }
14
+ authors = [
15
+ { name = "Matt Ferrera", email = "mattferrera@gmail.com" },
16
+ ]
17
+ classifiers = [
18
+ "Development Status :: 3 - Alpha",
19
+ "Topic :: Utilities",
20
+ "Operating System :: POSIX :: Linux",
21
+ "Programming Language :: Python :: 3.11",
22
+ "Programming Language :: Python :: 3.12",
23
+ "Programming Language :: Python :: 3.13",
24
+ "Natural Language :: English",
25
+ ]
26
+ keywords = ["pydantic", "migration", "versioning", "schema"]
27
+ dynamic = ["version"]
28
+ dependencies = [
29
+ "pydantic",
30
+ ]
31
+
32
+ [project.optional-dependencies]
33
+ dev = [
34
+ "mypy",
35
+ "pytest",
36
+ "pytest-cov",
37
+ "pytest-mock",
38
+ "pytest-xdist",
39
+ "ruff",
40
+ ]
41
+
42
+ [project.urls]
43
+ Homepage = "https://github.com/mferrera/pyrmute"
44
+ Repository = "https://github.com/mferrera/pyrmute"
45
+ Documentation = "https://github.com/mferrera/pyrmute"
46
+
47
+ [tool.setuptools_scm]
48
+ write_to = "src/pyrmute/_version.py"
49
+
50
+ [tool.coverage.run]
51
+ omit = [
52
+ "_version.py",
53
+ ]
54
+
55
+ [tool.coverage.report]
56
+ exclude_lines = [
57
+ "pragma: no cover",
58
+ "def __repr__",
59
+ "raise AssertionError",
60
+ "raise NotImplementedError",
61
+ "if __name__ == .__main__.:",
62
+ "if TYPE_CHECKING:",
63
+ ]
64
+
65
+ [tool.mypy]
66
+ check_untyped_defs = true
67
+ disallow_any_generics = true
68
+ disallow_incomplete_defs = true
69
+ disallow_untyped_decorators = true
70
+ disallow_untyped_defs = true
71
+ disallow_untyped_calls = true
72
+ disallow_subclassing_any = true
73
+ extra_checks = true
74
+ strict_equality = true
75
+ warn_redundant_casts = true
76
+ warn_unused_configs = true
77
+ warn_unused_ignores = true
78
+ warn_return_any = true
79
+ warn_unreachable = true
80
+ no_implicit_reexport = true
81
+ strict_optional = true
82
+ disallow_any_unimported = true
83
+ no_implicit_optional = true
84
+ show_error_codes = true
85
+ show_column_numbers = true
86
+ pretty = true
87
+
88
+ [tool.pytest.ini_options]
89
+ addopts = "-n auto --cov src/ --cov-report term-missing"
90
+ norecursedirs = [
91
+ ".git",
92
+ ".tox",
93
+ ".env",
94
+ ".venv",
95
+ "dist",
96
+ "build",
97
+ ]
98
+ testpaths = ["tests"]
99
+
100
+ [tool.ruff]
101
+ line-length = 88
102
+ exclude = ["_version.py"]
103
+
104
+ [tool.ruff.lint]
105
+ select = [
106
+ "B", # flake-8-bugbear
107
+ "C", # pylint-convention
108
+ "C90", # mccabe
109
+ "D", # pydocstyle
110
+ "E", # pycodestyle-error
111
+ "F", # pyflakes
112
+ "G", # logging-format
113
+ "I", # isort
114
+ "LOG", # logging
115
+ "NPY", # numpy
116
+ "PIE", # flake8-pie
117
+ "PL", # pylint
118
+ "Q", # flake8-quotes
119
+ "RET", # flake8-return
120
+ "RSE", # flake8-raise
121
+ "RUF", # ruff rules
122
+ "SIM", # flake8-simplify
123
+ "TCH", # flake8-type-checking
124
+ "TID", # flake8-tidy-imports
125
+ "UP", # pyupgrade
126
+ "W", # pylint-warnings
127
+ ]
128
+
129
+ [tool.ruff.lint.isort]
130
+ combine-as-imports = true
131
+
132
+ [tool.ruff.lint.pydocstyle]
133
+ convention = "google"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,20 @@
1
+ """pyrmute - versioned Pydantic models and schemas with migrations.
2
+
3
+ A package for managing versioned Pydantic models with automatic migrations
4
+ and schema management.
5
+ """
6
+
7
+ from ._version import __version__
8
+ from .model_manager import ModelManager
9
+ from .model_version import ModelVersion
10
+ from .types import JsonSchema, MigrationData, MigrationFunc, ModelMetadata
11
+
12
+ __all__ = [
13
+ "JsonSchema",
14
+ "MigrationData",
15
+ "MigrationFunc",
16
+ "ModelManager",
17
+ "ModelMetadata",
18
+ "ModelVersion",
19
+ "__version__",
20
+ ]