Skip to content

Commit 5c14ce1

Browse files
authored
Fix Pydantic deprecation and add mypy __all__ exports (#770)
* Update classifier to Production/Stable and fix TODO doc links * Fix Pydantic deprecation: use class-level model_fields access * Add __all__ export list for mypy compatibility
1 parent 0aac1f3 commit 5c14ce1

File tree

3 files changed

+223
-1
lines changed

3 files changed

+223
-1
lines changed

AGENTS.md

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Project Overview
6+
7+
Redis OM Python is an object mapping library for Redis that provides high-level abstractions to model and query Redis data with modern Python applications. It supports both async (aredis_om) and sync (redis_om) versions, with sync code automatically generated from async code using unasync.
8+
9+
## Development Commands
10+
11+
### Setup and Installation
12+
```bash
13+
# Install dependencies using Poetry (preferred)
14+
poetry install
15+
16+
# Or directly with pip
17+
pip install -e .
18+
```
19+
20+
### Core Development Tasks
21+
```bash
22+
# Run linting (includes isort, black, flake8, mypy, bandit)
23+
make lint
24+
25+
# Format code
26+
make format
27+
28+
# Run full test suite against redis-stack
29+
make test
30+
31+
# Run tests against OSS Redis
32+
make test_oss
33+
34+
# Generate sync code from async code (REQUIRED after any aredis_om changes)
35+
make sync
36+
37+
# Build distribution packages
38+
make dist
39+
40+
# Start Redis instances via Docker Compose
41+
make redis
42+
43+
# Run all linting, formatting, and tests
44+
make all
45+
```
46+
47+
**IMPORTANT**: Always run `make sync` after making any changes to `aredis_om/` or `tests/` to regenerate the corresponding sync versions.
48+
49+
### Testing Commands
50+
```bash
51+
# Run specific test file
52+
pytest tests/test_hash_model.py
53+
54+
# Run specific test with verbose output
55+
pytest tests/test_hash_model.py::test_values_method_with_specific_fields -v
56+
57+
# Run async tests (uses pytest-asyncio)
58+
pytest tests/ -v
59+
60+
# Run sync tests
61+
pytest tests_sync/ -v
62+
63+
# Run tests with coverage
64+
pytest --cov-report term-missing --cov aredis_om tests/
65+
```
66+
67+
### CLI Tools
68+
```bash
69+
# Migration CLI (async version, recommended)
70+
om migrate
71+
72+
# Legacy migration CLI (sync version)
73+
migrate
74+
```
75+
76+
## Code Architecture
77+
78+
### Dual Async/Sync Design
79+
- **aredis_om/**: Primary async implementation - **WRITE ALL CODE HERE**
80+
- **redis_om/**: Sync version auto-generated from async using unasync - **NEVER EDIT THIS DIRECTORY**
81+
- **tests/**: Async tests - **WRITE ALL TESTS HERE**
82+
- **tests_sync/**: Sync tests auto-generated from async tests - **NEVER EDIT THIS DIRECTORY**
83+
- **make_sync.py**: Script that generates sync versions using unasync transformations
84+
85+
### CRITICAL RULE: Only Edit Async Code
86+
**NEVER write, modify, or edit any files in `redis_om/` or `tests_sync/` directories. These are automatically generated from the async versions using unasync. All development must be done in `aredis_om/` and `tests/` directories only. The `make sync` command regenerates the sync versions.**
87+
88+
### Core Components
89+
90+
#### Model System (aredis_om/model/model.py)
91+
- **RedisModel**: Abstract base class for all models
92+
- **HashModel**: For Redis Hash storage (simple key-value fields)
93+
- **JsonModel**: For Redis JSON storage (complex nested structures)
94+
- **EmbeddedJsonModel**: For nested models within JsonModels
95+
96+
Key classes:
97+
- `FindQuery`: Handles search queries with RediSearch
98+
- `Expression/NegatedExpression`: Query expression trees
99+
- `FieldInfo`: Enhanced Pydantic field with Redis-specific options
100+
- `ModelMeta`: Metaclass handling model registration and field processing
101+
102+
#### Field Types and Indexing
103+
- Automatic field type detection for RediSearch indexing
104+
- Support for TAG, TEXT, NUMERIC, GEO, and VECTOR field types
105+
- Configurable indexing with `Field(index=True, sortable=True, full_text_search=True)`
106+
- Vector search support with FLAT and HNSW algorithms
107+
108+
#### Migration System (aredis_om/model/migrations/)
109+
- **migrator.py**: Core migration engine
110+
- **data_migrator.py**: Data transformation utilities
111+
- **datetime_migration.py**: Specific migration for datetime field indexing
112+
- Automatic index creation and schema management
113+
114+
#### Query System
115+
- Django-like ORM syntax: `Model.find(Model.field == value)`
116+
- Support for complex queries with AND, OR, NOT operations
117+
- KNN vector search capabilities
118+
- Pagination, sorting, and field projection
119+
- `.values()` and `.only()` methods for efficient field selection
120+
121+
### Key Features
122+
123+
#### DateTime Handling
124+
- Automatic conversion of datetime objects to Unix timestamps for Redis storage
125+
- Proper indexing support for datetime fields
126+
- Conversion back to datetime objects on retrieval
127+
128+
#### Connection Management
129+
- Multiple Redis connection support via Meta.database
130+
- Pipeline support for bulk operations
131+
- Async/await pattern throughout
132+
133+
#### Validation and Type Safety
134+
- Built on Pydantic v2 for robust data validation
135+
- Type hints throughout codebase
136+
- Automatic field type inference for indexing
137+
138+
## Development Patterns
139+
140+
**REMEMBER: All code changes must be made in `aredis_om/` directory only. Never edit `redis_om/`.**
141+
142+
### Model Definition
143+
```python
144+
from aredis_om import HashModel, JsonModel, Field
145+
import datetime
146+
147+
# Hash model for simple structures
148+
class User(HashModel, index=True):
149+
name: str = Field(index=True)
150+
email: str = Field(index=True)
151+
age: int = Field(index=True, sortable=True)
152+
153+
# JSON model for complex nested data
154+
class Order(JsonModel, index=True):
155+
user_id: str = Field(index=True)
156+
items: List[OrderItem]
157+
created_at: datetime.datetime
158+
159+
# Embedded models
160+
class Address(EmbeddedJsonModel):
161+
street: str = Field(index=True)
162+
city: str = Field(index=True)
163+
```
164+
165+
### Testing Patterns
166+
- Use `pytest.mark.asyncio` for async tests
167+
- Tests use `conftest.py` fixtures for Redis connection and cleanup
168+
- Separate test files for hash vs JSON models
169+
- Integration tests with actual Redis instances via Docker
170+
171+
### Migration Development
172+
- Migrations auto-discover models in the registry
173+
- Data migrations support field transformations
174+
- Always test migrations against representative data
175+
176+
## Project Structure Notes
177+
178+
- **docs/**: Comprehensive documentation in Markdown
179+
- **docker-compose.yml**: Redis Stack and OSS Redis instances for testing
180+
- **pyproject.toml**: Poetry configuration with CLI script definitions
181+
- **.github/**: CI/CD workflows and issue templates
182+
- **Session.vim**: Vim session configuration for development
183+
184+
## Important Implementation Details
185+
186+
- Primary keys default to ULID format for ordering and uniqueness
187+
- Boolean fields stored as "1"/"0" strings in HashModel, native booleans in JsonModel
188+
- Field validation occurs at model instantiation for indexed models
189+
- RediSearch schema generation is automatic based on field types and annotations
190+
- Pipeline operations supported throughout for performance
191+
- Comprehensive error handling with custom exception types
192+
193+
## CLI Integration
194+
195+
The project provides two CLI entry points:
196+
- `om`: Modern unified CLI using async components
197+
- `migrate`: Legacy CLI for backward compatibility
198+
199+
Both support model discovery, index creation, and data migration operations.

aredis_om/__init__.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,26 @@
1717
VectorFieldOptions,
1818
)
1919
from .model.types import Coordinates, GeoFilter
20+
21+
__all__ = [
22+
"Coordinates",
23+
"EmbeddedJsonModel",
24+
"Field",
25+
"FindQuery",
26+
"GeoFilter",
27+
"HashModel",
28+
"JsonModel",
29+
"KNNExpression",
30+
"MigrationError",
31+
"Migrator",
32+
"NotFoundError",
33+
"QueryNotSupportedError",
34+
"QuerySyntaxError",
35+
"RedisModel",
36+
"RedisModelError",
37+
"VectorFieldOptions",
38+
"get_redis_connection",
39+
"has_redis_json",
40+
"has_redisearch",
41+
"redis",
42+
]

aredis_om/model/model.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2700,7 +2700,7 @@ def _get_field_expirations(
27002700
expirations: Dict[str, int] = {}
27012701

27022702
# Collect default expirations from Field(expire=N)
2703-
for name, field in self.model_fields.items():
2703+
for name, field in self.__class__.model_fields.items():
27042704
field_info = field
27052705
# Handle metadata-wrapped FieldInfo
27062706
if (

0 commit comments

Comments
 (0)