Skip to content

Version 1.3.4 - #287

Merged
yedidyakfir merged 157 commits into
mainfrom
develop
Jul 21, 2026
Merged

Version 1.3.4#287
yedidyakfir merged 157 commits into
mainfrom
develop

Conversation

@yedidyakfir

@yedidyakfir yedidyakfir commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

  • New Features
    • Added configurable TTL cascading across related records and special fields, including depth controls and a CascadeResult with dangling counts.
    • Exposed cascade configuration via the public API, including CascadeTTL and result support.
  • Bug Fixes
    • Improved generic model initialization/serialization behavior.
    • Fixed priority-queue serialization expectations by requiring excluded fields.
  • Documentation
    • Added TTL cascade documentation and clarified RedisPriorityQueue exclude=True requirements.
  • Chores
    • Released version 1.3.4, expanded Redis/CI coverage (including Redis 8), and refreshed automation workflow actions/configuration.

YedidyaHKfir and others added 30 commits June 15, 2026 15:00
…d, we update base on the model settings, not the referred class
…not refreshed on afetch when referred model has read update
…pes-in-rapyer] - changelog and version bump to 1.3.4

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…o feature/247-stop-using-dynamic-types-in-rapyer
YedidyaHKfir and others added 13 commits July 20, 2026 15:29
- Delete unused extract_annotation from rapyer/utils/annotation.py
- Delete its sole test file tests/unit/cascade/test_extract_annotation.py
- field_with_flag (production superseder) and has_annotation untouched

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ecute sites

- Add shared aexecute_pipeline_with_cascade_self_heal + aretry_fcall_after_missing_function to registry.py
- ensure_pipeline/pipeline_with_execution route execute through the self-heal wrapper (lazy import, documented cycle)
- aset_ttl routes bare execute through the self-heal wrapper
- _apipeline replays FCALL on function-not-found, reusing aretry_fcall_after_missing_function
- Rewrite config.py freeze-exempt comment; drop resolved issue #284 notes
- Retry rewrites only the function-name slot; single retry then PersistentCascadeFunctionError
- fakeredis EXPIRE branch and single-FCALL atomicity preserved

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…call in test helpers

- Delete arun_fcall from registry.py (import + __all__ in scripts/__init__.py)
- handle_missing_function and PersistentCascadeFunctionError retained (used by self-heal)
- 3 integration _apply_cascade helpers call real_redis_client.fcall directly
- Production self-heal now covers what arun_fcall did (Task 2)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…284, RED)

- After FUNCTION FLUSH, aset_ttl(cascade=True) and refresh_ttl must reload the
  cascade function and still refresh the reachable subtree
- Currently fails: redis-py's async pipeline masks the function-not-found
  message, so the helper's string match never fires inside a pipeline

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…not error text (GREEN)

- redis-py's async pipeline annotate_exception (client.py:1585) overwrites
  exception.args with a non-f-string literal, destroying the "Function not found"
  message; every production FCALL runs inside a pipeline, so string-matching
  never fired there (only the deleted direct-client arun_fcall saw the real text)
- Add acascade_function_missing (FUNCTION LIST scan) + _pipeline_has_fcall guard
- Self-heal only fires on real Redis when the pipeline enqueued an FCALL and the
  cascade function is genuinely absent; other ResponseErrors re-raise unchanged
- Wire the registry-based detection into both the shared wrapper and _apipeline

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…drop cascade self-heal helpers

- context.py: ensure_pipeline + pipeline_with_execution use bare pipe.execute(), remove lazy registry imports
- base.py: aset_ttl uses pipe.execute(); _apipeline reverts to NOSCRIPT-only path (no FCALL-missing detection/replay)
- registry.py: delete six self-heal helpers; imports drop ResponseError, PersistentCascadeFunctionError, cascade.planner

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…te self-heal test, fix stale comments

