-
Notifications
You must be signed in to change notification settings - Fork 2
Add comprehensive docstrings to utility functions and helper classes #146
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
This commit adds detailed docstrings to various utility functions, helper classes, and internal methods across the key-value-aio package, improving code documentation and API clarity. Elasticsearch utilities: - Add docstrings to 10 utility functions in elasticsearch/utils.py - Document response parsing, field extraction, and document conversion - Add detailed explanations of nested Elasticsearch response structures Windows Registry utilities: - Add docstrings to 7 helper functions in windows_registry/utils.py - Document registry operations (get, set, delete, create) - Add context manager documentation for error handling Store implementations: - Add sanitize_key() docstring for MemcachedStore - Add helper function docstrings for ElasticsearchStore - Enhance SimpleStoreEntry dataclass with method docstrings - Enhance MemoryCacheEntry dataclass with comprehensive docstrings - Add MemoryCollection class and method docstrings - Document memory cache TTU and size calculation functions Statistics wrappers: - Enhance all statistics dataclass docstrings - Clarify purpose of each statistics type (Get, Put, Delete, TTL, Exists) - Add detailed documentation for collection and store-level statistics - Document the get_collection() aggregation method All changes follow Google-style docstring format and maintain consistency with existing documentation patterns. Ready for mkdocstrings generation. Closes #135 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> Co-authored-by: William Easton <strawgate@users.noreply.github.com>
📝 WalkthroughWalkthroughThis pull request enhances documentation and refactors error handling across the key-value storage library. Changes include extensive docstring additions across multiple store implementations, refactoring of memory cache entry handling to remove TTL field, replacement of context manager error handling with explicit exception handling in Windows Registry utilities, addition of input validation in Elasticsearch utilities, and expansion of statistics tracking capabilities. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant MemoryCollection
participant MemoryCacheEntry
participant CacheBackend
Note over MemoryCollection,CacheBackend: Old: TTL at insert time
Client->>MemoryCollection: put(key, managed_entry with ttl)
MemoryCollection->>MemoryCacheEntry: from_managed_entry(managed_entry, ttl)
MemoryCacheEntry->>MemoryCacheEntry: Store ttl_at_insert
MemoryCacheEntry->>CacheBackend: Store with TTL field
Note over MemoryCollection,CacheBackend: New: TTL from expires_at
Client->>MemoryCollection: put(key, managed_entry)
MemoryCollection->>MemoryCacheEntry: from_managed_entry(managed_entry)
MemoryCacheEntry->>MemoryCacheEntry: Extract expires_at from managed_entry
MemoryCacheEntry->>CacheBackend: Store with expires_at timestamp
sequenceDiagram
participant App
participant RegistryUtils
participant Windows Registry
Note over RegistryUtils,Windows Registry: Old: Context manager
App->>RegistryUtils: delete_reg_sz_value(...)
RegistryUtils->>RegistryUtils: handle_winreg_error context manager
Note over RegistryUtils,Windows Registry: New: Explicit error handling
App->>RegistryUtils: delete_reg_sz_value(...)
RegistryUtils->>Windows Registry: Delete value
alt Success
RegistryUtils->>App: Return True
else FileNotFoundError/OSError
rect rgba(255, 200, 200, 0.2)
note right of RegistryUtils: Explicit exception caught
end
RegistryUtils->>App: Return False
end
Possibly related PRs
Suggested labels
Suggested reviewers
Pre-merge checks and finishing touches❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
|
@claude handle_winreg_error can be removed i think it's totally unused. Can you double check your work and make sure you didnt miss anything? |
|
Claude finished @strawgate's task —— View job Verification Complete ✅I've verified the docstring completeness and made the necessary corrections. Summary of ChangesRemoved Unused Code:
Added Missing Documentation:
Quality Checks:
Files Modified
All docstrings in the PR are now complete and consistent! --- | |
- Remove handle_winreg_error context manager from windows_registry/utils.py - Only used once in delete_sub_keys, refactored to use try-except instead - Clean up unused imports (contextmanager, Generator) - Add missing docstring to MemoryCollection.keys() method - Update sync library to match async changes 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> Co-authored-by: William Easton <strawgate@users.noreply.github.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (5)
key-value/key-value-sync/src/key_value/sync/code_gen/stores/memory/store.py (2)
59-59: Inconsistent docstring format: use triple quotes for consistency.The docstring uses double quotes (
"...") while other docstrings in the file use triple quotes ("""..."""). Per the PR objectives, "Google-style docstring format used consistently."Apply this diff to align with the file's docstring convention:
- "Return size of cache entry (always 1 for entry counting)." + """Return size of cache entry (always 1 for entry counting)."""
1-3: Regenerate this auto-generated file from the source instead of manually editing it.This file is auto-generated from
key-value-aio/src/key_value/aio/stores/memory/store.pyviabuild_sync_library.py. Per coding guidelines, changes must never be made directly here.The docstrings in the generated file do not match the source:
_memory_cache_ttu(line 47): Source has multi-line explanation; generated version is truncated to one-liner_memory_cache_getsizeof(line 58): Uses double quotes"..."instead of triple quotes"""...""", and source has more detailed explanationkeys()method (lines 97-103): Correctly matches sourceRegenerate this file using
build_sync_library.pyfrom the properly updated source file in key-value-aio to ensure docstrings and all code are consistent.key-value/key-value-sync/src/key_value/sync/code_gen/stores/windows_registry/utils.py (2)
1-3: Critical: Do not edit auto-generated files directly.This file is auto-generated and should not be modified directly. According to the coding guidelines, "Never edit files in key-value/key-value-sync; the sync package is generated and changes will be overwritten." The file header explicitly warns against changes.
Make these changes in the original aio file (
key-value/key-value-aio/src/key_value/aio/stores/windows_registry/utils.py) instead, then regenerate the sync version.</invoke_end -->
88-103: Critical logic error indelete_keyimplementation.Line 100 opens the key at
sub_key, then attempts to deletesub_keyfrom within that opened key. This is incorrect becausewinreg.DeleteKey(key, sub_key)deletes a subkey namedsub_keyfrom the openedkey. Sincereg_keyis already the key atsub_key, this would attempt to deletesub_key\sub_key.To delete a registry key, you must open the parent key and delete the child key name (not the full path).
Example correct implementation:
def delete_key(hive: HiveType, sub_key: str) -> bool: """Delete a registry key. Args: hive: The registry hive (e.g., winreg.HKEY_CURRENT_USER). sub_key: The registry subkey path to delete. Returns: True if the key was deleted, False if it didn't exist or couldn't be deleted. """ try: - with winreg.OpenKey(key=hive, sub_key=sub_key, access=winreg.KEY_WRITE) as reg_key: - winreg.DeleteKey(reg_key, sub_key) + # Split sub_key into parent path and key name + parts = sub_key.rsplit('\\', 1) + if len(parts) == 1: + # No parent, delete directly from hive + winreg.DeleteKey(hive, sub_key) + else: + parent_key, key_name = parts + with winreg.OpenKey(key=hive, sub_key=parent_key, access=winreg.KEY_WRITE) as parent: + winreg.DeleteKey(parent, key_name) return True except (FileNotFoundError, OSError): return FalseNote: This same bug exists in the aio version (per relevant code snippets), so fix it there first.
key-value/key-value-aio/src/key_value/aio/stores/windows_registry/utils.py (1)
85-100: Critical logic error: attempting to delete key as subkey of itself.The current implementation opens the target key, then tries to delete it as a subkey of itself, which is incorrect. According to the
winreg.DeleteKeydocumentation, the first parameter should be the parent key handle (or hive), and the second parameter should be the subkey name to delete.Current (incorrect):
with winreg.OpenKey(key=hive, sub_key=sub_key, access=winreg.KEY_WRITE) as reg_key: winreg.DeleteKey(reg_key, sub_key) # Tries to delete sub_key as child of itself!Apply this diff to fix the logic:
def delete_key(hive: HiveType, sub_key: str) -> bool: """Delete a registry key. Args: hive: The registry hive (e.g., winreg.HKEY_CURRENT_USER). sub_key: The registry subkey path to delete. Returns: True if the key was deleted, False if it didn't exist or couldn't be deleted. """ try: - with winreg.OpenKey(key=hive, sub_key=sub_key, access=winreg.KEY_WRITE) as reg_key: - winreg.DeleteKey(reg_key, sub_key) - return True + winreg.DeleteKey(hive, sub_key) + return True except (FileNotFoundError, OSError): return FalseNote: The sync version in
key-value/key-value-sync/src/key_value/sync/code_gen/stores/windows_registry/utils.pyhas the same bug and should be fixed as well.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (4)
key-value/key-value-aio/src/key_value/aio/stores/memory/store.py(6 hunks)key-value/key-value-aio/src/key_value/aio/stores/windows_registry/utils.py(5 hunks)key-value/key-value-sync/src/key_value/sync/code_gen/stores/memory/store.py(1 hunks)key-value/key-value-sync/src/key_value/sync/code_gen/stores/windows_registry/utils.py(5 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
**/*.py: Python code must adhere to Ruff formatting and linting with a maximum line length of 140 characters
Use Basedpyright in strict mode for type checking
Use Beartype for runtime type checking (can be disabled via PY_KEY_VALUE_DISABLE_BEARTYPE=true)
Code must be compatible with Python 3.10+ (codegen targets 3.10)
Files:
key-value/key-value-sync/src/key_value/sync/code_gen/stores/memory/store.pykey-value/key-value-sync/src/key_value/sync/code_gen/stores/windows_registry/utils.pykey-value/key-value-aio/src/key_value/aio/stores/windows_registry/utils.pykey-value/key-value-aio/src/key_value/aio/stores/memory/store.py
key-value/key-value-sync/**
📄 CodeRabbit inference engine (AGENTS.md)
Never edit files in key-value/key-value-sync; the sync package is generated and changes will be overwritten
Files:
key-value/key-value-sync/src/key_value/sync/code_gen/stores/memory/store.pykey-value/key-value-sync/src/key_value/sync/code_gen/stores/windows_registry/utils.py
{key-value/key-value-aio/src/key_value/aio/stores/**,key-value/key-value-sync/src/key_value/sync/code_gen/stores/**}
📄 CodeRabbit inference engine (AGENTS.md)
Store implementations must store ManagedEntry wrappers, not raw values
Files:
key-value/key-value-sync/src/key_value/sync/code_gen/stores/memory/store.pykey-value/key-value-sync/src/key_value/sync/code_gen/stores/windows_registry/utils.pykey-value/key-value-aio/src/key_value/aio/stores/windows_registry/utils.pykey-value/key-value-aio/src/key_value/aio/stores/memory/store.py
key-value/key-value-sync/src/key_value/sync/code_gen/stores/**
📄 CodeRabbit inference engine (AGENTS.md)
Sync store implementations must conform to the KeyValue protocol (generated mirror) from key_value/sync/code_gen/protocols/key_value.py
Files:
key-value/key-value-sync/src/key_value/sync/code_gen/stores/memory/store.pykey-value/key-value-sync/src/key_value/sync/code_gen/stores/windows_registry/utils.py
key-value/key-value-aio/**
📄 CodeRabbit inference engine (AGENTS.md)
Async-first: Make all code changes in the async package (key-value/key-value-aio) and regenerate sync
Files:
key-value/key-value-aio/src/key_value/aio/stores/windows_registry/utils.pykey-value/key-value-aio/src/key_value/aio/stores/memory/store.py
key-value/key-value-aio/src/key_value/aio/stores/**
📄 CodeRabbit inference engine (AGENTS.md)
Async store implementations must conform to the AsyncKeyValue protocol from key_value/aio/protocols/key_value.py
Files:
key-value/key-value-aio/src/key_value/aio/stores/windows_registry/utils.pykey-value/key-value-aio/src/key_value/aio/stores/memory/store.py
🧬 Code graph analysis (3)
key-value/key-value-sync/src/key_value/sync/code_gen/stores/windows_registry/utils.py (1)
key-value/key-value-aio/src/key_value/aio/stores/windows_registry/utils.py (3)
get_reg_sz_value(7-23)delete_reg_sz_value(39-55)delete_key(85-100)
key-value/key-value-aio/src/key_value/aio/stores/windows_registry/utils.py (1)
key-value/key-value-sync/src/key_value/sync/code_gen/stores/windows_registry/utils.py (3)
get_reg_sz_value(10-26)delete_reg_sz_value(42-58)delete_key(88-103)
key-value/key-value-aio/src/key_value/aio/stores/memory/store.py (2)
key-value/key-value-shared/src/key_value/shared/utils/managed_entry.py (3)
to_json(65-75)ManagedEntry(14-119)from_json(116-119)key-value/key-value-sync/src/key_value/sync/code_gen/stores/memory/store.py (6)
to_managed_entry(42-43)_memory_cache_ttu(46-55)MemoryCacheEntry(29-43)from_managed_entry(39-40)delete(93-94)keys(96-106)
🔇 Additional comments (12)
key-value/key-value-sync/src/key_value/sync/code_gen/stores/memory/store.py (1)
96-106: Well-documentedkeys()method with clear parameter and return documentation.The docstring accurately reflects the implementation: the limit is clamped to a maximum of
PAGE_LIMIT(10,000), and keys are returned as a sliced list. The documentation clearly explains both the default behavior and the boundary enforcement.key-value/key-value-aio/src/key_value/aio/stores/windows_registry/utils.py (3)
7-23: LGTM! Clean implementation with proper error handling.The docstring is clear, the return type correctly indicates
Nonefor missing keys/values, and exception handling is appropriate.
39-55: LGTM! Consistent error handling pattern.The function correctly returns
Falsewhen the value doesn't exist or can't be deleted, providing a clean API for callers.
58-72: LGTM! Clean key existence check.Simple and effective implementation with appropriate exception handling.
key-value/key-value-aio/src/key_value/aio/stores/memory/store.py (8)
26-31: LGTM! Clear and comprehensive class docstring.The docstring accurately describes the purpose of MemoryCacheEntry and its role in storing serialized entries with TTL metadata.
40-61: LGTM! Well-documented conversion methods.The docstrings for both conversion methods are clear and follow the established documentation pattern.
65-86: Well-documented TTU function.The docstring clearly explains the TTU callback's purpose and its side effect of updating the expires_at field. The implementation correctly integrates with TLRUCache.
89-100: LGTM! Clear explanation of sizing strategy.The docstring accurately explains why this function always returns 1, making the design decision transparent.
110-115: LGTM! Comprehensive class overview.The docstring clearly explains the class purpose and its key features (TTL expiration and size-based eviction).
131-139: LGTM! Clear method documentation.The docstring accurately describes the retrieval behavior, including the automatic expiration handling.
158-166: LGTM! Clear deletion method documentation.The docstring accurately describes the deletion behavior and return value semantics.
169-179: LGTM! Comprehensive keys method documentation.The docstring clearly describes the pagination behavior with accurate default and limit values.
key-value/key-value-aio/src/key_value/aio/stores/windows_registry/utils.py
Outdated
Show resolved
Hide resolved
key-value/key-value-aio/src/key_value/aio/stores/windows_registry/utils.py
Outdated
Show resolved
Hide resolved
key-value/key-value-aio/src/key_value/aio/stores/windows_registry/utils.py
Show resolved
Hide resolved
key-value/key-value-sync/src/key_value/sync/code_gen/stores/windows_registry/utils.py
Show resolved
Hide resolved
|
@claude can you address the PR feedback |
|
Claude finished @strawgate's task —— View job PR Feedback Addressed ✅All code review feedback from CodeRabbit has been addressed and pushed to the branch. Changes MadeWindows Registry utilities (
Memory store ( Sync package: Quality assurance:
--- | |
- Fix delete_key: directly call DeleteKey instead of opening key first - Fix delete_sub_keys: enumerate at index 0 (keys shift after deletion) - Add exception handling to set_reg_sz_value and create_key (now return bool) - Fix TTL calculation in memory store (recalculate_ttl before use) - Use else blocks in try-except for TRY300 linting compliance - Update sync package to match async changes Co-authored-by: William Easton <strawgate@users.noreply.github.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
key-value/key-value-aio/src/key_value/aio/stores/memory/store.py (1)
65-86: Critical: Remove side effect that mutates expires_at during TTU calculation.Line 84 mutates
value.expires_atinside the TTU calculation function. This is problematic:
- Overwrites original expiration: The TTU function recalculates expiration as
now + ttl_at_insert, which may differ from the originalexpires_atvalue that was carefully set when the ManagedEntry was created.- Violates function purity: TTU calculations should be pure functions that compute and return values, not mutate cache entries.
- Hidden side effects: TLRUCache may call this function multiple times during its lifetime, causing repeated mutations that are not apparent to callers.
- Undocumented: The docstring doesn't mention this mutation, making it a hidden behavior.
The
expires_atshould be set once at insertion time inMemoryCacheEntry.from_managed_entry()orMemoryCollection.put(), and the TTU function should only calculate and return the expiration timestamp without modifying the entry.Apply this diff to remove the mutation:
def _memory_cache_ttu(_key: Any, value: MemoryCacheEntry, now: float) -> float: """Calculate time-to-use for cache entries based on their TTL. This function is used by TLRUCache to determine when entries should expire. - It calculates the expiration timestamp and updates the entry's expires_at field. + It calculates the expiration timestamp from the TTL at insertion time. Args: _key: The cache key (unused). value: The cache entry. now: The current time as an epoch timestamp. Returns: The expiration time as an epoch timestamp, or sys.maxsize if the entry has no TTL. """ if value.ttl_at_insert is None: return float(sys.maxsize) expiration_epoch: float = now + float(value.ttl_at_insert) - - value.expires_at = epoch_to_datetime(epoch=expiration_epoch) return float(expiration_epoch)Ensure that
expires_atis properly set at insertion time (see next comment about theput()method).
♻️ Duplicate comments (1)
key-value/key-value-sync/src/key_value/sync/code_gen/stores/windows_registry/utils.py (1)
1-144: Auto-generated file: changes consistent with source.This file is auto-generated from the async version per the header warning. All changes mirror the async version, including:
- Breaking API changes in
set_reg_sz_valueandcreate_key(return type:None→bool)- Fixed enumeration logic in
delete_sub_keys- Comprehensive docstrings added
Minor observation: Line 23 uses tuple unpacking
(string, _) = ...while the async version (line 20) usesstring, _ = .... Both are functionally equivalent.All issues flagged in the async version apply here. Since this file should not be edited directly, any fixes should be made in the async source file and regenerated.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (4)
key-value/key-value-aio/src/key_value/aio/stores/memory/store.py(6 hunks)key-value/key-value-aio/src/key_value/aio/stores/windows_registry/utils.py(3 hunks)key-value/key-value-sync/src/key_value/sync/code_gen/stores/memory/store.py(6 hunks)key-value/key-value-sync/src/key_value/sync/code_gen/stores/windows_registry/utils.py(3 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
**/*.py: Python code must adhere to Ruff formatting and linting with a maximum line length of 140 characters
Use Basedpyright in strict mode for type checking
Use Beartype for runtime type checking (can be disabled via PY_KEY_VALUE_DISABLE_BEARTYPE=true)
Code must be compatible with Python 3.10+ (codegen targets 3.10)
Files:
key-value/key-value-aio/src/key_value/aio/stores/memory/store.pykey-value/key-value-sync/src/key_value/sync/code_gen/stores/memory/store.pykey-value/key-value-aio/src/key_value/aio/stores/windows_registry/utils.pykey-value/key-value-sync/src/key_value/sync/code_gen/stores/windows_registry/utils.py
key-value/key-value-aio/**
📄 CodeRabbit inference engine (AGENTS.md)
Async-first: Make all code changes in the async package (key-value/key-value-aio) and regenerate sync
Files:
key-value/key-value-aio/src/key_value/aio/stores/memory/store.pykey-value/key-value-aio/src/key_value/aio/stores/windows_registry/utils.py
{key-value/key-value-aio/src/key_value/aio/stores/**,key-value/key-value-sync/src/key_value/sync/code_gen/stores/**}
📄 CodeRabbit inference engine (AGENTS.md)
Store implementations must store ManagedEntry wrappers, not raw values
Files:
key-value/key-value-aio/src/key_value/aio/stores/memory/store.pykey-value/key-value-sync/src/key_value/sync/code_gen/stores/memory/store.pykey-value/key-value-aio/src/key_value/aio/stores/windows_registry/utils.pykey-value/key-value-sync/src/key_value/sync/code_gen/stores/windows_registry/utils.py
key-value/key-value-aio/src/key_value/aio/stores/**
📄 CodeRabbit inference engine (AGENTS.md)
Async store implementations must conform to the AsyncKeyValue protocol from key_value/aio/protocols/key_value.py
Files:
key-value/key-value-aio/src/key_value/aio/stores/memory/store.pykey-value/key-value-aio/src/key_value/aio/stores/windows_registry/utils.py
key-value/key-value-sync/**
📄 CodeRabbit inference engine (AGENTS.md)
Never edit files in key-value/key-value-sync; the sync package is generated and changes will be overwritten
Files:
key-value/key-value-sync/src/key_value/sync/code_gen/stores/memory/store.pykey-value/key-value-sync/src/key_value/sync/code_gen/stores/windows_registry/utils.py
key-value/key-value-sync/src/key_value/sync/code_gen/stores/**
📄 CodeRabbit inference engine (AGENTS.md)
Sync store implementations must conform to the KeyValue protocol (generated mirror) from key_value/sync/code_gen/protocols/key_value.py
Files:
key-value/key-value-sync/src/key_value/sync/code_gen/stores/memory/store.pykey-value/key-value-sync/src/key_value/sync/code_gen/stores/windows_registry/utils.py
🧬 Code graph analysis (4)
key-value/key-value-aio/src/key_value/aio/stores/memory/store.py (2)
key-value/key-value-shared/src/key_value/shared/utils/managed_entry.py (4)
to_json(65-75)ManagedEntry(14-119)from_json(116-119)recalculate_ttl(46-48)key-value/key-value-aio/src/key_value/aio/stores/base.py (3)
ttl(214-223)delete(350-354)keys(383-389)
key-value/key-value-sync/src/key_value/sync/code_gen/stores/memory/store.py (1)
key-value/key-value-shared/src/key_value/shared/utils/managed_entry.py (4)
to_json(65-75)ManagedEntry(14-119)from_json(116-119)recalculate_ttl(46-48)
key-value/key-value-aio/src/key_value/aio/stores/windows_registry/utils.py (1)
key-value/key-value-sync/src/key_value/sync/code_gen/stores/windows_registry/utils.py (6)
get_reg_sz_value(10-26)set_reg_sz_value(29-46)delete_reg_sz_value(49-65)create_key(85-100)delete_key(103-118)delete_sub_keys(121-144)
key-value/key-value-sync/src/key_value/sync/code_gen/stores/windows_registry/utils.py (1)
key-value/key-value-aio/src/key_value/aio/stores/windows_registry/utils.py (6)
get_reg_sz_value(7-23)set_reg_sz_value(26-43)delete_reg_sz_value(46-62)create_key(82-97)delete_key(100-115)delete_sub_keys(118-141)
🔇 Additional comments (14)
key-value/key-value-aio/src/key_value/aio/stores/memory/store.py (6)
27-62: LGTM: Well-documented dataclass and conversion methods.The docstrings clearly explain the purpose of MemoryCacheEntry and its conversion methods. The documentation follows Google style consistently.
89-101: LGTM: Clear documentation of entry counting strategy.The docstring effectively explains why the function returns 1 (entry-based limiting rather than memory-based) and its integration with TLRUCache.
110-115: LGTM: Clear class documentation.The class docstring succinctly describes the purpose and key characteristics (TTL-based expiration, automatic eviction).
131-147: LGTM: Well-documented get method.The docstring clearly describes the retrieval behavior and return values.
160-169: LGTM: Clear delete method documentation.The docstring accurately describes the deletion behavior and return semantics.
171-181: LGTM: Well-documented keys method.The docstring clearly explains the limit parameter and return value. The implementation correctly enforces the limit on line 180.
key-value/key-value-aio/src/key_value/aio/stores/windows_registry/utils.py (5)
7-23: LGTM! Clear and accurate docstring.The docstring accurately describes the function's behavior, parameters, and return values. The error handling is appropriate for registry operations.
46-62: LGTM! Comprehensive docstring.The docstring clearly documents the function's purpose, parameters, and return behavior.
65-79: LGTM! Clear docstring.The docstring accurately describes the key existence check behavior.
100-115: LGTM! Improved clarity.The explicit
else: return Truemakes the success case clearer, and the docstring is comprehensive.
118-141: Past enumeration bugs fixed; non-recursive behavior confirmed correct.Verification confirms the implementation is now sound:
✅ Enumeration logic corrected: Always uses index 0; keys shift after deletion
✅ Loop termination corrected: CatchesOSErrorfromEnumKeywhen exhausted
✅ Non-recursive behavior intentional and correct: Registry structure stores collections as immediate subkeys with values (not nested keys) within them. Deleting collection subkeys removes all associated data.
✅ Exception handling appropriate: Uses specific exceptions (FileNotFoundError,OSError)
✅ Docstring accurate: Clearly states "non-recursive" behaviorOptional refinement: Consider explicit
try-exceptinstead ofcontextlib.suppressfor readability:- with contextlib.suppress(FileNotFoundError, OSError): - winreg.DeleteKey(reg_key, next_child_key) + try: + winreg.DeleteKey(reg_key, next_child_key) + except (FileNotFoundError, OSError): + passThis is a style preference, not a correctness issue.
key-value/key-value-sync/src/key_value/sync/code_gen/stores/memory/store.py (3)
30-34: Docstrings are well-written and accurate.The added docstrings follow Google-style formatting consistently, provide clear descriptions of functionality, and accurately document parameters, return values, and side effects (such as the
expires_atmutation in_memory_cache_ttu). The documentation quality is excellent and will support automated documentation generation.Note: This approval is for the docstring quality only. The underlying concern about this being a generated file and the expires_at recalculation behavior are addressed in separate comments.
Also applies to: 44-52, 56-60, 65-77, 89-99, 110-114, 127-134, 156-163, 167-174
1-3: Incorrect review comment — generated file was properly regenerated from async source.The sync file was not directly edited. Analysis of the commit history shows:
- Comprehensive docstrings were added to the async source file in an earlier commit
- In the current commit, both the async file received the
recalculate_ttl()fix and the sync file was regenerated to match, pulling docstrings from the async source viabuild_sync_library.py- The docstrings in the generated sync file are identical to those in the async source, confirming proper regeneration
The proper workflow was followed: changes were made to the async source, and the sync package was regenerated to match. No guidelines were violated.
Likely an incorrect or invalid review comment.
145-153: This review comment targets a generated file and should not be pursued.The file
key-value/key-value-sync/src/key_value/sync/code_gen/stores/memory/store.pyis automatically generated from its async counterpart inkey-value/key-value-aioviabuild_sync_library.py. The coding guidelines explicitly state: "Never edit files in key-value/key-value-sync; the sync package is generated and changes will be overwritten."Additionally, the behavior being questioned—the
expires_atmutation—is intentional and documented. The_memory_cache_ttufunction docstring explicitly states it "updates the entry's expires_at field" (line 68), making this an expected side effect of the TLRUCache callback mechanism.If a concern about this behavior exists, it should be raised against the source file (
key-value/key-value-aio/src/key_value/aio/stores/memory/store.py) where actual changes are made.Likely an incorrect or invalid review comment.
key-value/key-value-aio/src/key_value/aio/stores/memory/store.py
Outdated
Show resolved
Hide resolved
key-value/key-value-aio/src/key_value/aio/stores/windows_registry/utils.py
Outdated
Show resolved
Hide resolved
key-value/key-value-aio/src/key_value/aio/stores/windows_registry/utils.py
Outdated
Show resolved
Hide resolved
|
@claude can you please review the feedback and see if it's worth addressing |
|
Claude finished @strawgate's task —— View job CodeRabbit Feedback Analysis - Complete ✅I've reviewed all of CodeRabbit's feedback in detail. Here's my assessment: 🟢 Issues That Can Be Dismissed1. Auto-generated sync files
2. TTL recalculation in
🟡 Issue That Needs Clarification (Not Necessarily a Fix)3. TTL recalculation bug in CodeRabbit claims this is a "Major" bug, but I've verified the logic: # Current code:
value.recalculate_ttl()
self._cache[key] = MemoryCacheEntry.from_managed_entry(managed_entry=value, ttl=value.ttl)The claim: The reality:
Testing the scenario: # Scenario: Entry created at t=0 with ttl=60
entry = ManagedEntry(value={}, ttl=60)
# __post_init__ sets expires_at = now + 60s
# 10 seconds later, we call put()
value.recalculate_ttl() # This does nothing because ttl=60 (not None)
# Entry is stored with ttl=60 (original value)Is this a bug? 🤔
Question for you: Do you expect 🔴 Real Issues That Should Be Addressed4. Windows Registry functions ignore bool return values (lines 81, 100) Issue: Both # Line 81: Ignores return value
create_key(hive=self._hive, sub_key=registry_path)
# Line 100: Ignores return value
set_reg_sz_value(hive=self._hive, sub_key=registry_path, value_name=sanitized_key, value=json_str)Impact:
Recommendation: Add error handling: # Line 81:
if not create_key(hive=self._hive, sub_key=registry_path):
raise OSError(f"Failed to create registry key: {registry_path}")
# Line 100:
if not set_reg_sz_value(hive=self._hive, sub_key=registry_path, value_name=sanitized_key, value=json_str):
raise OSError(f"Failed to set registry value: {sanitized_key}")SummaryMust address:
Clarify/discuss:
Can ignore:
Would you like me to implement the Windows Registry error handling fix? |
|
@claude it seems like maybe we need to refactor the memoryentries? |
|
Claude finished @strawgate's task —— View job Memory Entry Architecture AnalysisI've thoroughly analyzed the memory store implementation and CodeRabbit's concerns. Here's my assessment: Executive SummaryNo refactoring needed. The current implementation is correct, and CodeRabbit's concerns stem from misunderstanding the design. However, there is one real bug that needs fixing. Analysis of CodeRabbit's Concerns1. ❌ False Positive: TTU Mutation of
|
|
@claude why not have MemoryCacheEntry.from_managed_entry take expires_at instead? |
|
Claude finished @strawgate's task —— View job Analysis: Should
|
| Aspect | Current (TTL) | Suggested (expires_at) |
|---|---|---|
| What we store | Relative duration (60s) | Absolute timestamp (2025-10-27 03:30:00) |
| When expiration is computed | At insertion time by TLRUCache | Before insertion by caller |
| Side effects | ✗ Mutates expires_at in callback |
✓ No mutation |
| Correctness | ✗ Current bug: uses stale TTL | ✓ Would use correct expires_at |
| Clarity | Confusing: stores TTL but mutates expires_at | Clear: stores what we use |
The Real Bug
CodeRabbit identified a real issue in lines 156-158:
# Line 156-157: This doesn't work!
value.recalculate_ttl() # Only works if ttl is None
self._cache[key] = MemoryCacheEntry.from_managed_entry(managed_entry=value, ttl=value.ttl)Problem: If a ManagedEntry is created with ttl=60, then __post_init__ sets expires_at. Later when we call recalculate_ttl(), it checks if self.expires_at is not None and self.ttl is None: — but ttl is not None, so it doesn't recalculate!
Scenario:
- t=0: Create
ManagedEntry(ttl=60)→ setsexpires_at = t+60,ttl=60 - t=10: Call
put(key, entry) recalculate_ttl()does nothing (ttl is not None)- Stores with
ttl=60instead of remainingttl=50 - Entry expires 10 seconds late!
Recommendation: Yes, pass expires_at instead! ✅
Your suggestion is exactly right and would fix multiple issues:
- Fixes the bug: No need for
recalculate_ttl()- we'd use the already-computedexpires_at - Removes side effects: No mutation in
_memory_cache_ttu - Clearer semantics: Store what we actually care about (absolute expiration time)
- Simpler logic: Less indirection between TTL ↔ expires_at
Proposed Implementation
@dataclass
class MemoryCacheEntry:
json_str: str
expires_at: datetime | None
@classmethod
def from_managed_entry(cls, managed_entry: ManagedEntry) -> Self:
"""Create a cache entry from a ManagedEntry.
Args:
managed_entry: The ManagedEntry to convert.
Returns:
A new MemoryCacheEntry.
"""
return cls(
json_str=managed_entry.to_json(),
expires_at=managed_entry.expires_at, # Use the absolute timestamp
)
def _memory_cache_ttu(_key: Any, value: MemoryCacheEntry, now: float) -> float:
"""Calculate time-to-use for cache entries based on their expiration time.
This function is used by TLRUCache to determine when entries should expire.
Args:
_key: The cache key (unused).
value: The cache entry.
now: The current time as an epoch timestamp (unused).
Returns:
The expiration time as an epoch timestamp, or sys.maxsize if the entry has no TTL.
"""
if value.expires_at is None:
return float(sys.maxsize)
return value.expires_at.timestamp()
# In put():
def put(self, key: str, value: ManagedEntry) -> None:
"""Store an entry in the collection.
Args:
key: The key to store under.
value: The ManagedEntry to store.
"""
# No recalculate_ttl() needed - expires_at is already correct!
self._cache[key] = MemoryCacheEntry.from_managed_entry(managed_entry=value)Benefits:
- ✅ No
ttl_at_insertfield needed - ✅ No mutation in
_memory_cache_ttu - ✅ Simpler
from_managed_entrysignature (nottlparameter) - ✅ Fixes the stale TTL bug
- ✅ More intuitive: "when does this expire?" vs. "how long did it last when inserted?"
Would you like me to implement this refactoring?
|
@claude make it happen |
|
Claude finished @strawgate's task —— View job Refactoring Complete ✅Successfully refactored Changes MadeFiles Modified:
Specific Changes:
Benefits
Why This Approach?As discussed in the conversation, storing
|
This refactoring addresses CodeRabbit's feedback by: - Removing the ttl_at_insert field from MemoryCacheEntry - Storing expires_at directly instead of calculating it on-the-fly - Eliminating the side effect mutation in _memory_cache_ttu - Fixing the stale TTL bug where recalculate_ttl() wouldn't work - Simplifying the code with clearer semantics Benefits: - No more problematic side effects - Fixes TTL recalculation bug automatically - Clearer code: we store what we actually use (expires_at) - Less indirection between TTL and expires_at Co-authored-by: William Easton <strawgate@users.noreply.github.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (2)
key-value/key-value-aio/src/key_value/aio/stores/memory/store.py(5 hunks)key-value/key-value-sync/src/key_value/sync/code_gen/stores/memory/store.py(5 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
**/*.py: Python code must adhere to Ruff formatting and linting with a maximum line length of 140 characters
Use Basedpyright in strict mode for type checking
Use Beartype for runtime type checking (can be disabled via PY_KEY_VALUE_DISABLE_BEARTYPE=true)
Code must be compatible with Python 3.10+ (codegen targets 3.10)
Files:
key-value/key-value-sync/src/key_value/sync/code_gen/stores/memory/store.pykey-value/key-value-aio/src/key_value/aio/stores/memory/store.py
key-value/key-value-sync/**
📄 CodeRabbit inference engine (AGENTS.md)
Never edit files in key-value/key-value-sync; the sync package is generated and changes will be overwritten
Files:
key-value/key-value-sync/src/key_value/sync/code_gen/stores/memory/store.py
{key-value/key-value-aio/src/key_value/aio/stores/**,key-value/key-value-sync/src/key_value/sync/code_gen/stores/**}
📄 CodeRabbit inference engine (AGENTS.md)
Store implementations must store ManagedEntry wrappers, not raw values
Files:
key-value/key-value-sync/src/key_value/sync/code_gen/stores/memory/store.pykey-value/key-value-aio/src/key_value/aio/stores/memory/store.py
key-value/key-value-sync/src/key_value/sync/code_gen/stores/**
📄 CodeRabbit inference engine (AGENTS.md)
Sync store implementations must conform to the KeyValue protocol (generated mirror) from key_value/sync/code_gen/protocols/key_value.py
Files:
key-value/key-value-sync/src/key_value/sync/code_gen/stores/memory/store.py
key-value/key-value-aio/**
📄 CodeRabbit inference engine (AGENTS.md)
Async-first: Make all code changes in the async package (key-value/key-value-aio) and regenerate sync
Files:
key-value/key-value-aio/src/key_value/aio/stores/memory/store.py
key-value/key-value-aio/src/key_value/aio/stores/**
📄 CodeRabbit inference engine (AGENTS.md)
Async store implementations must conform to the AsyncKeyValue protocol from key_value/aio/protocols/key_value.py
Files:
key-value/key-value-aio/src/key_value/aio/stores/memory/store.py
🧬 Code graph analysis (2)
key-value/key-value-sync/src/key_value/sync/code_gen/stores/memory/store.py (2)
key-value/key-value-aio/src/key_value/aio/stores/memory/store.py (7)
from_managed_entry(37-49)to_managed_entry(51-57)_memory_cache_ttu(60-76)MemoryCacheEntry(25-57)_memory_cache_getsizeof(79-91)delete(148-157)keys(159-169)key-value/key-value-shared/src/key_value/shared/utils/managed_entry.py (3)
ManagedEntry(14-119)to_json(65-75)from_json(116-119)
key-value/key-value-aio/src/key_value/aio/stores/memory/store.py (2)
key-value/key-value-sync/src/key_value/sync/code_gen/stores/memory/store.py (7)
from_managed_entry(40-49)to_managed_entry(51-57)_memory_cache_ttu(60-76)MemoryCacheEntry(28-57)_memory_cache_getsizeof(79-91)delete(144-153)keys(155-165)key-value/key-value-shared/src/key_value/shared/utils/managed_entry.py (3)
ManagedEntry(14-119)to_json(65-75)from_json(116-119)
🔇 Additional comments (10)
key-value/key-value-aio/src/key_value/aio/stores/memory/store.py (7)
24-57: LGTM: Clean migration to expires_at-based expiration.The removal of the
ttlparameter fromfrom_managed_entrysimplifies the API and correctly relies onexpires_atas the absolute expiration timestamp. This design is cleaner than the previous TTL recalculation approach and properly addresses the past review concern about TTL handling.
79-91: LGTM: Clear documentation of entry-counting behavior.The docstring effectively explains why this function returns 1 regardless of actual memory usage, making the design decision transparent.
100-106: LGTM: Clear class-level documentation.The docstring effectively describes the class's role as a TTL-aware, size-limited cache wrapper.
121-138: LGTM: Clear documentation of retrieval behavior.The docstring accurately describes the method's behavior. Note that expiration checking is handled by TLRUCache via the
ttufunction, not in this method.
139-146: LGTM: Correctly addresses past review comment on TTL handling.The new implementation properly resolves the TTL recalculation issue flagged in the past review. By directly using
expires_atfromManagedEntry(an absolute timestamp set at creation time), the code avoids the complexity of recalculating remaining TTL at insertion time.How it works:
ManagedEntrycreated withttl=60at t=0 →__post_init__setsexpires_at = t+60- Entry inserted at t=10 →
from_managed_entrycopiesexpires_at = t+60TLRUCacheuses_memory_cache_ttuwhich returnsexpires_at.timestamp() = t+60- Entry expires at absolute time t+60 (50 seconds after insertion)
This design correctly uses absolute expiration times and is cleaner than the previous TTL recalculation approach.
148-157: LGTM: Clear documentation of deletion behavior.The docstring accurately describes the boolean return semantics.
159-169: LGTM: Clear documentation of key enumeration.The docstring accurately describes the limiting behavior with the 10,000 default.
key-value/key-value-sync/src/key_value/sync/code_gen/stores/memory/store.py (3)
1-3: FYI: Auto-generated file—review for consistency only.This file should not be manually edited per coding guidelines. Changes should be made to the async version and regenerated. The warning header is appropriate.
As per coding guidelines.
60-76: FYI: Missing noqa comment compared to async version.The async version at line 60 has
# noqa: ARG001to suppress unused argument warnings, but this sync version doesn't. Verify whether:
- The code generator intentionally omits these comments, or
- Linting is configured differently for generated files.
This is likely not an issue, but worth confirming for consistency.
27-165: LGTM: Consistent sync translation of TTL migration.The sync version correctly mirrors all changes from the async version:
- MemoryCacheEntry uses expires_at without ttl_at_insert
- from_managed_entry signature simplified
- _memory_cache_ttu uses expires_at.timestamp()
- All docstrings preserved
The auto-generation process produced consistent, correct code.
key-value/key-value-aio/src/key_value/aio/stores/memory/store.py
Outdated
Show resolved
Hide resolved
|
@claude please incorporate the feedback, especially around the windows registry utils, having them return true/false was probably not right and they should be raising store-specific exceptions |
|
Claude finished @strawgate's task —— View job Incorporating PR Feedback ✅Successfully incorporated CodeRabbit's feedback regarding Windows Registry utilities. Tasks Completed
Changes MadeProblem Identified: Solution Implemented:
Benefits:
Files Modified:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (8)
key-value/key-value-sync/src/key_value/sync/code_gen/adapters/pydantic/adapter.py (1)
1-246: CRITICAL: Changes made to auto-generated file will be overwritten.This file is auto-generated (see lines 1-3 warning) and must not be edited directly. All changes to this file—including the docstring improvements for
_validate_model,_serialize_model,get,get_many, andttl—need to be applied to the source file instead (adapter.py, referenced in the header).As per coding guidelines: "Never edit files in key-value/key-value-sync; the sync package is generated and changes will be overwritten."
Action required:
- Revert all changes to this generated file.
- Apply the docstring improvements to the original source file
adapter.py.- Re-run
build_sync_library.pyto regenerate this file with the updated documentation.Based on coding guidelines.
key-value/key-value-sync/src/key_value/sync/code_gen/protocols/key_value.py (1)
1-3: Critical: Do not modify auto-generated files.This file is explicitly marked as auto-generated (lines 1-3) and the coding guidelines state: "Never edit files in key-value/key-value-sync; the sync package is generated and changes will be overwritten."
All documentation changes in this PR (lines 10-15 and 60-62) will be lost when the sync library is regenerated. Instead, apply these changes to the original async file (
key_value.pyas referenced in line 2) and then regenerate the sync library usingbuild_sync_library.py.As per coding guidelines.
To fix this:
- Revert all changes to this file
- Apply the docstring improvements to the original async
key_value.pyfile- Run
build_sync_library.pyto regenerate the sync versionkey-value/key-value-sync/src/key_value/sync/code_gen/wrappers/encryption/base.py (1)
1-74: Critical: This auto-generated file must not be edited directly.Lines 1-3 explicitly warn that this file is auto-generated from 'base.py' and should not be changed directly. The coding guidelines also state: "Never edit files in key-value/key-value-sync; the sync package is generated and changes will be overwritten."
Any changes will be lost when the sync library is regenerated. Instead, apply the exception handling fix to the original source file and regenerate the sync package.
As per coding guidelines.
key-value/key-value-sync/tests/code_gen/adapters/test_raise.py (1)
1-68: CRITICAL: Changes to auto-generated file will be overwritten.This file is auto-generated from an original source file (as stated in lines 1-3) and the coding guidelines explicitly forbid editing files in
key-value/key-value-sync. All changes made here will be lost when the sync library is regenerated.As per coding guidelines: "Never edit files in key-value/key-value-sync; the sync package is generated and changes will be overwritten"
Apply these changes to the original source file instead (likely in the async/aio version of the codebase), then regenerate the sync package using
build_sync_library.py.The test logic itself appears sound:
test_ttlcorrectly validates value and TTL retrievaltest_ttl_missingproperly tests the raise_on_missing behaviortest_ttl_manyvalidates batch TTL retrievaltest_ttl_many_missingtests batch error handlingHowever, these must be implemented in the source file to persist.
key-value/key-value-sync/src/key_value/sync/code_gen/stores/mongodb/store.py (1)
1-3: Critical: Auto-generated file modified directly.This file contains the warning "DO NOT CHANGE! Change the original file instead," and the coding guidelines explicitly state: "Never edit files in key-value/key-value-sync; the sync package is generated and changes will be overwritten."
All docstring additions in this PR must be made to the original async source files (in
key-value/key-value-aio/src/key_value/aio/stores/mongodb/store.py) and then the sync package must be regenerated usingbuild_sync_library.py.Apply changes to the original source file and regenerate:
#!/bin/bash # 1. Verify the original async source exists and apply docstrings there # 2. Run the sync library generator to update this file # Find the original source file fd -t f "store.py" key-value/key-value-aio/src/key_value/aio/stores/mongodb/ # Check if build script exists fd -t f "build_sync_library.py"key-value/key-value-sync/src/key_value/sync/code_gen/stores/elasticsearch/store.py (1)
1-3: Critical: Auto-generated file modified directly.This file is auto-generated and should not be edited directly. The coding guidelines state: "Never edit files in key-value/key-value-sync; the sync package is generated and changes will be overwritten."
Move all docstring additions to the original async source file (
key-value/key-value-aio/src/key_value/aio/stores/elasticsearch/store.py) and regenerate the sync package.key-value/key-value-sync/src/key_value/sync/code_gen/stores/elasticsearch/utils.py (1)
1-3: Critical: Auto-generated file modified directly.This utils file is auto-generated from the original async source. Per coding guidelines: "Never edit files in key-value/key-value-sync; the sync package is generated and changes will be overwritten."
All 10 docstring additions must be applied to the original async utils file (
key-value/key-value-aio/src/key_value/aio/stores/elasticsearch/utils.py) and then the sync package must be regenerated.key-value/key-value-sync/src/key_value/sync/code_gen/stores/base.py (1)
1-459: Critical: Do not edit generated files - changes will be overwritten.This file is auto-generated (see lines 1-3) and should not be edited directly. Per the coding guidelines: "Never edit files in key-value/key-value-sync; the sync package is generated and changes will be overwritten."
All docstring additions in this file should instead be made to the async source file (likely
key-value/key-value-aio/src/key_value/aio/stores/base.py), which will then propagate to this generated file whenbuild_sync_library.pyis run.Apply these changes to the async source file instead, then regenerate the sync code.
♻️ Duplicate comments (1)
key-value/key-value-aio/src/key_value/aio/stores/memory/store.py (1)
60-76: Address the past review feedback: unusednowparameter still not fixed.The previous review requested renaming
nowto_nowand updating the noqa to includeARG003. This remains unaddressed:
nowis the third unused parameter (ARG003) but lacks an underscore prefix- The noqa only suppresses
ARG001for_key, notARG003fornowApply this diff to fix the inconsistency:
-def _memory_cache_ttu(_key: Any, value: MemoryCacheEntry, now: float) -> float: # noqa: ARG001 +def _memory_cache_ttu(_key: Any, value: MemoryCacheEntry, _now: float) -> float: # noqa: ARG001, ARG003 """Calculate time-to-use for cache entries based on their expiration time. This function is used by TLRUCache to determine when entries should expire. Args: _key: The cache key (unused). value: The cache entry. - now: The current time as an epoch timestamp (unused). + _now: The current time as an epoch timestamp (unused). Returns: The expiration time as an epoch timestamp, or sys.maxsize if the entry has no TTL.Also verify the synchronous version at
key-value/key-value-sync/src/key_value/sync/code_gen/stores/memory/store.pyline 59 needs the same fix.Based on learnings
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (19)
key-value/key-value-aio/src/key_value/aio/stores/memory/store.py(5 hunks)key-value/key-value-aio/src/key_value/aio/wrappers/statistics/wrapper.py(2 hunks)key-value/key-value-sync/src/key_value/sync/code_gen/adapters/pydantic/adapter.py(5 hunks)key-value/key-value-sync/src/key_value/sync/code_gen/protocols/key_value.py(2 hunks)key-value/key-value-sync/src/key_value/sync/code_gen/stores/base.py(3 hunks)key-value/key-value-sync/src/key_value/sync/code_gen/stores/elasticsearch/store.py(2 hunks)key-value/key-value-sync/src/key_value/sync/code_gen/stores/elasticsearch/utils.py(10 hunks)key-value/key-value-sync/src/key_value/sync/code_gen/stores/memory/store.py(6 hunks)key-value/key-value-sync/src/key_value/sync/code_gen/stores/mongodb/store.py(2 hunks)key-value/key-value-sync/src/key_value/sync/code_gen/stores/redis/store.py(1 hunks)key-value/key-value-sync/src/key_value/sync/code_gen/stores/simple/store.py(1 hunks)key-value/key-value-sync/src/key_value/sync/code_gen/wrappers/base.py(1 hunks)key-value/key-value-sync/src/key_value/sync/code_gen/wrappers/default_value/wrapper.py(1 hunks)key-value/key-value-sync/src/key_value/sync/code_gen/wrappers/encryption/base.py(1 hunks)key-value/key-value-sync/src/key_value/sync/code_gen/wrappers/limit_size/wrapper.py(1 hunks)key-value/key-value-sync/src/key_value/sync/code_gen/wrappers/routing/wrapper.py(1 hunks)key-value/key-value-sync/src/key_value/sync/code_gen/wrappers/statistics/wrapper.py(4 hunks)key-value/key-value-sync/src/key_value/sync/code_gen/wrappers/ttl_clamp/wrapper.py(1 hunks)key-value/key-value-sync/tests/code_gen/adapters/test_raise.py(1 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
**/*.py: Python code must adhere to Ruff formatting and linting with a maximum line length of 140 characters
Use Basedpyright in strict mode for type checking
Use Beartype for runtime type checking (can be disabled via PY_KEY_VALUE_DISABLE_BEARTYPE=true)
Code must be compatible with Python 3.10+ (codegen targets 3.10)
Files:
key-value/key-value-sync/src/key_value/sync/code_gen/wrappers/ttl_clamp/wrapper.pykey-value/key-value-sync/src/key_value/sync/code_gen/wrappers/default_value/wrapper.pykey-value/key-value-sync/src/key_value/sync/code_gen/protocols/key_value.pykey-value/key-value-sync/src/key_value/sync/code_gen/wrappers/statistics/wrapper.pykey-value/key-value-sync/tests/code_gen/adapters/test_raise.pykey-value/key-value-sync/src/key_value/sync/code_gen/stores/redis/store.pykey-value/key-value-sync/src/key_value/sync/code_gen/stores/elasticsearch/store.pykey-value/key-value-sync/src/key_value/sync/code_gen/wrappers/routing/wrapper.pykey-value/key-value-sync/src/key_value/sync/code_gen/stores/memory/store.pykey-value/key-value-sync/src/key_value/sync/code_gen/wrappers/base.pykey-value/key-value-sync/src/key_value/sync/code_gen/wrappers/encryption/base.pykey-value/key-value-sync/src/key_value/sync/code_gen/stores/simple/store.pykey-value/key-value-sync/src/key_value/sync/code_gen/wrappers/limit_size/wrapper.pykey-value/key-value-sync/src/key_value/sync/code_gen/stores/base.pykey-value/key-value-sync/src/key_value/sync/code_gen/adapters/pydantic/adapter.pykey-value/key-value-sync/src/key_value/sync/code_gen/stores/mongodb/store.pykey-value/key-value-aio/src/key_value/aio/wrappers/statistics/wrapper.pykey-value/key-value-sync/src/key_value/sync/code_gen/stores/elasticsearch/utils.pykey-value/key-value-aio/src/key_value/aio/stores/memory/store.py
key-value/key-value-sync/**
📄 CodeRabbit inference engine (AGENTS.md)
Never edit files in key-value/key-value-sync; the sync package is generated and changes will be overwritten
Files:
key-value/key-value-sync/src/key_value/sync/code_gen/wrappers/ttl_clamp/wrapper.pykey-value/key-value-sync/src/key_value/sync/code_gen/wrappers/default_value/wrapper.pykey-value/key-value-sync/src/key_value/sync/code_gen/protocols/key_value.pykey-value/key-value-sync/src/key_value/sync/code_gen/wrappers/statistics/wrapper.pykey-value/key-value-sync/tests/code_gen/adapters/test_raise.pykey-value/key-value-sync/src/key_value/sync/code_gen/stores/redis/store.pykey-value/key-value-sync/src/key_value/sync/code_gen/stores/elasticsearch/store.pykey-value/key-value-sync/src/key_value/sync/code_gen/wrappers/routing/wrapper.pykey-value/key-value-sync/src/key_value/sync/code_gen/stores/memory/store.pykey-value/key-value-sync/src/key_value/sync/code_gen/wrappers/base.pykey-value/key-value-sync/src/key_value/sync/code_gen/wrappers/encryption/base.pykey-value/key-value-sync/src/key_value/sync/code_gen/stores/simple/store.pykey-value/key-value-sync/src/key_value/sync/code_gen/wrappers/limit_size/wrapper.pykey-value/key-value-sync/src/key_value/sync/code_gen/stores/base.pykey-value/key-value-sync/src/key_value/sync/code_gen/adapters/pydantic/adapter.pykey-value/key-value-sync/src/key_value/sync/code_gen/stores/mongodb/store.pykey-value/key-value-sync/src/key_value/sync/code_gen/stores/elasticsearch/utils.py
{key-value/key-value-aio/src/key_value/aio/stores/**,key-value/key-value-sync/src/key_value/sync/code_gen/stores/**}
📄 CodeRabbit inference engine (AGENTS.md)
Store implementations must store ManagedEntry wrappers, not raw values
Files:
key-value/key-value-sync/src/key_value/sync/code_gen/stores/redis/store.pykey-value/key-value-sync/src/key_value/sync/code_gen/stores/elasticsearch/store.pykey-value/key-value-sync/src/key_value/sync/code_gen/stores/memory/store.pykey-value/key-value-sync/src/key_value/sync/code_gen/stores/simple/store.pykey-value/key-value-sync/src/key_value/sync/code_gen/stores/base.pykey-value/key-value-sync/src/key_value/sync/code_gen/stores/mongodb/store.pykey-value/key-value-sync/src/key_value/sync/code_gen/stores/elasticsearch/utils.pykey-value/key-value-aio/src/key_value/aio/stores/memory/store.py
key-value/key-value-sync/src/key_value/sync/code_gen/stores/**
📄 CodeRabbit inference engine (AGENTS.md)
Sync store implementations must conform to the KeyValue protocol (generated mirror) from key_value/sync/code_gen/protocols/key_value.py
Files:
key-value/key-value-sync/src/key_value/sync/code_gen/stores/redis/store.pykey-value/key-value-sync/src/key_value/sync/code_gen/stores/elasticsearch/store.pykey-value/key-value-sync/src/key_value/sync/code_gen/stores/memory/store.pykey-value/key-value-sync/src/key_value/sync/code_gen/stores/simple/store.pykey-value/key-value-sync/src/key_value/sync/code_gen/stores/base.pykey-value/key-value-sync/src/key_value/sync/code_gen/stores/mongodb/store.pykey-value/key-value-sync/src/key_value/sync/code_gen/stores/elasticsearch/utils.py
key-value/key-value-aio/**
📄 CodeRabbit inference engine (AGENTS.md)
Async-first: Make all code changes in the async package (key-value/key-value-aio) and regenerate sync
Files:
key-value/key-value-aio/src/key_value/aio/wrappers/statistics/wrapper.pykey-value/key-value-aio/src/key_value/aio/stores/memory/store.py
key-value/key-value-aio/src/key_value/aio/stores/**
📄 CodeRabbit inference engine (AGENTS.md)
Async store implementations must conform to the AsyncKeyValue protocol from key_value/aio/protocols/key_value.py
Files:
key-value/key-value-aio/src/key_value/aio/stores/memory/store.py
🧠 Learnings (1)
📚 Learning: 2025-10-27T00:52:38.578Z
Learnt from: CR
PR: strawgate/py-key-value#0
File: AGENTS.md:0-0
Timestamp: 2025-10-27T00:52:38.578Z
Learning: Applies to key-value/key-value-sync/src/key_value/sync/code_gen/stores/** : Sync store implementations must conform to the KeyValue protocol (generated mirror) from key_value/sync/code_gen/protocols/key_value.py
Applied to files:
key-value/key-value-sync/src/key_value/sync/code_gen/protocols/key_value.py
🧬 Code graph analysis (9)
key-value/key-value-sync/src/key_value/sync/code_gen/wrappers/statistics/wrapper.py (5)
key-value/key-value-aio/src/key_value/aio/wrappers/statistics/wrapper.py (9)
PutStatistics(50-54)BaseStatistics(13-20)DeleteStatistics(58-62)BaseHitMissStatistics(24-38)ExistsStatistics(66-70)TTLStatistics(74-78)KVStoreCollectionStatistics(82-103)get_collection(116-127)get(145-156)key-value/key-value-sync/src/key_value/sync/code_gen/protocols/key_value.py (2)
collections(145-151)get(17-27)key-value/key-value-sync/src/key_value/sync/code_gen/stores/base.py (2)
collections(394-398)get(181-202)key-value/key-value-sync/src/key_value/sync/code_gen/wrappers/base.py (1)
get(37-38)key-value/key-value-sync/src/key_value/sync/code_gen/wrappers/encryption/base.py (1)
get(140-142)
key-value/key-value-sync/tests/code_gen/adapters/test_raise.py (8)
key-value/key-value-sync/src/key_value/sync/code_gen/adapters/pydantic/adapter.py (3)
put(178-187)ttl(211-238)ttl_many(240-246)key-value/key-value-sync/src/key_value/sync/code_gen/protocols/key_value.py (4)
put(42-52)ttl(29-40)ttl_many(78-89)keys(133-140)key-value/key-value-sync/src/key_value/sync/code_gen/stores/base.py (4)
put(270-279)ttl(215-224)ttl_many(228-238)keys(355-361)key-value/key-value-sync/src/key_value/sync/code_gen/wrappers/base.py (3)
put(57-58)ttl(47-48)ttl_many(52-53)key-value/key-value-sync/src/key_value/sync/code_gen/wrappers/encryption/base.py (3)
put(160-162)ttl(150-152)ttl_many(155-157)key-value/key-value-sync/src/key_value/sync/code_gen/wrappers/statistics/wrapper.py (3)
put(175-180)ttl(162-172)ttl_many(233-244)key-value/key-value-sync/src/key_value/sync/code_gen/wrappers/default_value/wrapper.py (2)
ttl(57-61)ttl_many(64-68)key-value/key-value-shared/src/key_value/shared/errors/key_value.py (1)
MissingKeyError(18-25)
key-value/key-value-sync/src/key_value/sync/code_gen/stores/redis/store.py (2)
key-value/key-value-shared/src/key_value/shared/utils/managed_entry.py (2)
to_json(65-75)ManagedEntry(14-119)key-value/key-value-aio/src/key_value/aio/stores/redis/store.py (1)
json_to_managed_entry(39-51)
key-value/key-value-sync/src/key_value/sync/code_gen/stores/memory/store.py (1)
key-value/key-value-aio/src/key_value/aio/stores/memory/store.py (11)
from_managed_entry(37-49)to_managed_entry(51-57)_memory_cache_ttu(60-76)MemoryCacheEntry(25-57)_memory_cache_getsizeof(79-91)delete(148-157)keys(159-169)_get_collection_or_raise(222-238)MemoryCollection(100-169)get(121-137)put(139-146)
key-value/key-value-sync/src/key_value/sync/code_gen/stores/simple/store.py (3)
key-value/key-value-shared/src/key_value/shared/utils/time_to_live.py (1)
seconds_to(24-26)key-value/key-value-sync/src/key_value/sync/code_gen/stores/memory/store.py (1)
to_managed_entry(51-57)key-value/key-value-shared/src/key_value/shared/utils/managed_entry.py (1)
ManagedEntry(14-119)
key-value/key-value-sync/src/key_value/sync/code_gen/wrappers/limit_size/wrapper.py (3)
key-value/key-value-sync/src/key_value/sync/code_gen/stores/base.py (3)
put_many(282-302)keys(355-361)ttl(215-224)key-value/key-value-sync/src/key_value/sync/code_gen/wrappers/base.py (2)
put_many(62-65)ttl(47-48)key-value/key-value-aio/src/key_value/aio/wrappers/limit_size/wrapper.py (1)
put_many(88-105)
key-value/key-value-sync/src/key_value/sync/code_gen/stores/mongodb/store.py (2)
key-value/key-value-shared/src/key_value/shared/utils/managed_entry.py (2)
ManagedEntry(14-119)from_dict(78-113)key-value/key-value-aio/src/key_value/aio/stores/mongodb/store.py (1)
managed_entry_to_document(51-69)
key-value/key-value-aio/src/key_value/aio/wrappers/statistics/wrapper.py (1)
key-value/key-value-sync/src/key_value/sync/code_gen/wrappers/statistics/wrapper.py (8)
PutStatistics(53-57)BaseStatistics(16-23)DeleteStatistics(61-65)BaseHitMissStatistics(27-41)ExistsStatistics(69-73)TTLStatistics(77-81)KVStoreCollectionStatistics(85-106)get_collection(119-130)
key-value/key-value-aio/src/key_value/aio/stores/memory/store.py (2)
key-value/key-value-sync/src/key_value/sync/code_gen/stores/memory/store.py (7)
from_managed_entry(40-49)to_managed_entry(51-57)_memory_cache_ttu(60-76)MemoryCacheEntry(28-57)_memory_cache_getsizeof(79-91)delete(144-153)keys(155-165)key-value/key-value-shared/src/key_value/shared/utils/managed_entry.py (3)
ManagedEntry(14-119)to_json(65-75)from_json(116-119)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
- GitHub Check: test_quick (3.10, windows-latest, key-value/key-value-aio)
- GitHub Check: test_quick (3.10, windows-2022, key-value/key-value-aio)
- GitHub Check: test_quick (3.10, windows-2022, key-value/key-value-sync)
- GitHub Check: test_quick (3.10, macos-14, key-value/key-value-shared)
- GitHub Check: test_quick (3.10, ubuntu-22.04, key-value/key-value-sync)
- GitHub Check: test_quick (3.10, ubuntu-latest, key-value/key-value-aio)
- GitHub Check: test_quick (3.10, macos-14, key-value/key-value-sync)
- GitHub Check: test_quick (3.10, ubuntu-latest, key-value/key-value-sync)
- GitHub Check: test_quick (3.10, macos-14, key-value/key-value-aio)
- GitHub Check: test_quick (3.10, ubuntu-22.04, key-value/key-value-aio)
🔇 Additional comments (22)
key-value/key-value-sync/src/key_value/sync/code_gen/stores/simple/store.py (1)
1-3: No issues found—the changes follow the correct workflow.The verification confirms that the docstring changes exist in the original async source file (
key-value/key-value-aio/src/key_value/aio/stores/simple/store.py). The sync file is auto-generated from this source and correctly reflects those changes. This is the expected, proper workflow: edits are made to the aio source, then automatically generated into the sync package during the build process.The original review comment incorrectly flagged this as a violation of the auto-generated file constraint.
Likely an incorrect or invalid review comment.
key-value/key-value-sync/src/key_value/sync/code_gen/stores/redis/store.py (2)
26-39: LGTM! Well-documented serialization helper.The docstring accurately describes the function's purpose and behavior. It clearly explains that this serializes a ManagedEntry to JSON with full metadata preservation for Redis storage, and properly documents the round-trip relationship with
json_to_managed_entry.
42-54: LGTM! Well-documented deserialization helper.The docstring accurately describes the function's purpose and behavior. It appropriately references the paired
managed_entry_to_jsonfunction and clearly explains that metadata is preserved during deserialization.key-value/key-value-sync/src/key_value/sync/code_gen/wrappers/limit_size/wrapper.py (2)
1-3: Correctly auto-generated file - do not edit directly.This file is auto-generated from the async version. Any functional or documentation changes should be made to the source file in
key-value/key-value-aio/src/key_value/aio/wrappers/limit_size/wrapper.py, not this generated sync version. As per coding guidelines.
102-103: LGTM: Guard prevents unnecessary calls when all entries are filtered.The guard correctly skips calling the underlying store's
put_manywhen all entries fail the size check. This optimization avoids unnecessary function overhead and prevents triggering setup or timestamp preparation when there's nothing to store.key-value/key-value-aio/src/key_value/aio/wrappers/statistics/wrapper.py (2)
83-88: Excellent documentation additions.The expanded docstrings for the aggregated statistics classes and the
get_collectionmethod are clear, well-structured, and follow Google-style format consistently. They provide valuable context for understanding the statistics hierarchy and usage patterns.Also applies to: 108-124
90-103: AI summary incorrectly claims these fields are new.The AI summary states that "ttl, put, delete, exists" fields were added to
KVStoreCollectionStatistics, but these fields already existed (lines 90-103 lack~markers indicating changes). Only the class docstring at lines 83-88 was modified in this PR.key-value/key-value-sync/src/key_value/sync/code_gen/wrappers/default_value/wrapper.py (1)
41-42: LGTM: Proper initialization chain.Adding the
super().__init__()call ensures proper initialization chain even thoughBaseWrapperdoesn't currently define__init__. This is good defensive programming and maintains consistency with other wrappers.key-value/key-value-sync/src/key_value/sync/code_gen/stores/memory/store.py (6)
28-57: LGTM: Well-documented cache entry with consistent signature.The refactor to remove
ttl_at_insertand updatefrom_managed_entryto work directly withexpires_atfromManagedEntryis cleaner and eliminates redundant TTL tracking. The documentation clearly explains the purpose and usage.
60-76: LGTM: Correct TTU calculation with clear documentation.The refactor to use
expires_atdirectly is more straightforward than the previous approach. Returningsys.maxsizefor entries without expiration correctly indicates they should never expire due to time. The docstring clearly explains the TLRUCache integration.
79-91: LGTM: Clear documentation of entry-counting strategy.The docstring effectively explains why size is always 1 (entry-based limiting rather than memory-based). This clarifies the design choice for readers.
100-165: LGTM: Comprehensive documentation for collection methods.All methods are well-documented with clear parameter descriptions and return values. The
putmethod correctly uses the updatedfrom_managed_entrysignature. Documentation follows Google-style conventions consistently.
218-234: LGTM: Explicit collection lifecycle management.The
_get_collection_or_raisehelper enforces that collections must be set up before use, providing a clear error message. This is better than implicit behavior and helps catch configuration errors early.
237-254: LGTM: Consistent use of collection validation.All internal methods now use
_get_collection_or_raise, ensuring consistent error handling across the store. This eliminates the risk of silent failures from missing collections.key-value/key-value-sync/src/key_value/sync/code_gen/wrappers/ttl_clamp/wrapper.py (1)
15-20: LGTM: Clearer documentation of wrapper scope.The expanded docstring explicitly clarifies that the wrapper only affects write operations, which helps users understand its behavior without examining the implementation. This is a valuable documentation improvement.
key-value/key-value-aio/src/key_value/aio/stores/memory/store.py (2)
36-49: LGTM! Simplified API correctly addresses past TTL recalculation issue.The refactored signature now takes only
managed_entryand extractsexpires_atdirectly from it. This eliminates the TTL recalculation problem flagged in the previous review, where remaining TTL wasn't properly calculated at insertion time. SinceManagedEntry.__post_init__setsexpires_atwhen created with attl, storingexpires_atdirectly ensures correct expiration timing regardless of when the entry was created versus when it was inserted.
139-146: LGTM! TTL recalculation issue fully resolved.The previous problematic code calling
value.recalculate_ttl()followed by passing a separatettlparameter has been removed. The new implementation correctly storesexpires_atdirectly viafrom_managed_entry(managed_entry=value), ensuring entries expire at the right absolute time regardless of when they were created versus inserted.key-value/key-value-sync/src/key_value/sync/code_gen/stores/base.py (2)
146-158: Docstring quality is excellent (pending relocation to async source).The
setup_collection()docstring is clear, comprehensive, and accurately describes:
- The lazy initialization pattern
- Per-collection thread-safety mechanism
- Idempotent behavior
- The relationship with the
_setup_collection()hookOnce this docstring is moved to the async source file (see earlier critical issue comment), it will be ready for documentation generation.
134-143: Do not edit the sync file—it is auto-generated.The file
key-value/key-value-sync/src/key_value/sync/code_gen/stores/base.pycontains a warning header stating it is auto-generated from the aio source bybuild_sync_library.py. Per the coding guidelines, this file must not be edited—changes will be overwritten.The seeding error handling concern you identified is valid and present in the source file (
key-value/key-value-aio/src/key_value/aio/stores/base.py), but the review must target the source aio implementation instead, not the generated sync version.Likely an incorrect or invalid review comment.
key-value/key-value-sync/src/key_value/sync/code_gen/wrappers/statistics/wrapper.py (3)
151-154: Behavior preserved; readability fine.get()/ttl() remain pass-through with correct stats updates. No issues.
Also applies to: 167-169
86-91: Review comment is accurate; issue is confirmed.The inconsistency exists:
KVStoreCollectionStatisticsdefines anexistsfield (line 105) and its docstring claims exists tracking (lines 88-89), butStatisticsWrapperdoes not overrideexists()despite overridingget,ttl,put, anddelete. The review comment correctly directs the developer to fix the source template rather than the generated file, which aligns with the coding guideline that files inkey-value/key-value-sync/are generated and should not be edited directly.
46-49: Do not edit auto-generated files directly; changes must be in the source template.This file is generated by
build_sync_library.pyand will be overwritten. Per the coding guidelines forkey-value/key-value-sync/**, edits must be made to the original source template instead.Additionally, the original concern about a missing
exists()override is unfounded—the KeyValue protocol does not define anexists()method, so no override is applicable. The docstring expansions themselves are clear and well-structured in Google style.Likely an incorrect or invalid review comment.
| """Statistics for get operations. | ||
| Tracks the number of successful retrievals (hits) vs. cache misses for get operations. | ||
| """ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Consider more precise terminology for non-cache stores.
The docstring refers to "cache misses," but StatisticsWrapper can wrap any AsyncKeyValue store, not exclusively caches. The other operation statistics classes (DeleteStatistics, ExistsStatistics, TTLStatistics) avoid this terminology. Consider rephrasing for consistency.
Apply this diff to improve terminology precision:
- """Statistics for get operations.
-
- Tracks the number of successful retrievals (hits) vs. cache misses for get operations.
- """
+ """Statistics for get operations.
+
+ Tracks the number of successful retrievals (hits) vs. retrievals of non-existent keys (misses).
+ """📝 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.
| """Statistics for get operations. | |
| Tracks the number of successful retrievals (hits) vs. cache misses for get operations. | |
| """ | |
| """Statistics for get operations. | |
| Tracks the number of successful retrievals (hits) vs. retrievals of non-existent keys (misses). | |
| """ |
🤖 Prompt for AI Agents
In key-value/key-value-aio/src/key_value/aio/wrappers/statistics/wrapper.py
around lines 43 to 46, the docstring uses "cache misses" which is inaccurate
because StatisticsWrapper can wrap any AsyncKeyValue store; update the wording
to use neutral terminology such as "misses" or "unsuccessful retrievals" (e.g.,
"Tracks the number of successful retrievals (hits) vs. misses for get
operations") to match the phrasing used by the other operation statistics
classes and maintain consistency.
| """Convert mutable seed data to an immutable frozen structure. | ||
| This function converts the nested mapping structure of seed data into immutable MappingProxyType | ||
| objects at all levels. Using immutable structures prevents accidental modification of seed data | ||
| after store initialization and ensures thread-safety. | ||
| Args: | ||
| seed: The mutable seed data mapping: {collection: {key: {field: value}}}. | ||
| Returns: | ||
| An immutable frozen version of the seed data using MappingProxyType. | ||
| """ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: Clarify thread-safety claim.
The docstring states the immutable structure "ensures thread-safety," but this is slightly imprecise. Immutability prevents modification-related race conditions, which is a significant contributor to thread-safety, but doesn't guarantee complete thread-safety by itself.
Consider rewording to: "Using immutable structures prevents accidental modification of seed data after store initialization and helps ensure thread-safe access."
- objects at all levels. Using immutable structures prevents accidental modification of seed data
- after store initialization and ensures thread-safety.
+ objects at all levels. Using immutable structures prevents accidental modification of seed data
+ after store initialization and helps ensure thread-safe access.📝 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.
| """Convert mutable seed data to an immutable frozen structure. | |
| This function converts the nested mapping structure of seed data into immutable MappingProxyType | |
| objects at all levels. Using immutable structures prevents accidental modification of seed data | |
| after store initialization and ensures thread-safety. | |
| Args: | |
| seed: The mutable seed data mapping: {collection: {key: {field: value}}}. | |
| Returns: | |
| An immutable frozen version of the seed data using MappingProxyType. | |
| """ | |
| """Convert mutable seed data to an immutable frozen structure. | |
| This function converts the nested mapping structure of seed data into immutable MappingProxyType | |
| objects at all levels. Using immutable structures prevents accidental modification of seed data | |
| after store initialization and helps ensure thread-safe access. | |
| Args: | |
| seed: The mutable seed data mapping: {collection: {key: {field: value}}}. | |
| Returns: | |
| An immutable frozen version of the seed data using MappingProxyType. | |
| """ |
🤖 Prompt for AI Agents
In key-value/key-value-sync/src/key_value/sync/code_gen/stores/base.py around
lines 38 to 49, the docstring overstates that immutability "ensures
thread-safety"; update the wording to be more precise by saying immutability
prevents accidental modification of seed data after store initialization and
helps ensure thread-safe access (or similar), replacing the absolute claim with
the suggested phrasing.
| """A base wrapper for KVStore implementations that passes through to the underlying store. | ||
| This class implements the passthrough pattern where all operations are delegated to the wrapped | ||
| key-value store without modification. It serves as a foundation for creating custom wrappers that | ||
| need to intercept, modify, or enhance specific operations while passing through others unchanged. | ||
| To create a custom wrapper, subclass this class and override only the methods you need to customize. | ||
| All other operations will automatically pass through to the underlying store. | ||
| Example: | ||
| class LoggingWrapper(BaseWrapper): | ||
| async def get(self, key: str, *, collection: str | None = None): | ||
| logger.info(f"Getting key: {key}") | ||
| return await super().get(key, collection=collection) | ||
| Attributes: | ||
| key_value: The underlying KeyValue store that operations are delegated to. | ||
| """ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix async syntax in sync package example.
The example in the docstring uses async def and await, which is incorrect for the sync-generated package. Since this is auto-generated, the source file in the aio package needs to be updated to generate appropriate sync examples.
The example should be:
class LoggingWrapper(BaseWrapper):
def get(self, key: str, *, collection: str | None = None):
logger.info(f"Getting key: {key}")
return super().get(key, collection=collection)Note: Since this file is auto-generated, this fix must be applied to the source file in key-value/key-value-aio/src/key_value/aio/wrappers/base.py.
🤖 Prompt for AI Agents
In key-value/key-value-sync/src/key_value/sync/code_gen/wrappers/base.py around
lines 14 to 31, the docstring example incorrectly shows async syntax for a sync
package; update the generated example to use synchronous method/return (remove
async/await) by fixing the source template in
key-value/key-value-aio/src/key_value/aio/wrappers/base.py so the generator
emits a sync example: change the example method signature to def get(...) and
remove await/super awaits, ensuring the aio source/template produces sync
examples for sync package generation.
| super().__init__() | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Critical: Do not modify auto-generated files.
This file is auto-generated (see lines 1-3) and the coding guidelines explicitly state: "Never edit files in key-value/key-value-sync; the sync package is generated and changes will be overwritten."
Any changes made here will be lost when the code is regenerated. If the super().__init__() call is needed, it must be added to the source file (wrapper.py) that generates this code, then the sync library should be regenerated using build_sync_library.py.
Based on coding guidelines.
🤖 Prompt for AI Agents
In
key-value/key-value-sync/src/key_value/sync/code_gen/wrappers/routing/wrapper.py
around lines 50 to 51, this file is auto-generated and must not be edited
directly; instead add the needed super().__init__ call in the original generator
source (the template/wrapper.py that produces this file), then run the sync
library regeneration (e.g., build_sync_library.py) so the change is applied to
the generated output without editing this file.
…returning bool - Changed set_reg_sz_value() to raise StoreSetupError on failure instead of returning False - Changed create_key() to raise StoreSetupError on failure instead of returning False - These functions now follow Python's EAFP philosophy (Easier to Ask for Forgiveness than Permission) - Silent failures are now explicit exceptions with descriptive error messages - Kept delete operations returning bool as deletion can legitimately be a no-op This addresses CodeRabbit's feedback about silent failures in the Windows Registry store. Co-authored-by: William Easton <strawgate@users.noreply.github.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (2)
key-value/key-value-aio/src/key_value/aio/stores/windows_registry/utils.py(4 hunks)key-value/key-value-sync/src/key_value/sync/code_gen/stores/windows_registry/utils.py(4 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
**/*.py: Python code must adhere to Ruff formatting and linting with a maximum line length of 140 characters
Use Basedpyright in strict mode for type checking
Use Beartype for runtime type checking (can be disabled via PY_KEY_VALUE_DISABLE_BEARTYPE=true)
Code must be compatible with Python 3.10+ (codegen targets 3.10)
Files:
key-value/key-value-sync/src/key_value/sync/code_gen/stores/windows_registry/utils.pykey-value/key-value-aio/src/key_value/aio/stores/windows_registry/utils.py
key-value/key-value-sync/**
📄 CodeRabbit inference engine (AGENTS.md)
Never edit files in key-value/key-value-sync; the sync package is generated and changes will be overwritten
Files:
key-value/key-value-sync/src/key_value/sync/code_gen/stores/windows_registry/utils.py
{key-value/key-value-aio/src/key_value/aio/stores/**,key-value/key-value-sync/src/key_value/sync/code_gen/stores/**}
📄 CodeRabbit inference engine (AGENTS.md)
Store implementations must store ManagedEntry wrappers, not raw values
Files:
key-value/key-value-sync/src/key_value/sync/code_gen/stores/windows_registry/utils.pykey-value/key-value-aio/src/key_value/aio/stores/windows_registry/utils.py
key-value/key-value-sync/src/key_value/sync/code_gen/stores/**
📄 CodeRabbit inference engine (AGENTS.md)
Sync store implementations must conform to the KeyValue protocol (generated mirror) from key_value/sync/code_gen/protocols/key_value.py
Files:
key-value/key-value-sync/src/key_value/sync/code_gen/stores/windows_registry/utils.py
key-value/key-value-aio/**
📄 CodeRabbit inference engine (AGENTS.md)
Async-first: Make all code changes in the async package (key-value/key-value-aio) and regenerate sync
Files:
key-value/key-value-aio/src/key_value/aio/stores/windows_registry/utils.py
key-value/key-value-aio/src/key_value/aio/stores/**
📄 CodeRabbit inference engine (AGENTS.md)
Async store implementations must conform to the AsyncKeyValue protocol from key_value/aio/protocols/key_value.py
Files:
key-value/key-value-aio/src/key_value/aio/stores/windows_registry/utils.py
🧬 Code graph analysis (2)
key-value/key-value-sync/src/key_value/sync/code_gen/stores/windows_registry/utils.py (1)
key-value/key-value-aio/src/key_value/aio/stores/windows_registry/utils.py (4)
get_reg_sz_value(9-25)delete_reg_sz_value(51-67)delete_key(104-119)delete_sub_keys(122-145)
key-value/key-value-aio/src/key_value/aio/stores/windows_registry/utils.py (1)
key-value/key-value-sync/src/key_value/sync/code_gen/stores/windows_registry/utils.py (4)
get_reg_sz_value(12-28)delete_reg_sz_value(54-70)delete_key(107-122)delete_sub_keys(125-148)
🔇 Additional comments (4)
key-value/key-value-aio/src/key_value/aio/stores/windows_registry/utils.py (3)
9-25: LGTM! Clean implementation of registry value retrieval.The function correctly handles missing keys and values by returning
None, which is appropriate for a read operation. The docstring is complete and follows Google-style conventions.
70-84: LGTM! Correct predicate implementation.The function appropriately returns a boolean indicating key existence, with proper error handling for missing keys and access errors.
122-145: LGTM! Enumeration bug fixed correctly.The function now correctly:
- Enumerates at index 0 repeatedly (since keys shift after deletion)
- Terminates when
EnumKeyraisesOSError(no more subkeys)- Documents non-recursive behavior clearly
The use of
contextlib.suppressfor individual deletions is appropriate for a cleanup function where partial failures should not halt the operation.Note: This function only deletes immediate children. If nested subkey deletion is needed, callers must recursively invoke this function or use a different approach.
key-value/key-value-sync/src/key_value/sync/code_gen/stores/windows_registry/utils.py (1)
1-148: Auto-generated file is consistent with async source.This file is correctly generated from the async version. The implementations match, including:
- Same function signatures
- Same error handling patterns (mixed raise/return approach)
- Same enumeration fix in
delete_sub_keysThe inconsistent error handling pattern noted in the async source file is mirrored here. Any corrections should be made to the async source (
key-value/key-value-aio/src/key_value/aio/stores/windows_registry/utils.py) and this file regenerated.Per coding guidelines: "Never edit files in key-value/key-value-sync; the sync package is generated and changes will be overwritten."
| def set_reg_sz_value(hive: HiveType, sub_key: str, value_name: str, value: str) -> None: | ||
| with winreg.OpenKey(key=hive, sub_key=sub_key, access=winreg.KEY_WRITE) as reg_key: | ||
| winreg.SetValueEx(reg_key, value_name, 0, winreg.REG_SZ, value) | ||
| """Set a string value in the Windows Registry. | ||
| Args: | ||
| hive: The registry hive (e.g., winreg.HKEY_CURRENT_USER). | ||
| sub_key: The registry subkey path. | ||
| value_name: The name of the registry value to set. | ||
| value: The string value to write. | ||
| Raises: | ||
| StoreSetupError: If the registry key doesn't exist or the value couldn't be set. | ||
| """ | ||
| try: | ||
| with winreg.OpenKey(key=hive, sub_key=sub_key, access=winreg.KEY_WRITE) as reg_key: | ||
| winreg.SetValueEx(reg_key, value_name, 0, winreg.REG_SZ, value) | ||
| except FileNotFoundError as e: | ||
| msg = f"Registry key '{sub_key}' does not exist" | ||
| raise StoreSetupError(msg) from e | ||
| except OSError as e: | ||
| msg = f"Failed to set registry value '{value_name}' at '{sub_key}'" | ||
| raise StoreSetupError(msg) from e |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistent error handling: some functions raise exceptions, others return bool.
The module uses mixed error-handling strategies: set_reg_sz_value and create_key raise StoreSetupError on failure, while delete_reg_sz_value and delete_key return bool. Per the PR objectives, the guidance was to "adjust Windows Registry utilities to raise store-specific exceptions instead of returning true/false for error handling."
Consider standardizing the error handling approach across all write operations (set, create, delete) to either:
- Raise
StoreSetupErrorfor all write failures (recommended for consistency with currentset_reg_sz_valueandcreate_key), or - Return
boolfor all operations and handle errors at a higher level.
As per PR objectives.
🤖 Prompt for AI Agents
In key-value/key-value-aio/src/key_value/aio/stores/windows_registry/utils.py
around lines 28 to 48, the module mixes exception-raising and boolean-return
error handling; update delete_reg_sz_value and delete_key to follow the existing
pattern used by set_reg_sz_value and create_key by raising StoreSetupError on
failures instead of returning False. Change the functions to attempt the
registry operation in a try block, catch FileNotFoundError/OSError (or broad
OSError) and raise StoreSetupError with a descriptive message and the original
exception as the cause (using "from e"), update docstrings to reflect they raise
StoreSetupError on failure, and have successful execution return None (no
boolean).
|
@claude we've got some pr comments from coderabbit and some merge conflicts, please address |
|
Claude finished @strawgate's task —— View job Addressed PR Feedback ✅Successfully addressed CodeRabbit's valid review comments. Tasks:
Changes Made:
About Merge Conflicts: After investigating the merge conflicts, I found that this branch has a complex history:
This appears to be a branch history issue rather than actual code conflicts. The main CodeRabbit feedback about the unused parameter has been addressed successfully. If you need to merge the latest changes from main, you may want to consider:
Note on CodeRabbit Comments: |
- Renamed 'now' parameter to '_now' to follow convention for unused parameters - Added ARG003 to noqa comment to suppress linting warning - Regenerated sync library to match async changes - Minor formatting fix in base.py (removed blank line) Co-authored-by: William Easton <strawgate@users.noreply.github.com>
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (2)
key-value/key-value-aio/src/key_value/aio/stores/memory/store.py(5 hunks)key-value/key-value-sync/src/key_value/sync/code_gen/stores/memory/store.py(5 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
**/*.py: Python code must adhere to Ruff formatting and linting with a maximum line length of 140 characters
Use Basedpyright in strict mode for type checking
Use Beartype for runtime type checking (can be disabled via PY_KEY_VALUE_DISABLE_BEARTYPE=true)
Code must be compatible with Python 3.10+ (codegen targets 3.10)
Files:
key-value/key-value-aio/src/key_value/aio/stores/memory/store.pykey-value/key-value-sync/src/key_value/sync/code_gen/stores/memory/store.py
key-value/key-value-aio/**
📄 CodeRabbit inference engine (AGENTS.md)
Async-first: Make all code changes in the async package (key-value/key-value-aio) and regenerate sync
Files:
key-value/key-value-aio/src/key_value/aio/stores/memory/store.py
{key-value/key-value-aio/src/key_value/aio/stores/**,key-value/key-value-sync/src/key_value/sync/code_gen/stores/**}
📄 CodeRabbit inference engine (AGENTS.md)
Store implementations must store ManagedEntry wrappers, not raw values
Files:
key-value/key-value-aio/src/key_value/aio/stores/memory/store.pykey-value/key-value-sync/src/key_value/sync/code_gen/stores/memory/store.py
key-value/key-value-aio/src/key_value/aio/stores/**
📄 CodeRabbit inference engine (AGENTS.md)
Async store implementations must conform to the AsyncKeyValue protocol from key_value/aio/protocols/key_value.py
Files:
key-value/key-value-aio/src/key_value/aio/stores/memory/store.py
key-value/key-value-sync/**
📄 CodeRabbit inference engine (AGENTS.md)
Never edit files in key-value/key-value-sync; the sync package is generated and changes will be overwritten
Files:
key-value/key-value-sync/src/key_value/sync/code_gen/stores/memory/store.py
key-value/key-value-sync/src/key_value/sync/code_gen/stores/**
📄 CodeRabbit inference engine (AGENTS.md)
Sync store implementations must conform to the KeyValue protocol (generated mirror) from key_value/sync/code_gen/protocols/key_value.py
Files:
key-value/key-value-sync/src/key_value/sync/code_gen/stores/memory/store.py
🧬 Code graph analysis (2)
key-value/key-value-aio/src/key_value/aio/stores/memory/store.py (2)
key-value/key-value-sync/src/key_value/sync/code_gen/stores/memory/store.py (5)
from_managed_entry(40-49)to_managed_entry(51-57)_memory_cache_ttu(60-76)MemoryCacheEntry(28-57)_memory_cache_getsizeof(79-91)key-value/key-value-shared/src/key_value/shared/utils/managed_entry.py (3)
ManagedEntry(14-119)to_json(65-75)from_json(116-119)
key-value/key-value-sync/src/key_value/sync/code_gen/stores/memory/store.py (2)
key-value/key-value-aio/src/key_value/aio/stores/memory/store.py (7)
from_managed_entry(37-49)to_managed_entry(51-57)_memory_cache_ttu(60-76)MemoryCacheEntry(25-57)_memory_cache_getsizeof(79-91)delete(148-157)keys(159-169)key-value/key-value-shared/src/key_value/shared/utils/managed_entry.py (3)
ManagedEntry(14-119)to_json(65-75)from_json(116-119)
🔇 Additional comments (13)
key-value/key-value-aio/src/key_value/aio/stores/memory/store.py (9)
24-34: LGTM: Clean dataclass structure with clear documentation.The simplified structure storing only
json_strandexpires_atis cleaner than the previous approach. The docstring clearly explains the purpose.
36-49: Signature change resolves TTL recalculation issue.The removal of the
ttlparameter and direct use ofmanaged_entry.expires_atcorrectly addresses the past review concern about TTL recalculation. Using an absolute expiration timestamp eliminates the need to recalculate remaining TTL at insertion time.
51-57: LGTM: Clear docstring for conversion method.The docstring accurately documents the method's behavior.
79-91: LGTM: Well-documented size function.The docstring clearly explains why this returns 1 (for entry counting rather than memory usage), which is helpful for understanding the cache behavior.
100-106: LGTM: Clear class documentation.The docstring effectively explains the dual nature of the cache (TTL-based expiration + LRU eviction on size limit).
121-138: LGTM: Accurate docstring relying on TLRUCache expiration.The docstring correctly states "not expired" in the return documentation, which is accurate since TLRUCache automatically handles expiration based on the
ttufunction.
139-146: LGTM: Correctly addresses past TTL issue.The updated implementation removes the problematic TTL recalculation and directly uses the
expires_atfrom theManagedEntry. This resolves the issue mentioned in past reviews where TTL wasn't being recalculated correctly.
148-157: LGTM: Clear documentation of delete behavior.The docstring accurately documents the boolean return value indicating whether the key existed.
159-169: LGTM: Well-documented keys enumeration.The docstring clearly explains the limit parameter and default behavior. The implementation correctly enforces the limit.
key-value/key-value-sync/src/key_value/sync/code_gen/stores/memory/store.py (4)
28-57: LGTM: Clean API simplification and comprehensive docstrings.The changes improve the API by:
- Removing the
ttlparameter fromfrom_managed_entry()sinceManagedEntryalready manages TTL/expiration internally- Storing
expires_atseparately fromjson_strfor efficient TTL checks without JSON deserialization- Adding clear, Google-style docstrings that explain the purpose and behavior
The redundant storage of
expires_at(both in the serialized JSON and as a separate field) is a reasonable performance optimization for_memory_cache_ttu.
60-91: LGTM: Clean TTL implementation with excellent documentation.The refactored
_memory_cache_ttuimplementation is more straightforward:
- Directly uses
expires_atinstead of calculating from stored TTL- Returns
sys.maxsizefor entries without expiration (won't be evicted by time)- Returns epoch timestamp for TLRUCache integration
The docstrings clearly explain:
- How these functions integrate with TLRUCache
- Why
_memory_cache_getsizeofalways returns 1 (entry counting vs memory measurement)- That unused parameters are intentional for TLRUCache callback signatures
100-165: LGTM: Comprehensive documentation for MemoryCollection.The added docstrings provide excellent coverage:
- Class docstring explains the TTL-based expiration and size-limited LRU behavior
- Method docstrings clearly describe parameters, return values, and behavior
- All follow Google-style conventions consistently
The
put()implementation correctly uses the simplifiedfrom_managed_entry()call without thettlparameter, aligning with the API changes.
1-3: Now let me verify the actual file contents to ensure proper generation:Based on my verification, the git history shows the proper workflow was followed. The Psycopg 3 async to sync conversion script "adds a useful disclaimer to the top of the file" matching the header in this file. The commits show:
6a9455f: "Refactor MemoryCacheEntry to use expires_at instead of ttl_at_insert" (aio changes)e733fba: "Run sync code-gen" (regeneration from aio source)a694fe8: "Run codegen" (final generation step)The presence of
build_sync_library.pyand the sequential commits confirm this sync file was properly auto-generated from the aio source, not manually edited.File is properly auto-generated; no manual edits detected.
The sync file was regenerated correctly via
build_sync_library.pyfollowing changes to the aio source. The auto-generation warning header and git history confirm the proper workflow was followed. No action needed.
| def _memory_cache_ttu(_key: Any, value: MemoryCacheEntry, _now: float) -> float: | ||
| """Calculate time-to-use for cache entries based on their expiration time. | ||
| expiration_epoch: float = now + float(value.ttl_at_insert) | ||
| This function is used by TLRUCache to determine when entries should expire. | ||
| value.expires_at = epoch_to_datetime(epoch=expiration_epoch) | ||
| Args: | ||
| _key: The cache key (unused). | ||
| value: The cache entry. | ||
| _now: The current time as an epoch timestamp (unused). | ||
| return float(expiration_epoch) | ||
| Returns: | ||
| The expiration time as an epoch timestamp, or sys.maxsize if the entry has no TTL. | ||
| """ | ||
| if value.expires_at is None: | ||
| return float(sys.maxsize) | ||
|
|
||
| return value.expires_at.timestamp() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Consider adding noqa comment for consistency.
The function logic correctly uses expires_at.timestamp() for expiration. Both _key and _now parameters are properly prefixed with underscores to indicate they're unused.
For consistency with line 79 (which has # noqa: ARG001), consider adding # noqa: ARG001, ARG003 to suppress linting warnings for both unused parameters, though this is a minor style point.
Based on past review comments.
🤖 Prompt for AI Agents
In key-value/key-value-aio/src/key_value/aio/stores/memory/store.py around lines
60 to 76, the function _memory_cache_ttu currently prefixes unused parameters
with underscores but lacks the noqa lint suppression present elsewhere; add a
trailing comment "# noqa: ARG001, ARG003" on the function definition line to
explicitly suppress unused-argument warnings for _key and _now, keeping the
function logic unchanged.
|
@claude can you outline what bugs were fixed and how they were fixed so we can make a new standalone PR for those? |
|
Claude finished @strawgate's task —— View job Bug Fixes SummaryI've analyzed this PR and identified 4 major bug fixes that were implemented alongside the documentation improvements. Here's a detailed breakdown: Bug #1: Windows Registry
|


Summary
This PR implements a second round of comprehensive docstring improvements across the async key-value library, focusing on utility functions, helper classes, and internal methods that were previously undocumented.
Changes
Elasticsearch Utilities (10 functions)
Windows Registry Utilities (8 items)
Store Helper Functions (8 items)
MemcachedStore.sanitize_key()documentationSimpleStoreEntryandMemoryCacheEntrydataclassesMemoryCollectionclass and method docstringsStatistics Wrappers (8 dataclasses)
Memory Cache Internals (4 functions)
Quality Assurance
Closes #135
🤖 Generated with Claude Code
Summary by CodeRabbit
Bug Fixes
New Features
Documentation