crochet-migration 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.
Files changed (36) hide show
  1. crochet_migration-0.1.0/.gitignore +21 -0
  2. crochet_migration-0.1.0/LICENSE +21 -0
  3. crochet_migration-0.1.0/PKG-INFO +278 -0
  4. crochet_migration-0.1.0/README.md +246 -0
  5. crochet_migration-0.1.0/pyproject.toml +64 -0
  6. crochet_migration-0.1.0/src/crochet/__init__.py +3 -0
  7. crochet_migration-0.1.0/src/crochet/cli.py +327 -0
  8. crochet_migration-0.1.0/src/crochet/config.py +116 -0
  9. crochet_migration-0.1.0/src/crochet/errors.py +75 -0
  10. crochet_migration-0.1.0/src/crochet/ingest/__init__.py +5 -0
  11. crochet_migration-0.1.0/src/crochet/ingest/batch.py +61 -0
  12. crochet_migration-0.1.0/src/crochet/ir/__init__.py +23 -0
  13. crochet_migration-0.1.0/src/crochet/ir/diff.py +199 -0
  14. crochet_migration-0.1.0/src/crochet/ir/hash.py +36 -0
  15. crochet_migration-0.1.0/src/crochet/ir/parser.py +251 -0
  16. crochet_migration-0.1.0/src/crochet/ir/schema.py +196 -0
  17. crochet_migration-0.1.0/src/crochet/ledger/__init__.py +5 -0
  18. crochet_migration-0.1.0/src/crochet/ledger/sqlite.py +282 -0
  19. crochet_migration-0.1.0/src/crochet/migrations/__init__.py +6 -0
  20. crochet_migration-0.1.0/src/crochet/migrations/engine.py +279 -0
  21. crochet_migration-0.1.0/src/crochet/migrations/operations.py +267 -0
  22. crochet_migration-0.1.0/src/crochet/migrations/template.py +105 -0
  23. crochet_migration-0.1.0/src/crochet/scaffold/__init__.py +6 -0
  24. crochet_migration-0.1.0/src/crochet/scaffold/node.py +48 -0
  25. crochet_migration-0.1.0/src/crochet/scaffold/relationship.py +52 -0
  26. crochet_migration-0.1.0/src/crochet/verify.py +141 -0
  27. crochet_migration-0.1.0/tests/__init__.py +0 -0
  28. crochet_migration-0.1.0/tests/conftest.py +92 -0
  29. crochet_migration-0.1.0/tests/test_cli.py +152 -0
  30. crochet_migration-0.1.0/tests/test_config.py +41 -0
  31. crochet_migration-0.1.0/tests/test_ingest.py +82 -0
  32. crochet_migration-0.1.0/tests/test_ir.py +287 -0
  33. crochet_migration-0.1.0/tests/test_ledger.py +103 -0
  34. crochet_migration-0.1.0/tests/test_migrations.py +273 -0
  35. crochet_migration-0.1.0/tests/test_scaffold.py +61 -0
  36. crochet_migration-0.1.0/tests/test_verify.py +66 -0