- errors/cascade.py + __init__.py: remove PersistentCascadeFunctionError and its __all__ entry
- delete tests/integration/foreign_keys/test_cascade_self_heal.py
- config.py: cascade_function_name freeze-exemption comment now references init_rapyer(), not the removed self-heal path

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rigin/develop' into codex/fix-init-rapyer-connection-rebind

# Conflicts:
#	rapyer/init.py
…onnection-rebind

Fix init_rapyer connection rebinding order

@github-advanced-security github-advanced-security AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Semgrep OSS found more than 20 potential problems in the proposed changes. Check the Files changed tab for more details.

Comment thread rapyer/scripts/loader.py Dismissed
Comment thread rapyer/scripts/loader.py
SF_SAVE_FILENAME = "save.lua"
SF_LOAD_FILENAME = "load.lua"
CASCADE_LIB_TOKEN = "RAPYER_CASCADE_LIB"
CASCADE_FN_TOKEN = "RAPYER_CASCADE_FN"
Comment thread rapyer/scripts/loader.py Dismissed
@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 0f0adb67-f0d6-4183-9fb7-119d5ae0e0be

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • ✅ Review completed - (🔄 Check again to review again)
📝 Walkthrough

Walkthrough

Adds configurable TTL cascading through Redis Functions, including graph planning, depth controls, dangling-key results, initialization validation, and special-field refreshes. Refactors generic Redis type handling and relational resolution, expands Redis and fakeredis tests, and updates CI workflows, Redis support, documentation, and release metadata.

Changes

TTL cascade contracts and initialization

