runic-py 0.2.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.
Files changed (47) hide show
  1. runic_py-0.2.0/.gitignore +117 -0
  2. runic_py-0.2.0/LICENSE.md +21 -0
  3. runic_py-0.2.0/PKG-INFO +192 -0
  4. runic_py-0.2.0/README.md +171 -0
  5. runic_py-0.2.0/pyproject.toml +267 -0
  6. runic_py-0.2.0/runic/__init__.py +13 -0
  7. runic_py-0.2.0/runic/migrate/__init__.py +27 -0
  8. runic_py-0.2.0/runic/migrate/adapters/__init__.py +129 -0
  9. runic_py-0.2.0/runic/migrate/adapters/falkordb.py +353 -0
  10. runic_py-0.2.0/runic/migrate/autogen.py +242 -0
  11. runic_py-0.2.0/runic/migrate/checksum.py +14 -0
  12. runic_py-0.2.0/runic/migrate/cli.py +880 -0
  13. runic_py-0.2.0/runic/migrate/config.py +8 -0
  14. runic_py-0.2.0/runic/migrate/context.py +526 -0
  15. runic_py-0.2.0/runic/migrate/exceptions.py +18 -0
  16. runic_py-0.2.0/runic/migrate/introspect.py +556 -0
  17. runic_py-0.2.0/runic/migrate/manifest.py +81 -0
  18. runic_py-0.2.0/runic/migrate/operations.py +173 -0
  19. runic_py-0.2.0/runic/migrate/script.py +452 -0
  20. runic_py-0.2.0/runic/migrate/service.py +27 -0
  21. runic_py-0.2.0/runic/migrate/templates/env.py.mako +86 -0
  22. runic_py-0.2.0/runic/migrate/templates/script.py.mako +27 -0
  23. runic_py-0.2.0/runic/migrate/testing.py +48 -0
  24. runic_py-0.2.0/runic/migrate/version.py +38 -0
  25. runic_py-0.2.0/runic/orm/__init__.py +82 -0
  26. runic_py-0.2.0/runic/orm/core/__init__.py +0 -0
  27. runic_py-0.2.0/runic/orm/core/descriptors.py +305 -0
  28. runic_py-0.2.0/runic/orm/core/metadata.py +216 -0
  29. runic_py-0.2.0/runic/orm/core/models.py +312 -0
  30. runic_py-0.2.0/runic/orm/core/types.py +158 -0
  31. runic_py-0.2.0/runic/orm/exceptions.py +30 -0
  32. runic_py-0.2.0/runic/orm/mapper/__init__.py +0 -0
  33. runic_py-0.2.0/runic/orm/mapper/mapper.py +361 -0
  34. runic_py-0.2.0/runic/orm/mapper/relationship_loader.py +251 -0
  35. runic_py-0.2.0/runic/orm/repository/__init__.py +12 -0
  36. runic_py-0.2.0/runic/orm/repository/async_repository.py +180 -0
  37. runic_py-0.2.0/runic/orm/repository/cypher.py +67 -0
  38. runic_py-0.2.0/runic/orm/repository/pagination.py +105 -0
  39. runic_py-0.2.0/runic/orm/repository/protocol.py +91 -0
  40. runic_py-0.2.0/runic/orm/repository/repository.py +190 -0
  41. runic_py-0.2.0/runic/orm/schema/__init__.py +11 -0
  42. runic_py-0.2.0/runic/orm/schema/index_manager.py +195 -0
  43. runic_py-0.2.0/runic/orm/schema/schema_manager.py +173 -0
  44. runic_py-0.2.0/runic/orm/session/__init__.py +0 -0
  45. runic_py-0.2.0/runic/orm/session/async_session.py +340 -0
  46. runic_py-0.2.0/runic/orm/session/connection_pool.py +56 -0
  47. runic_py-0.2.0/runic/orm/session/session.py +385 -0