@@ -0,0 +1,21 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *$py.class
4
+ *.so
5
+ *.egg-info/
6
+ dist/
7
+ build/
8
+ .eggs/
9
+ *.egg
10
+ .venv/
11
+ venv/
12
+ env/
13
+ .env
14
+ .crochet/
15
+ *.db
16
+ .mypy_cache/
17
+ .pytest_cache/
18
+ .ruff_cache/
19
+ htmlcov/
20
+ .coverage
21
+ *.log
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Keshav Dial
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,278 @@
1
+ Metadata-Version: 2.4
2
+ Name: crochet-migration
3
+ Version: 0.1.0
4
+ Summary: Versioned schema & data migrations for neomodel Neo4j graphs
5
+ Project-URL: Homepage, https://github.com/keshavd/crochet
6
+ Project-URL: Repository, https://github.com/keshavd/crochet
7
+ Project-URL: Issues, https://github.com/keshavd/crochet/issues
8
+ Author-email: Keshav Dial <y.inuyasha@gmail.com>
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: database,graph,migrations,neo4j,neomodel,schema
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Topic :: Database
21
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
+ Requires-Python: >=3.10
23
+ Requires-Dist: click>=8.0
24
+ Requires-Dist: neomodel>=5.0
25
+ Requires-Dist: toml>=0.10
26
+ Provides-Extra: dev
27
+ Requires-Dist: mypy; extra == 'dev'
28
+ Requires-Dist: pytest-cov; extra == 'dev'
29
+ Requires-Dist: pytest>=7.0; extra == 'dev'
30
+ Requires-Dist: ruff; extra == 'dev'
31
+ Description-Content-Type: text/markdown
32
+
33
+ # Crochet
34
+
35
+ Versioned schema & data migrations for [neomodel](https://github.com/neo4j-contrib/neomodel) Neo4j graphs.
36
+
37
+ Crochet is a Git-backed, migration-driven framework that makes neomodel-defined
38
+ Neo4j graphs evolvable, auditable, and rollback-safe without relying on database
39
+ introspection.
40
+
41
+ ## Problem It Solves
42
+
43
+ - neomodel has no native schema diff or migration system
44
+ - Neo4j is schemaless, so schema drift is silent
45
+ - Data loading and schema evolution are often intertwined but unmanaged
46
+ - Rollbacks are usually impossible or unsafe
47
+ - Git history and database state frequently diverge
48
+
49
+ Crochet enforces alignment between neomodel code, data ingests, and the live
50
+ graph.
51
+
52
+ ## Installation
53
+
54
+ ```bash
55
+ pip install crochet
56
+ ```
57
+
58
+ For development:
59
+
60
+ ```bash
61
+ pip install -e ".[dev]"
62
+ ```
63
+
64
+ ## Quick Start
65
+
66
+ ### 1. Initialize a project
67
+
68
+ ```bash
69
+ crochet new-project --name my-graph
70
+ ```
71
+
72
+ This creates:
73
+
74
+ ```
75
+ my-graph/
76
+ crochet.toml # project config
77
+ models/ # neomodel definitions
78
+ migrations/ # migration files
79
+ .crochet/ledger.db # SQLite ledger
80
+ ```
81
+
82
+ ### 2. Create node and relationship models
83
+
84
+ ```bash
85
+ crochet create-node Person
86
+ crochet create-relationship Friendship --rel-type FRIENDS_WITH
87
+ ```
88
+
89
+ Each model gets an immutable `__kgid__` identifier. Models can be renamed or
90
+ moved across files without losing identity, because the `__kgid__` is what
91
+ Crochet tracks — not class names or file paths.
92
+
93
+ ```python
94
+ # models/person.py
95
+ from neomodel import StructuredNode, StringProperty, IntegerProperty
96
+
97
+ class Person(StructuredNode):
98
+ __kgid__ = "person_v1"
99
+ name = StringProperty(required=True, unique_index=True)
100
+ age = IntegerProperty(index=True)
101
+ ```
102
+
103
+ ### 3. Create a migration
104
+
105
+ ```bash
106
+ crochet create-migration "add person node"
107
+ ```
108
+
109
+ Crochet snapshots the current schema IR, diffs it against the previous
110
+ snapshot, and scaffolds a migration file with detected changes as comments:
111
+
112
+ ```python
113
+ # migrations/0001_add_person_node.py
114
+
115
+ revision_id = "0001_add_person_node"
116
+ parent_id = None
117
+ schema_hash = "a1b2c3..."
118
+ rollback_safe = True
119
+
120
+ def upgrade(ctx):
121
+ ctx.add_unique_constraint("Person", "name")
122
+ ctx.add_index("Person", "age")
123
+
124
+ def downgrade(ctx):
125
+ ctx.drop_index("Person", "age")
126
+ ctx.drop_unique_constraint("Person", "name")
127
+ ```
128
+
129
+ ### 4. Apply migrations
130
+
131
+ ```bash
132
+ crochet upgrade # apply all pending
133
+ crochet upgrade --dry-run # preview without executing
134
+ crochet upgrade --target 0001_add_person_node # apply up to a specific revision
135
+ ```
136
+
137
+ ### 5. Revert migrations
138
+
139
+ ```bash
140
+ crochet downgrade # revert the most recent migration
141
+ crochet downgrade --target 0001_add_person_node # revert down to a target
142
+ ```
143
+
144
+ Rollback-unsafe migrations will refuse to downgrade and raise an error.
145
+
146
+ ### 6. Check status and verify
147
+
148
+ ```bash
149
+ crochet status # show applied/pending migrations, head, batches
150
+ crochet verify # check ledger chain, file presence, schema hash consistency
151
+ ```
152
+
153
+ ## Core Concepts
154
+
155
+ ### Intermediate Representation (IR)
156
+
157
+ neomodel files are parsed into an intermediate schema representation. IR
158
+ snapshots can be hashed, serialized, and diffed. No Neo4j connection is
159
+ required for schema comparison.
160
+
161
+ ### Hash-Chained Migrations
162
+
163
+ Migrations are ordered by a parent chain (Alembic-style). Each migration
164
+ records the schema hash at the time it was created, so drift between code and
165
+ migrations is detectable.
166
+
167
+ ### SQLite Ledger
168
+
169
+ A local SQLite database (`.crochet/ledger.db`) is the authoritative record of:
170
+
171
+ - Applied migrations and their order
172
+ - Dataset batches with file checksums and loader versions
173
+ - Schema snapshots for diffing
174
+
175
+ ### Deterministic Data Ingest
176
+
177
+ Data loading is a first-class migration operation. The `MigrationContext`
178
+ provides helpers for batch-tracked ingests:
179
+
180
+ ```python
181
+ def upgrade(ctx):
182
+ batch_id = ctx.begin_batch()
183
+ ctx.create_nodes("Person", [
184
+ {"name": "Alice", "age": 30},
185
+ {"name": "Bob", "age": 25},
186
+ ])
187
+ ```
188
+
189
+ Every node and relationship created through a batch is tagged with
190
+ `_crochet_batch`, enabling delete-by-batch rollback.
191
+
192
+ ### Rollback Semantics
193
+
194
+ Rollbacks are explicitly declared, not assumed:
195
+
196
+ - Append-only ingests support `delete_nodes_by_batch` / `delete_relationships_by_batch`
197
+ - Destructive transforms must set `rollback_safe = False`
198
+ - Unsafe downgrades are prevented by policy
199
+
200
+ ## Migration Context Operations
201
+
202
+ The `MigrationContext` passed to `upgrade()` and `downgrade()` provides:
203
+
204
+ | Operation | Description |
205
+ |-----------|-------------|
206
+ | `add_unique_constraint(label, prop)` | Create a uniqueness constraint |
207
+ | `drop_unique_constraint(label, prop)` | Drop a uniqueness constraint |
208
+ | `add_node_property_existence_constraint(label, prop)` | Create a NOT NULL constraint |
209
+ | `drop_node_property_existence_constraint(label, prop)` | Drop a NOT NULL constraint |
210
+ | `add_index(label, prop)` | Create an index |
211
+ | `drop_index(label, prop)` | Drop an index |
212
+ | `rename_label(old, new)` | Rename a node label |
213
+ | `rename_relationship_type(old, new)` | Rename a relationship type |
214
+ | `add_node_property(label, prop, default)` | Add a property with optional default |
215
+ | `remove_node_property(label, prop)` | Remove a property |
216
+ | `rename_node_property(label, old, new)` | Rename a property |
217
+ | `run_cypher(cypher, params)` | Execute raw Cypher |
218
+ | `begin_batch(batch_id)` | Start a tracked data batch |
219
+ | `create_nodes(label, data)` | Batch-create nodes |
220
+ | `create_relationships(src, tgt, type, data)` | Batch-create relationships |
221
+ | `delete_nodes_by_batch(label, batch_id)` | Delete nodes by batch |
222
+ | `delete_relationships_by_batch(type, batch_id)` | Delete relationships by batch |
223
+
224
+ ## Configuration
225
+
226
+ `crochet.toml`:
227
+
228
+ ```toml
229
+ [project]
230
+ name = "my-graph"
231
+ models_path = "models"
232
+ migrations_path = "migrations"
233
+
234
+ [neo4j]
235
+ uri = "bolt://localhost:7687"
236
+ username = "neo4j"
237
+
238
+ [ledger]
239
+ path = ".crochet/ledger.db"
240
+ ```
241
+
242
+ Neo4j credentials can be overridden with environment variables:
243
+
244
+ - `CROCHET_NEO4J_URI`
245
+ - `CROCHET_NEO4J_USERNAME`
246
+ - `CROCHET_NEO4J_PASSWORD`
247
+
248
+ ## CLI Reference
249
+
250
+ | Command | Description |
251
+ |---------|-------------|
252
+ | `crochet new-project` | Initialize a new Crochet project |
253
+ | `crochet create-node NAME` | Scaffold a StructuredNode model |
254
+ | `crochet create-relationship NAME` | Scaffold a StructuredRel model |
255
+ | `crochet create-migration DESC` | Create a new migration file |
256
+ | `crochet upgrade` | Apply pending migrations |
257
+ | `crochet downgrade` | Revert the most recent migration |
258
+ | `crochet status` | Show migration status |
259
+ | `crochet verify` | Run verification checks |
260
+
261
+ ## Design Principles
262
+
263
+ - **No hidden magic** — all changes are explicit migration files
264
+ - **Code > database state** — neomodel files are the source of truth
265
+ - **Determinism over convenience** — schema IR is hashed and diffed
266
+ - **Rollback is a contract, not a guess** — explicitly declared per migration
267
+ - **Git history and graph state must agree** — ledger + hash chains enforce this
268
+
269
+ ## Development
270
+
271
+ ```bash
272
+ pip install -e ".[dev]"
273
+ pytest
274
+ ```
275
+
276
+ ## License
277
+
278
+ MIT
@@ -0,0 +1,246 @@
1
+ # Crochet
2
+
3
+ Versioned schema & data migrations for [neomodel](https://github.com/neo4j-contrib/neomodel) Neo4j graphs.
4
+
5
+ Crochet is a Git-backed, migration-driven framework that makes neomodel-defined
6
+ Neo4j graphs evolvable, auditable, and rollback-safe without relying on database
7
+ introspection.
8
+
9
+ ## Problem It Solves
10
+
11
+ - neomodel has no native schema diff or migration system
12
+ - Neo4j is schemaless, so schema drift is silent
13
+ - Data loading and schema evolution are often intertwined but unmanaged
14
+ - Rollbacks are usually impossible or unsafe
15
+ - Git history and database state frequently diverge
16
+
17
+ Crochet enforces alignment between neomodel code, data ingests, and the live
18
+ graph.
19
+
20
+ ## Installation
21
+
22
+ ```bash
23
+ pip install crochet
24
+ ```
25
+
26
+ For development:
27
+
28
+ ```bash
29
+ pip install -e ".[dev]"
30
+ ```
31
+
32
+ ## Quick Start
33
+
34
+ ### 1. Initialize a project
35
+
36
+ ```bash
37
+ crochet new-project --name my-graph
38
+ ```
39
+
40
+ This creates:
41
+
42
+ ```
43
+ my-graph/
44
+ crochet.toml # project config
45
+ models/ # neomodel definitions
46
+ migrations/ # migration files
47
+ .crochet/ledger.db # SQLite ledger
48
+ ```
49
+
50
+ ### 2. Create node and relationship models
51
+
52
+ ```bash
53
+ crochet create-node Person
54
+ crochet create-relationship Friendship --rel-type FRIENDS_WITH
55
+ ```
56
+
57
+ Each model gets an immutable `__kgid__` identifier. Models can be renamed or
58
+ moved across files without losing identity, because the `__kgid__` is what
59
+ Crochet tracks — not class names or file paths.
60
+
61
+ ```python
62
+ # models/person.py
63
+ from neomodel import StructuredNode, StringProperty, IntegerProperty
64
+
65
+ class Person(StructuredNode):
66
+ __kgid__ = "person_v1"
67
+ name = StringProperty(required=True, unique_index=True)
68
+ age = IntegerProperty(index=True)
69
+ ```
70
+
71
+ ### 3. Create a migration
72
+
73
+ ```bash
74
+ crochet create-migration "add person node"
75
+ ```
76
+
77
+ Crochet snapshots the current schema IR, diffs it against the previous
78
+ snapshot, and scaffolds a migration file with detected changes as comments:
79
+
80
+ ```python
81
+ # migrations/0001_add_person_node.py
82
+
83
+ revision_id = "0001_add_person_node"
84
+ parent_id = None
85
+ schema_hash = "a1b2c3..."
86
+ rollback_safe = True
87
+
88
+ def upgrade(ctx):
89
+ ctx.add_unique_constraint("Person", "name")
90
+ ctx.add_index("Person", "age")
91
+
92
+ def downgrade(ctx):
93
+ ctx.drop_index("Person", "age")
94
+ ctx.drop_unique_constraint("Person", "name")
95
+ ```
96
+
97
+ ### 4. Apply migrations
98
+
99
+ ```bash
100
+ crochet upgrade # apply all pending
101
+ crochet upgrade --dry-run # preview without executing
102
+ crochet upgrade --target 0001_add_person_node # apply up to a specific revision
103
+ ```
104
+
105
+ ### 5. Revert migrations
106
+
107
+ ```bash
108
+ crochet downgrade # revert the most recent migration
109
+ crochet downgrade --target 0001_add_person_node # revert down to a target
110
+ ```
111
+
112
+ Rollback-unsafe migrations will refuse to downgrade and raise an error.
113
+
114
+ ### 6. Check status and verify
115
+
116
+ ```bash
117
+ crochet status # show applied/pending migrations, head, batches
118
+ crochet verify # check ledger chain, file presence, schema hash consistency
119
+ ```
120
+
121
+ ## Core Concepts
122
+
123
+ ### Intermediate Representation (IR)
124
+
125
+ neomodel files are parsed into an intermediate schema representation. IR
126
+ snapshots can be hashed, serialized, and diffed. No Neo4j connection is
127
+ required for schema comparison.
128
+
129
+ ### Hash-Chained Migrations
130
+
131
+ Migrations are ordered by a parent chain (Alembic-style). Each migration
132
+ records the schema hash at the time it was created, so drift between code and
133
+ migrations is detectable.
134
+
135
+ ### SQLite Ledger
136
+
137
+ A local SQLite database (`.crochet/ledger.db`) is the authoritative record of:
138
+
139
+ - Applied migrations and their order
140
+ - Dataset batches with file checksums and loader versions
141
+ - Schema snapshots for diffing
142
+
143
+ ### Deterministic Data Ingest
144
+
145
+ Data loading is a first-class migration operation. The `MigrationContext`
146
+ provides helpers for batch-tracked ingests:
147
+
148
+ ```python
149
+ def upgrade(ctx):
150
+ batch_id = ctx.begin_batch()
151
+ ctx.create_nodes("Person", [
152
+ {"name": "Alice", "age": 30},
153
+ {"name": "Bob", "age": 25},
154
+ ])
155
+ ```
156
+
157
+ Every node and relationship created through a batch is tagged with
158
+ `_crochet_batch`, enabling delete-by-batch rollback.
159
+
160
+ ### Rollback Semantics
161
+
162
+ Rollbacks are explicitly declared, not assumed:
163
+
164
+ - Append-only ingests support `delete_nodes_by_batch` / `delete_relationships_by_batch`
165
+ - Destructive transforms must set `rollback_safe = False`
166
+ - Unsafe downgrades are prevented by policy
167
+
168
+ ## Migration Context Operations
169
+
170
+ The `MigrationContext` passed to `upgrade()` and `downgrade()` provides:
171
+
172
+ | Operation | Description |
173
+ |-----------|-------------|
174
+ | `add_unique_constraint(label, prop)` | Create a uniqueness constraint |
175
+ | `drop_unique_constraint(label, prop)` | Drop a uniqueness constraint |
176
+ | `add_node_property_existence_constraint(label, prop)` | Create a NOT NULL constraint |
177
+ | `drop_node_property_existence_constraint(label, prop)` | Drop a NOT NULL constraint |
178
+ | `add_index(label, prop)` | Create an index |
179
+ | `drop_index(label, prop)` | Drop an index |
180
+ | `rename_label(old, new)` | Rename a node label |
181
+ | `rename_relationship_type(old, new)` | Rename a relationship type |
182
+ | `add_node_property(label, prop, default)` | Add a property with optional default |
183
+ | `remove_node_property(label, prop)` | Remove a property |
184
+ | `rename_node_property(label, old, new)` | Rename a property |
185
+ | `run_cypher(cypher, params)` | Execute raw Cypher |
186
+ | `begin_batch(batch_id)` | Start a tracked data batch |
187
+ | `create_nodes(label, data)` | Batch-create nodes |
188
+ | `create_relationships(src, tgt, type, data)` | Batch-create relationships |
189
+ | `delete_nodes_by_batch(label, batch_id)` | Delete nodes by batch |
190
+ | `delete_relationships_by_batch(type, batch_id)` | Delete relationships by batch |
191
+
192
+ ## Configuration
193
+
194
+ `crochet.toml`:
195
+
196
+ ```toml
197
+ [project]
198
+ name = "my-graph"
199
+ models_path = "models"
200
+ migrations_path = "migrations"
201
+
202
+ [neo4j]
203
+ uri = "bolt://localhost:7687"
204
+ username = "neo4j"
205
+
206
+ [ledger]
207
+ path = ".crochet/ledger.db"
208
+ ```
209
+
210
+ Neo4j credentials can be overridden with environment variables:
211
+
212
+ - `CROCHET_NEO4J_URI`
213
+ - `CROCHET_NEO4J_USERNAME`
214
+ - `CROCHET_NEO4J_PASSWORD`
215
+
216
+ ## CLI Reference
217
+
218
+ | Command | Description |
219
+ |---------|-------------|
220
+ | `crochet new-project` | Initialize a new Crochet project |
221
+ | `crochet create-node NAME` | Scaffold a StructuredNode model |
222
+ | `crochet create-relationship NAME` | Scaffold a StructuredRel model |
223
+ | `crochet create-migration DESC` | Create a new migration file |
224
+ | `crochet upgrade` | Apply pending migrations |
225
+ | `crochet downgrade` | Revert the most recent migration |
226
+ | `crochet status` | Show migration status |
227
+ | `crochet verify` | Run verification checks |
228
+
229
+ ## Design Principles
230
+
231
+ - **No hidden magic** — all changes are explicit migration files
232
+ - **Code > database state** — neomodel files are the source of truth
233
+ - **Determinism over convenience** — schema IR is hashed and diffed
234
+ - **Rollback is a contract, not a guess** — explicitly declared per migration
235
+ - **Git history and graph state must agree** — ledger + hash chains enforce this
236
+
237
+ ## Development
238
+
239
+ ```bash
240
+ pip install -e ".[dev]"
241
+ pytest
242
+ ```
243
+
244
+ ## License
245
+
246
+ MIT
@@ -0,0 +1,64 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "crochet-migration"
7
+ version = "0.1.0"
8
+ description = "Versioned schema & data migrations for neomodel Neo4j graphs"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = {text = "MIT"}
12
+ authors = [
13
+ { name = "Keshav Dial", email = "y.inuyasha@gmail.com" },
14
+ ]
15
+ keywords = ["neo4j", "neomodel", "migrations", "schema", "graph", "database"]
16
+ classifiers = [
17
+ "Development Status :: 3 - Alpha",
18
+ "Intended Audience :: Developers",
19
+ "License :: OSI Approved :: MIT License",
20
+ "Programming Language :: Python :: 3",
21
+ "Programming Language :: Python :: 3.10",
22
+ "Programming Language :: Python :: 3.11",
23
+ "Programming Language :: Python :: 3.12",
24
+ "Programming Language :: Python :: 3.13",
25
+ "Topic :: Database",
26
+ "Topic :: Software Development :: Libraries :: Python Modules",
27
+ ]
28
+ dependencies = [
29
+ "neomodel>=5.0",
30
+ "click>=8.0",
31
+ "toml>=0.10",
32
+ ]
33
+
34
+ [project.optional-dependencies]
35
+ dev = [
36
+ "pytest>=7.0",
37
+ "pytest-cov",
38
+ "ruff",
39
+ "mypy",
40
+ ]
41
+
42
+ [project.urls]
43
+ Homepage = "https://github.com/keshavd/crochet"
44
+ Repository = "https://github.com/keshavd/crochet"
45
+ Issues = "https://github.com/keshavd/crochet/issues"
46
+
47
+ [project.scripts]
48
+ crochet = "crochet.cli:main"
49
+
50
+ [tool.hatch.build.targets.wheel]
51
+ packages = ["src/crochet"]
52
+
53
+ [tool.pytest.ini_options]
54
+ testpaths = ["tests"]
55
+ pythonpath = ["src"]
56
+
57
+ [tool.ruff]
58
+ target-version = "py310"
59
+ line-length = 99
60
+
61
+ [tool.mypy]
62
+ python_version = "3.10"
63
+ warn_return_any = true
64
+ warn_unused_configs = true
@@ -0,0 +1,3 @@
1
+ """Crochet — Versioned schema & data migrations for neomodel Neo4j graphs."""
2
+
3
+ __version__ = "0.1.0"