wry 0.5.3.dev1__tar.gz → 0.6.2__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.6.2/.cursorrules +11 -0
- wry-0.6.2/AGENTS.md +266 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/CHANGELOG.md +2 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/CONTRIBUTING.md +5 -5
- {wry-0.5.3.dev1 → wry-0.6.2}/DEPRECATION.md +1 -1
- {wry-0.5.3.dev1/wry.egg-info → wry-0.6.2}/PKG-INFO +4 -4
- {wry-0.5.3.dev1 → wry-0.6.2}/README.md +3 -3
- {wry-0.5.3.dev1 → wry-0.6.2}/RELEASE_PROCESS.md +2 -2
- wry-0.6.2/TODO.md +75 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/test_exclude_enum.py +4 -4
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/test_help_system.py +6 -6
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/test_type_checking_imports.py +5 -11
- wry-0.6.2/wry/_version.py +24 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/wry/core/model.py +3 -2
- {wry-0.5.3.dev1 → wry-0.6.2}/wry/help_system.py +21 -20
- {wry-0.5.3.dev1 → wry-0.6.2/wry.egg-info}/PKG-INFO +4 -4
- {wry-0.5.3.dev1 → wry-0.6.2}/wry.egg-info/SOURCES.txt +3 -1
- wry-0.6.2/wry.egg-info/scm_file_list.json +140 -0
- wry-0.6.2/wry.egg-info/scm_version.json +8 -0
- wry-0.5.3.dev1/.cursorrules +0 -198
- wry-0.5.3.dev1/AI_KNOWLEDGE_BASE.md +0 -2913
- wry-0.5.3.dev1/TODO.md +0 -184
- wry-0.5.3.dev1/wry/_version.py +0 -34
- {wry-0.5.3.dev1 → wry-0.6.2}/.github/workflows/ci-cd.yml +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/.gitignore +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/.markdownlint.json +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/.pre-commit-config.yaml +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/LICENSE +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/check.sh +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/examples/autowrymodel_comprehensive.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/examples/config.json +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/examples/multimodel_comprehensive.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/examples/sample_config.json +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/examples/wrymodel_comprehensive.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/pyproject.toml +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/scripts/README.md +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/scripts/extract_release_notes.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/scripts/test_all_versions.sh +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/scripts/test_ci_locally.sh +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/scripts/test_with_act.sh +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/scripts/update-dependencies.sh +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/setup.cfg +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/README.md +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/__init__.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/features/__init__.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/features/test_auto_model.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/features/test_inheritance.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/features/test_multi_model.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/features/test_source_precedence.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/integration/__init__.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/integration/test_boolean_flags_integration.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/integration/test_click_edge_cases.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/integration/test_click_integration.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/integration/test_click_integration_extended.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/integration/test_context_handling.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/__init__.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/auto_model/__init__.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/auto_model/test_auto_model_annotation_inference.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/auto_model/test_auto_model_edge_cases.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/auto_model/test_auto_model_field_processing.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/auto_model/test_auto_model_list_fields.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/auto_model/test_boolean_on_off_flags.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/auto_model/test_comma_separated_lists.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/auto_model/test_field_annotation_handling.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/auto_model/test_field_annotations.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/auto_model/test_new_marker_api.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/auto_model/test_optional_list_comma_separated.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/auto_model/test_type_inference.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/click/README_TESTING_STRATEGY.md +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/click/__init__.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/click/test_argument_types.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/click/test_bool_flag_handling.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/click/test_click_config_building.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/click/test_click_constraint_formatting.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/click/test_click_decorator_edge_cases.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/click/test_click_interval_constraints.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/click/test_click_lambda_parsing.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/click/test_click_length_constraints.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/click/test_click_parameter_generation.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/click/test_click_predicate_handling.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/click/test_closure_extraction_errors.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/click/test_closure_handling.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/click/test_constraint_behavior.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/click/test_constraint_edge_cases.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/click/test_env_vars_option.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/click/test_explicit_argument_help_injection.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/click/test_field_alias_with_click_options.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/click/test_format_constraint_text.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/click/test_json_config_loading.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/click/test_lambda_behavior.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/click/test_lambda_error_handling.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/click/test_predicate_source_errors.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/click/test_strict_mode_errors.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/click/test_type_handling.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/core/__init__.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/core/test_accessors.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/core/test_advanced_features.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/core/test_classvar_migration.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/core/test_core.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/core/test_edge_cases.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/core/test_env_utils.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/core/test_field_constraint_extraction.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/core/test_field_utils.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/core/test_field_utils_edge_cases.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/core/test_sources.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/core/test_type_checking_blocks.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/model/__init__.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/model/test_accessor_caching.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/model/test_extract_edge_cases.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/model/test_extract_subset_edge_cases.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/model/test_model_click_context_handling.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/model/test_model_data_extraction.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/model/test_model_default_handling.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/model/test_model_edge_cases.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/model/test_model_environment_integration.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/model/test_model_extract_subset_edge_cases.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/model/test_model_extraction_methods.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/model/test_model_field_errors.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/model/test_model_object_extraction.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/model/test_non_dict_object_extraction.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/model/test_object_attribute_extraction.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/multi_model/__init__.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/multi_model/test_multi_model.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/multi_model/test_type_checking.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/test_argument_help_injection.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/test_auto_model_field_processing.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/test_comprehensive_imports.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/test_generate_click_classmethod.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/test_init.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/test_init_edge_cases.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/test_init_version_edge_cases.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/test_model_extraction_methods.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/test_multiple_option_bug.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/test_variadic_argument_bug.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/test_version_fallback.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/tests/unit/test_version_parsing.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/wry/__init__.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/wry/auto_model.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/wry/click_integration.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/wry/comma_separated.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/wry/core/__init__.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/wry/core/accessors.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/wry/core/env_utils.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/wry/core/field_utils.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/wry/core/sources.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/wry/multi_model.py +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/wry/py.typed +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/wry.egg-info/dependency_links.txt +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/wry.egg-info/requires.txt +0 -0
- {wry-0.5.3.dev1 → wry-0.6.2}/wry.egg-info/top_level.txt +0 -0
wry-0.6.2/.cursorrules
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Cursor AI Rules for wry Repository
|
|
2
|
+
|
|
3
|
+
Read `AGENTS.md` for the complete AI assistant reference, including:
|
|
4
|
+
- Architecture overview
|
|
5
|
+
- Critical gotchas and edge cases
|
|
6
|
+
- Development rules and pre-commit requirements
|
|
7
|
+
- Correct vs incorrect patterns
|
|
8
|
+
- Debugging quick reference
|
|
9
|
+
|
|
10
|
+
For comprehensive contributor guidelines, see `CONTRIBUTING.md`.
|
|
11
|
+
For release workflow, see `RELEASE_PROCESS.md`.
|
wry-0.6.2/AGENTS.md
ADDED
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
# AGENTS.md - AI Assistant Reference for wry
|
|
2
|
+
|
|
3
|
+
> For user-facing docs see README.md. For contributor guidelines see CONTRIBUTING.md.
|
|
4
|
+
> For version history see CHANGELOG.md. For release workflow see RELEASE_PROCESS.md.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## What is wry?
|
|
9
|
+
|
|
10
|
+
**wry** (Why Repeat Yourself?) is a Python library that eliminates repetitive CLI configuration by:
|
|
11
|
+
|
|
12
|
+
1. Defining configuration once in Pydantic models
|
|
13
|
+
2. Automatically generating Click CLI parameters
|
|
14
|
+
3. Supporting multiple configuration sources (CLI / ENV / JSON / DEFAULT)
|
|
15
|
+
4. Tracking exactly where each value came from
|
|
16
|
+
5. Enforcing strict precedence: **CLI > JSON > ENV > DEFAULT**
|
|
17
|
+
|
|
18
|
+
**Key innovation**: Source tracking — no other library tells you *where* each config value came from.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Architecture Overview
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
wry/
|
|
26
|
+
├── __init__.py # Public API exports
|
|
27
|
+
├── click_integration.py # Click parameter generation (largest module)
|
|
28
|
+
├── auto_model.py # AutoWryModel — zero-config model via __init_subclass__
|
|
29
|
+
├── multi_model.py # Multi-model support (split_kwargs, create_models)
|
|
30
|
+
├── help_system.py # Documentation system
|
|
31
|
+
├── comma_separated.py # CommaSeparated list types
|
|
32
|
+
└── core/
|
|
33
|
+
├── model.py # WryModel base class, from_click_context(), source tracking
|
|
34
|
+
├── sources.py # ValueSource enum, TrackedValue, FieldWithSource
|
|
35
|
+
├── accessors.py # Property accessors (source, minimum, maximum, etc.)
|
|
36
|
+
├── field_utils.py # Constraint extraction from Pydantic fields
|
|
37
|
+
└── env_utils.py # Environment variable handling and type conversion
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
**Key classes**: `WryModel` (explicit annotations), `AutoWryModel` (auto-generates options for all fields)
|
|
41
|
+
|
|
42
|
+
**Key flow**: User defines Pydantic model -> `generate_click_parameters()` creates Click decorators -> `from_click_context()` builds model with source tracking
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Critical Gotchas
|
|
47
|
+
|
|
48
|
+
These are the most common issues that trip up both users and AI assistants.
|
|
49
|
+
|
|
50
|
+
### 1. `env_prefix` and other config must be ClassVar
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
# WRONG - Pydantic treats as a field, generates CLI option, breaks config
|
|
54
|
+
class Config(AutoWryModel):
|
|
55
|
+
env_prefix: str = "MYAPP_"
|
|
56
|
+
|
|
57
|
+
# CORRECT
|
|
58
|
+
class Config(AutoWryModel):
|
|
59
|
+
wry_env_prefix: ClassVar[str] = "MYAPP_"
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Without `ClassVar`, the attribute appears in `model_fields` and gets a CLI option generated. Use the `wry_` prefixed names (v0.6.0+). Old unprefixed names still work but emit deprecation warnings.
|
|
63
|
+
|
|
64
|
+
### 2. Source tracking requires context
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
# NO source tracking - all sources show as CLI
|
|
68
|
+
@Config.generate_click_parameters()
|
|
69
|
+
def main(**kwargs):
|
|
70
|
+
config = Config(**kwargs) # Wrong
|
|
71
|
+
|
|
72
|
+
# FULL source tracking
|
|
73
|
+
@Config.generate_click_parameters()
|
|
74
|
+
@click.pass_context # Required
|
|
75
|
+
def main(ctx: click.Context, **kwargs):
|
|
76
|
+
config = Config.from_click_context(ctx, **kwargs) # Correct
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### 3. Boolean fields use on/off pattern by default (v0.6.0+)
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
debug: bool = Field(default=False)
|
|
83
|
+
# Generates: --debug/--no-debug (not just --debug)
|
|
84
|
+
|
|
85
|
+
# Opt out to single flag:
|
|
86
|
+
debug: Annotated[bool, AutoOption(flag_enable_on_off=False)] = Field(default=False)
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### 4. List fields auto-get multiple=True
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
tags: list[str] = Field(default_factory=list)
|
|
93
|
+
# Usage: --tags python --tags rust (NOT --tags python,rust)
|
|
94
|
+
|
|
95
|
+
# For comma-separated: use Annotated[list[str], CommaSeparated]
|
|
96
|
+
# Or model-wide: wry_comma_separated_lists: ClassVar[bool] = True
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### 5. Arguments are always optional in Click (for --config compatibility)
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
input_file: Annotated[str, AutoArgument] = Field()
|
|
103
|
+
# Click sees required=False, but Pydantic still validates it's required
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### 6. Click argument doesn't accept help parameter
|
|
107
|
+
|
|
108
|
+
wry works around this by injecting help text into the command docstring. Use `Field(description="...")` for argument help.
|
|
109
|
+
|
|
110
|
+
### 7. Click 8.4+ compatibility
|
|
111
|
+
|
|
112
|
+
Click 8.4.0 changed `ParameterSource` from a string-valued to integer-valued enum. wry v0.6.1+ handles this. If source tracking silently fails (all values show as DEFAULT), upgrade wry.
|
|
113
|
+
|
|
114
|
+
### 8. Pydantic 2.11+ deprecation
|
|
115
|
+
|
|
116
|
+
Use `cls.model_fields` or `self.__class__.model_fields`, never `self.model_fields` (deprecated).
|
|
117
|
+
|
|
118
|
+
### 9. eager_json_config must not modify param.default
|
|
119
|
+
|
|
120
|
+
The JSON config callback only sets `p.required = False` on fields found in JSON. It must NOT set `p.default = json_value` — doing so breaks Click's parameter source detection and causes CLI values to be treated as defaults. (Fixed in v0.2.2.)
|
|
121
|
+
|
|
122
|
+
### 10. Duplicate decorator detection
|
|
123
|
+
|
|
124
|
+
```python
|
|
125
|
+
@Config.generate_click_parameters()
|
|
126
|
+
@Config.generate_click_parameters() # Error in strict mode (default)
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## Correct vs Incorrect Patterns
|
|
132
|
+
|
|
133
|
+
### Pattern: Creating a config model
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
# CORRECT - AutoWryModel for simple cases
|
|
137
|
+
class Config(AutoWryModel):
|
|
138
|
+
wry_env_prefix: ClassVar[str] = "APP_"
|
|
139
|
+
host: str = Field(default="localhost", description="Server host")
|
|
140
|
+
port: int = Field(default=8080, ge=1, le=65535)
|
|
141
|
+
|
|
142
|
+
# CORRECT - WryModel for mixed arguments/options
|
|
143
|
+
class Config(WryModel):
|
|
144
|
+
input_file: Annotated[str, AutoArgument] = Field(description="Input")
|
|
145
|
+
format: Annotated[str, AutoOption] = Field(default="json")
|
|
146
|
+
internal: Annotated[str, AutoExclude] = Field(default="")
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Pattern: Using aliases for CLI names
|
|
150
|
+
|
|
151
|
+
```python
|
|
152
|
+
class Config(AutoWryModel):
|
|
153
|
+
# Python: config.db_url | CLI: --database-url | Env: APP_DATABASE_URL
|
|
154
|
+
db_url: str = Field(alias="database_url", default="sqlite:///app.db")
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
No extra configuration needed — `validate_by_name=True` and `validate_by_alias=True` are set by WryModel.
|
|
158
|
+
|
|
159
|
+
### Pattern: Multi-model commands
|
|
160
|
+
|
|
161
|
+
```python
|
|
162
|
+
@click.command()
|
|
163
|
+
@multi_model(ServerConfig, DatabaseConfig)
|
|
164
|
+
@click.pass_context
|
|
165
|
+
def serve(ctx, **kwargs):
|
|
166
|
+
configs = create_models(ctx, kwargs, ServerConfig, DatabaseConfig)
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## Development Rules
|
|
172
|
+
|
|
173
|
+
### Pre-Commit Requirements
|
|
174
|
+
|
|
175
|
+
Before any commit, ensure:
|
|
176
|
+
|
|
177
|
+
1. **CHANGELOG.md**: Add entry under `[Unreleased]` for ANY change
|
|
178
|
+
2. **Tests**: Add/update tests, ensure all pass (`pytest`)
|
|
179
|
+
3. **Code quality**: Type annotations, docstrings, no dead code
|
|
180
|
+
4. **Linting**: `ruff check`, `ruff format`, `mypy` must pass
|
|
181
|
+
5. **TODO.md**: Mark completed tasks if applicable
|
|
182
|
+
6. **Conventional Commits**: `feat:`, `fix:`, `docs:`, `refactor:`, `test:`, `chore:`
|
|
183
|
+
|
|
184
|
+
The pre-commit hook runs all checks automatically. **Never use `--no-verify`.**
|
|
185
|
+
|
|
186
|
+
### Code Style
|
|
187
|
+
|
|
188
|
+
- Type annotations on all functions (use `-> None` for void)
|
|
189
|
+
- Google-style docstrings on public API
|
|
190
|
+
- Fix linter errors properly — avoid `# type: ignore`, `# noqa`, `cast()` unless truly necessary
|
|
191
|
+
- Use `git rm` / `git mv` for tracked files (preserves history)
|
|
192
|
+
|
|
193
|
+
### Testing
|
|
194
|
+
|
|
195
|
+
- **Never skip/disable tests** to make suites pass — fix the issue
|
|
196
|
+
- Test all four sources: CLI, ENV, JSON, DEFAULT
|
|
197
|
+
- Test source tracking for new features
|
|
198
|
+
- Use `CliRunner` for Click command tests
|
|
199
|
+
- Coverage requirement: 90%+
|
|
200
|
+
- Test organization: `tests/unit/`, `tests/integration/`, `tests/features/`
|
|
201
|
+
|
|
202
|
+
### wry-Specific Rules
|
|
203
|
+
|
|
204
|
+
- All `WryModel`/`AutoWryModel` config attributes must use `ClassVar`
|
|
205
|
+
- Source tracking is a core feature — ensure it works for new features
|
|
206
|
+
- List fields auto-get `multiple=True` unless comma-separated is enabled
|
|
207
|
+
- Update README.md for user-facing changes, AGENTS.md for architecture/API changes
|
|
208
|
+
- See CONTRIBUTING.md for comprehensive guidelines
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## Debugging Quick Reference
|
|
213
|
+
|
|
214
|
+
| User says | Check |
|
|
215
|
+
|-----------|-------|
|
|
216
|
+
| "Sources all show as CLI" | Using `@click.pass_context` + `from_click_context()`? |
|
|
217
|
+
| "CLI doesn't override config file" | Version >= 0.2.2? (bug fixed) |
|
|
218
|
+
| "Env vars not working" | `env_prefix` is `ClassVar`? Try `--show-env-vars` |
|
|
219
|
+
| "Required field not enforced" | Version >= 0.2.2? Has no default? Not satisfied by env/config? |
|
|
220
|
+
| "Argument help not showing" | Using `Field(description="...")`? Version >= 0.2.3? |
|
|
221
|
+
| "Field excluded but still in CLI" | Using `Annotated[str, AutoExclude]`? (not `AutoExclude[str]`) |
|
|
222
|
+
| "Source tracking shows DEFAULT for everything" | Click 8.4+ issue — upgrade wry to 0.6.1+ |
|
|
223
|
+
|
|
224
|
+
### Key Test Files
|
|
225
|
+
|
|
226
|
+
- `tests/features/test_source_precedence.py` — Tests all 4 sources with proper precedence
|
|
227
|
+
- `tests/features/test_inheritance.py` — Model inheritance scenarios
|
|
228
|
+
- `tests/features/test_auto_model.py` — AutoWryModel features
|
|
229
|
+
|
|
230
|
+
### Useful Commands
|
|
231
|
+
|
|
232
|
+
```bash
|
|
233
|
+
pytest # All tests
|
|
234
|
+
pytest tests/features/test_source_precedence.py -xvs # Key precedence test
|
|
235
|
+
pytest --cov=wry --cov-report=term-missing # Coverage
|
|
236
|
+
python -m wry.help_system ai # This file via help system
|
|
237
|
+
./check.sh # Pre-commit checks
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
## Key Files for Common Tasks
|
|
243
|
+
|
|
244
|
+
| Task | Files to modify |
|
|
245
|
+
|------|----------------|
|
|
246
|
+
| Add new field type support | `click_integration.py`, `env_utils.py`, tests |
|
|
247
|
+
| Add new source type | `sources.py`, `model.py` (from_click_context) |
|
|
248
|
+
| Change CLI generation | `click_integration.py`, `auto_model.py` |
|
|
249
|
+
| Fix source tracking | `model.py` (lines ~586-624) |
|
|
250
|
+
| Add new accessor | `accessors.py`, `model.py` (add @property) |
|
|
251
|
+
| Add new constraint | `field_utils.py`, `click_integration.py` (format_constraint_text) |
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
## Configuration Precedence (how it works internally)
|
|
256
|
+
|
|
257
|
+
`from_click_context()` builds config in 4 layers:
|
|
258
|
+
|
|
259
|
+
1. **DEFAULT** — Pydantic field defaults
|
|
260
|
+
2. **ENV** — `get_env_values()` reads `os.environ` with `env_prefix`
|
|
261
|
+
3. **JSON** — `ctx.obj['json_data']` from eager `--config` callback
|
|
262
|
+
4. **CLI** — `ctx.get_parameter_source()` checks for `COMMANDLINE`
|
|
263
|
+
|
|
264
|
+
Each layer overrides the previous. The result is a dict of `TrackedValue(value, source)` objects passed to `create_with_sources()`.
|
|
265
|
+
|
|
266
|
+
**Critical detail**: Click's `get_parameter_source()` returns an enum. wry uses `.name` (not `str()`) to check for `"COMMANDLINE"` — this is what Click 8.4+ compatibility depends on.
|
|
@@ -43,7 +43,7 @@ wry/
|
|
|
43
43
|
│
|
|
44
44
|
├── scripts/ # Development tools
|
|
45
45
|
├── docs/ # Documentation
|
|
46
|
-
├──
|
|
46
|
+
├── AGENTS.md # Complete reference for AI/LLMs
|
|
47
47
|
├── README.md # User documentation
|
|
48
48
|
└── CHANGELOG.md # Version history
|
|
49
49
|
```
|
|
@@ -448,7 +448,7 @@ def test_feature_with_clear_name():
|
|
|
448
448
|
- `Removed` - Removed features
|
|
449
449
|
- `Security` - Security fixes
|
|
450
450
|
- [ ] **README.md**: Update if user-facing features, usage, or API changed
|
|
451
|
-
- [ ] **
|
|
451
|
+
- [ ] **AGENTS.md**: Update if architecture, implementation details, or patterns changed
|
|
452
452
|
- [ ] **Module docstrings**: Update docstrings in modified modules
|
|
453
453
|
- [ ] **Examples**: Add or update examples if demonstrating new features
|
|
454
454
|
|
|
@@ -456,7 +456,7 @@ def test_feature_with_clear_name():
|
|
|
456
456
|
|
|
457
457
|
- **Do not create excessive markdown files** unless explicitly needed
|
|
458
458
|
- If markdown files exist, add content to the appropriate existing file
|
|
459
|
-
- If unsure which file is appropriate, consider whether the content belongs in README.md,
|
|
459
|
+
- If unsure which file is appropriate, consider whether the content belongs in README.md, AGENTS.md, or CHANGELOG.md
|
|
460
460
|
- Before creating a new markdown file, ask: Is this really necessary?
|
|
461
461
|
|
|
462
462
|
### 2. Code Quality
|
|
@@ -639,7 +639,7 @@ If pre-commit hooks are failing:
|
|
|
639
639
|
✅ Write comprehensive docstrings
|
|
640
640
|
✅ Add tests for edge cases
|
|
641
641
|
✅ Use `from_click_context()` for source tracking
|
|
642
|
-
✅ Update both README.md and
|
|
642
|
+
✅ Update both README.md and AGENTS.md
|
|
643
643
|
|
|
644
644
|
### DON'T
|
|
645
645
|
|
|
@@ -665,7 +665,7 @@ For information about creating releases, see **`RELEASE_PROCESS.md`**.
|
|
|
665
665
|
## Questions?
|
|
666
666
|
|
|
667
667
|
- Check `examples/` for usage patterns
|
|
668
|
-
- Check `
|
|
668
|
+
- Check `AGENTS.md` for complete technical reference
|
|
669
669
|
- Check `README.md` for user documentation
|
|
670
670
|
- Check `RELEASE_PROCESS.md` for release workflow
|
|
671
671
|
- Check `TODO.md` for current tasks and planned features
|
|
@@ -146,7 +146,7 @@ When removing deprecated features in v1.0.0:
|
|
|
146
146
|
- [ ] Remove deprecation sections from `CHANGELOG.md`
|
|
147
147
|
- [ ] Remove migration guide from `CHANGELOG.md`
|
|
148
148
|
- [ ] Remove deprecated patterns from examples
|
|
149
|
-
- [ ] Update `
|
|
149
|
+
- [ ] Update `AGENTS.md` to remove old API references
|
|
150
150
|
- [ ] Update `README.md` to remove old patterns
|
|
151
151
|
- [ ] Archive this `DEPRECATION.md` file
|
|
152
152
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: wry
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.2
|
|
4
4
|
Summary: Why Repeat Yourself? - Define your CLI once with Pydantic models
|
|
5
5
|
Author-email: Tyler House <26489166+tahouse@users.noreply.github.com>
|
|
6
6
|
License: MIT
|
|
@@ -1019,7 +1019,7 @@ We welcome contributions! Please see **`CONTRIBUTING.md`** for comprehensive gui
|
|
|
1019
1019
|
|
|
1020
1020
|
- 📖 **`CONTRIBUTING.md`** - Complete contributor guide (for humans)
|
|
1021
1021
|
- 🤖 **`.cursorrules`** - AI assistant quick reference
|
|
1022
|
-
- 📚 **`
|
|
1022
|
+
- 📚 **`AGENTS.md`** - AI/LLM assistant reference
|
|
1023
1023
|
- 🚀 **`RELEASE_PROCESS.md`** - Release workflow and versioning
|
|
1024
1024
|
|
|
1025
1025
|
### Development Setup
|
|
@@ -1208,7 +1208,7 @@ wry has comprehensive documentation for different audiences:
|
|
|
1208
1208
|
|
|
1209
1209
|
### Technical Reference
|
|
1210
1210
|
|
|
1211
|
-
- 📚 **`
|
|
1211
|
+
- 📚 **`AGENTS.md`** - AI/LLM assistant reference
|
|
1212
1212
|
- 📝 **`CHANGELOG.md`** - Version history and all changes
|
|
1213
1213
|
- 🧪 **`tests/README.md`** - Test organization and structure
|
|
1214
1214
|
- 🔧 **`scripts/README.md`** - Development scripts and tools
|
|
@@ -1233,7 +1233,7 @@ wry has comprehensive documentation for different audiences:
|
|
|
1233
1233
|
**I'm an AI assistant, I want to...**
|
|
1234
1234
|
|
|
1235
1235
|
- Quick reference → `.cursorrules`
|
|
1236
|
-
- Technical details → `
|
|
1236
|
+
- Technical details → `AGENTS.md`
|
|
1237
1237
|
- Code patterns → `CONTRIBUTING.md`
|
|
1238
1238
|
- Test examples → `tests/features/test_source_precedence.py`
|
|
1239
1239
|
|
|
@@ -975,7 +975,7 @@ We welcome contributions! Please see **`CONTRIBUTING.md`** for comprehensive gui
|
|
|
975
975
|
|
|
976
976
|
- 📖 **`CONTRIBUTING.md`** - Complete contributor guide (for humans)
|
|
977
977
|
- 🤖 **`.cursorrules`** - AI assistant quick reference
|
|
978
|
-
- 📚 **`
|
|
978
|
+
- 📚 **`AGENTS.md`** - AI/LLM assistant reference
|
|
979
979
|
- 🚀 **`RELEASE_PROCESS.md`** - Release workflow and versioning
|
|
980
980
|
|
|
981
981
|
### Development Setup
|
|
@@ -1164,7 +1164,7 @@ wry has comprehensive documentation for different audiences:
|
|
|
1164
1164
|
|
|
1165
1165
|
### Technical Reference
|
|
1166
1166
|
|
|
1167
|
-
- 📚 **`
|
|
1167
|
+
- 📚 **`AGENTS.md`** - AI/LLM assistant reference
|
|
1168
1168
|
- 📝 **`CHANGELOG.md`** - Version history and all changes
|
|
1169
1169
|
- 🧪 **`tests/README.md`** - Test organization and structure
|
|
1170
1170
|
- 🔧 **`scripts/README.md`** - Development scripts and tools
|
|
@@ -1189,7 +1189,7 @@ wry has comprehensive documentation for different audiences:
|
|
|
1189
1189
|
**I'm an AI assistant, I want to...**
|
|
1190
1190
|
|
|
1191
1191
|
- Quick reference → `.cursorrules`
|
|
1192
|
-
- Technical details → `
|
|
1192
|
+
- Technical details → `AGENTS.md`
|
|
1193
1193
|
- Code patterns → `CONTRIBUTING.md`
|
|
1194
1194
|
- Test examples → `tests/features/test_source_precedence.py`
|
|
1195
1195
|
|
|
@@ -47,7 +47,7 @@ Follow these steps IN ORDER:
|
|
|
47
47
|
|
|
48
48
|
3. **Update documentation**
|
|
49
49
|
- Update README.md if needed
|
|
50
|
-
- Update
|
|
50
|
+
- Update AGENTS.md version numbers
|
|
51
51
|
- Update any affected documentation
|
|
52
52
|
|
|
53
53
|
4. **Commit the release preparation**
|
|
@@ -75,7 +75,7 @@ Continue development by:
|
|
|
75
75
|
- Archive or remove completed items from the released version
|
|
76
76
|
- Add new tasks or features planned for next release
|
|
77
77
|
- Update roadmap and priorities
|
|
78
|
-
3. Update version numbers in
|
|
78
|
+
3. Update version numbers in AGENTS.md if not already done
|
|
79
79
|
|
|
80
80
|
## Example
|
|
81
81
|
|
wry-0.6.2/TODO.md
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# TODO List for wry
|
|
2
|
+
|
|
3
|
+
## Current Sprint
|
|
4
|
+
|
|
5
|
+
### In Progress
|
|
6
|
+
|
|
7
|
+
- [ ] Achieve higher code coverage
|
|
8
|
+
- Current coverage: ~90%
|
|
9
|
+
- Target: 95%+ for core modules
|
|
10
|
+
|
|
11
|
+
### Completed (Recent)
|
|
12
|
+
|
|
13
|
+
- [x] Click 8.4+ compatibility fix (v0.6.1)
|
|
14
|
+
- [x] Boolean on/off flags (`--option/--no-option`) (v0.6.0)
|
|
15
|
+
- [x] Callable marker API: `AutoOption()`, `AutoArgument()`, `AutoExclude()` (v0.6.0)
|
|
16
|
+
- [x] wry-prefixed ClassVars for configuration (v0.6.0)
|
|
17
|
+
- [x] Comma-separated list support (v0.5.0)
|
|
18
|
+
- [x] Model inheritance support (v0.4.1)
|
|
19
|
+
- [x] Pydantic alias-based CLI option generation (v0.4.0)
|
|
20
|
+
- [x] Comprehensive test suite (538 tests, all passing)
|
|
21
|
+
- [x] Consolidated AI docs into AGENTS.md
|
|
22
|
+
|
|
23
|
+
## Future Enhancements
|
|
24
|
+
|
|
25
|
+
### High Priority
|
|
26
|
+
|
|
27
|
+
- [ ] **Short option aliases for CLI options**
|
|
28
|
+
- Allow specifying short form: `--node/-n`, `--cluster/-c`
|
|
29
|
+
- Possible API: `AutoOption(short='n')` or auto-generate from first letter
|
|
30
|
+
- Need conflict detection
|
|
31
|
+
|
|
32
|
+
- [ ] **Document/improve environment variable support for arguments**
|
|
33
|
+
- Arguments CAN use env vars via `from_click_context()` but it's not obvious
|
|
34
|
+
- Add env var info to argument docstring injection
|
|
35
|
+
- Document prominently in README
|
|
36
|
+
|
|
37
|
+
- [ ] Add support for YAML configuration files
|
|
38
|
+
- [ ] Add support for TOML configuration files
|
|
39
|
+
- [ ] Add async support for Click commands
|
|
40
|
+
- [ ] Create documentation site (Sphinx/MkDocs)
|
|
41
|
+
|
|
42
|
+
### Medium Priority
|
|
43
|
+
|
|
44
|
+
- [ ] Add support for configuration file validation/schema generation
|
|
45
|
+
- [ ] Create migration guide from plain Click to wry
|
|
46
|
+
- [ ] Add benchmarks comparing performance with plain Click
|
|
47
|
+
|
|
48
|
+
### Low Priority
|
|
49
|
+
|
|
50
|
+
- [ ] Add support for custom value source types
|
|
51
|
+
- [ ] Add support for remote configuration sources
|
|
52
|
+
- [ ] Create plugin system for extensions
|
|
53
|
+
|
|
54
|
+
## Technical Debt
|
|
55
|
+
|
|
56
|
+
- [ ] Use newer Python 3.10+ syntax where appropriate (Union types with `|`, etc.)
|
|
57
|
+
- [ ] Improve error messages for validation failures
|
|
58
|
+
- [ ] Optimize import times
|
|
59
|
+
|
|
60
|
+
## Documentation
|
|
61
|
+
|
|
62
|
+
- [ ] Create API documentation site
|
|
63
|
+
- [ ] Create comparison with similar libraries (Typer, Clidantic, etc.)
|
|
64
|
+
|
|
65
|
+
## Release Planning
|
|
66
|
+
|
|
67
|
+
- [ ] v0.7.0 - Short option aliases, YAML/TOML support
|
|
68
|
+
- [ ] v1.0.0 - API stability guarantee, remove deprecated v0.6.0 APIs
|
|
69
|
+
|
|
70
|
+
## Notes
|
|
71
|
+
|
|
72
|
+
- Keep backward compatibility in mind for all changes
|
|
73
|
+
- Follow semantic versioning strictly
|
|
74
|
+
- Ensure all new features have corresponding tests
|
|
75
|
+
- Update documentation for every public API change
|
|
@@ -45,11 +45,11 @@ class TestExcludeEnum:
|
|
|
45
45
|
# Test that excluded fields are not available as CLI options
|
|
46
46
|
result = runner.invoke(cli, ["--polymorphic-input", "changed"])
|
|
47
47
|
assert result.exit_code != 0
|
|
48
|
-
assert "no such option
|
|
48
|
+
assert "no such option" in result.output.lower()
|
|
49
49
|
|
|
50
50
|
result = runner.invoke(cli, ["--computed-result", "changed"])
|
|
51
51
|
assert result.exit_code != 0
|
|
52
|
-
assert "no such option
|
|
52
|
+
assert "no such option" in result.output.lower()
|
|
53
53
|
|
|
54
54
|
# Test that regular fields work
|
|
55
55
|
result = runner.invoke(cli, ["--name", "Alice", "--count", "5"])
|
|
@@ -81,7 +81,7 @@ class TestExcludeEnum:
|
|
|
81
81
|
# Test that excluded field is not available
|
|
82
82
|
result = runner.invoke(cli, ["--excluded-field", "changed"])
|
|
83
83
|
assert result.exit_code != 0
|
|
84
|
-
assert "no such option
|
|
84
|
+
assert "no such option" in result.output.lower()
|
|
85
85
|
|
|
86
86
|
# Test that regular fields work
|
|
87
87
|
result = runner.invoke(cli, ["--name", "Bob"])
|
|
@@ -107,7 +107,7 @@ class TestExcludeEnum:
|
|
|
107
107
|
# Test that conflicted field is excluded
|
|
108
108
|
result = runner.invoke(cli, ["--conflicted", "changed"])
|
|
109
109
|
assert result.exit_code != 0
|
|
110
|
-
assert "no such option
|
|
110
|
+
assert "no such option" in result.output.lower()
|
|
111
111
|
|
|
112
112
|
# Normal field should work
|
|
113
113
|
result = runner.invoke(cli, ["--normal", "changed"])
|
|
@@ -16,17 +16,17 @@ class TestHelpSystem:
|
|
|
16
16
|
assert len(content) > 100
|
|
17
17
|
|
|
18
18
|
def test_get_help_content_ai(self):
|
|
19
|
-
"""Test getting AI
|
|
19
|
+
"""Test getting AI assistant reference."""
|
|
20
20
|
content = get_help_content("ai")
|
|
21
|
-
assert "AI
|
|
22
|
-
assert "
|
|
23
|
-
assert len(content) >
|
|
21
|
+
assert "AI Assistant Reference" in content
|
|
22
|
+
assert "Architecture Overview" in content
|
|
23
|
+
assert len(content) > 500
|
|
24
24
|
|
|
25
25
|
def test_get_help_content_sources(self):
|
|
26
26
|
"""Test getting source tracking info."""
|
|
27
27
|
content = get_help_content("sources")
|
|
28
|
-
# Should extract from
|
|
29
|
-
assert "
|
|
28
|
+
# Should extract from AGENTS.md or README, or return not found
|
|
29
|
+
assert "Configuration Precedence" in content or "Source Tracking" in content or "not found" in content
|
|
30
30
|
|
|
31
31
|
def test_get_help_content_architecture(self):
|
|
32
32
|
"""Test getting architecture info."""
|
|
@@ -1,22 +1,16 @@
|
|
|
1
1
|
"""Test TYPE_CHECKING imports coverage."""
|
|
2
2
|
|
|
3
|
-
from unittest.mock import patch
|
|
4
|
-
|
|
5
3
|
|
|
6
4
|
class TestTypeCheckingImports:
|
|
7
5
|
"""Test TYPE_CHECKING conditional imports."""
|
|
8
6
|
|
|
9
|
-
def
|
|
10
|
-
"""Test _version module
|
|
11
|
-
# Import the module first to ensure it exists
|
|
7
|
+
def test_version_module_importable(self):
|
|
8
|
+
"""Test _version module can be imported and has version info."""
|
|
12
9
|
import wry._version
|
|
13
10
|
|
|
14
|
-
#
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
assert hasattr(wry._version, "__version__")
|
|
18
|
-
assert hasattr(wry._version, "VERSION_TUPLE")
|
|
19
|
-
assert hasattr(wry._version, "COMMIT_ID")
|
|
11
|
+
# The auto-generated module should always have version info
|
|
12
|
+
assert hasattr(wry._version, "__version__")
|
|
13
|
+
assert isinstance(wry._version.__version__, str)
|
|
20
14
|
|
|
21
15
|
def test_core_modules_type_checking(self):
|
|
22
16
|
"""Test TYPE_CHECKING blocks in core modules."""
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# file generated by vcs-versioning
|
|
2
|
+
# don't change, don't track in version control
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
__all__ = [
|
|
6
|
+
"__version__",
|
|
7
|
+
"__version_tuple__",
|
|
8
|
+
"version",
|
|
9
|
+
"version_tuple",
|
|
10
|
+
"__commit_id__",
|
|
11
|
+
"commit_id",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
version: str
|
|
15
|
+
__version__: str
|
|
16
|
+
__version_tuple__: tuple[int | str, ...]
|
|
17
|
+
version_tuple: tuple[int | str, ...]
|
|
18
|
+
commit_id: str | None
|
|
19
|
+
__commit_id__: str | None
|
|
20
|
+
|
|
21
|
+
__version__ = version = '0.6.2'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 6, 2)
|
|
23
|
+
|
|
24
|
+
__commit_id__ = commit_id = 'gb87b408a4'
|
|
@@ -601,9 +601,10 @@ class WryModel(BaseModel):
|
|
|
601
601
|
param_source = ctx.get_parameter_source(field_name)
|
|
602
602
|
|
|
603
603
|
if param_source is not None:
|
|
604
|
-
|
|
604
|
+
# Use .name for Click 8.4+ compatibility (integer-valued enum)
|
|
605
|
+
source_name = param_source.name if hasattr(param_source, "name") else str(param_source)
|
|
605
606
|
# Only override if it's actually from CLI
|
|
606
|
-
if "COMMANDLINE" in
|
|
607
|
+
if "COMMANDLINE" in source_name:
|
|
607
608
|
config_data[field_name] = TrackedValue(value, ValueSource.CLI)
|
|
608
609
|
continue
|
|
609
610
|
# Skip if it's DEFAULT or ENVIRONMENT - already handled above
|