wry 0.4.1__tar.gz → 0.5.1.dev3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- wry-0.5.1.dev3/.cursorrules +192 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/AI_KNOWLEDGE_BASE.md +159 -1
- {wry-0.4.1 → wry-0.5.1.dev3}/CHANGELOG.md +100 -0
- wry-0.5.1.dev3/CONTRIBUTING.md +633 -0
- {wry-0.4.1/wry.egg-info → wry-0.5.1.dev3}/PKG-INFO +153 -1
- {wry-0.4.1 → wry-0.5.1.dev3}/README.md +152 -0
- wry-0.5.1.dev3/tests/unit/auto_model/test_auto_model_list_fields.py +433 -0
- wry-0.5.1.dev3/tests/unit/auto_model/test_comma_separated_lists.py +508 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/wry/__init__.py +4 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/wry/_version.py +3 -3
- {wry-0.4.1 → wry-0.5.1.dev3}/wry/auto_model.py +8 -1
- {wry-0.4.1 → wry-0.5.1.dev3}/wry/click_integration.py +40 -2
- wry-0.5.1.dev3/wry/comma_separated.py +182 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/wry/core/model.py +1 -0
- {wry-0.4.1 → wry-0.5.1.dev3/wry.egg-info}/PKG-INFO +153 -1
- {wry-0.4.1 → wry-0.5.1.dev3}/wry.egg-info/SOURCES.txt +5 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/.github/workflows/ci-cd.yml +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/.gitignore +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/.markdownlint.json +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/.pre-commit-config.yaml +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/LICENSE +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/RELEASE_PROCESS.md +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/TODO.md +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/check.sh +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/examples/autowrymodel_comprehensive.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/examples/config.json +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/examples/multimodel_comprehensive.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/examples/sample_config.json +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/examples/wrymodel_comprehensive.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/pyproject.toml +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/scripts/README.md +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/scripts/extract_release_notes.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/scripts/test_all_versions.sh +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/scripts/test_ci_locally.sh +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/scripts/test_with_act.sh +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/scripts/update-dependencies.sh +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/setup.cfg +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/README.md +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/__init__.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/features/__init__.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/features/test_auto_model.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/features/test_inheritance.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/features/test_multi_model.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/features/test_source_precedence.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/integration/__init__.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/integration/test_click_edge_cases.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/integration/test_click_integration.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/integration/test_click_integration_extended.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/integration/test_context_handling.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/__init__.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/auto_model/__init__.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/auto_model/test_auto_model_annotation_inference.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/auto_model/test_auto_model_edge_cases.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/auto_model/test_auto_model_field_processing.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/auto_model/test_field_annotation_handling.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/auto_model/test_field_annotations.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/auto_model/test_type_inference.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/click/README_TESTING_STRATEGY.md +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/click/__init__.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/click/test_argument_types.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/click/test_bool_flag_handling.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/click/test_click_config_building.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/click/test_click_constraint_formatting.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/click/test_click_decorator_edge_cases.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/click/test_click_interval_constraints.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/click/test_click_lambda_parsing.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/click/test_click_length_constraints.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/click/test_click_parameter_generation.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/click/test_click_predicate_handling.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/click/test_closure_extraction_errors.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/click/test_closure_handling.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/click/test_constraint_behavior.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/click/test_constraint_edge_cases.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/click/test_env_vars_option.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/click/test_explicit_argument_help_injection.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/click/test_field_alias_with_click_options.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/click/test_format_constraint_text.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/click/test_json_config_loading.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/click/test_lambda_behavior.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/click/test_lambda_error_handling.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/click/test_predicate_source_errors.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/click/test_strict_mode_errors.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/click/test_type_handling.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/core/__init__.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/core/test_accessors.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/core/test_advanced_features.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/core/test_core.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/core/test_edge_cases.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/core/test_env_utils.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/core/test_field_constraint_extraction.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/core/test_field_utils.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/core/test_field_utils_edge_cases.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/core/test_sources.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/core/test_type_checking_blocks.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/model/__init__.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/model/test_accessor_caching.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/model/test_extract_edge_cases.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/model/test_extract_subset_edge_cases.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/model/test_model_click_context_handling.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/model/test_model_data_extraction.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/model/test_model_default_handling.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/model/test_model_edge_cases.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/model/test_model_environment_integration.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/model/test_model_extract_subset_edge_cases.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/model/test_model_extraction_methods.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/model/test_model_field_errors.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/model/test_model_object_extraction.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/model/test_non_dict_object_extraction.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/model/test_object_attribute_extraction.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/multi_model/__init__.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/multi_model/test_multi_model.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/multi_model/test_type_checking.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/test_argument_help_injection.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/test_auto_model_field_processing.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/test_comprehensive_imports.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/test_exclude_enum.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/test_generate_click_classmethod.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/test_help_system.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/test_init.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/test_init_edge_cases.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/test_init_version_edge_cases.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/test_model_extraction_methods.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/test_multiple_option_bug.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/test_type_checking_imports.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/test_variadic_argument_bug.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/test_version_fallback.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/tests/unit/test_version_parsing.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/wry/core/__init__.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/wry/core/accessors.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/wry/core/env_utils.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/wry/core/field_utils.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/wry/core/sources.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/wry/help_system.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/wry/multi_model.py +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/wry/py.typed +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/wry.egg-info/dependency_links.txt +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/wry.egg-info/requires.txt +0 -0
- {wry-0.4.1 → wry-0.5.1.dev3}/wry.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# Cursor AI Rules for wry Repository
|
|
2
|
+
|
|
3
|
+
> **Note**: These rules are the AI assistant's quick reference. For comprehensive guidelines,
|
|
4
|
+
> examples, and detailed explanations, see `CONTRIBUTING.md`.
|
|
5
|
+
|
|
6
|
+
## Pre-Commit Requirements
|
|
7
|
+
|
|
8
|
+
Before making any commit, AI assistants MUST:
|
|
9
|
+
|
|
10
|
+
1. **Update Documentation**:
|
|
11
|
+
- README.md if user-facing changes
|
|
12
|
+
- AI_KNOWLEDGE_BASE.md if architecture/API changes
|
|
13
|
+
- CHANGELOG.md with entry under [Unreleased]
|
|
14
|
+
- Module docstrings if relevant
|
|
15
|
+
|
|
16
|
+
2. **Ensure Code Quality**:
|
|
17
|
+
- Add type annotations to all new functions
|
|
18
|
+
- Add docstrings to all public functions/classes
|
|
19
|
+
- Follow DRY principles
|
|
20
|
+
- Remove dead code and unused imports
|
|
21
|
+
|
|
22
|
+
3. **Update/Add Tests**:
|
|
23
|
+
- Add tests for new functionality
|
|
24
|
+
- Update tests for changed behavior
|
|
25
|
+
- Ensure tests pass (run pytest)
|
|
26
|
+
|
|
27
|
+
4. **Run Checks**:
|
|
28
|
+
- Ensure pre-commit hooks will pass
|
|
29
|
+
- Fix linter errors (ruff, mypy)
|
|
30
|
+
- Format code properly (ruff format)
|
|
31
|
+
|
|
32
|
+
5. **Follow Conventional Commits**:
|
|
33
|
+
- Use format: `type: description`
|
|
34
|
+
- Types: feat, fix, docs, refactor, test, chore, build
|
|
35
|
+
|
|
36
|
+
## Reference
|
|
37
|
+
|
|
38
|
+
**Full development guidelines**: See `CONTRIBUTING.md` for:
|
|
39
|
+
|
|
40
|
+
- Complete code organization principles
|
|
41
|
+
- Detailed examples of adding features
|
|
42
|
+
- wry-specific development patterns
|
|
43
|
+
- Comprehensive pre-commit checklist
|
|
44
|
+
- Pull request process
|
|
45
|
+
|
|
46
|
+
**Quick links**:
|
|
47
|
+
|
|
48
|
+
- Architecture & concepts: `CONTRIBUTING.md` "Core Concepts" section
|
|
49
|
+
- Code patterns: `CONTRIBUTING.md` "Configuration Models" section
|
|
50
|
+
- Testing guide: `CONTRIBUTING.md` "Testing" section
|
|
51
|
+
- Pre-commit checklist: `CONTRIBUTING.md` "Pre-Commit Checklist" section
|
|
52
|
+
|
|
53
|
+
## Enforcement
|
|
54
|
+
|
|
55
|
+
The pre-commit hook automatically runs checks on commit.
|
|
56
|
+
All checks must pass before commit succeeds.
|
|
57
|
+
|
|
58
|
+
## General Development Guidelines
|
|
59
|
+
|
|
60
|
+
### Date and Time
|
|
61
|
+
|
|
62
|
+
- Use the `date` terminal command to learn the current date
|
|
63
|
+
- Never assume or hardcode dates in dynamic contexts
|
|
64
|
+
|
|
65
|
+
### Python Best Practices
|
|
66
|
+
|
|
67
|
+
#### Type Annotations
|
|
68
|
+
|
|
69
|
+
- **ALWAYS** add type annotations to all functions, methods, and class attributes
|
|
70
|
+
- Include return types for all functions (use `-> None` for void functions)
|
|
71
|
+
- Use proper generic types from `typing` module
|
|
72
|
+
- Prefer modern Python 3.10+ syntax (e.g., `list[str]` over `List[str]`)
|
|
73
|
+
|
|
74
|
+
#### Documentation
|
|
75
|
+
|
|
76
|
+
- Add comprehensive docstrings to:
|
|
77
|
+
- All modules (at the top of the file)
|
|
78
|
+
- All classes (describing purpose, attributes, and usage)
|
|
79
|
+
- All public functions and methods (describing parameters, return values, and exceptions)
|
|
80
|
+
- Use consistent docstring format (Google style preferred)
|
|
81
|
+
|
|
82
|
+
#### Code Quality
|
|
83
|
+
|
|
84
|
+
- **DRY Principles**: Don't Repeat Yourself - extract common logic into reusable functions/classes
|
|
85
|
+
- **Clean Code**: Write self-documenting code with clear variable and function names
|
|
86
|
+
- **No Dead Code**: Remove unused variables, functions, and commented-out code unless it serves as important documentation
|
|
87
|
+
- **Maintainability**: Prioritize code that is easy to understand, modify, and extend
|
|
88
|
+
|
|
89
|
+
### Linter and Type Checker Compliance
|
|
90
|
+
|
|
91
|
+
#### Fixing Issues Properly
|
|
92
|
+
|
|
93
|
+
- **ALWAYS** fix linter errors and type checker warnings properly
|
|
94
|
+
- **AVOID** using ignore directives like `# type: ignore`, `# noqa` as quick fixes
|
|
95
|
+
- **AVOID** using `cast()` unless absolutely critical for complex type scenarios
|
|
96
|
+
- Investigate the root cause and fix issues with proper type annotations and code structure
|
|
97
|
+
- If an ignore directive is truly necessary, add a detailed comment explaining why
|
|
98
|
+
|
|
99
|
+
#### Working Directory
|
|
100
|
+
|
|
101
|
+
- **ALWAYS** ensure you're in the correct directory before:
|
|
102
|
+
- Running commands
|
|
103
|
+
- Creating files
|
|
104
|
+
- Executing scripts
|
|
105
|
+
- Making git operations
|
|
106
|
+
|
|
107
|
+
### Testing
|
|
108
|
+
|
|
109
|
+
#### Test Coverage
|
|
110
|
+
|
|
111
|
+
- **NEVER** ignore, skip, or disable test cases just to make test suites pass
|
|
112
|
+
- If a test fails, fix the underlying issue or update the test if requirements changed
|
|
113
|
+
- Add tests for all new functionality
|
|
114
|
+
- Update tests when changing existing behavior
|
|
115
|
+
- Ensure all tests **PASS** before considering work complete
|
|
116
|
+
|
|
117
|
+
#### Test Organization
|
|
118
|
+
|
|
119
|
+
- Place test code in the most logical location (follow project structure under `tests/`)
|
|
120
|
+
- Name test files and functions clearly to indicate what they're testing
|
|
121
|
+
- Use descriptive test names: `test_<function>_<scenario>_<expected_result>`
|
|
122
|
+
|
|
123
|
+
### Documentation Management
|
|
124
|
+
|
|
125
|
+
#### Markdown Files
|
|
126
|
+
|
|
127
|
+
- **Do not create excessive markdown files** unless explicitly instructed
|
|
128
|
+
- If markdown files exist, add content to the appropriate existing file
|
|
129
|
+
- If unsure which file is appropriate, **ask the user** where content should go
|
|
130
|
+
- Before creating a new markdown file, consider: Did the user actually request documentation?
|
|
131
|
+
|
|
132
|
+
### Git Best Practices
|
|
133
|
+
|
|
134
|
+
#### Committing Changes
|
|
135
|
+
|
|
136
|
+
- Attempt to commit changes after completing major features or fixes
|
|
137
|
+
- Use **Conventional Commits** format: `<type>: <description>`
|
|
138
|
+
- Examples: `feat: add comma-separated list support`, `fix: handle ClassVar in AutoWryModel`
|
|
139
|
+
|
|
140
|
+
#### Pre-Commit Hooks - CRITICAL RULE
|
|
141
|
+
|
|
142
|
+
- **NEVER** use `git commit --no-verify` or `--no-gpg-sign` to bypass pre-commit hooks
|
|
143
|
+
- **ONLY EXCEPTION**: When the user explicitly says it's okay
|
|
144
|
+
- If pre-commit hooks fail:
|
|
145
|
+
1. Fix the underlying issue (don't bypass)
|
|
146
|
+
2. Ask the user for guidance if you can't fix it
|
|
147
|
+
3. Wait for user approval before using --no-verify
|
|
148
|
+
- Pre-commit hooks catch bugs, enforce quality, and save code review time
|
|
149
|
+
- Bypassing them should be extremely rare (emergency situations only with approval)
|
|
150
|
+
|
|
151
|
+
#### File Operations
|
|
152
|
+
|
|
153
|
+
- **Strongly prefer** using Git commands for file operations:
|
|
154
|
+
- Use `git rm` instead of `rm` when deleting tracked files
|
|
155
|
+
- Use `git mv` instead of `mv` when moving/renaming tracked files
|
|
156
|
+
- This ensures Git properly tracks file history instead of treating operations as delete+add
|
|
157
|
+
- Always pass `--yes` or appropriate non-interactive flags to avoid user prompts
|
|
158
|
+
- **NEVER** use `git push --force` to main/master without explicit user approval
|
|
159
|
+
- **NEVER** use `git reset --hard` without explicit user approval
|
|
160
|
+
|
|
161
|
+
## wry-Specific Guidelines
|
|
162
|
+
|
|
163
|
+
### Model Development
|
|
164
|
+
|
|
165
|
+
- All `WryModel` and `AutoWryModel` classes should use `ClassVar` for class-level configuration
|
|
166
|
+
- Source tracking is a core feature - ensure it works for new features
|
|
167
|
+
- List fields automatically get `multiple=True` unless `comma_separated_lists` is enabled
|
|
168
|
+
- Document behavior in both README.md and AI_KNOWLEDGE_BASE.md
|
|
169
|
+
|
|
170
|
+
### Click Integration
|
|
171
|
+
|
|
172
|
+
- All Click parameter generation should respect Pydantic field metadata
|
|
173
|
+
- Help text should be clear and include constraints
|
|
174
|
+
- Arguments should inject help into docstrings (Click limitation workaround)
|
|
175
|
+
|
|
176
|
+
### Testing Requirements
|
|
177
|
+
|
|
178
|
+
- Test all four configuration sources: CLI, ENV, JSON, DEFAULT
|
|
179
|
+
- Test source tracking for new features
|
|
180
|
+
- Test both standard and edge cases
|
|
181
|
+
- Use `CliRunner` for Click command tests
|
|
182
|
+
|
|
183
|
+
## Summary
|
|
184
|
+
|
|
185
|
+
These rules ensure:
|
|
186
|
+
|
|
187
|
+
- High code quality and maintainability
|
|
188
|
+
- Proper type safety and documentation
|
|
189
|
+
- Comprehensive test coverage
|
|
190
|
+
- Clean git history
|
|
191
|
+
- Consistent development practices
|
|
192
|
+
- wry's core features (source tracking, Click integration) work correctly
|
|
@@ -938,17 +938,175 @@ modified_arg = click.argument("field") # No help parameter
|
|
|
938
938
|
|
|
939
939
|
### 5. List Fields Auto-Get multiple=True
|
|
940
940
|
|
|
941
|
+
**Automatic behavior**: wry detects `list[T]` and `tuple[T, ...]` types and automatically adds `multiple=True` to the generated Click option.
|
|
942
|
+
|
|
941
943
|
```python
|
|
942
944
|
tags: list[str] = Field(default_factory=list)
|
|
943
945
|
|
|
944
946
|
# Auto-generates:
|
|
945
947
|
click.option("--tags", multiple=True, type=click.STRING)
|
|
946
948
|
|
|
947
|
-
# Usage:
|
|
949
|
+
# CORRECT Usage - specify option multiple times:
|
|
948
950
|
# --tags python --tags rust --tags go
|
|
949
951
|
# Result: tags=["python", "rust", "go"]
|
|
952
|
+
|
|
953
|
+
# Also correct - single value:
|
|
954
|
+
# --tags python
|
|
955
|
+
# Result: tags=["python"]
|
|
956
|
+
|
|
957
|
+
# Also correct - no values (uses default):
|
|
958
|
+
# (no --tags)
|
|
959
|
+
# Result: tags=[]
|
|
960
|
+
```
|
|
961
|
+
|
|
962
|
+
**IMPORTANT - Comma-separated values NOT supported**:
|
|
963
|
+
|
|
964
|
+
```python
|
|
965
|
+
# ❌ INCORRECT - This does NOT work as expected:
|
|
966
|
+
# --tags python,rust,go
|
|
967
|
+
# Result: tags=["python,rust,go"] ← Single string with commas!
|
|
968
|
+
|
|
969
|
+
# This is Click's behavior, not a wry limitation.
|
|
970
|
+
# Users MUST pass the option multiple times for multiple values.
|
|
971
|
+
```
|
|
972
|
+
|
|
973
|
+
**Why not comma-separated?**
|
|
974
|
+
|
|
975
|
+
- Click's `multiple=True` expects the option to be repeated
|
|
976
|
+
- Comma parsing would require custom Click types
|
|
977
|
+
- This matches standard Unix CLI conventions (see: grep -e, docker -v)
|
|
978
|
+
|
|
979
|
+
**Works with all list types**:
|
|
980
|
+
|
|
981
|
+
```python
|
|
982
|
+
tags: list[str] # Strings
|
|
983
|
+
ports: list[int] # Integers (with type validation)
|
|
984
|
+
flags: list[bool] # Booleans
|
|
985
|
+
values: tuple[str, ...] # Tuples also supported
|
|
986
|
+
```
|
|
987
|
+
|
|
988
|
+
**Tests**: See `tests/unit/auto_model/test_auto_model_list_fields.py` for comprehensive test coverage (11 tests)
|
|
989
|
+
|
|
990
|
+
**Comma-Separated Alternative (NEW)**:
|
|
991
|
+
|
|
992
|
+
For users who prefer comma-separated input, wry offers **two approaches**:
|
|
993
|
+
|
|
994
|
+
**Approach 1: Per-Field Annotation (fine-grained control)**
|
|
995
|
+
|
|
996
|
+
```python
|
|
997
|
+
from wry import AutoWryModel, CommaSeparated
|
|
998
|
+
from typing import Annotated
|
|
999
|
+
|
|
1000
|
+
class Config(AutoWryModel):
|
|
1001
|
+
# Standard: --tags a --tags b --tags c
|
|
1002
|
+
standard_tags: list[str] = Field(default_factory=list)
|
|
1003
|
+
|
|
1004
|
+
# Comma-separated: --csv-tags a,b,c
|
|
1005
|
+
csv_tags: Annotated[list[str], CommaSeparated] = Field(
|
|
1006
|
+
default_factory=list,
|
|
1007
|
+
description="Comma-separated tags"
|
|
1008
|
+
)
|
|
1009
|
+
|
|
1010
|
+
# Works with all types:
|
|
1011
|
+
ports: Annotated[list[int], CommaSeparated] = Field(default_factory=list)
|
|
1012
|
+
values: Annotated[list[float], CommaSeparated] = Field(default_factory=list)
|
|
1013
|
+
```
|
|
1014
|
+
|
|
1015
|
+
**Approach 2: Model-Wide ClassVar (all list fields)**
|
|
1016
|
+
|
|
1017
|
+
```python
|
|
1018
|
+
from wry import AutoWryModel
|
|
1019
|
+
from typing import ClassVar
|
|
1020
|
+
|
|
1021
|
+
class Config(AutoWryModel):
|
|
1022
|
+
# Enable comma-separated for ALL list fields
|
|
1023
|
+
comma_separated_lists: ClassVar[bool] = True
|
|
1024
|
+
|
|
1025
|
+
# All these now accept comma-separated input
|
|
1026
|
+
tags: list[str] = Field(default_factory=list) # --tags a,b,c
|
|
1027
|
+
ports: list[int] = Field(default_factory=list) # --ports 80,443
|
|
1028
|
+
values: list[float] = Field(default_factory=list) # --values 1.5,2.7
|
|
950
1029
|
```
|
|
951
1030
|
|
|
1031
|
+
**Which to use?**
|
|
1032
|
+
|
|
1033
|
+
- **Per-field**: When only specific fields should be comma-separated, or mixing styles
|
|
1034
|
+
- **Model-wide**: When all lists should consistently use comma-separated (Docker-style CLIs)
|
|
1035
|
+
|
|
1036
|
+
**How it works**:
|
|
1037
|
+
|
|
1038
|
+
- **Per-field**: Detects `CommaSeparated` in field metadata
|
|
1039
|
+
- **Model-wide**: Checks `comma_separated_lists: ClassVar[bool]` on model class
|
|
1040
|
+
- Per-field annotation takes priority over model-wide setting
|
|
1041
|
+
- Uses custom Click `ParamType` (CommaSeparatedStrings, CommaSeparatedInts, CommaSeparatedFloats)
|
|
1042
|
+
- Disables `multiple=True` for comma-separated fields
|
|
1043
|
+
- Parses comma-separated input and strips whitespace
|
|
1044
|
+
- Filters out empty items from multiple commas
|
|
1045
|
+
|
|
1046
|
+
**Model-wide ClassVar details**:
|
|
1047
|
+
|
|
1048
|
+
- Works like `env_prefix: ClassVar[str]` - a class-level configuration
|
|
1049
|
+
- Defined as `comma_separated_lists: ClassVar[bool] = False` in WryModel base
|
|
1050
|
+
- NOT included in Pydantic model fields (won't appear in `model_fields` or `model_dump()`)
|
|
1051
|
+
- AutoWryModel skips ClassVar fields during automatic processing
|
|
1052
|
+
- Can be overridden in child classes
|
|
1053
|
+
|
|
1054
|
+
**Trade-offs**:
|
|
1055
|
+
|
|
1056
|
+
- ✅ More concise for many values
|
|
1057
|
+
- ✅ Familiar to users of tools accepting comma-separated lists
|
|
1058
|
+
- ⚠️ Cannot combine with repeating option
|
|
1059
|
+
- ⚠️ Commas in values need escaping/quoting
|
|
1060
|
+
- ⚠️ Less discoverable (users might not know about comma support)
|
|
1061
|
+
|
|
1062
|
+
**When to use**:
|
|
1063
|
+
|
|
1064
|
+
- Tool has established comma-separated convention
|
|
1065
|
+
- Users expect Docker-style `-p 80,443,8080` syntax
|
|
1066
|
+
- Values never contain commas
|
|
1067
|
+
|
|
1068
|
+
**When NOT to use**:
|
|
1069
|
+
|
|
1070
|
+
- Users are accustomed to `grep -e` style repetition
|
|
1071
|
+
- Values might contain commas
|
|
1072
|
+
- Discoverability is important (repeating options is more obvious)
|
|
1073
|
+
|
|
1074
|
+
**Default recommendation**: Use standard `multiple=True` (default behavior) unless you have specific reasons to use comma-separated.
|
|
1075
|
+
|
|
1076
|
+
**Test Coverage (22 tests total)**:
|
|
1077
|
+
|
|
1078
|
+
Standard `multiple=True` tests (`test_auto_model_list_fields.py` - 11 tests):
|
|
1079
|
+
|
|
1080
|
+
- ✅ Auto-generation of `multiple=True` for `list[str]`, `list[int]`, `list[bool]`, `tuple[T, ...]`
|
|
1081
|
+
- ✅ Default values (Field default, default_factory)
|
|
1082
|
+
- ✅ Pydantic constraints (min_length, max_length) enforcement
|
|
1083
|
+
- ✅ Source tracking (CLI/ENV/JSON/DEFAULT)
|
|
1084
|
+
- ✅ JSON config integration
|
|
1085
|
+
- ✅ Help text generation
|
|
1086
|
+
- ✅ Empty list vs no value distinction
|
|
1087
|
+
- ✅ Environment variable behavior documented
|
|
1088
|
+
|
|
1089
|
+
Comma-separated tests (`test_comma_separated_lists.py` - 11 tests):
|
|
1090
|
+
|
|
1091
|
+
- ✅ Per-field annotation: `Annotated[list[T], CommaSeparated]` for str/int/float
|
|
1092
|
+
- ✅ Model-wide ClassVar: `comma_separated_lists: ClassVar[bool] = True`
|
|
1093
|
+
- ✅ Mixed usage (standard + comma-separated in same model)
|
|
1094
|
+
- ✅ Per-field annotation overrides model-wide setting
|
|
1095
|
+
- ✅ Whitespace handling, empty item filtering, trailing commas
|
|
1096
|
+
- ✅ Type conversion validation (invalid int/float)
|
|
1097
|
+
- ✅ Pydantic validation still works (min_length, max_length)
|
|
1098
|
+
- ✅ JSON config integration with comma-separated
|
|
1099
|
+
- ✅ Source tracking works correctly
|
|
1100
|
+
- ✅ ClassVar not included in model_fields or model_dump()
|
|
1101
|
+
|
|
1102
|
+
Edge cases validated:
|
|
1103
|
+
|
|
1104
|
+
- Multiple consecutive commas → filtered
|
|
1105
|
+
- Single value without comma → works
|
|
1106
|
+
- Mixing both styles in same model → works
|
|
1107
|
+
- Type conversion errors → proper error messages
|
|
1108
|
+
- Default values with both approaches → works
|
|
1109
|
+
|
|
952
1110
|
### 6. Optional Types Handled
|
|
953
1111
|
|
|
954
1112
|
```python
|
|
@@ -7,6 +7,106 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **Development guidelines** 📚
|
|
13
|
+
- Created `.cursorrules` as AI assistant's quick reference guide
|
|
14
|
+
- Created `CONTRIBUTING.md` as comprehensive contributor guide
|
|
15
|
+
- `.cursorrules` references `CONTRIBUTING.md` for detailed explanations
|
|
16
|
+
- Both tailored specifically for wry development patterns
|
|
17
|
+
|
|
18
|
+
### Tests
|
|
19
|
+
|
|
20
|
+
- **Additional comma-separated test** (494 total tests)
|
|
21
|
+
- `test_model_wide_setting_does_not_affect_non_list_fields`
|
|
22
|
+
- Validates that `comma_separated_lists: ClassVar[bool] = True` only affects list fields
|
|
23
|
+
- Non-list fields (str, int, bool) work normally
|
|
24
|
+
- Explicit `click.option` decorators (like `-vvv` for verbose) are not affected
|
|
25
|
+
- Tests real-world use case: model-wide comma-separated + verbose counting
|
|
26
|
+
|
|
27
|
+
## [0.5.0] - 2025-10-14
|
|
28
|
+
|
|
29
|
+
### Added
|
|
30
|
+
|
|
31
|
+
- **Comprehensive list field support** 🎯
|
|
32
|
+
- `list[str]`, `list[int]`, `list[float]`, `tuple[T, ...]` automatically get `multiple=True`
|
|
33
|
+
- Standard behavior: `--tags python --tags rust --tags go` (repeat option)
|
|
34
|
+
- Users must repeat the option for multiple values (Click's standard `multiple=True`)
|
|
35
|
+
- Comma-separated values NOT supported by default (documented as intentional)
|
|
36
|
+
|
|
37
|
+
- **Comma-separated list input (opt-in)** ✨
|
|
38
|
+
- Two ways to enable comma-separated parsing:
|
|
39
|
+
1. **Per-field annotation**: `Annotated[list[str], CommaSeparated]`
|
|
40
|
+
2. **Model-wide ClassVar**: `comma_separated_lists: ClassVar[bool] = True`
|
|
41
|
+
- Usage: `--tags python,rust,go` (single invocation with commas)
|
|
42
|
+
- Works with all list types: `list[str]`, `list[int]`, `list[float]`
|
|
43
|
+
- Custom Click ParamTypes: `CommaSeparatedStrings`, `CommaSeparatedInts`, `CommaSeparatedFloats`
|
|
44
|
+
- Per-field annotation takes priority over model-wide setting
|
|
45
|
+
- Automatically strips whitespace and filters empty items
|
|
46
|
+
- Full Pydantic validation preserved (min_length, max_length, etc.)
|
|
47
|
+
|
|
48
|
+
- **ClassVar configuration: `comma_separated_lists`**
|
|
49
|
+
- Works like `env_prefix: ClassVar[str]` - class-level configuration
|
|
50
|
+
- NOT included in Pydantic model fields (won't appear in `model_fields` or `model_dump()`)
|
|
51
|
+
- Can be set on model class to enable comma-separated for all list fields
|
|
52
|
+
- Can be overridden in child classes
|
|
53
|
+
- AutoWryModel correctly skips ClassVar fields during processing
|
|
54
|
+
|
|
55
|
+
### Fixed
|
|
56
|
+
|
|
57
|
+
- **AutoWryModel ClassVar handling** 🐛
|
|
58
|
+
- Fixed bug where ClassVar annotations (like `env_prefix`, `comma_separated_lists`) would cause errors
|
|
59
|
+
- AutoWryModel now properly skips ClassVar fields during automatic processing
|
|
60
|
+
- Prevents `TypeError: typing.ClassVar[T] is not valid as type argument`
|
|
61
|
+
|
|
62
|
+
### Tests
|
|
63
|
+
|
|
64
|
+
- **22 new comprehensive tests** (471 → 493 total tests)
|
|
65
|
+
- `tests/unit/auto_model/test_auto_model_list_fields.py` - 11 tests for standard behavior
|
|
66
|
+
- Multiple types (str, int, bool, tuple)
|
|
67
|
+
- Default values, constraints, source tracking
|
|
68
|
+
- JSON config, environment variables, help text
|
|
69
|
+
- `tests/unit/auto_model/test_comma_separated_lists.py` - 11 tests for comma-separated
|
|
70
|
+
- Per-field annotations (7 tests)
|
|
71
|
+
- Model-wide ClassVar (2 tests)
|
|
72
|
+
- Mixed usage (2 tests)
|
|
73
|
+
- Edge cases: whitespace, empty items, type validation
|
|
74
|
+
|
|
75
|
+
### Documentation
|
|
76
|
+
|
|
77
|
+
- **README.md List Type Fields section**
|
|
78
|
+
- Clear explanation of standard `multiple=True` behavior
|
|
79
|
+
- Documentation that comma-separated is NOT default (by design)
|
|
80
|
+
- Two approaches for comma-separated (per-field and model-wide)
|
|
81
|
+
- Usage examples for both approaches
|
|
82
|
+
- Trade-offs and recommendations
|
|
83
|
+
- Implementation notes (ClassVar, priority rules, type support)
|
|
84
|
+
|
|
85
|
+
- **AI_KNOWLEDGE_BASE.md comprehensive update**
|
|
86
|
+
- Edge case #5: List Fields Auto-Get multiple=True (expanded significantly)
|
|
87
|
+
- Detailed explanation of both standard and comma-separated approaches
|
|
88
|
+
- How it works: detection, type selection, parsing, priority
|
|
89
|
+
- Model-wide ClassVar details (similar to env_prefix pattern)
|
|
90
|
+
- Complete test coverage breakdown (22 tests documented)
|
|
91
|
+
- Edge cases validated
|
|
92
|
+
- When to use each approach
|
|
93
|
+
|
|
94
|
+
- **Module docstrings**
|
|
95
|
+
- `wry/comma_separated.py` - Complete module documentation with both approaches
|
|
96
|
+
- Custom ParamType implementations with full docstrings
|
|
97
|
+
|
|
98
|
+
### Technical Details
|
|
99
|
+
|
|
100
|
+
- New module: `wry/comma_separated.py` with custom Click ParamTypes
|
|
101
|
+
- Modified `wry/core/model.py`: Added `comma_separated_lists: ClassVar[bool] = False`
|
|
102
|
+
- Modified `wry/auto_model.py`: Skip ClassVar fields (lines 62-68)
|
|
103
|
+
- Modified `wry/click_integration.py`: Detect and handle comma-separated (lines 431-454)
|
|
104
|
+
- Export `CommaSeparated` from `wry/__init__.py`
|
|
105
|
+
|
|
106
|
+
### Breaking Changes
|
|
107
|
+
|
|
108
|
+
None - all changes are opt-in or additive.
|
|
109
|
+
|
|
10
110
|
## [0.4.1] - 2025-10-07
|
|
11
111
|
|
|
12
112
|
### Fixed
|