Layer / File(s) Summary
Cascade configuration and planning
rapyer/cascade/*, rapyer/errors/*, rapyer/config.py
Adds CascadeTTL, cascade plan structures, validation errors, deterministic plan serialization, and metadata freezing.
Initialization and public API
rapyer/init.py, rapyer/base.py, rapyer/result.py, rapyer/__init__.py
Adds cascade initialization, Redis Function registration, aset_ttl(..., cascade=...), automatic refresh routing, and public CascadeResult.
Redis Function execution
rapyer/scripts/*
Generates plan-specific Lua libraries and applies atomic graph traversal, TTL refreshes, special-key refreshes, and dangling counts.
Cascade validation
tests/models/cascade_types.py, tests/unit/cascade/*, tests/integration/foreign_keys/*
Covers configuration, planning, graph cycles, depth budgets, special fields, corrupted references, concurrency, and real Redis behavior.

Generic type and serialization plumbing

Layer / File(s) Summary
Shared Redis type contracts
rapyer/types/*, rapyer/types/convert.py, rapyer/utils/*
Replaces dynamic original_type metadata with wrapped_python_type, adds generic argument resolution, and updates Pydantic schema construction.
Relational and model wiring
rapyer/base.py, rapyer/types/foreign_key.py, rapyer/types/relational.py
Uses runtime generic targets, avoids per-field dynamic foreign-key subclasses, updates child linking, lazy PK creation, and special-field paths.
Serialization coverage
tests/unit/models/*, tests/unit/types/*, tests/models/special_types.py
Updates priority-queue exclusion behavior and verifies native model dumps and shared foreign-key typing.

Repository automation and release configuration

Layer / File(s) Summary
CI and dependency workflows
.github/*, tox.ini, pyproject.toml
Adds branch-dependent Redis matrices, Redis 8 targets, explicit permissions, newer GitHub Actions versions, Dependabot target branches, and updated Redis constraints.
Benchmarks and documentation
benchmarks/conftest.py, docs/*, mkdocs.yml, CHANGELOG.md
Adds Unix-socket benchmark configuration, documents generic models, TTL cascade, and priority-queue serialization requirements, and records release 1.3.4.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Application
  participant AtomicRedisModel
  participant CascadePlanner
  participant RedisFunction
  participant Redis

  Application->>AtomicRedisModel: init_rapyer(cascade_ttl)
  AtomicRedisModel->>CascadePlanner: build and validate plan
  CascadePlanner-->>AtomicRedisModel: plan JSON and function names
  AtomicRedisModel->>Redis: register cascade function
  Application->>AtomicRedisModel: aset_ttl(cascade=True)
  AtomicRedisModel->>RedisFunction: FCALL cascade_apply
  RedisFunction->>Redis: JSON.GET references and EXPIRE keys
  Redis-->>RedisFunction: dangling child and special counts
  RedisFunction-->>AtomicRedisModel: CascadeResult payload
  AtomicRedisModel-->>Application: CascadeResult
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 27.45% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title matches the release/version-bump nature of the change set and points to the primary change.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch develop

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Comment thread rapyer/init.py
raise
try:
await model.adelete_index()
except ResponseError:
@github-actions

Copy link
Copy Markdown

Coverage report

Total coverage: 99%

Full report
Name                                                     Stmts   Miss  Cover
----------------------------------------------------------------------------
rapyer/__init__.py                                           5      0   100%
rapyer/actions.py                                          213      0   100%
rapyer/base.py                                             866      2    99%
rapyer/cascade/__init__.py                                   3      0   100%
rapyer/cascade/planner.py                                  144      5    97%
rapyer/cascade/spec.py                                      13      0   100%
rapyer/cascade/ttl.py                                        5      0   100%
rapyer/config.py                                            45      0   100%
rapyer/context.py                                           40      0   100%
rapyer/errors/__init__.py                                   11      0   100%
rapyer/errors/base.py                                       23      0   100%
rapyer/errors/cascade.py                                     8      0   100%
rapyer/errors/delete.py                                      3      0   100%
rapyer/errors/find.py                                       15      0   100%
rapyer/fields/__init__.py                                    4      0   100%
rapyer/fields/expression.py                                108      0   100%
rapyer/fields/index.py                                      20      0   100%
rapyer/fields/key.py                                        19      0   100%
rapyer/fields/safe_load.py                                  14      0   100%
rapyer/init.py                                              67      0   100%
rapyer/links.py                                              2      0   100%
rapyer/result.py                                            31      0   100%
rapyer/scripts/__init__.py                                   5      0   100%
rapyer/scripts/constants.py                                 17      0   100%
rapyer/scripts/loader.py                                    38      0   100%
rapyer/scripts/lua/__init__.py                               0      0   100%
rapyer/scripts/lua/atomic/__init__.py                        0      0   100%
rapyer/scripts/lua/cascade/__init__.py                       0      0   100%
rapyer/scripts/lua/datetime/__init__.py                      0      0   100%
rapyer/scripts/lua/dict/__init__.py                          0      0   100%
rapyer/scripts/lua/list/__init__.py                          0      0   100%
rapyer/scripts/lua/numeric/__init__.py                       0      0   100%
rapyer/scripts/lua/sf/__init__.py                            0      0   100%
rapyer/scripts/lua/sf/redis_priority_queue/__init__.py       0      0   100%
rapyer/scripts/lua/sf/redis_set/__init__.py                  0      0   100%
rapyer/scripts/lua/string/__init__.py                        0      0   100%
rapyer/scripts/registry.py                                  63      0   100%
rapyer/types/__init__.py                                    13      0   100%
rapyer/types/base.py                                       103      0   100%
rapyer/types/byte.py                                        33      0   100%
rapyer/types/convert.py                                     53      0   100%
rapyer/types/datetime.py                                    77      0   100%
rapyer/types/dct.py                                        116      0   100%
rapyer/types/float.py                                       65      0   100%
rapyer/types/foreign_key.py                                 68      0   100%
rapyer/types/generic.py                                     83      0   100%
rapyer/types/init.py                                        10      0   100%
rapyer/types/integer.py                                     58      0   100%
rapyer/types/lst.py                                        129      0   100%
rapyer/types/priority_queue.py                             102      0   100%
rapyer/types/redis_set.py                                  196      0   100%
rapyer/types/relational.py                                  24      0   100%
rapyer/types/special.py                                     39      0   100%
rapyer/types/string.py                                      22      0   100%
rapyer/typing_support.py                                     3      0   100%
rapyer/utils/__init__.py                                     0      0   100%
rapyer/utils/annotation.py                                  62      1    98%
rapyer/utils/fields.py                                      43      0   100%
rapyer/utils/pythonic.py                                    21      0   100%
rapyer/utils/redis.py                                       77      0   100%
----------------------------------------------------------------------------
TOTAL                                                     3179      8    99%

@codspeed-hq

codspeed-hq Bot commented Jul 21, 2026

Copy link
Copy Markdown

Merging this PR will regress 0 benchmarks

⚡ 75 improved benchmarks
❌ 3 (👁 3) regressed benchmarks
✅ 90 untouched benchmarks
🆕 3 new benchmarks

Performance Changes

Mode Benchmark BASE HEAD Efficiency
WallTime test_benchmark_with_ttl 1.5 ms 1.2 ms +23.91%
WallTime test_benchmark 561.3 µs 453.8 µs +23.7%
WallTime test_benchmark 1.4 ms 1.2 ms +22.83%
WallTime test_benchmark 3 ms 2.5 ms +21.59%
WallTime test_benchmark 2.7 ms 2.2 ms +20.7%
WallTime test_benchmark 1.7 ms 1.4 ms +20.67%
WallTime test_benchmark 1.4 ms 1.2 ms +19.79%
WallTime test_benchmark_with_ttl 548.7 µs 458.8 µs +19.58%
WallTime test_benchmark_with_ttl 2.2 ms 1.9 ms +19.15%
WallTime test_benchmark 1.8 ms 1.5 ms +19.03%
WallTime test_benchmark 927.2 µs 780.7 µs +18.77%
WallTime test_benchmark 1.5 ms 1.2 ms +18.72%
WallTime test_benchmark 1.4 ms 1.2 ms +18.24%
WallTime test_benchmark 2.6 ms 2.2 ms +18.16%
WallTime test_benchmark 1.5 ms 1.3 ms +18.02%
WallTime test_benchmark 1.4 ms 1.2 ms +17.77%
WallTime test_benchmark_with_ttl 1.9 ms 1.6 ms +17.58%
WallTime test_benchmark 1.5 ms 1.3 ms +17.57%
WallTime test_benchmark 1.5 ms 1.3 ms +17.26%
WallTime test_benchmark 1.4 ms 1.2 ms +17.19%
... ... ... ... ... ...

ℹ️ Only the first 20 benchmarks are displayed. Go to the app to view all benchmarks.

Tip

Curious why this is faster? Comment @codspeedbot explain why this is faster on this PR, or directly use the CodSpeed MCP with your agent.


Comparing develop (8d6ff3a) with main (9b3c9af)

Open in CodSpeed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (7)
tests/unit/cascade/conftest.py (1)

74-125: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicated setup/teardown logic between the two fixtures.

setup_fake_redis_for_cascade_models and setup_fake_redis_for_cascade_apply differ only by the register_scripts call, yet both fully repeat the snapshot/wire/restore loop. Extracting the shared body (e.g. a helper context manager, or having the async fixture wrap the sync one) would avoid the two copies drifting if the snapshot/restore fields ever change.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/cascade/conftest.py` around lines 74 - 125, Extract the duplicated
model snapshot, fakeredis wiring, relational-target resolution, and teardown
logic from setup_fake_redis_for_cascade_models and
setup_fake_redis_for_cascade_apply into one shared helper or fixture. Keep
register_scripts(fake_redis_client, is_fakeredis=True) only in the cascade-apply
setup path, while ensuring both fixtures restore all original Meta fields after
yielding.
tests/integration/foreign_keys/test_cascade_depth_and_gate.py (1)

27-36: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Same _apply_cascade FCALL helper copy-pasted across three integration test files. All three define an identical async helper that calls real_redis_client.fcall(type(root).Meta.cascade_function_name, 1, root.key, type(root).__name__, SPECIAL_FIELD_KEY_PREFIX, type(root).Meta.ttl, 1 if cascade else 0). If the FCALL argument order or signature ever changes, all three copies must be updated in lockstep or tests silently diverge.

  • tests/integration/foreign_keys/test_cascade_depth_and_gate.py#L27-L36: move this helper into a shared conftest/fixture module and import it here.
  • tests/integration/foreign_keys/test_cascade_graph_shapes.py#L16-L25: import the shared helper instead of redefining it.
  • tests/integration/foreign_keys/test_cascade_ttl_apply.py#L21-L30: import the shared helper instead of redefining it.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/integration/foreign_keys/test_cascade_depth_and_gate.py` around lines
27 - 36, Move the duplicated async _apply_cascade helper into a shared conftest
or fixture module, preserving its existing FCALL argument order and behavior. In
tests/integration/foreign_keys/test_cascade_depth_and_gate.py#L27-L36, define
and expose the shared helper, then import it in
tests/integration/foreign_keys/test_cascade_graph_shapes.py#L16-L25 and
tests/integration/foreign_keys/test_cascade_ttl_apply.py#L21-L30 while removing
their local definitions.
tests/models/cascade_types.py (1)

317-345: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Cascade fixture model list duplicated verbatim in two files. ALL_CASCADE_MODELS and CASCADE_PLANNER_MODELS contain the exact same 27 classes in the exact same order, maintained independently.

  • tests/models/cascade_types.py#L317-L345: keep ALL_CASCADE_MODELS as the single source of truth.
  • tests/unit/cascade/conftest.py#L36-L64: import and reuse ALL_CASCADE_MODELS from tests/models/cascade_types.py instead of redefining CASCADE_PLANNER_MODELS.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/models/cascade_types.py` around lines 317 - 345, Keep
ALL_CASCADE_MODELS in tests/models/cascade_types.py as the single source of
truth without changing its contents. In tests/unit/cascade/conftest.py, remove
the duplicated CASCADE_PLANNER_MODELS definition and import/reuse
ALL_CASCADE_MODELS from tests/models/cascade_types.py; update any references if
needed so planner fixtures use the shared list.
rapyer/types/base.py (1)

26-30: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

wrapped_python_type has no default, and RedisBytes is the one subclass that never sets it.

The base ClassVar[type] declaration has no fallback, so it's only safe as long as every subclass either sets it or (like RedisBytes) fully overrides __get_pydantic_core_schema__ to avoid touching it. That's fragile for future maintenance — any generic introspection of wrapped_python_type across redis types would blow up on RedisBytes.

  • rapyer/types/base.py#L26-L30: give wrapped_python_type a safe default (or an explicit "not implemented" property) on BaseRedisType so subclasses that forget to set it fail predictably rather than only by accident of which methods they happen to override.
  • rapyer/types/byte.py#L10-L36: declare wrapped_python_type: ClassVar[type] = bytes on RedisBytes for consistency with RedisStr/RedisDatetime/RedisList, even though the custom schema override doesn't currently need it.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rapyer/types/base.py` around lines 26 - 30, Provide a safe default for
wrapped_python_type on BaseRedisType, then explicitly set wrapped_python_type to
bytes on RedisBytes for consistency with the other Redis type subclasses. Update
rapyer/types/base.py lines 26-30 and rapyer/types/byte.py lines 10-36; no other
behavior needs to change.
rapyer/base.py (1)

866-874: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove the unused _ttl_keys() helper. Nothing in the repo calls it anymore, so it can be dropped unless there’s an external caller.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rapyer/base.py` around lines 866 - 874, Remove the unused _ttl_keys method
from the model class, including its docstring and list construction; do not
alter _iter_special_fields or other TTL-related behavior.
rapyer/types/convert.py (1)

95-97: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Fix typo in method name.

The method name covert_generic_type has a typo (missing 'r'). Consider renaming it to convert_generic_type (and updating any callers, e.g., in rapyer.utils.annotation) to maintain naming consistency with convert_flat_type.

♻️ Proposed refactor
-    def covert_generic_type(
-        self, type_to_covert: type, generic_values: tuple[type]
+    def convert_generic_type(
+        self, type_to_convert: type, generic_values: tuple[type]
     ) -> type:
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rapyer/types/convert.py` around lines 95 - 97, Rename the TypeConverter
method covert_generic_type to convert_generic_type, and update every caller such
as rapyer.utils.annotation to use the corrected name while preserving the
existing behavior and consistency with convert_flat_type.
rapyer/init.py (1)

76-81: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Filter ResponseError to avoid silently swallowing unexpected initialization failures.

When override_old_idx is False, catching and indiscriminately swallowing ResponseError during index creation successfully suppresses the expected "Index already exists" exception. However, it will also silently suppress actual critical failures (e.g., RediSearch module missing, schema syntax errors, invalid configurations), leaving the application running without an index.

Consider checking the error message so you only suppress the benign index-existence error.

🛠️ Proposed fix to narrow the suppression
-                    try:
-                        await model.acreate_index()
-                    except ResponseError:
-                        if override_old_idx:
-                            raise
+                    try:
+                        await model.acreate_index()
+                    except ResponseError as e:
+                        if override_old_idx or "Index already exists" not in str(e):
+                            raise
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rapyer/init.py` around lines 76 - 81, Update the ResponseError handling
around model.acreate_index() in initialization to suppress only the known “index
already exists” condition when override_old_idx is false. Re-raise all other
ResponseError instances, including module, schema, and configuration failures;
preserve the current re-raise behavior when override_old_idx is true.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@rapyer/types/lst.py`:
- Around line 36-39: Update the build_typed_original classmethod to handle empty
source_args before accessing source_args[0]. For unparameterized RedisList/list
annotations, return the established Any fallback or explicitly reject them;
preserve the existing parameterized behavior.

In `@tests/unit/cascade/test_init_rapyer_cascade_ttl.py`:
- Around line 56-58: Wrap the `init_rapyer(mock_redis_client)` call in the
test’s `REDIS_MODELS` patch context, patching `rapyer.init.REDIS_MODELS` with
the existing `cascade_models` fixture. Keep the test’s current arrange and
assertion behavior unchanged while ensuring initialization processes only the
fixture models.

---

Nitpick comments:
In `@rapyer/base.py`:
- Around line 866-874: Remove the unused _ttl_keys method from the model class,
including its docstring and list construction; do not alter _iter_special_fields
or other TTL-related behavior.

In `@rapyer/init.py`:
- Around line 76-81: Update the ResponseError handling around
model.acreate_index() in initialization to suppress only the known “index
already exists” condition when override_old_idx is false. Re-raise all other
ResponseError instances, including module, schema, and configuration failures;
preserve the current re-raise behavior when override_old_idx is true.

In `@rapyer/types/base.py`:
- Around line 26-30: Provide a safe default for wrapped_python_type on
BaseRedisType, then explicitly set wrapped_python_type to bytes on RedisBytes
for consistency with the other Redis type subclasses. Update
rapyer/types/base.py lines 26-30 and rapyer/types/byte.py lines 10-36; no other
behavior needs to change.

In `@rapyer/types/convert.py`:
- Around line 95-97: Rename the TypeConverter method covert_generic_type to
convert_generic_type, and update every caller such as rapyer.utils.annotation to
use the corrected name while preserving the existing behavior and consistency
with convert_flat_type.

In `@tests/integration/foreign_keys/test_cascade_depth_and_gate.py`:
- Around line 27-36: Move the duplicated async _apply_cascade helper into a
shared conftest or fixture module, preserving its existing FCALL argument order
and behavior. In
tests/integration/foreign_keys/test_cascade_depth_and_gate.py#L27-L36, define
and expose the shared helper, then import it in
tests/integration/foreign_keys/test_cascade_graph_shapes.py#L16-L25 and
tests/integration/foreign_keys/test_cascade_ttl_apply.py#L21-L30 while removing
their local definitions.

In `@tests/models/cascade_types.py`:
- Around line 317-345: Keep ALL_CASCADE_MODELS in tests/models/cascade_types.py
as the single source of truth without changing its contents. In
tests/unit/cascade/conftest.py, remove the duplicated CASCADE_PLANNER_MODELS
definition and import/reuse ALL_CASCADE_MODELS from
tests/models/cascade_types.py; update any references if needed so planner
fixtures use the shared list.

In `@tests/unit/cascade/conftest.py`:
- Around line 74-125: Extract the duplicated model snapshot, fakeredis wiring,
relational-target resolution, and teardown logic from
setup_fake_redis_for_cascade_models and setup_fake_redis_for_cascade_apply into
one shared helper or fixture. Keep register_scripts(fake_redis_client,
is_fakeredis=True) only in the cascade-apply setup path, while ensuring both
fixtures restore all original Meta fields after yielding.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 46f99462-d0dd-47ee-a83f-b009971d80c3

📥 Commits

Reviewing files that changed from the base of the PR and between 9b3c9af and 61a1f65.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock, !**/*.lock, !**/uv.lock
📒 Files selected for processing (96)
  • .coderabbit.yaml
  • .github/dependabot.yml
  • .github/redis-matrix.json
  • .github/workflows/bandit.yml
  • .github/workflows/ci.yml
  • .github/workflows/codeql.yml
  • .github/workflows/coverage.yml
  • .github/workflows/docs.yml
  • .github/workflows/pm.yml
  • .github/workflows/publish.yml
  • .github/workflows/release.yml
  • .github/workflows/security.yml
  • .github/workflows/semgrep.yml
  • .github/workflows/speed.yml
  • CHANGELOG.md
  • benchmarks/conftest.py
  • docs/documentation/initialization.md
  • docs/documentation/special-fields/foreign-keys.md
  • docs/documentation/special-fields/priority-queue.md
  • docs/documentation/special-fields/ttl-cascade.md
  • mkdocs.yml
  • pyproject.toml
  • rapyer/__init__.py
  • rapyer/base.py
  • rapyer/cascade/__init__.py
  • rapyer/cascade/planner.py
  • rapyer/cascade/spec.py
  • rapyer/cascade/ttl.py
  • rapyer/config.py
  • rapyer/errors/__init__.py
  • rapyer/errors/cascade.py
  • rapyer/init.py
  • rapyer/result.py
  • rapyer/scripts/__init__.py
  • rapyer/scripts/constants.py
  • rapyer/scripts/loader.py
  • rapyer/scripts/lua/cascade/__init__.py
  • rapyer/scripts/lua/cascade/library.lua
  • rapyer/scripts/registry.py
  • rapyer/types/base.py
  • rapyer/types/byte.py
  • rapyer/types/convert.py
  • rapyer/types/datetime.py
  • rapyer/types/dct.py
  • rapyer/types/float.py
  • rapyer/types/foreign_key.py
  • rapyer/types/generic.py
  • rapyer/types/integer.py
  • rapyer/types/lst.py
  • rapyer/types/priority_queue.py
  • rapyer/types/redis_set.py
  • rapyer/types/relational.py
  • rapyer/types/string.py
  • rapyer/utils/annotation.py
  • rapyer/utils/pythonic.py
  • tests/action_groups.py
  • tests/conftest.py
  • tests/integration/actions/redis_types/test_foreign_key.py
  • tests/integration/actions/ttl.py
  • tests/integration/conftest.py
  • tests/integration/foreign_keys/conftest.py
  • tests/integration/foreign_keys/test_cascade_action_boundary.py
  • tests/integration/foreign_keys/test_cascade_concurrent_mutation.py
  • tests/integration/foreign_keys/test_cascade_depth_and_gate.py
  • tests/integration/foreign_keys/test_cascade_graph_shapes.py
  • tests/integration/foreign_keys/test_cascade_ttl_apply.py
  • tests/integration/foreign_keys/test_foreign_key.py
  • tests/integration/functioninality/test_rapyer_aget.py
  • tests/integration/lst/test_redis_list_remove_range.py
  • tests/integration/pipeline/test_pipeline_noscript_recovery.py
  • tests/models/cascade_types.py
  • tests/models/collection_types.py
  • tests/models/foreign_key_types.py
  • tests/models/registry.py
  • tests/models/special_types.py
  • tests/unit/cascade/__init__.py
  • tests/unit/cascade/conftest.py
  • tests/unit/cascade/test_aset_ttl_cascade_flag.py
  • tests/unit/cascade/test_cascade_action_boundary.py
  • tests/unit/cascade/test_cascade_apply_lua_syntax.py
  • tests/unit/cascade/test_cascade_classification.py
  • tests/unit/cascade/test_cascade_plan_injection.py
  • tests/unit/cascade/test_cascade_plan_table.py
  • tests/unit/cascade/test_cascade_ttl_config.py
  • tests/unit/cascade/test_cascade_ttl_required_validation.py
  • tests/unit/cascade/test_init_rapyer_cascade_ttl.py
  • tests/unit/cascade/test_meta_ttl_freeze.py
  • tests/unit/cascade/test_refresh_ttl_cascade_branch.py
  • tests/unit/conftest.py
  • tests/unit/models/test_model_dump.py
  • tests/unit/test_base_functions.py
  • tests/unit/test_init_rapyer.py
  • tests/unit/test_refresh_ttl_if_needed.py
  • tests/unit/types/test_foreign_key.py
  • tests/unit/types/test_special_types.py
  • tox.ini

