red-queen 0.1.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.
Files changed (43) hide show
  1. red_queen-0.1.1/.github/workflows/ci.yml +44 -0
  2. red_queen-0.1.1/.github/workflows/conventional-commits.yml +15 -0
  3. red_queen-0.1.1/.github/workflows/release-please.yml +40 -0
  4. red_queen-0.1.1/.gitignore +5 -0
  5. red_queen-0.1.1/.pre-commit-config.yaml +21 -0
  6. red_queen-0.1.1/.python-version +1 -0
  7. red_queen-0.1.1/.release-please-manifest.json +3 -0
  8. red_queen-0.1.1/CHANGELOG.md +8 -0
  9. red_queen-0.1.1/LICENSE +21 -0
  10. red_queen-0.1.1/PKG-INFO +207 -0
  11. red_queen-0.1.1/README.md +193 -0
  12. red_queen-0.1.1/pyproject.toml +58 -0
  13. red_queen-0.1.1/release-please-config.json +18 -0
  14. red_queen-0.1.1/src/red_queen/__init__.py +31 -0
  15. red_queen-0.1.1/src/red_queen/__main__.py +11 -0
  16. red_queen-0.1.1/src/red_queen/_codegen.py +285 -0
  17. red_queen-0.1.1/src/red_queen/_config.py +200 -0
  18. red_queen-0.1.1/src/red_queen/_decorator.py +168 -0
  19. red_queen-0.1.1/src/red_queen/_diff.py +56 -0
  20. red_queen-0.1.1/src/red_queen/_discovery.py +122 -0
  21. red_queen-0.1.1/src/red_queen/_migration.py +219 -0
  22. red_queen-0.1.1/src/red_queen/_revision.py +188 -0
  23. red_queen-0.1.1/src/red_queen/_state.py +37 -0
  24. red_queen-0.1.1/src/red_queen/_types.py +71 -0
  25. red_queen-0.1.1/src/red_queen/_util.py +125 -0
  26. red_queen-0.1.1/src/red_queen/commands/__init__.py +33 -0
  27. red_queen-0.1.1/src/red_queen/commands/diff.py +55 -0
  28. red_queen-0.1.1/src/red_queen/commands/down.py +70 -0
  29. red_queen-0.1.1/src/red_queen/commands/reset.py +97 -0
  30. red_queen-0.1.1/src/red_queen/commands/revision.py +79 -0
  31. red_queen-0.1.1/src/red_queen/commands/show.py +47 -0
  32. red_queen-0.1.1/src/red_queen/commands/up.py +67 -0
  33. red_queen-0.1.1/src/red_queen/py.typed +0 -0
  34. red_queen-0.1.1/src/red_queen/types/__init__.py +27 -0
  35. red_queen-0.1.1/tests/__init__.py +0 -0
  36. red_queen-0.1.1/tests/conftest.py +55 -0
  37. red_queen-0.1.1/tests/test_config.py +140 -0
  38. red_queen-0.1.1/tests/test_decorator.py +171 -0
  39. red_queen-0.1.1/tests/test_diff.py +106 -0
  40. red_queen-0.1.1/tests/test_migration.py +103 -0
  41. red_queen-0.1.1/tests/test_revision.py +106 -0
  42. red_queen-0.1.1/tests/test_util.py +132 -0
  43. red_queen-0.1.1/uv.lock +459 -0
