5.5 KiB
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_xxxfor tests that should passtest_i_cannot_xxxfor 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:
- First provide a clear explanation of the problem
- Do not immediately propose a new version
- Wait for validation of the bug analysis before proposing solutions
Development Commands
Testing
# 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
# 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:
make_observable(obj)replaces the object's class with a dynamically created subclass- The subclass overrides
__setattr__to intercept attribute changes - Listeners are stored in a
_listenersdict on the object instance - Two types of callbacks exist:
- Attribute callbacks: Triggered on specific attribute changes via
bind() - Event listeners: Triggered via
add_event_listener()for events likeAFTER_PROPERTY_CHANGE
- Attribute callbacks: Triggered on specific attribute changes via
Event System
AFTER_PROPERTY_CHANGEevent 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>ortest_<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()andunbind_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
_