Comment thread rapyer/types/lst.py
Comment on lines +56 to +58
# Act
await init_rapyer(mock_redis_client)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Add the missing REDIS_MODELS patch context to isolate the test.

This test requests the cascade_models fixture but currently omits the with patch("rapyer.init.REDIS_MODELS", cascade_models): block that is used in the adjacent test. Without it, init_rapyer() will process the entire global REDIS_MODELS registry, which couples the test's success to the stability of the global registry and introduces unnecessary processing overhead.

🛠️ Proposed fix
-    # Act
-    await init_rapyer(mock_redis_client)
+    # Act
+    with patch("rapyer.init.REDIS_MODELS", cascade_models):
+        await init_rapyer(mock_redis_client)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Act
await init_rapyer(mock_redis_client)
# Act
with patch("rapyer.init.REDIS_MODELS", cascade_models):
await init_rapyer(mock_redis_client)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/cascade/test_init_rapyer_cascade_ttl.py` around lines 56 - 58,
Wrap the `init_rapyer(mock_redis_client)` call in the test’s `REDIS_MODELS`
patch context, patching `rapyer.init.REDIS_MODELS` with the existing
`cascade_models` fixture. Keep the test’s current arrange and assertion behavior
unchanged while ensuring initialization processes only the fixture models.

…or FK graphs

Benchmark aset_ttl(cascade=True) across three FK shapes: a root with
two direct FKs, a 10-layer FK chain, and a root holding a list of 10
FKs. Chain uses a per-field CascadeTTL marker (not Meta.cascade_ttl,
which init_rapyer resets to None when no cascade arg is passed) so the
whole chain is walked.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants