155 lines
5.5 KiB
Markdown
155 lines
5.5 KiB
Markdown
# CLAUDE.md
|
|
|
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
|
|
## Project Overview
|
|
|
|
MyUtils is a Python utility library providing dynamic object manipulation capabilities. The library focuses on three core utilities: Observable (attribute change tracking), Expando (dynamic dictionary wrapper), and Dummy (null-safe mock object).
|
|
|
|
## Development Workflow & Collaboration Guidelines
|
|
|
|
### Developer Profile
|
|
You are an experienced Python developer producing Python 3.12 code.
|
|
|
|
### Development Process
|
|
- All proposed code must be testable
|
|
- **Before writing any code**, explain the possible implementation options
|
|
- Wait for mutual validation and understanding of requirements before producing code
|
|
|
|
### Collaboration Style
|
|
- Ask clarifying questions to refine understanding or suggest alternative approaches
|
|
- **Ask questions one at a time** - wait for complete understanding of the answer before asking the next
|
|
- When you have multiple questions, indicate progress (e.g., "Question 1/5")
|
|
|
|
### Communication
|
|
- Conversations can be in French or English
|
|
- **All code, documentation, and comments must be exclusively in English**
|
|
|
|
### Code Standards
|
|
- Follow PEP 8 conventions for Python code style
|
|
- Use Google or NumPy format for docstrings
|
|
- Variable and function names must be explicit and in snake_case
|
|
- Never use emojis in code
|
|
|
|
### Dependency Management
|
|
- List all external dependencies required for installation
|
|
- When possible, propose alternatives using only Python standard library
|
|
|
|
### Unit Testing
|
|
- Use pytest library for unit tests
|
|
- **Before writing tests**, list the tests you plan to implement with explanations of why they're important
|
|
- Wait for validation before implementing tests
|
|
- Unless explicitly needed (e.g., inheritance), write tests as functions, not classes
|
|
- Test function naming patterns:
|
|
- `test_i_can_xxx` for tests that should pass
|
|
- `test_i_cannot_xxx` for edge cases that should raise errors/exceptions
|
|
|
|
### File Management
|
|
- When adding or modifying a file, always provide the complete file path
|
|
|
|
### Error Handling
|
|
- When presented with a code execution error:
|
|
1. First provide a clear explanation of the problem
|
|
2. **Do not** immediately propose a new version
|
|
3. Wait for validation of the bug analysis before proposing solutions
|
|
|
|
## Development Commands
|
|
|
|
### Testing
|
|
```bash
|
|
# Run all tests
|
|
pytest
|
|
|
|
# Run specific test file
|
|
pytest tests/test_observable.py
|
|
pytest tests/test_expando.py
|
|
pytest tests/test_dummy.py
|
|
|
|
# Run with verbose output
|
|
pytest -v
|
|
|
|
# Run specific test
|
|
pytest tests/test_observable.py::test_i_can_make_an_object_observable
|
|
```
|
|
|
|
### Package Management
|
|
```bash
|
|
# Install development dependencies
|
|
pip install -r requirements.txt
|
|
|
|
# Install package in development mode
|
|
pip install -e .
|
|
|
|
# Install with development extras
|
|
pip install -e ".[dev]"
|
|
```
|
|
|
|
## Architecture
|
|
|
|
### Observable Pattern Implementation
|
|
|
|
The Observable module uses **dynamic class substitution** to add observability to any Python object:
|
|
|
|
1. `make_observable(obj)` replaces the object's class with a dynamically created subclass
|
|
2. The subclass overrides `__setattr__` to intercept attribute changes
|
|
3. Listeners are stored in a `_listeners` dict on the object instance
|
|
4. Two types of callbacks exist:
|
|
- **Attribute callbacks**: Triggered on specific attribute changes via `bind()`
|
|
- **Event listeners**: Triggered via `add_event_listener()` for events like `AFTER_PROPERTY_CHANGE`
|
|
|
|
#### Event System
|
|
|
|
- `AFTER_PROPERTY_CHANGE` event fires after all attribute callbacks execute
|
|
- Event listeners receive: `(attr_name, old_value, new_value, callback_results)`
|
|
- Empty string `""` as attr_name registers listener for ALL attributes
|
|
- Return values from attribute callbacks are collected and passed to event listeners
|
|
|
|
### Expando Pattern
|
|
|
|
Expando wraps dictionaries to enable dot-notation access:
|
|
- Uses `__getattr__` to intercept attribute access and delegate to internal dict
|
|
- Nested dicts are automatically wrapped in Expando instances
|
|
- `get(path)` method supports path notation (`"a.b.c"`) and list traversal
|
|
- When path encounters a list, it collects values from all list items
|
|
|
|
### ProxyObject
|
|
|
|
ProxyObject (currently in development) maps object attributes to a different structure using a mappings dictionary. Note: Implementation appears incomplete - `_create_props()` is defined but never called.
|
|
|
|
## Testing Conventions
|
|
|
|
- Test files use pytest fixtures (`data`, `observable_data`)
|
|
- Test names follow pattern: `test_i_can_<action>` or `test_<behavior>`
|
|
- Tests are organized by feature with separator comments
|
|
- Each test is self-contained with its own callbacks/data
|
|
|
|
## Package Structure
|
|
|
|
```
|
|
src/myutils/ # Main package code
|
|
├── __init__.py # Package exports (currently empty)
|
|
├── observable.py # Observable implementation
|
|
├── Expando.py # Expando wrapper
|
|
├── Dummy.py # Dummy mock object
|
|
└── ProxyObject.py # ProxyObject (incomplete)
|
|
|
|
tests/ # Test suite
|
|
├── test_observable.py
|
|
├── test_expando.py
|
|
└── test_dummy.py
|
|
```
|
|
|
|
## Important Patterns
|
|
|
|
### Observable Callback Semantics
|
|
- Callbacks must be the **same object** to unbind (not just equivalent lambdas)
|
|
- `unbind()` and `unbind_all()` fail silently if callback/attribute doesn't exist
|
|
- Multiple instances have independent listeners
|
|
- `make_observable()` is idempotent (safe to call multiple times)
|
|
|
|
### Naming Convention
|
|
- Use English for persona names (per global CLAUDE.md)
|
|
- Class names use PascalCase
|
|
- Functions use snake_case
|
|
- Private attributes prefixed with `_`
|