@@ -0,0 +1,44 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+ workflow_dispatch:
9
+
10
+ jobs:
11
+ ruff:
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - uses: actions/checkout@v6
15
+ - uses: astral-sh/setup-uv@v7
16
+ with:
17
+ enable-cache: true
18
+ - run: uv sync --dev
19
+ - run: uv run ruff check .
20
+ - run: uv run ruff format --check .
21
+
22
+ ty:
23
+ runs-on: ubuntu-latest
24
+ steps:
25
+ - uses: actions/checkout@v6
26
+ - uses: astral-sh/setup-uv@v7
27
+ with:
28
+ enable-cache: true
29
+ - run: uv sync --dev
30
+ - run: uv run ty check src/
31
+
32
+ pytest:
33
+ runs-on: ubuntu-latest
34
+ strategy:
35
+ matrix:
36
+ python-version: ["3.10", "3.11", "3.12", "3.13"]
37
+ steps:
38
+ - uses: actions/checkout@v6
39
+ - uses: astral-sh/setup-uv@v7
40
+ with:
41
+ enable-cache: true
42
+ - run: uv python install ${{ matrix.python-version }}
43
+ - run: uv sync --dev --python ${{ matrix.python-version }}
44
+ - run: uv run --python ${{ matrix.python-version }} pytest
@@ -0,0 +1,15 @@
1
+ name: Conventional Commits
2
+
3
+ on:
4
+ pull_request:
5
+ branches: [main]
6
+
7
+ jobs:
8
+ conventional-commits:
9
+ if: ${{ !startsWith(github.head_ref, 'release-please--') }}
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v6
13
+ with:
14
+ fetch-depth: 0
15
+ - uses: webiny/action-conventional-commits@v1.3.0
@@ -0,0 +1,40 @@
1
+ name: Release Please
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+
7
+ permissions:
8
+ contents: write
9
+ pull-requests: write
10
+ id-token: write
11
+
12
+ jobs:
13
+ release-please:
14
+ runs-on: ubuntu-latest
15
+ outputs:
16
+ release_created: ${{ steps.release.outputs.release_created }}
17
+ steps:
18
+ - uses: googleapis/release-please-action@v4
19
+ id: release
20
+ with:
21
+ token: ${{ secrets.GITHUB_TOKEN }}
22
+ config-file: release-please-config.json
23
+ manifest-file: .release-please-manifest.json
24
+
25
+ publish:
26
+ needs: release-please
27
+ if: needs.release-please.outputs.release_created == 'true'
28
+ runs-on: ubuntu-latest
29
+ environment:
30
+ name: pypi
31
+ url: https://pypi.org/p/red-queen
32
+ permissions:
33
+ id-token: write
34
+ steps:
35
+ - uses: actions/checkout@v6
36
+ - uses: astral-sh/setup-uv@v7
37
+ with:
38
+ enable-cache: true
39
+ - run: uv build
40
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,5 @@
1
+ __pycache__/
2
+ *.pyc
3
+ .venv/
4
+ dist/
5
+ *.egg-info/
@@ -0,0 +1,21 @@
1
+ repos:
2
+ - repo: local
3
+ hooks:
4
+ - id: ruff-check
5
+ name: ruff check
6
+ entry: uv run ruff check --fix
7
+ language: system
8
+ types: [python]
9
+
10
+ - id: ruff-format
11
+ name: ruff format
12
+ entry: uv run ruff format
13
+ language: system
14
+ types: [python]
15
+
16
+ - id: ty
17
+ name: ty check
18
+ entry: uv run ty check src/
19
+ language: system
20
+ pass_filenames: false
21
+ files: ^src/
@@ -0,0 +1 @@
1
+ 3.13
@@ -0,0 +1,3 @@
1
+ {
2
+ ".": "0.1.1"
3
+ }
@@ -0,0 +1,8 @@
1
+ # Changelog
2
+
3
+ ## [0.1.1](https://github.com/mahdilamb/red-queen/compare/red-queen-v0.1.0...red-queen-v0.1.1) (2026-04-12)
4
+
5
+
6
+ ### Features
7
+
8
+ * initial release of red-queen ([2c69149](https://github.com/mahdilamb/red-queen/commit/2c691498b342112aed5f7af48e8cce83cee3b587))
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mahdi Lamb
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,207 @@
1
+ Metadata-Version: 2.4
2
+ Name: red-queen
3
+ Version: 0.1.1
4
+ Summary: Redis schema migration tool with Pydantic model tracking
5
+ Author-email: Mahdi Lamb <mahdilamb@gmail.com>
6
+ License-Expression: MIT
7
+ License-File: LICENSE
8
+ Requires-Python: >=3.10
9
+ Requires-Dist: click>=8.1.0
10
+ Requires-Dist: pydantic>=2.0.0
11
+ Requires-Dist: redis>=7.4.0
12
+ Requires-Dist: tomli>=2.0.0; python_version < '3.11'
13
+ Description-Content-Type: text/markdown
14
+
15
+ # red-queen
16
+
17
+ Schema migration tool for Redis-backed Pydantic models. Track model changes, generate versioned migration scripts, and apply them using async SCAN-based key iteration.
18
+
19
+ ## Installation
20
+
21
+ ```toml
22
+ # pyproject.toml
23
+ dependencies = ["red-queen"]
24
+ ```
25
+
26
+ ## Quick start
27
+
28
+ ### 1. Decorate your models
29
+
30
+ ```python
31
+ from pydantic import BaseModel, Field, RootModel
32
+ from red_queen import red_queen, migrates_from
33
+ from typing import Annotated
34
+
35
+ @red_queen(key="user:{user_id}:profile:")
36
+ class UserProfile(BaseModel):
37
+ name: str
38
+ email: str
39
+
40
+ @red_queen(key="agent:session:{session_id}:display")
41
+ class DisplayMessages(RootModel[list[DisplayMessage]]):
42
+ """Stored as a JSON array."""
43
+
44
+ # Field renames
45
+ @red_queen(key="item:{item_id}")
46
+ class Item(BaseModel):
47
+ title: Annotated[str, migrates_from("name")] # explicit rename
48
+ label: Annotated[str, Field(alias="old_label")] # alias-based rename
49
+ ```
50
+
51
+ Key patterns use f-string style placeholders. `match` is auto-derived by replacing `{...}` with `*` for SCAN.
52
+
53
+ ### 2. Configure in pyproject.toml
54
+
55
+ ```toml
56
+ [tool.red-queen]
57
+ migrations_dir = "migrations"
58
+ deletion_protection = false # or true, or an integer (TTL in seconds)
59
+
60
+ [tool.red-queen.profiles.default]
61
+ default = true
62
+ host = "localhost" # defaults to localhost
63
+ port = 6379 # defaults to 6379
64
+ db = 0 # defaults to 0
65
+ migrations_collection = "my_collection"
66
+ model_search_path = ["myapp.models"]
67
+ ```
68
+
69
+ `host`, `port`, and `db` default to `localhost`, `6379`, and `0`. All string values support `$ENV_VAR` expansion.
70
+
71
+ **Profile resolution order:** `--profile` CLI flag > `RED_QUEEN_PROFILE` env var > profile with `default = true`.
72
+
73
+ Multiple profiles (e.g. local + docker):
74
+
75
+ ```toml
76
+ [tool.red-queen.profiles.default]
77
+ default = true
78
+ migrations_collection = "agent"
79
+ model_search_path = ["agent.types"]
80
+
81
+ [tool.red-queen.profiles.docker]
82
+ host = "redis"
83
+ migrations_collection = "agent"
84
+ model_search_path = ["agent.types"]
85
+ ```
86
+
87
+ ### 3. Generate and apply migrations
88
+
89
+ ```bash
90
+ # Create the initial schema snapshot
91
+ red-queen revision -m "initial"
92
+
93
+ # Show current state
94
+ red-queen show
95
+
96
+ # After changing models, generate a new revision
97
+ red-queen revision -m "add email field"
98
+
99
+ # Check if there are pending changes (exit 1 if none, useful in CI)
100
+ red-queen revision --check
101
+
102
+ # Show what changed
103
+ red-queen diff
104
+
105
+ # Apply pending migrations (stages first, prompts for confirmation)
106
+ red-queen up
107
+
108
+ # Apply without confirmation
109
+ red-queen up --auto-apply
110
+
111
+ # Downgrade to a specific revision
112
+ red-queen down 0001
113
+ red-queen down --root # revert all
114
+
115
+ # Reset to a specific revision (up or down as needed)
116
+ red-queen reset 0002
117
+ red-queen reset --root
118
+ ```
119
+
120
+ All mutation commands (`up`, `down`, `reset`) support `--auto-apply` to skip the staging confirmation prompt.
121
+
122
+ ## Model discovery
123
+
124
+ `model_search_path` accepts:
125
+
126
+ - **Directories:** `"src/myapp/models"` -- walks all `.py` files
127
+ - **Single files:** `"src/myapp/models.py"`
128
+ - **Dotted module paths:** `"myapp.models"` -- imports the module and recursively walks all submodules
129
+
130
+ ## Schema tracking
131
+
132
+ Snapshots use `model_json_schema()`, which captures the full recursive schema including nested models. A change to any nested model triggers a new revision.
133
+
134
+ ## Generated migrations
135
+
136
+ Revisions auto-generate `upgrade` and `downgrade` functions:
137
+
138
+ - **Field added with default** -- sets the default value
139
+ - **Field added, optional (factory)** -- infers zero-value from type (`[]`, `{}`, `""`, `0`, etc.)
140
+ - **Field added, required, no default** -- `# TODO` comment
141
+ - **Field removed** -- backs up values, deletes from data
142
+
143
+ ## Deletion protection
144
+
145
+ Controls what happens when fields are removed:
146
+
147
+ ```toml
148
+ [tool.red-queen]
149
+ deletion_protection = false # backup without TTL (default)
150
+ deletion_protection = true # generate TODO, don't delete
151
+ deletion_protection = 3600 # backup with 1-hour TTL
152
+ ```
153
+
154
+ When using an integer TTL, backups expire after the specified seconds. If a downgrade runs after the TTL, a warning is emitted for each key where the backup has expired and fields cannot be restored.
155
+
156
+ ## Python API
157
+
158
+ ```python
159
+ from red_queen import (
160
+ red_queen,
161
+ migrates_from,
162
+ auto_migrate_up,
163
+ migrate_up,
164
+ migrate_down,
165
+ apply_plan,
166
+ find_one,
167
+ get_one,
168
+ )
169
+ ```
170
+
171
+ ### Auto-migrate on startup
172
+
173
+ ```python
174
+ from red_queen import auto_migrate_up
175
+
176
+ # Resolves config, connects to Redis, applies all pending migrations.
177
+ # Uses RED_QUEEN_PROFILE env var or default profile.
178
+ await auto_migrate_up()
179
+ ```
180
+
181
+ ### FastAPI lifespan example
182
+
183
+ ```python
184
+ from red_queen import auto_migrate_up
185
+
186
+ @asynccontextmanager
187
+ async def lifespan(app: FastAPI):
188
+ await auto_migrate_up()
189
+ yield
190
+ ```
191
+
192
+ ### Query utilities
193
+
194
+ ```python
195
+ # find_one: format key pattern with args/kwargs, then GET
196
+ profile = await find_one(UserProfile, "123")
197
+ profile = await find_one(UserProfile, user_id="123")
198
+ raw = await find_one(UserProfile, "123", return_raw=True)
199
+
200
+ # get_one: GET by full literal key
201
+ profile = await get_one(UserProfile, "user:123:profile:")
202
+ raw = await get_one(UserProfile, "user:123:profile:", return_raw=True)
203
+ ```
204
+
205
+ ### Low-level API
206
+
207
+ For full control, use `migrate_up` / `migrate_down` directly with an explicit Redis client, migrations dir, and model list. See the CLI command implementations for examples.
@@ -0,0 +1,193 @@
1
+ # red-queen
2
+
3
+ Schema migration tool for Redis-backed Pydantic models. Track model changes, generate versioned migration scripts, and apply them using async SCAN-based key iteration.
4
+
5
+ ## Installation
6
+
7
+ ```toml
8
+ # pyproject.toml
9
+ dependencies = ["red-queen"]
10
+ ```
11
+
12
+ ## Quick start
13
+
14
+ ### 1. Decorate your models
15
+
16
+ ```python
17
+ from pydantic import BaseModel, Field, RootModel
18
+ from red_queen import red_queen, migrates_from
19
+ from typing import Annotated
20
+
21
+ @red_queen(key="user:{user_id}:profile:")
22
+ class UserProfile(BaseModel):
23
+ name: str
24
+ email: str
25
+
26
+ @red_queen(key="agent:session:{session_id}:display")
27
+ class DisplayMessages(RootModel[list[DisplayMessage]]):
28
+ """Stored as a JSON array."""
29
+
30
+ # Field renames
31
+ @red_queen(key="item:{item_id}")
32
+ class Item(BaseModel):
33
+ title: Annotated[str, migrates_from("name")] # explicit rename
34
+ label: Annotated[str, Field(alias="old_label")] # alias-based rename
35
+ ```
36
+
37
+ Key patterns use f-string style placeholders. `match` is auto-derived by replacing `{...}` with `*` for SCAN.
38
+
39
+ ### 2. Configure in pyproject.toml
40
+
41
+ ```toml
42
+ [tool.red-queen]
43
+ migrations_dir = "migrations"
44
+ deletion_protection = false # or true, or an integer (TTL in seconds)
45
+
46
+ [tool.red-queen.profiles.default]
47
+ default = true
48
+ host = "localhost" # defaults to localhost
49
+ port = 6379 # defaults to 6379
50
+ db = 0 # defaults to 0
51
+ migrations_collection = "my_collection"
52
+ model_search_path = ["myapp.models"]
53
+ ```
54
+
55
+ `host`, `port`, and `db` default to `localhost`, `6379`, and `0`. All string values support `$ENV_VAR` expansion.
56
+
57
+ **Profile resolution order:** `--profile` CLI flag > `RED_QUEEN_PROFILE` env var > profile with `default = true`.
58
+
59
+ Multiple profiles (e.g. local + docker):
60
+
61
+ ```toml
62
+ [tool.red-queen.profiles.default]
63
+ default = true
64
+ migrations_collection = "agent"
65
+ model_search_path = ["agent.types"]
66
+
67
+ [tool.red-queen.profiles.docker]
68
+ host = "redis"
69
+ migrations_collection = "agent"
70
+ model_search_path = ["agent.types"]
71
+ ```
72
+
73
+ ### 3. Generate and apply migrations
74
+
75
+ ```bash
76
+ # Create the initial schema snapshot
77
+ red-queen revision -m "initial"
78
+
79
+ # Show current state
80
+ red-queen show
81
+
82
+ # After changing models, generate a new revision
83
+ red-queen revision -m "add email field"
84
+
85
+ # Check if there are pending changes (exit 1 if none, useful in CI)
86
+ red-queen revision --check
87
+
88
+ # Show what changed
89
+ red-queen diff
90
+
91
+ # Apply pending migrations (stages first, prompts for confirmation)
92
+ red-queen up
93
+
94
+ # Apply without confirmation
95
+ red-queen up --auto-apply
96
+
97
+ # Downgrade to a specific revision
98
+ red-queen down 0001
99
+ red-queen down --root # revert all
100
+
101
+ # Reset to a specific revision (up or down as needed)
102
+ red-queen reset 0002
103
+ red-queen reset --root
104
+ ```
105
+
106
+ All mutation commands (`up`, `down`, `reset`) support `--auto-apply` to skip the staging confirmation prompt.
107
+
108
+ ## Model discovery
109
+
110
+ `model_search_path` accepts:
111
+
112
+ - **Directories:** `"src/myapp/models"` -- walks all `.py` files
113
+ - **Single files:** `"src/myapp/models.py"`
114
+ - **Dotted module paths:** `"myapp.models"` -- imports the module and recursively walks all submodules
115
+
116
+ ## Schema tracking
117
+
118
+ Snapshots use `model_json_schema()`, which captures the full recursive schema including nested models. A change to any nested model triggers a new revision.
119
+
120
+ ## Generated migrations
121
+
122
+ Revisions auto-generate `upgrade` and `downgrade` functions:
123
+
124
+ - **Field added with default** -- sets the default value
125
+ - **Field added, optional (factory)** -- infers zero-value from type (`[]`, `{}`, `""`, `0`, etc.)
126
+ - **Field added, required, no default** -- `# TODO` comment
127
+ - **Field removed** -- backs up values, deletes from data
128
+
129
+ ## Deletion protection
130
+
131
+ Controls what happens when fields are removed:
132
+
133
+ ```toml
134
+ [tool.red-queen]
135
+ deletion_protection = false # backup without TTL (default)
136
+ deletion_protection = true # generate TODO, don't delete
137
+ deletion_protection = 3600 # backup with 1-hour TTL
138
+ ```
139
+
140
+ When using an integer TTL, backups expire after the specified seconds. If a downgrade runs after the TTL, a warning is emitted for each key where the backup has expired and fields cannot be restored.
141
+
142
+ ## Python API
143
+
144
+ ```python
145
+ from red_queen import (
146
+ red_queen,
147
+ migrates_from,
148
+ auto_migrate_up,
149
+ migrate_up,
150
+ migrate_down,
151
+ apply_plan,
152
+ find_one,
153
+ get_one,
154
+ )
155
+ ```
156
+
157
+ ### Auto-migrate on startup
158
+
159
+ ```python
160
+ from red_queen import auto_migrate_up
161
+
162
+ # Resolves config, connects to Redis, applies all pending migrations.
163
+ # Uses RED_QUEEN_PROFILE env var or default profile.
164
+ await auto_migrate_up()
165
+ ```
166
+
167
+ ### FastAPI lifespan example
168
+
169
+ ```python
170
+ from red_queen import auto_migrate_up
171
+
172
+ @asynccontextmanager
173
+ async def lifespan(app: FastAPI):
174
+ await auto_migrate_up()
175
+ yield
176
+ ```
177
+
178
+ ### Query utilities
179
+
180
+ ```python
181
+ # find_one: format key pattern with args/kwargs, then GET
182
+ profile = await find_one(UserProfile, "123")
183
+ profile = await find_one(UserProfile, user_id="123")
184
+ raw = await find_one(UserProfile, "123", return_raw=True)
185
+
186
+ # get_one: GET by full literal key
187
+ profile = await get_one(UserProfile, "user:123:profile:")
188
+ raw = await get_one(UserProfile, "user:123:profile:", return_raw=True)
189
+ ```
190
+
191
+ ### Low-level API
192
+
193
+ For full control, use `migrate_up` / `migrate_down` directly with an explicit Redis client, migrations dir, and model list. See the CLI command implementations for examples.
@@ -0,0 +1,58 @@
1
+ [project]
2
+ name = "red-queen"
3
+ version = "0.1.1"
4
+ description = "Redis schema migration tool with Pydantic model tracking"
5
+ readme = "README.md"
6
+ authors = [
7
+ { name = "Mahdi Lamb", email = "mahdilamb@gmail.com" }
8
+ ]
9
+ license = "MIT"
10
+ requires-python = ">=3.10"
11
+ dependencies = [
12
+ "click>=8.1.0",
13
+ "pydantic>=2.0.0",
14
+ "redis>=7.4.0",
15
+ "tomli>=2.0.0; python_version < '3.11'",
16
+ ]
17
+
18
+ [project.scripts]
19
+ red-queen = "red_queen.__main__:main"
20
+
21
+ [build-system]
22
+ requires = ["hatchling"]
23
+ build-backend = "hatchling.build"
24
+
25
+ [tool.ruff]
26
+ target-version = "py310"
27
+ extend-exclude = ["**/migrations"]
28
+
29
+ [tool.ruff.lint]
30
+ select = [
31
+ "E", # pycodestyle errors
32
+ "W", # pycodestyle warnings
33
+ "F", # pyflakes
34
+ "I", # isort
35
+ "N", # pep8-naming
36
+ "UP", # pyupgrade
37
+ "B", # flake8-bugbear
38
+ "SIM", # flake8-simplify
39
+ "TCH", # flake8-type-checking
40
+ "RUF", # ruff-specific rules
41
+ ]
42
+
43
+ [tool.ruff.lint.isort]
44
+ known-first-party = ["red_queen"]
45
+
46
+ [tool.pytest.ini_options]
47
+ testpaths = ["tests"]
48
+ asyncio_mode = "auto"
49
+ addopts = "--import-mode=importlib"
50
+
51
+ [dependency-groups]
52
+ dev = [
53
+ "fakeredis>=2.35.0",
54
+ "pytest>=9.0.3",
55
+ "pytest-asyncio>=1.3.0",
56
+ "ruff>=0.15.10",
57
+ "ty>=0.0.29",
58
+ ]
@@ -0,0 +1,18 @@
1
+ {
2
+ "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json",
3
+ "packages": {
4
+ ".": {
5
+ "release-type": "python",
6
+ "package-name": "red-queen",
7
+ "bump-minor-pre-major": true,
8
+ "bump-patch-for-minor-pre-major": true,
9
+ "extra-files": [
10
+ {
11
+ "type": "toml",
12
+ "path": "uv.lock",
13
+ "jsonpath": "$.package[?(@.name=='red-queen')].version"
14
+ }
15
+ ]
16
+ }
17
+ }
18
+ }
@@ -0,0 +1,31 @@
1
+ """Redis migration tool with Pydantic model tracking."""
2
+
3
+ from red_queen._config import load_config, resolve_profile
4
+ from red_queen._decorator import (
5
+ get_registered_model,
6
+ get_registry,
7
+ migrates_from,
8
+ red_queen,
9
+ )
10
+ from red_queen._migration import (
11
+ apply_plan,
12
+ auto_migrate_up,
13
+ migrate_down,
14
+ migrate_up,
15
+ )
16
+ from red_queen._util import find_one, get_one
17
+
18
+ __all__ = [
19
+ "apply_plan",
20
+ "auto_migrate_up",
21
+ "find_one",
22
+ "get_one",
23
+ "get_registered_model",
24
+ "get_registry",
25
+ "load_config",
26
+ "migrate_down",
27
+ "migrate_up",
28
+ "migrates_from",
29
+ "red_queen",
30
+ "resolve_profile",
31
+ ]
@@ -0,0 +1,11 @@
1
+ """CLI entry point for red-queen."""
2
+
3
+ from red_queen.commands import cli
4
+
5
+
6
+ def main() -> None:
7
+ cli()
8
+
9
+
10
+ if __name__ == "__main__":
11
+ main()