Added ProxyObject + CLAUDE.md
This commit is contained in:
154
CLAUDE.md
Normal file
154
CLAUDE.md
Normal file
@@ -0,0 +1,154 @@
|
||||
# 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 `_`
|
||||
Reference in New Issue
Block a user