sqlcrucible 0.2.1__tar.gz → 0.2.2__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.
Files changed (88) hide show
  1. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/.github/workflows/docs.yml +17 -6
  2. sqlcrucible-0.2.2/PKG-INFO +81 -0
  3. sqlcrucible-0.2.2/README.md +63 -0
  4. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/src/sqlcrucible/_version.py +2 -2
  5. sqlcrucible-0.2.1/PKG-INFO +0 -673
  6. sqlcrucible-0.2.1/README.md +0 -655
  7. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/.github/workflows/ci.yml +0 -0
  8. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/.gitignore +0 -0
  9. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/.python-version +0 -0
  10. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/LICENSE +0 -0
  11. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/docs/comparison.md +0 -0
  12. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/docs/getting-started.md +0 -0
  13. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/docs/guide/advanced.md +0 -0
  14. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/docs/guide/defining-entities.md +0 -0
  15. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/docs/guide/field-mapping.md +0 -0
  16. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/docs/guide/inheritance.md +0 -0
  17. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/docs/guide/relationships.md +0 -0
  18. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/docs/guide/type-conversion.md +0 -0
  19. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/docs/index.md +0 -0
  20. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/docs/reference/api.md +0 -0
  21. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/mkdocs.yml +0 -0
  22. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/noxfile.py +0 -0
  23. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/pyproject.toml +0 -0
  24. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/src/sqlcrucible/__init__.py +0 -0
  25. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/src/sqlcrucible/conversion/__init__.py +0 -0
  26. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/src/sqlcrucible/conversion/dicts.py +0 -0
  27. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/src/sqlcrucible/conversion/exceptions.py +0 -0
  28. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/src/sqlcrucible/conversion/function.py +0 -0
  29. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/src/sqlcrucible/conversion/literals.py +0 -0
  30. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/src/sqlcrucible/conversion/noop.py +0 -0
  31. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/src/sqlcrucible/conversion/registry.py +0 -0
  32. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/src/sqlcrucible/conversion/sequences.py +0 -0
  33. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/src/sqlcrucible/conversion/unions.py +0 -0
  34. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/src/sqlcrucible/entity/__init__.py +0 -0
  35. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/src/sqlcrucible/entity/annotations.py +0 -0
  36. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/src/sqlcrucible/entity/automodel.py +0 -0
  37. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/src/sqlcrucible/entity/core.py +0 -0
  38. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/src/sqlcrucible/entity/field_metadata.py +0 -0
  39. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/src/sqlcrucible/entity/field_resolution.py +0 -0
  40. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/src/sqlcrucible/entity/fields.py +0 -0
  41. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/src/sqlcrucible/entity/sa_conversion.py +0 -0
  42. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/src/sqlcrucible/entity/sa_type.py +0 -0
  43. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/src/sqlcrucible/stubs/__init__.py +0 -0
  44. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/src/sqlcrucible/stubs/__main__.py +0 -0
  45. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/src/sqlcrucible/utils/__init__.py +0 -0
  46. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/src/sqlcrucible/utils/collections.py +0 -0
  47. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/src/sqlcrucible/utils/properties.py +0 -0
  48. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/src/sqlcrucible/utils/sa_fields.py +0 -0
  49. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/src/sqlcrucible/utils/types/__init__.py +0 -0
  50. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/src/sqlcrucible/utils/types/annotations.py +0 -0
  51. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/src/sqlcrucible/utils/types/equivalence.py +0 -0
  52. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/src/sqlcrucible/utils/types/forward_refs.py +0 -0
  53. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/src/sqlcrucible/utils/types/match.py +0 -0
  54. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/src/sqlcrucible/utils/types/params.py +0 -0
  55. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/src/sqlcrucible/utils/types/transformer.py +0 -0
  56. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/tests/__init__.py +0 -0
  57. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/tests/conversion/__init__.py +0 -0
  58. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/tests/conversion/conftest.py +0 -0
  59. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/tests/conversion/test_dicts.py +0 -0
  60. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/tests/conversion/test_literals.py +0 -0
  61. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/tests/conversion/test_noop.py +0 -0
  62. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/tests/conversion/test_registry.py +0 -0
  63. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/tests/conversion/test_sequences.py +0 -0
  64. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/tests/conversion/test_unions.py +0 -0
  65. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/tests/entity/__init__.py +0 -0
  66. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/tests/entity/test_attrs_entity.py +0 -0
  67. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/tests/entity/test_concrete_table_inheritance.py +0 -0
  68. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/tests/entity/test_custom_sa_model.py +0 -0
  69. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/tests/entity/test_dataclass_entity.py +0 -0
  70. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/tests/entity/test_joined_table_inheritance.py +0 -0
  71. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/tests/entity/test_pydantic_entity.py +0 -0
  72. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/tests/entity/test_relationships_back_populates.py +0 -0
  73. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/tests/entity/test_relationships_cycles.py +0 -0
  74. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/tests/entity/test_relationships_eager.py +0 -0
  75. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/tests/entity/test_relationships_many_to_many.py +0 -0
  76. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/tests/entity/test_relationships_one_to_many_child.py +0 -0
  77. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/tests/entity/test_relationships_one_to_many_parent.py +0 -0
  78. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/tests/entity/test_relationships_one_to_one.py +0 -0
  79. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/tests/entity/test_relationships_self_referential.py +0 -0
  80. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/tests/entity/test_sa_type.py +0 -0
  81. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/tests/entity/test_single_table_inheritance.py +0 -0
  82. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/tests/stubs/__init__.py +0 -0
  83. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/tests/stubs/sample_models.py +0 -0
  84. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/tests/stubs/test_stub_typecheck.py +0 -0
  85. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/tests/utils/types/test_annotations.py +0 -0
  86. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/tests/utils/types/test_forward_refs.py +0 -0
  87. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/tests/utils/types/test_params.py +0 -0
  88. {sqlcrucible-0.2.1 → sqlcrucible-0.2.2}/uv.lock +0 -0
@@ -5,13 +5,20 @@ on:
5
5
  tags: ["*"]
6
6
  workflow_dispatch:
7
7
  inputs:
8
+ action:
9
+ description: "Action to perform"
10
+ type: choice
11
+ options:
12
+ - deploy
13
+ - delete
14
+ default: deploy
8
15
  version:
9
- description: "Version to deploy (e.g., 0.1.0)"
16
+ description: "Version to deploy or delete (e.g., 0.1.0, pr-123)"
10
17
  required: true
11
18
  latest:
12
- description: "Update 'latest' alias"
19
+ description: "Update 'latest' alias (deploy only)"
13
20
  type: boolean
14
- default: true
21
+ default: false
15
22
 
16
23
  permissions:
17
24
  contents: write
@@ -21,7 +28,7 @@ concurrency:
21
28
  cancel-in-progress: false
22
29
 
23
30
  jobs:
24
- deploy:
31
+ docs:
25
32
  runs-on: ubuntu-latest
26
33
  steps:
27
34
  - uses: actions/checkout@v4
@@ -36,16 +43,20 @@ jobs:
36
43
  git config user.name "github-actions[bot]"
37
44
  git config user.email "github-actions[bot]@users.noreply.github.com"
38
45
 
39
- - name: Deploy docs
46
+ - name: Deploy or delete docs
40
47
  run: |
41
48
  if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
42
49
  VERSION="${{ github.event.inputs.version }}"
43
- if [ "${{ github.event.inputs.latest }}" = "true" ]; then
50
+ if [ "${{ github.event.inputs.action }}" = "delete" ]; then
51
+ uv run --group docs mike delete --push "$VERSION"
52
+ elif [ "${{ github.event.inputs.latest }}" = "true" ]; then
44
53
  uv run --group docs mike deploy --push --update-aliases "$VERSION" latest
54
+ uv run --group docs mike set-default --push latest
45
55
  else
46
56
  uv run --group docs mike deploy --push "$VERSION"
47
57
  fi
48
58
  else
49
59
  VERSION="${GITHUB_REF#refs/tags/}"
50
60
  uv run --group docs mike deploy --push --update-aliases "$VERSION" latest
61
+ uv run --group docs mike set-default --push latest
51
62
  fi
@@ -0,0 +1,81 @@
1
+ Metadata-Version: 2.4
2
+ Name: sqlcrucible
3
+ Version: 0.2.2
4
+ Summary: Add your description here
5
+ Author-email: Richard Rae-Jones <sqlcrucible@richard.rdrj.uk>
6
+ License-Expression: MIT
7
+ License-File: LICENSE
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Classifier: Programming Language :: Python :: 3.11
10
+ Classifier: Programming Language :: Python :: 3.12
11
+ Classifier: Programming Language :: Python :: 3.13
12
+ Classifier: Programming Language :: Python :: 3.14
13
+ Requires-Python: >=3.11
14
+ Requires-Dist: pydantic~=2.10
15
+ Requires-Dist: sqlalchemy~=2.0
16
+ Requires-Dist: typing-extensions~=4.15
17
+ Description-Content-Type: text/markdown
18
+
19
+ # SQLCrucible
20
+
21
+ Get the full power of Pydantic for your API and the full power of SQLAlchemy for your database, without compromising on either.
22
+
23
+ SQLCrucible lets you define a single model class that works as both a Pydantic model and a SQLAlchemy table, with explicit conversion between the two. Your Pydantic models stay pure Pydantic (working with FastAPI, validation, serialization), your SQLAlchemy models stay pure SQLAlchemy (supporting relationships, inheritance, Alembic), and conversion only happens when you ask for it.
24
+
25
+ ## Key Features
26
+
27
+ - **Explicit conversion** — `to_sa_model()` and `from_sa_model()` make it clear when you're crossing the boundary between Pydantic and SQLAlchemy
28
+ - **Native SQLAlchemy** — use `mapped_column()`, `relationship()`, and `__mapper_args__` directly; if SQLAlchemy supports it, so does SQLCrucible
29
+ - **Escape hatches everywhere** — mix with plain SQLAlchemy models, attach entities to existing tables, customize generated models, or drop down to raw queries
30
+ - **Full inheritance support** — single table, joined table, and concrete table inheritance all work out of the box
31
+ - **Type stub generation** — generate `.pyi` stubs for IDE autocompletion and type checking of SQLAlchemy columns
32
+ - **Multiple frameworks** — works with Pydantic, dataclasses, and attrs
33
+
34
+ ## Example
35
+
36
+ ```python
37
+ from typing import Annotated
38
+ from uuid import UUID, uuid4
39
+
40
+ from pydantic import Field
41
+ from sqlalchemy import create_engine, select
42
+ from sqlalchemy.orm import Session, mapped_column
43
+
44
+ from sqlcrucible import SAType, SQLCrucibleBaseModel
45
+
46
+ class Artist(SQLCrucibleBaseModel):
47
+ __sqlalchemy_params__ = {"__tablename__": "artist"}
48
+
49
+ id: Annotated[UUID, mapped_column(primary_key=True)] = Field(default_factory=uuid4)
50
+ name: str
51
+
52
+ engine = create_engine("sqlite:///:memory:")
53
+ SAType[Artist].__table__.metadata.create_all(engine)
54
+
55
+ artist = Artist(name="Bob Dylan")
56
+ with Session(engine) as session:
57
+ session.add(artist.to_sa_model())
58
+ session.commit()
59
+
60
+ with Session(engine) as session:
61
+ sa_artist = session.scalar(
62
+ select(SAType[Artist]).where(SAType[Artist].name == "Bob Dylan")
63
+ )
64
+ artist = Artist.from_sa_model(sa_artist)
65
+ ```
66
+
67
+ ## Installation
68
+
69
+ ```bash
70
+ pip install sqlcrucible
71
+ ```
72
+
73
+ ## Documentation
74
+
75
+ Full documentation is available at [sqlcrucible.rdrj.uk](https://sqlcrucible.rdrj.uk/).
76
+
77
+ ---
78
+
79
+ <p align="center">
80
+ 🏴󠁧󠁢󠁳󠁣󠁴󠁿 Made with haggis
81
+ </p>
@@ -0,0 +1,63 @@
1
+ # SQLCrucible
2
+
3
+ Get the full power of Pydantic for your API and the full power of SQLAlchemy for your database, without compromising on either.
4
+
5
+ SQLCrucible lets you define a single model class that works as both a Pydantic model and a SQLAlchemy table, with explicit conversion between the two. Your Pydantic models stay pure Pydantic (working with FastAPI, validation, serialization), your SQLAlchemy models stay pure SQLAlchemy (supporting relationships, inheritance, Alembic), and conversion only happens when you ask for it.
6
+
7
+ ## Key Features
8
+
9
+ - **Explicit conversion** — `to_sa_model()` and `from_sa_model()` make it clear when you're crossing the boundary between Pydantic and SQLAlchemy
10
+ - **Native SQLAlchemy** — use `mapped_column()`, `relationship()`, and `__mapper_args__` directly; if SQLAlchemy supports it, so does SQLCrucible
11
+ - **Escape hatches everywhere** — mix with plain SQLAlchemy models, attach entities to existing tables, customize generated models, or drop down to raw queries
12
+ - **Full inheritance support** — single table, joined table, and concrete table inheritance all work out of the box
13
+ - **Type stub generation** — generate `.pyi` stubs for IDE autocompletion and type checking of SQLAlchemy columns
14
+ - **Multiple frameworks** — works with Pydantic, dataclasses, and attrs
15
+
16
+ ## Example
17
+
18
+ ```python
19
+ from typing import Annotated
20
+ from uuid import UUID, uuid4
21
+
22
+ from pydantic import Field
23
+ from sqlalchemy import create_engine, select
24
+ from sqlalchemy.orm import Session, mapped_column
25
+
26
+ from sqlcrucible import SAType, SQLCrucibleBaseModel
27
+
28
+ class Artist(SQLCrucibleBaseModel):
29
+ __sqlalchemy_params__ = {"__tablename__": "artist"}
30
+
31
+ id: Annotated[UUID, mapped_column(primary_key=True)] = Field(default_factory=uuid4)
32
+ name: str
33
+
34
+ engine = create_engine("sqlite:///:memory:")
35
+ SAType[Artist].__table__.metadata.create_all(engine)
36
+
37
+ artist = Artist(name="Bob Dylan")
38
+ with Session(engine) as session:
39
+ session.add(artist.to_sa_model())
40
+ session.commit()
41
+
42
+ with Session(engine) as session:
43
+ sa_artist = session.scalar(
44
+ select(SAType[Artist]).where(SAType[Artist].name == "Bob Dylan")
45
+ )
46
+ artist = Artist.from_sa_model(sa_artist)
47
+ ```
48
+
49
+ ## Installation
50
+
51
+ ```bash
52
+ pip install sqlcrucible
53
+ ```
54
+
55
+ ## Documentation
56
+
57
+ Full documentation is available at [sqlcrucible.rdrj.uk](https://sqlcrucible.rdrj.uk/).
58
+
59
+ ---
60
+
61
+ <p align="center">
62
+ 🏴󠁧󠁢󠁳󠁣󠁴󠁿 Made with haggis
63
+ </p>
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '0.2.1'
32
- __version_tuple__ = version_tuple = (0, 2, 1)
31
+ __version__ = version = '0.2.2'
32
+ __version_tuple__ = version_tuple = (0, 2, 2)
33
33
 
34
34
  __commit_id__ = commit_id = None