@@ -0,0 +1,117 @@
1
+ __pycache__/
2
+ __pypackages__/
3
+ .cache
4
+ .coverage
5
+ .coverage.*
6
+ .dmypy.json
7
+ .DS_Store
8
+ .eggs/
9
+ .env
10
+ .env.backup
11
+ .env.docker
12
+ .hypothesis/
13
+ .idea/
14
+ .installed.cfg
15
+ .ipynb_checkpoints
16
+ .mypy_cache/
17
+ .nox/
18
+ .pdm.toml
19
+ .pybuilder/
20
+ .pyre/
21
+ .pytest_cache/
22
+ .Python
23
+ .python_packages
24
+ .pytype/
25
+ .ropeproject
26
+ .scrapy
27
+ .spyderproject
28
+ .spyproject
29
+ .states
30
+ .tox/
31
+ .venv
32
+ .venv.mac
33
+ .web
34
+ .webassets-cache
35
+ *.bak
36
+ *.cover
37
+ *.db
38
+ *.egg
39
+ *.egg-info/
40
+ *.kv-env.*
41
+ *.log
42
+ *.manifest
43
+ *.mo
44
+ *.pot
45
+ *.py,cover
46
+ *.py[cod]
47
+ *.sage.py
48
+ *.so
49
+ *.spec
50
+ *.terraform.lock.hcl
51
+ *.tfplan
52
+ *.tfstate
53
+ *.tfstate.*.backup
54
+ *.tfstate.backup
55
+ *.tfvars
56
+ **/.terraform/*
57
+ *$py.class
58
+ /site
59
+ /vectorstore/
60
+ aila-storage/
61
+ assets/external/
62
+ build/
63
+ celerybeat-schedule
64
+ celerybeat.pid
65
+ configuration/config.abaz009.yaml
66
+ configuration/config.bubb001.yaml
67
+ configuration/config.stie104.yaml
68
+ configuration/config.voro047.yaml
69
+ connector examples/sharepoint.json
70
+ cover/
71
+ coverage.xml
72
+ cython_debug/
73
+ db.sqlite3
74
+ db.sqlite3-journal
75
+ develop-eggs/
76
+ dist/
77
+ dmypy.json
78
+ docs/_build/
79
+ Documents/
80
+ downloads/
81
+ eggs/
82
+ env.bak/
83
+ env/
84
+ ENV/
85
+ htmlcov/
86
+ instance/
87
+ ipython_config.py
88
+ knowledge/migrate.py
89
+ lib/
90
+ lib64/
91
+ local_settings.py
92
+ local.settings.json
93
+ MANIFEST
94
+ nosetests.xml
95
+ out
96
+ parts/
97
+ pip-delete-this-directory.txt
98
+ pip-log.txt
99
+ Pipfile
100
+ profile_default/
101
+ sdist/
102
+ share/python-wheels/
103
+ sketchpad/
104
+ sketchpad/
105
+ stores/
106
+ target/
107
+ tests/mcp_test.py
108
+ tmp.txt
109
+ uploaded_files/
110
+ uploads/
111
+ var/
112
+ venv.bak/
113
+ venv/
114
+ wheels/
115
+ .task/
116
+ .runic
117
+ runic_test/
@@ -0,0 +1,21 @@
1
+ # MIT License
2
+
3
+ Copyright (c) 2025 Jens Rehpöhler
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.
@@ -0,0 +1,192 @@
1
+ Metadata-Version: 2.4
2
+ Name: runic-py
3
+ Version: 0.2.0
4
+ Summary: Graph schema migrations for FalkorDB.
5
+ Project-URL: Homepage, https://runic-py.readthedocs.io/latest/
6
+ Project-URL: Repository, https://github.com/jenreh/runic
7
+ Author: Jens Rehpöhler
8
+ License: MIT
9
+ License-File: LICENSE.md
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3 :: Only
14
+ Classifier: Topic :: Home Automation
15
+ Requires-Python: >=3.14
16
+ Requires-Dist: falkordb<2.0.0,>=1.6.0
17
+ Requires-Dist: mako<2.0.0,>=1.3.0
18
+ Requires-Dist: rich<16.0.0,>=15.0.0
19
+ Requires-Dist: typer<1.0.0,>=0.26.0
20
+ Description-Content-Type: text/markdown
21
+
22
+ <div align="center">
23
+ <img src="docs/source/_static/runic.svg" width="240" alt="Runic logo">
24
+
25
+ # Runic
26
+
27
+ **Graph schema migrations for FalkorDB.**
28
+
29
+ ![Version](https://img.shields.io/badge/version-0.2.0-blue)
30
+ [![Python](https://img.shields.io/badge/python-3.14%2B-orange)](https://www.python.org)
31
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green)](LICENSE.md)
32
+
33
+ [Features](#features) • [Installation](#installation) • [A Simple Example](#a-simple-example) • [Documentation](#documentation)
34
+
35
+ </div>
36
+
37
+ ---
38
+
39
+ **Runic** is a lightweight, Alembic-style migration framework built specifically for [FalkorDB](https://falkordb.com/).
40
+ It brings robust revision tracking, linear graph migrations, and a powerful CLI to graph database environments, managing schema versioning through Cypher scripts and native FalkorDB syntax.
41
+
42
+ ## Features
43
+
44
+ - **Alembic-Style Workflow** — Familiar CLI verbs like `init`, `revision`, `upgrade`, `downgrade`, and `current`.
45
+ - **Graph-Native** — Treats your database as a graph. Stores migration states intelligently inside dedicated nodes (e.g., `:_FalkorMigrateVersion`).
46
+ - **Idempotent Cypher** — Encourages explicit, heavily-guarded migration steps, supporting robust backward capability even without transactional DDLs.
47
+ - **Offline & Dry Run** — Review generated Cypher scripts thoroughly before executing them in production.
48
+ - **Rollback Snapshots** — Advanced capabilities utilizing `GRAPH.COPY` for high-risk, non-reversible data migrations.
49
+
50
+ ## Installation
51
+
52
+ Install via `pip` or `uv`:
53
+
54
+ ```bash
55
+ uv pip install runic
56
+ ```
57
+
58
+ Or add it to an existing project:
59
+
60
+ ```bash
61
+ uv add runic
62
+ ```
63
+
64
+ > [!NOTE]
65
+ > Runic requires Python 3.14+ and is optimized for the latest FalkorDB clients.
66
+
67
+ ## A Simple Example
68
+
69
+ Initialize your project and generate a new revision:
70
+
71
+ ```bash
72
+ # Set up a new runic environment
73
+ runic init
74
+
75
+ # Create your first revision script
76
+ runic revision -m "create user index"
77
+ ```
78
+
79
+ This generates a revision file in `runic/versions`. Open it and define your upgrades and downgrades:
80
+
81
+ ```python
82
+ """create user index
83
+
84
+ Revision ID: 1975ea83b712
85
+ Revises: None
86
+ Create Date: 2026-05-30 14:00:00.000000
87
+ """
88
+
89
+ from datetime import UTC, datetime
90
+
91
+ revision = "1975ea83b712"
92
+ down_revision = None
93
+ message = "create user index"
94
+ create_date = datetime.fromisoformat("2026-05-30T14:00:00+00:00")
95
+ branch_labels = []
96
+ depends_on = []
97
+ irreversible = False
98
+ snapshot = False
99
+
100
+
101
+ def upgrade(op) -> None:
102
+ op.create_range_index("User", "email")
103
+
104
+
105
+ def downgrade(op) -> None:
106
+ op.drop_range_index("User", "email")
107
+ ```
108
+
109
+ Then apply your changes:
110
+
111
+ ```bash
112
+ runic upgrade # apply all pending revisions
113
+ runic downgrade # roll back one step (default target: -1)
114
+ runic downgrade 1975e # roll back to a revision — prefix is enough
115
+ ```
116
+
117
+ ## Baselining an existing graph
118
+
119
+ If you have a FalkorDB graph that was built without Runic, use `baseline` to bring it under management without re-running anything on the source:
120
+
121
+ ```bash
122
+ # Introspect the live graph, generate a root revision, and stamp it as applied
123
+ runic baseline -m "baseline"
124
+ # Generated: runic/versions/<hex>_baseline.py
125
+ # Stamped: <hex>
126
+
127
+ # Verify the graph is now tracked
128
+ runic current
129
+ # <hex> baseline
130
+ ```
131
+
132
+ The generated revision recreates all indexes and constraints from scratch — safe to replay on a fresh empty graph (CI, cloning, new tenants):
133
+
134
+ ```bash
135
+ runic upgrade head # rebuilds the full schema on an empty graph
136
+ ```
137
+
138
+ Re-running `baseline` on an already-managed graph is refused:
139
+
140
+ ```bash
141
+ runic baseline -m "again"
142
+ # Error: Graph already managed by runic.migrate. Use `runic upgrade` instead.
143
+ ```
144
+
145
+ To mark an existing graph as baselined without generating a file (useful when you manage the revision file yourself):
146
+
147
+ ```bash
148
+ runic baseline --stamp-only
149
+ ```
150
+
151
+ ### Baseline → autogenerate workflow
152
+
153
+ Once you have a baseline revision, use the standard autogenerate workflow to evolve the schema:
154
+
155
+ ```bash
156
+ # After changing your SchemaManifest in env.py:
157
+ runic revision --autogenerate -m "add embedding index"
158
+ runic upgrade head
159
+ ```
160
+
161
+ The baseline revision is the root of the chain (`down_revision = None`). Future revisions chain off it normally.
162
+
163
+ ## Programmatic SDK
164
+
165
+ Use runic directly in Python — no CLI, no `env.py` needed:
166
+
167
+ ```python
168
+ from pathlib import Path
169
+ from runic import Runic, init
170
+ from runic.migrate.adapters import create_adapter
171
+
172
+ # One-time setup: scaffold the migration directory
173
+ init(Path("runic/"))
174
+
175
+ # Connect and run
176
+ adapter = create_adapter(
177
+ "falkordb",
178
+ url="falkor://localhost:6379",
179
+ graph_name="my_graph",
180
+ )
181
+ runic = Runic(adapter, script_location=Path("runic/"))
182
+ runic.migrate.upgrade("head")
183
+
184
+ print("current:", runic.migrate.current())
185
+ print("history:", runic.migrate.get_history())
186
+ ```
187
+
188
+ `Runic` is the single class you need. It handles upgrades, downgrades, stamping, history queries, and revision creation in one coherent API.
189
+
190
+ ## Documentation
191
+
192
+ For a full conceptual overview, advanced CLI usage, and deep dives into branching or multi-head resolution, visit the complete [Runic Documentation](https://runic-py.readthedocs.io/latest/).
@@ -0,0 +1,171 @@
1
+ <div align="center">
2
+ <img src="docs/source/_static/runic.svg" width="240" alt="Runic logo">
3
+
4
+ # Runic
5
+
6
+ **Graph schema migrations for FalkorDB.**
7
+
8
+ ![Version](https://img.shields.io/badge/version-0.2.0-blue)
9
+ [![Python](https://img.shields.io/badge/python-3.14%2B-orange)](https://www.python.org)
10
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green)](LICENSE.md)
11
+
12
+ [Features](#features) • [Installation](#installation) • [A Simple Example](#a-simple-example) • [Documentation](#documentation)
13
+
14
+ </div>
15
+
16
+ ---
17
+
18
+ **Runic** is a lightweight, Alembic-style migration framework built specifically for [FalkorDB](https://falkordb.com/).
19
+ It brings robust revision tracking, linear graph migrations, and a powerful CLI to graph database environments, managing schema versioning through Cypher scripts and native FalkorDB syntax.
20
+
21
+ ## Features
22
+
23
+ - **Alembic-Style Workflow** — Familiar CLI verbs like `init`, `revision`, `upgrade`, `downgrade`, and `current`.
24
+ - **Graph-Native** — Treats your database as a graph. Stores migration states intelligently inside dedicated nodes (e.g., `:_FalkorMigrateVersion`).
25
+ - **Idempotent Cypher** — Encourages explicit, heavily-guarded migration steps, supporting robust backward capability even without transactional DDLs.
26
+ - **Offline & Dry Run** — Review generated Cypher scripts thoroughly before executing them in production.
27
+ - **Rollback Snapshots** — Advanced capabilities utilizing `GRAPH.COPY` for high-risk, non-reversible data migrations.
28
+
29
+ ## Installation
30
+
31
+ Install via `pip` or `uv`:
32
+
33
+ ```bash
34
+ uv pip install runic
35
+ ```
36
+
37
+ Or add it to an existing project:
38
+
39
+ ```bash
40
+ uv add runic
41
+ ```
42
+
43
+ > [!NOTE]
44
+ > Runic requires Python 3.14+ and is optimized for the latest FalkorDB clients.
45
+
46
+ ## A Simple Example
47
+
48
+ Initialize your project and generate a new revision:
49
+
50
+ ```bash
51
+ # Set up a new runic environment
52
+ runic init
53
+
54
+ # Create your first revision script
55
+ runic revision -m "create user index"
56
+ ```
57
+
58
+ This generates a revision file in `runic/versions`. Open it and define your upgrades and downgrades:
59
+
60
+ ```python
61
+ """create user index
62
+
63
+ Revision ID: 1975ea83b712
64
+ Revises: None
65
+ Create Date: 2026-05-30 14:00:00.000000
66
+ """
67
+
68
+ from datetime import UTC, datetime
69
+
70
+ revision = "1975ea83b712"
71
+ down_revision = None
72
+ message = "create user index"
73
+ create_date = datetime.fromisoformat("2026-05-30T14:00:00+00:00")
74
+ branch_labels = []
75
+ depends_on = []
76
+ irreversible = False
77
+ snapshot = False
78
+
79
+
80
+ def upgrade(op) -> None:
81
+ op.create_range_index("User", "email")
82
+
83
+
84
+ def downgrade(op) -> None:
85
+ op.drop_range_index("User", "email")
86
+ ```
87
+
88
+ Then apply your changes:
89
+
90
+ ```bash
91
+ runic upgrade # apply all pending revisions
92
+ runic downgrade # roll back one step (default target: -1)
93
+ runic downgrade 1975e # roll back to a revision — prefix is enough
94
+ ```
95
+
96
+ ## Baselining an existing graph
97
+
98
+ If you have a FalkorDB graph that was built without Runic, use `baseline` to bring it under management without re-running anything on the source:
99
+
100
+ ```bash
101
+ # Introspect the live graph, generate a root revision, and stamp it as applied
102
+ runic baseline -m "baseline"
103
+ # Generated: runic/versions/<hex>_baseline.py
104
+ # Stamped: <hex>
105
+
106
+ # Verify the graph is now tracked
107
+ runic current
108
+ # <hex> baseline
109
+ ```
110
+
111
+ The generated revision recreates all indexes and constraints from scratch — safe to replay on a fresh empty graph (CI, cloning, new tenants):
112
+
113
+ ```bash
114
+ runic upgrade head # rebuilds the full schema on an empty graph
115
+ ```
116
+
117
+ Re-running `baseline` on an already-managed graph is refused:
118
+
119
+ ```bash
120
+ runic baseline -m "again"
121
+ # Error: Graph already managed by runic.migrate. Use `runic upgrade` instead.
122
+ ```
123
+
124
+ To mark an existing graph as baselined without generating a file (useful when you manage the revision file yourself):
125
+
126
+ ```bash
127
+ runic baseline --stamp-only
128
+ ```
129
+
130
+ ### Baseline → autogenerate workflow
131
+
132
+ Once you have a baseline revision, use the standard autogenerate workflow to evolve the schema:
133
+
134
+ ```bash
135
+ # After changing your SchemaManifest in env.py:
136
+ runic revision --autogenerate -m "add embedding index"
137
+ runic upgrade head
138
+ ```
139
+
140
+ The baseline revision is the root of the chain (`down_revision = None`). Future revisions chain off it normally.
141
+
142
+ ## Programmatic SDK
143
+
144
+ Use runic directly in Python — no CLI, no `env.py` needed:
145
+
146
+ ```python
147
+ from pathlib import Path
148
+ from runic import Runic, init
149
+ from runic.migrate.adapters import create_adapter
150
+
151
+ # One-time setup: scaffold the migration directory
152
+ init(Path("runic/"))
153
+
154
+ # Connect and run
155
+ adapter = create_adapter(
156
+ "falkordb",
157
+ url="falkor://localhost:6379",
158
+ graph_name="my_graph",
159
+ )
160
+ runic = Runic(adapter, script_location=Path("runic/"))
161
+ runic.migrate.upgrade("head")
162
+
163
+ print("current:", runic.migrate.current())
164
+ print("history:", runic.migrate.get_history())
165
+ ```
166
+
167
+ `Runic` is the single class you need. It handles upgrades, downgrades, stamping, history queries, and revision creation in one coherent API.
168
+
169
+ ## Documentation
170
+
171
+ For a full conceptual overview, advanced CLI usage, and deep dives into branching or multi-head resolution, visit the complete [Runic Documentation](https://runic-py.readthedocs.io/latest/).