wry 0.5.2__tar.gz → 0.5.3.dev1__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.
Files changed (144) hide show
  1. {wry-0.5.2 → wry-0.5.3.dev1}/AI_KNOWLEDGE_BASE.md +80 -18
  2. {wry-0.5.2 → wry-0.5.3.dev1}/CHANGELOG.md +117 -0
  3. {wry-0.5.2 → wry-0.5.3.dev1}/CONTRIBUTING.md +24 -12
  4. wry-0.5.3.dev1/DEPRECATION.md +189 -0
  5. {wry-0.5.2/wry.egg-info → wry-0.5.3.dev1}/PKG-INFO +122 -1
  6. {wry-0.5.2 → wry-0.5.3.dev1}/README.md +121 -0
  7. {wry-0.5.2 → wry-0.5.3.dev1}/examples/autowrymodel_comprehensive.py +33 -5
  8. {wry-0.5.2 → wry-0.5.3.dev1}/examples/multimodel_comprehensive.py +9 -9
  9. {wry-0.5.2 → wry-0.5.3.dev1}/examples/wrymodel_comprehensive.py +24 -12
  10. wry-0.5.3.dev1/tests/integration/test_boolean_flags_integration.py +172 -0
  11. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/auto_model/test_auto_model_annotation_inference.py +5 -5
  12. wry-0.5.3.dev1/tests/unit/auto_model/test_boolean_on_off_flags.py +327 -0
  13. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/auto_model/test_field_annotation_handling.py +4 -4
  14. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/auto_model/test_field_annotations.py +5 -5
  15. wry-0.5.3.dev1/tests/unit/auto_model/test_new_marker_api.py +266 -0
  16. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/auto_model/test_type_inference.py +5 -5
  17. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/click/test_bool_flag_handling.py +3 -3
  18. wry-0.5.3.dev1/tests/unit/core/test_classvar_migration.py +147 -0
  19. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/test_init.py +12 -4
  20. {wry-0.5.2 → wry-0.5.3.dev1}/wry/__init__.py +12 -5
  21. {wry-0.5.2 → wry-0.5.3.dev1}/wry/_version.py +3 -3
  22. {wry-0.5.2 → wry-0.5.3.dev1}/wry/auto_model.py +16 -11
  23. {wry-0.5.2 → wry-0.5.3.dev1}/wry/click_integration.py +198 -31
  24. {wry-0.5.2 → wry-0.5.3.dev1}/wry/comma_separated.py +33 -6
  25. {wry-0.5.2 → wry-0.5.3.dev1}/wry/core/env_utils.py +1 -1
  26. {wry-0.5.2 → wry-0.5.3.dev1}/wry/core/model.py +42 -1
  27. {wry-0.5.2 → wry-0.5.3.dev1/wry.egg-info}/PKG-INFO +122 -1
  28. {wry-0.5.2 → wry-0.5.3.dev1}/wry.egg-info/SOURCES.txt +5 -0
  29. {wry-0.5.2 → wry-0.5.3.dev1}/.cursorrules +0 -0
  30. {wry-0.5.2 → wry-0.5.3.dev1}/.github/workflows/ci-cd.yml +0 -0
  31. {wry-0.5.2 → wry-0.5.3.dev1}/.gitignore +0 -0
  32. {wry-0.5.2 → wry-0.5.3.dev1}/.markdownlint.json +0 -0
  33. {wry-0.5.2 → wry-0.5.3.dev1}/.pre-commit-config.yaml +0 -0
  34. {wry-0.5.2 → wry-0.5.3.dev1}/LICENSE +0 -0
  35. {wry-0.5.2 → wry-0.5.3.dev1}/RELEASE_PROCESS.md +0 -0
  36. {wry-0.5.2 → wry-0.5.3.dev1}/TODO.md +0 -0
  37. {wry-0.5.2 → wry-0.5.3.dev1}/check.sh +0 -0
  38. {wry-0.5.2 → wry-0.5.3.dev1}/examples/config.json +0 -0
  39. {wry-0.5.2 → wry-0.5.3.dev1}/examples/sample_config.json +0 -0
  40. {wry-0.5.2 → wry-0.5.3.dev1}/pyproject.toml +0 -0
  41. {wry-0.5.2 → wry-0.5.3.dev1}/scripts/README.md +0 -0
  42. {wry-0.5.2 → wry-0.5.3.dev1}/scripts/extract_release_notes.py +0 -0
  43. {wry-0.5.2 → wry-0.5.3.dev1}/scripts/test_all_versions.sh +0 -0
  44. {wry-0.5.2 → wry-0.5.3.dev1}/scripts/test_ci_locally.sh +0 -0
  45. {wry-0.5.2 → wry-0.5.3.dev1}/scripts/test_with_act.sh +0 -0
  46. {wry-0.5.2 → wry-0.5.3.dev1}/scripts/update-dependencies.sh +0 -0
  47. {wry-0.5.2 → wry-0.5.3.dev1}/setup.cfg +0 -0
  48. {wry-0.5.2 → wry-0.5.3.dev1}/tests/README.md +0 -0
  49. {wry-0.5.2 → wry-0.5.3.dev1}/tests/__init__.py +0 -0
  50. {wry-0.5.2 → wry-0.5.3.dev1}/tests/features/__init__.py +0 -0
  51. {wry-0.5.2 → wry-0.5.3.dev1}/tests/features/test_auto_model.py +0 -0
  52. {wry-0.5.2 → wry-0.5.3.dev1}/tests/features/test_inheritance.py +0 -0
  53. {wry-0.5.2 → wry-0.5.3.dev1}/tests/features/test_multi_model.py +0 -0
  54. {wry-0.5.2 → wry-0.5.3.dev1}/tests/features/test_source_precedence.py +0 -0
  55. {wry-0.5.2 → wry-0.5.3.dev1}/tests/integration/__init__.py +0 -0
  56. {wry-0.5.2 → wry-0.5.3.dev1}/tests/integration/test_click_edge_cases.py +0 -0
  57. {wry-0.5.2 → wry-0.5.3.dev1}/tests/integration/test_click_integration.py +0 -0
  58. {wry-0.5.2 → wry-0.5.3.dev1}/tests/integration/test_click_integration_extended.py +0 -0
  59. {wry-0.5.2 → wry-0.5.3.dev1}/tests/integration/test_context_handling.py +0 -0
  60. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/__init__.py +0 -0
  61. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/auto_model/__init__.py +0 -0
  62. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/auto_model/test_auto_model_edge_cases.py +0 -0
  63. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/auto_model/test_auto_model_field_processing.py +0 -0
  64. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/auto_model/test_auto_model_list_fields.py +0 -0
  65. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/auto_model/test_comma_separated_lists.py +0 -0
  66. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/auto_model/test_optional_list_comma_separated.py +0 -0
  67. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/click/README_TESTING_STRATEGY.md +0 -0
  68. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/click/__init__.py +0 -0
  69. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/click/test_argument_types.py +0 -0
  70. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/click/test_click_config_building.py +0 -0
  71. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/click/test_click_constraint_formatting.py +0 -0
  72. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/click/test_click_decorator_edge_cases.py +0 -0
  73. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/click/test_click_interval_constraints.py +0 -0
  74. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/click/test_click_lambda_parsing.py +0 -0
  75. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/click/test_click_length_constraints.py +0 -0
  76. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/click/test_click_parameter_generation.py +0 -0
  77. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/click/test_click_predicate_handling.py +0 -0
  78. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/click/test_closure_extraction_errors.py +0 -0
  79. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/click/test_closure_handling.py +0 -0
  80. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/click/test_constraint_behavior.py +0 -0
  81. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/click/test_constraint_edge_cases.py +0 -0
  82. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/click/test_env_vars_option.py +0 -0
  83. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/click/test_explicit_argument_help_injection.py +0 -0
  84. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/click/test_field_alias_with_click_options.py +0 -0
  85. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/click/test_format_constraint_text.py +0 -0
  86. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/click/test_json_config_loading.py +0 -0
  87. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/click/test_lambda_behavior.py +0 -0
  88. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/click/test_lambda_error_handling.py +0 -0
  89. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/click/test_predicate_source_errors.py +0 -0
  90. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/click/test_strict_mode_errors.py +0 -0
  91. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/click/test_type_handling.py +0 -0
  92. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/core/__init__.py +0 -0
  93. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/core/test_accessors.py +0 -0
  94. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/core/test_advanced_features.py +0 -0
  95. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/core/test_core.py +0 -0
  96. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/core/test_edge_cases.py +0 -0
  97. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/core/test_env_utils.py +0 -0
  98. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/core/test_field_constraint_extraction.py +0 -0
  99. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/core/test_field_utils.py +0 -0
  100. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/core/test_field_utils_edge_cases.py +0 -0
  101. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/core/test_sources.py +0 -0
  102. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/core/test_type_checking_blocks.py +0 -0
  103. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/model/__init__.py +0 -0
  104. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/model/test_accessor_caching.py +0 -0
  105. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/model/test_extract_edge_cases.py +0 -0
  106. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/model/test_extract_subset_edge_cases.py +0 -0
  107. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/model/test_model_click_context_handling.py +0 -0
  108. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/model/test_model_data_extraction.py +0 -0
  109. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/model/test_model_default_handling.py +0 -0
  110. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/model/test_model_edge_cases.py +0 -0
  111. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/model/test_model_environment_integration.py +0 -0
  112. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/model/test_model_extract_subset_edge_cases.py +0 -0
  113. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/model/test_model_extraction_methods.py +0 -0
  114. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/model/test_model_field_errors.py +0 -0
  115. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/model/test_model_object_extraction.py +0 -0
  116. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/model/test_non_dict_object_extraction.py +0 -0
  117. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/model/test_object_attribute_extraction.py +0 -0
  118. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/multi_model/__init__.py +0 -0
  119. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/multi_model/test_multi_model.py +0 -0
  120. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/multi_model/test_type_checking.py +0 -0
  121. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/test_argument_help_injection.py +0 -0
  122. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/test_auto_model_field_processing.py +0 -0
  123. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/test_comprehensive_imports.py +0 -0
  124. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/test_exclude_enum.py +0 -0
  125. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/test_generate_click_classmethod.py +0 -0
  126. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/test_help_system.py +0 -0
  127. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/test_init_edge_cases.py +0 -0
  128. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/test_init_version_edge_cases.py +0 -0
  129. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/test_model_extraction_methods.py +0 -0
  130. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/test_multiple_option_bug.py +0 -0
  131. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/test_type_checking_imports.py +0 -0
  132. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/test_variadic_argument_bug.py +0 -0
  133. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/test_version_fallback.py +0 -0
  134. {wry-0.5.2 → wry-0.5.3.dev1}/tests/unit/test_version_parsing.py +0 -0
  135. {wry-0.5.2 → wry-0.5.3.dev1}/wry/core/__init__.py +0 -0
  136. {wry-0.5.2 → wry-0.5.3.dev1}/wry/core/accessors.py +0 -0
  137. {wry-0.5.2 → wry-0.5.3.dev1}/wry/core/field_utils.py +0 -0
  138. {wry-0.5.2 → wry-0.5.3.dev1}/wry/core/sources.py +0 -0
  139. {wry-0.5.2 → wry-0.5.3.dev1}/wry/help_system.py +0 -0
  140. {wry-0.5.2 → wry-0.5.3.dev1}/wry/multi_model.py +0 -0
  141. {wry-0.5.2 → wry-0.5.3.dev1}/wry/py.typed +0 -0
  142. {wry-0.5.2 → wry-0.5.3.dev1}/wry.egg-info/dependency_links.txt +0 -0
  143. {wry-0.5.2 → wry-0.5.3.dev1}/wry.egg-info/requires.txt +0 -0
  144. {wry-0.5.2 → wry-0.5.3.dev1}/wry.egg-info/top_level.txt +0 -0
@@ -1,10 +1,11 @@
1
1
  # wry - Comprehensive AI/LLM Knowledge Base
2
2
 
3
- **Last Updated**: 2025-10-14
4
- **Version**: 0.5.0+
3
+ **Last Updated**: 2025-10-19
4
+ **Version**: 0.6.0+
5
5
  **Purpose**: Complete reference for AI assistants and LLMs to understand wry without reading the entire codebase
6
6
 
7
7
  **Related Documentation**:
8
+
8
9
  - 📖 **`CONTRIBUTING.md`** - Comprehensive contributor guide (referenced by `.cursorrules`)
9
10
  - 🤖 **`.cursorrules`** - AI assistant quick reference (references this file and CONTRIBUTING.md)
10
11
  - 📘 **`README.md`** - User-facing documentation
@@ -23,10 +24,13 @@
23
24
  4. Tracking exactly where each value came from
24
25
  5. Enforcing strict precedence: CLI > JSON > ENV > DEFAULT
25
26
  6. **NEW v0.3.2**: Automatic alias-based CLI option generation
27
+ 7. **NEW v0.6.0**: Boolean on/off flags (`--option/--no-option` pattern)
28
+ 8. **NEW v0.6.0**: Callable marker API with parameters (`AutoOption()`, `AutoArgument()`, `AutoExclude()`)
29
+ 9. **NEW v0.6.0**: wry-prefixed ClassVars for future-proof configuration
26
30
 
27
31
  **Key Innovation**: Single source of truth for configuration with comprehensive source tracking.
28
32
 
29
- **Stats**: 494 tests (all passing), 92%+ coverage, supports Python 3.10-3.12, Pydantic v2.11+ compatible
33
+ **Stats**: 535 tests (all passing), 88%+ coverage, supports Python 3.10-3.12, Pydantic v2.11+ compatible
30
34
 
31
35
  **For Contributors**: See `CONTRIBUTING.md` for development guidelines and `.cursorrules` for AI assistant rules
32
36
 
@@ -878,26 +882,42 @@ def eager_json_config(ctx, param, value):
878
882
 
879
883
  ## Edge Cases & Gotchas
880
884
 
881
- ### 1. env_prefix Must Be ClassVar ⚠️
885
+ ### 1. wry_ Prefixed ClassVars (v0.6.0+) ⚠️
886
+
887
+ **NEW v0.6.0**: Use `wry_` prefixed ClassVars for configuration.
882
888
 
883
889
  ```python
884
- # WRONG - Creates a field, shadows parent
890
+ # OLD (deprecated but still works):
885
891
  class Config(AutoWryModel):
886
- env_prefix: str = "MYAPP_" #
892
+ env_prefix: ClassVar[str] = "MYAPP_" # ⚠️ Deprecated
893
+ comma_separated_lists: ClassVar[bool] = True # ⚠️ Deprecated
887
894
 
888
- # CORRECT - Class attribute, not a field
895
+ # NEW (recommended):
889
896
  class Config(AutoWryModel):
890
- env_prefix: ClassVar[str] = "MYAPP_" # ✅
897
+ wry_env_prefix: ClassVar[str] = "MYAPP_" # ✅ New naming
898
+ wry_comma_separated_lists: ClassVar[bool] = True # ✅ New naming
899
+ wry_boolean_off_prefix: ClassVar[str] = "no" # ✅ New feature
900
+
901
+ # WRONG - Not using ClassVar:
902
+ class Config(AutoWryModel):
903
+ wry_env_prefix: str = "MYAPP_" # ❌ Still wrong!
891
904
  ```
892
905
 
893
- **Why this matters**:
906
+ **Why ClassVar matters**:
894
907
 
895
908
  - Without `ClassVar`, Pydantic treats it as a field
896
909
  - Field appears in `model_fields`, gets CLI option generated
897
- - Shadows `WryModel.env_prefix` class attribute
898
- - Env var detection breaks
910
+ - Shadows `WryModel` class attributes
911
+ - Configuration breaks
912
+
913
+ **Why wry_ prefix?**
899
914
 
900
- **How to detect**: Warning message about shadowing parent attribute.
915
+ - Avoids namespace collisions with user fields
916
+ - Makes wry configuration explicit
917
+ - Future-proof for new configuration options
918
+ - Old names auto-migrate with deprecation warnings
919
+
920
+ **Migration**: Old names still work (auto-migrated) but emit `DeprecationWarning`.
901
921
 
902
922
  ### 2. Source Tracking Requires Context
903
923
 
@@ -1125,18 +1145,36 @@ timeout: Optional[int] = Field(default=None)
1125
1145
  # Generates: click.option("--timeout", type=click.INT, default=None)
1126
1146
  ```
1127
1147
 
1128
- ### 7. Boolean Fields Become Flags
1148
+ ### 7. Boolean Fields Use On/Off Pattern (NEW v0.6.0)
1149
+
1150
+ **Changed in v0.6.0**: Boolean fields now generate `--option/--no-option` pattern by default.
1129
1151
 
1130
1152
  ```python
1131
1153
  debug: bool = Field(default=False)
1132
1154
 
1133
- # Auto-generates:
1134
- click.option("--debug", is_flag=True)
1155
+ # Auto-generates (NEW):
1156
+ click.option("--debug/--no-debug", default=False)
1157
+
1158
+ # Usage:
1159
+ # --debug (sets to True)
1160
+ # --no-debug (sets to False)
1135
1161
 
1136
- # Usage: --debug (sets to True)
1137
- # NOT: --debug true (doesn't work with flags)
1162
+ # Customization:
1163
+ verbose: Annotated[bool, AutoOption(flag_off_option="quiet")] = Field(default=False)
1164
+ # → --verbose/--quiet
1165
+
1166
+ # Opt-out to single flag (old behavior):
1167
+ simple: Annotated[bool, AutoOption(flag_enable_on_off=False)] = Field(default=False)
1168
+ # → --simple (single flag)
1138
1169
  ```
1139
1170
 
1171
+ **Why the change?**
1172
+
1173
+ - More explicit: users can clearly specify both on and off states
1174
+ - Follows Click best practices
1175
+ - Better UX: `--no-debug` is clearer than absence of `--debug`
1176
+ - Backwards compatible via opt-out
1177
+
1140
1178
  ### 8. Arguments Are Always Optional (For --config)
1141
1179
 
1142
1180
  ```python
@@ -1705,8 +1743,32 @@ class TrackedValue
1705
1743
  class FieldWithSource
1706
1744
  """Value wrapper exposing .source attribute."""
1707
1745
 
1746
+ # NEW v0.6.0: Callable marker classes
1747
+ class WryOption
1748
+ """Marker for auto-generated Click options with customization.
1749
+
1750
+ Parameters:
1751
+ required: bool = False
1752
+ flag_enable_on_off: bool = True (for bool fields)
1753
+ flag_off_prefix: str | None = None (for bool fields)
1754
+ flag_off_option: str | None = None (for bool fields)
1755
+ """
1756
+
1757
+ class WryArgument
1758
+ """Marker for auto-generated Click arguments."""
1759
+
1760
+ class WryExclude
1761
+ """Marker to exclude field from CLI generation."""
1762
+
1763
+ # Public API aliases
1764
+ AutoOption = WryOption # Backwards-compatible name
1765
+ AutoArgument = WryArgument # Backwards-compatible name
1766
+ AutoExclude = WryExclude # Backwards-compatible name
1767
+
1768
+ # DEPRECATED v0.6.0: Old enum-based API
1708
1769
  class AutoClickParameter(Enum)
1709
- """OPTION, REQUIRED_OPTION, ARGUMENT, EXCLUDE"""
1770
+ """Deprecated: Use AutoOption(), AutoArgument(), AutoExclude() instead.
1771
+ OPTION, REQUIRED_OPTION, ARGUMENT, EXCLUDE"""
1710
1772
 
1711
1773
  # Accessors (returned by @property)
1712
1774
  class SourceAccessor
@@ -7,6 +7,123 @@ 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
+ - **Boolean on/off flags** - Boolean fields now generate `--option/--no-option` pattern by default 🎚️
13
+ - Makes CLI interfaces more explicit - users can explicitly set false: `--no-debug`
14
+ - Default behavior: `debug: bool = Field(default=False)` → `--debug/--no-debug`
15
+ - Custom off-option: `AutoOption(flag_off_option="quiet")` → `--verbose/--quiet`
16
+ - Custom prefix: `AutoOption(flag_off_prefix="skip")` → `--check/--skip-check`
17
+ - Single flag opt-out: `AutoOption(flag_enable_on_off=False)` → `--debug` (old behavior)
18
+ - Model-wide customization: `wry_boolean_off_prefix: ClassVar[str] = "disable"`
19
+ - Collision detection: warns and falls back to single flag if off-option conflicts with existing field
20
+ - Works with aliases: `debug: bool = Field(alias="verbose")` → `--verbose/--no-verbose`
21
+ - Full source tracking support (CLI/ENV/JSON/DEFAULT)
22
+ - Follows Click best practices: <https://click.palletsprojects.com/en/stable/options/#boolean>
23
+ - **39 new tests** covering all scenarios
24
+
25
+ - **Callable marker API** - Refactored Auto* markers from Enum to callable classes 🔧
26
+ - `AutoOption()` replaces `AutoClickParameter.OPTION`
27
+ - `AutoOption(required=True)` replaces `AutoClickParameter.REQUIRED_OPTION`
28
+ - `AutoArgument()` replaces `AutoClickParameter.ARGUMENT`
29
+ - `AutoExclude()` replaces `AutoClickParameter.EXCLUDE`
30
+ - All markers now support parameters for future extensibility
31
+ - Boolean-specific parameters: `flag_enable_on_off`, `flag_off_prefix`, `flag_off_option`
32
+ - List-specific parameter: `comma_separated` - replaces standalone `CommaSeparated` marker
33
+ - Example: `AutoOption(comma_separated=True)` replaces `Annotated[list[str], CommaSeparated]`
34
+ - Internal: Uses Wry-specific naming (WryOption, WryArgument, WryExclude classes)
35
+ - Public API: AutoOption, AutoArgument, AutoExclude are aliases to Wry* classes
36
+ - Follows PEP 593 Annotated pattern: <https://peps.python.org/pep-0593/>
37
+
38
+ - **wry_ prefixed ClassVars** - New naming convention for class-level configuration 🏷️
39
+ - `wry_env_prefix: ClassVar[str]` replaces `env_prefix`
40
+ - `wry_comma_separated_lists: ClassVar[bool]` replaces `comma_separated_lists`
41
+ - `wry_boolean_off_prefix: ClassVar[str]` - new feature for boolean flags
42
+ - Avoids namespace collisions with user fields
43
+ - Future-proof for additional configuration options
44
+ - **10 new tests** for migration and new features
45
+
46
+ ### Deprecated
47
+
48
+ - `AutoClickParameter` enum - Use `AutoOption()`, `AutoArgument()`, `AutoExclude()` instead
49
+ - Old enum values still work but emit `DeprecationWarning`
50
+ - Will be removed in next major version (v1.0.0)
51
+
52
+ - `CommaSeparated` standalone marker - Use `AutoOption(comma_separated=True)` instead
53
+ - Old standalone marker still works but emits `DeprecationWarning`
54
+ - Will be removed in next major version (v1.0.0)
55
+
56
+ - `env_prefix` ClassVar - Use `wry_env_prefix` instead
57
+ - Auto-migrates with `DeprecationWarning`
58
+ - Will be removed in next major version (v1.0.0)
59
+
60
+ - `comma_separated_lists` ClassVar - Use `wry_comma_separated_lists` instead
61
+ - Auto-migrates with `DeprecationWarning`
62
+ - Will be removed in next major version (v1.0.0)
63
+
64
+ ### Migration Guide
65
+
66
+ **From Enum to Callable API:**
67
+
68
+ ```python
69
+ # Old (deprecated):
70
+ field: Annotated[str, AutoClickParameter.OPTION] = Field(default="value")
71
+ required: Annotated[str, AutoClickParameter.REQUIRED_OPTION] = Field(...)
72
+
73
+ # New (recommended):
74
+ field: Annotated[str, AutoOption()] = Field(default="value")
75
+ required: Annotated[str, AutoOption(required=True)] = Field(...)
76
+ ```
77
+
78
+ **ClassVar Migration:**
79
+
80
+ ```python
81
+ # Old (deprecated):
82
+ class Config(AutoWryModel):
83
+ env_prefix: ClassVar[str] = "MYAPP_"
84
+ comma_separated_lists: ClassVar[bool] = True
85
+
86
+ # New (recommended):
87
+ class Config(AutoWryModel):
88
+ wry_env_prefix: ClassVar[str] = "MYAPP_"
89
+ wry_comma_separated_lists: ClassVar[bool] = True
90
+ wry_boolean_off_prefix: ClassVar[str] = "no" # Optional, "no" is default
91
+ ```
92
+
93
+ **Comma-Separated Lists:**
94
+
95
+ ```python
96
+ # Old (deprecated):
97
+ tags: Annotated[list[str], CommaSeparated] = Field(default_factory=list)
98
+
99
+ # New (recommended):
100
+ tags: Annotated[list[str], AutoOption(comma_separated=True)] = Field(default_factory=list)
101
+ ```
102
+
103
+ **Boolean On/Off Examples:**
104
+
105
+ ```python
106
+ # Default on/off pattern
107
+ debug: bool = Field(default=False) # --debug/--no-debug
108
+
109
+ # Custom off-option
110
+ verbose: Annotated[bool, AutoOption(flag_off_option="quiet")] = Field(default=False)
111
+ # → --verbose/--quiet
112
+
113
+ # Opt-out to single flag
114
+ simple: Annotated[bool, AutoOption(flag_enable_on_off=False)] = Field(default=False)
115
+ # → --simple (old behavior)
116
+ ```
117
+
118
+ ### Internal Changes
119
+
120
+ - Updated all internal code to use `wry_*` prefixed ClassVars
121
+ - Metadata processing loop refactored to support multiple marker types
122
+ - Boolean flag generation supports on/off pattern with customization
123
+ - Comprehensive backwards compatibility layer with migration warnings
124
+ - **Total test count: 535 tests (all passing)** ✨
125
+ - Coverage: 88.5%+ (slight drop due to new features, will improve with more usage)
126
+
10
127
  ## [0.5.2] - 2025-10-14
11
128
 
12
129
  ### Fixed
@@ -228,11 +228,13 @@ def test_your_feature_with_click():
228
228
  - If an ignore directive is truly necessary, add a detailed comment explaining why
229
229
 
230
230
  **Example - Bad**:
231
+
231
232
  ```python
232
233
  result = some_function() # type: ignore # ❌ Don't do this
233
234
  ```
234
235
 
235
236
  **Example - Good**:
237
+
236
238
  ```python
237
239
  # Fix the type annotation properly
238
240
  def some_function() -> dict[str, Any]: # ✅ Proper return type
@@ -289,9 +291,10 @@ from wry import AutoWryModel, AutoOption
289
291
  class MyConfig(AutoWryModel):
290
292
  """Configuration for my CLI tool."""
291
293
 
292
- # Class-level configuration (NOT a field)
293
- env_prefix: ClassVar[str] = "MYAPP_"
294
- comma_separated_lists: ClassVar[bool] = False # Optional
294
+ # Class-level configuration (NOT a field) - use wry_ prefix (v0.6.0+)
295
+ wry_env_prefix: ClassVar[str] = "MYAPP_"
296
+ wry_comma_separated_lists: ClassVar[bool] = False # Optional
297
+ wry_boolean_off_prefix: ClassVar[str] = "no" # Optional, customize boolean off-options
295
298
 
296
299
  # Fields become CLI options automatically
297
300
  host: str = Field(
@@ -324,7 +327,8 @@ def main(ctx: click.Context, **kwargs: Any) -> None:
324
327
  **Key Points**:
325
328
 
326
329
  - Extend `AutoWryModel` for automatic option generation
327
- - Use `ClassVar` for class-level config (`env_prefix`, `comma_separated_lists`)
330
+ - Use `ClassVar` for class-level config (`wry_env_prefix`, `wry_comma_separated_lists`, `wry_boolean_off_prefix`)
331
+ - Use new callable API: `AutoOption()`, `AutoArgument()`, `AutoExclude()`
328
332
  - Use `generate_click_parameters()` decorator
329
333
  - Load config with `from_click_context(ctx, **kwargs)` for source tracking
330
334
  - Access sources with `config.source.field_name`
@@ -343,7 +347,7 @@ class Config(AutoWryModel):
343
347
 
344
348
  # Or model-wide comma-separated:
345
349
  class CommaSepConfig(AutoWryModel):
346
- comma_separated_lists: ClassVar[bool] = True # All lists use comma-separated
350
+ wry_comma_separated_lists: ClassVar[bool] = True # All lists use comma-separated
347
351
 
348
352
  tags: list[str] = Field(default_factory=list) # Now: --tags python,rust,go
349
353
  ```
@@ -449,6 +453,7 @@ def test_feature_with_clear_name():
449
453
  - [ ] **Examples**: Add or update examples if demonstrating new features
450
454
 
451
455
  **Documentation Management**:
456
+
452
457
  - **Do not create excessive markdown files** unless explicitly needed
453
458
  - If markdown files exist, add content to the appropriate existing file
454
459
  - If unsure which file is appropriate, consider whether the content belongs in README.md, AI_KNOWLEDGE_BASE.md, or CHANGELOG.md
@@ -460,7 +465,7 @@ def test_feature_with_clear_name():
460
465
  - [ ] **Docstrings**: All public functions/classes/modules have comprehensive docstrings (Google style)
461
466
  - [ ] **No dead code**: Remove unused imports, variables, commented code
462
467
  - [ ] **DRY principle**: No duplicate code - extract common logic
463
- - [ ] **ClassVar for class config**: Use `ClassVar` for `env_prefix`, `comma_separated_lists`
468
+ - [ ] **ClassVar for class config**: Use `ClassVar` for `wry_env_prefix`, `wry_comma_separated_lists`, `wry_boolean_off_prefix`
464
469
 
465
470
  ### 3. Tests
466
471
 
@@ -497,7 +502,7 @@ mypy wry/
497
502
 
498
503
  - [ ] **Source tracking works**: If touching config/model code, verify source tracking
499
504
  - [ ] **Precedence correct**: CLI > JSON > ENV > DEFAULT (verify if changing)
500
- - [ ] **ClassVar not in fields**: Ensure `env_prefix`, `comma_separated_lists` use `ClassVar`
505
+ - [ ] **ClassVar not in fields**: Ensure `wry_env_prefix`, `wry_comma_separated_lists`, `wry_boolean_off_prefix` use `ClassVar`
501
506
  - [ ] **Examples still work**: Run examples if you changed core functionality
502
507
  - [ ] **Help text clear**: Generated --help output is helpful
503
508
 
@@ -529,7 +534,7 @@ Use [Conventional Commits](https://www.conventionalcommits.org/) format:
529
534
  feat: add comma-separated list support
530
535
 
531
536
  - Add CommaSeparated marker for per-field annotation
532
- - Add comma_separated_lists ClassVar for model-wide setting
537
+ - Add wry_comma_separated_lists ClassVar for model-wide setting
533
538
  - Per-field annotation takes priority over model-wide
534
539
  - Full Pydantic validation preserved
535
540
 
@@ -547,6 +552,7 @@ Closes #42
547
552
  - Always pass `--yes` or appropriate non-interactive flags to avoid user prompts
548
553
 
549
554
  **Example**:
555
+
550
556
  ```bash
551
557
  # Bad - Git sees this as delete + add
552
558
  rm old_file.py
@@ -576,16 +582,20 @@ git mv old_file.py new_file.py
576
582
  ## Pull Request Process
577
583
 
578
584
  1. **Branch**: Create feature branch from `main`
585
+
579
586
  ```bash
580
587
  git checkout -b feature/your-feature-name
581
588
  ```
589
+
582
590
  2. **Complete checklist**: Follow Pre-Commit Checklist above
583
591
  3. **Commit**: Make your commit with conventional commit message
584
592
  4. **Test**: Pre-commit hook will run checks automatically
585
593
  5. **Push**: Push to remote
594
+
586
595
  ```bash
587
596
  git push -u origin feature/your-feature-name
588
597
  ```
598
+
589
599
  6. **PR**: Submit with clear description referencing checklist items
590
600
 
591
601
  ## Critical Rules
@@ -614,9 +624,10 @@ If pre-commit hooks are failing:
614
624
  2. **DRY everywhere**: Configuration defined once, used everywhere
615
625
  3. **Examples are crucial**: Users learn from examples - keep them clear and comprehensive
616
626
  4. **Test all 4 sources**: When adding config features, test CLI/ENV/JSON/DEFAULT
617
- 5. **ClassVar correctness**: `env_prefix` and `comma_separated_lists` must be ClassVar
618
- 6. **Explicit decorators work**: Users can always use explicit `click.option()` - preserve this
619
- 7. **No surprises**: Behavior should match documentation exactly
627
+ 5. **ClassVar correctness**: `wry_env_prefix`, `wry_comma_separated_lists`, `wry_boolean_off_prefix` must be ClassVar
628
+ 6. **New callable API**: Use `AutoOption()`, `AutoArgument()`, `AutoExclude()` not old enum
629
+ 7. **Explicit decorators work**: Users can always use explicit `click.option()` - preserve this
630
+ 8. **No surprises**: Behavior should match documentation exactly
620
631
 
621
632
  ## Guidelines
622
633
 
@@ -633,7 +644,7 @@ If pre-commit hooks are failing:
633
644
  ### DON'T
634
645
 
635
646
  ❌ Break source precedence (CLI > JSON > ENV > DEFAULT)
636
- ❌ Make `env_prefix` or `comma_separated_lists` regular fields
647
+ ❌ Make `wry_env_prefix`, `wry_comma_separated_lists`, or `wry_boolean_off_prefix` regular fields
637
648
  ❌ Skip testing source tracking
638
649
  ❌ Bypass pre-commit hooks
639
650
  ❌ Create duplicate functionality
@@ -645,6 +656,7 @@ If pre-commit hooks are failing:
645
656
  For information about creating releases, see **`RELEASE_PROCESS.md`**.
646
657
 
647
658
  **Key points**:
659
+
648
660
  - During development: Add all changes to `[Unreleased]` in CHANGELOG.md
649
661
  - When releasing: Convert `[Unreleased]` to `[X.Y.Z] - YYYY-MM-DD`
650
662
  - Tag the release commit: `git tag -s vX.Y.Z`
@@ -0,0 +1,189 @@
1
+ # Deprecation Tracking
2
+
3
+ This document tracks all deprecated features for easy removal in future versions.
4
+
5
+ ## Deprecated in v0.6.0 → Remove in v1.0.0
6
+
7
+ ### 1. AutoClickParameter Enum
8
+
9
+ **Location**: `wry/click_integration.py:97-115`
10
+ **Deprecated**: v0.6.0
11
+ **Remove**: v1.0.0
12
+ **Replacement**: `AutoOption()`, `AutoArgument()`, `AutoExclude()`
13
+
14
+ **Code markers**:
15
+
16
+ - Class definition: `wry/click_integration.py:97` (marked with `# DEPRECATED v0.6.0`)
17
+ - Detection logic: `wry/click_integration.py:492-517` (marked with `# DEPRECATED v0.6.0` and `# TODO: Remove in v1.0.0`)
18
+
19
+ **Migration**:
20
+
21
+ ```python
22
+ # Old:
23
+ field: Annotated[str, AutoClickParameter.OPTION]
24
+
25
+ # New:
26
+ field: Annotated[str, AutoOption()]
27
+ ```
28
+
29
+ ### 2. Standalone CommaSeparated Marker
30
+
31
+ **Location**: `wry/comma_separated.py:171-203`
32
+ **Deprecated**: v0.6.0
33
+ **Remove**: v1.0.0
34
+ **Replacement**: `AutoOption(comma_separated=True)`
35
+
36
+ **Code markers**:
37
+
38
+ - Class definition: `wry/comma_separated.py:171` (marked with `# DEPRECATED v0.6.0`)
39
+ - Detection logic: `wry/click_integration.py:463-480` (marked with `# DEPRECATED v0.6.0` and `# TODO: Remove in v1.0.0`)
40
+
41
+ **Migration**:
42
+
43
+ ```python
44
+ # Old:
45
+ tags: Annotated[list[str], CommaSeparated]
46
+
47
+ # New:
48
+ tags: Annotated[list[str], AutoOption(comma_separated=True)]
49
+ ```
50
+
51
+ ### 3. Unprefixed env_prefix ClassVar
52
+
53
+ **Location**: `wry/core/model.py:67`
54
+ **Deprecated**: v0.6.0
55
+ **Remove**: v1.0.0
56
+ **Replacement**: `wry_env_prefix`
57
+
58
+ **Code markers**:
59
+
60
+ - ClassVar definition: `wry/core/model.py:67` (marked with `# DEPRECATED v0.6.0`)
61
+ - Migration logic: `wry/core/model.py:77-88` (marked with `# DEPRECATED v0.6.0` and `# TODO: Remove in v1.0.0`)
62
+
63
+ **Migration**:
64
+
65
+ ```python
66
+ # Old:
67
+ class Config(AutoWryModel):
68
+ env_prefix: ClassVar[str] = "MYAPP_"
69
+
70
+ # New:
71
+ class Config(AutoWryModel):
72
+ wry_env_prefix: ClassVar[str] = "MYAPP_"
73
+ ```
74
+
75
+ ### 4. Unprefixed comma_separated_lists ClassVar
76
+
77
+ **Location**: `wry/core/model.py:68`
78
+ **Deprecated**: v0.6.0
79
+ **Remove**: v1.0.0
80
+ **Replacement**: `wry_comma_separated_lists`
81
+
82
+ **Code markers**:
83
+
84
+ - ClassVar definition: `wry/core/model.py:68` (marked with `# DEPRECATED v0.6.0`)
85
+ - Migration logic: `wry/core/model.py:90-101` (marked with `# DEPRECATED v0.6.0` and `# TODO: Remove in v1.0.0`)
86
+
87
+ **Migration**:
88
+
89
+ ```python
90
+ # Old:
91
+ class Config(AutoWryModel):
92
+ comma_separated_lists: ClassVar[bool] = True
93
+
94
+ # New:
95
+ class Config(AutoWryModel):
96
+ wry_comma_separated_lists: ClassVar[bool] = True
97
+ ```
98
+
99
+ ### 5. Using Wry Marker Classes Without Calling Them
100
+
101
+ **Location**: `wry/click_integration.py:481-491`
102
+ **Deprecated**: v0.6.0
103
+ **Remove**: v1.0.0
104
+ **Replacement**: Call the class (add parentheses)
105
+
106
+ **Code markers**:
107
+
108
+ - Detection logic: `wry/click_integration.py:481-491` (marked with `# DEPRECATED v0.6.0` and `# TODO: Remove in v1.0.0`)
109
+
110
+ **Migration**:
111
+
112
+ ```python
113
+ # Old (works but not recommended):
114
+ field: Annotated[str, AutoOption]
115
+
116
+ # New:
117
+ field: Annotated[str, AutoOption()]
118
+ ```
119
+
120
+ ## Removal Checklist for v1.0.0
121
+
122
+ When removing deprecated features in v1.0.0:
123
+
124
+ ### Code Removal
125
+
126
+ - [ ] Remove `AutoClickParameter` enum class (`wry/click_integration.py:97-115`)
127
+ - [ ] Remove AutoClickParameter detection block (`wry/click_integration.py:492-517`)
128
+ - [ ] Remove `CommaSeparated` marker class (`wry/comma_separated.py:171-203`)
129
+ - [ ] Remove CommaSeparated detection block (`wry/click_integration.py:463-480`)
130
+ - [ ] Remove `env_prefix` ClassVar (`wry/core/model.py:67`)
131
+ - [ ] Remove env_prefix migration block (`wry/core/model.py:77-88`)
132
+ - [ ] Remove `comma_separated_lists` ClassVar (`wry/core/model.py:68`)
133
+ - [ ] Remove comma_separated_lists migration block (`wry/core/model.py:90-101`)
134
+ - [ ] Remove uncalled marker class detection (`wry/click_integration.py:481-491`)
135
+
136
+ ### Test Updates
137
+
138
+ - [ ] Remove or update tests using `AutoClickParameter` enum
139
+ - [ ] Remove or update tests using standalone `CommaSeparated`
140
+ - [ ] Remove or update tests using `env_prefix` without deprecation expectations
141
+ - [ ] Remove or update tests using `comma_separated_lists` without deprecation expectations
142
+ - [ ] Update `test_classvar_migration.py` - these tests won't be needed
143
+
144
+ ### Documentation Updates
145
+
146
+ - [ ] Remove deprecation sections from `CHANGELOG.md`
147
+ - [ ] Remove migration guide from `CHANGELOG.md`
148
+ - [ ] Remove deprecated patterns from examples
149
+ - [ ] Update `AI_KNOWLEDGE_BASE.md` to remove old API references
150
+ - [ ] Update `README.md` to remove old patterns
151
+ - [ ] Archive this `DEPRECATION.md` file
152
+
153
+ ## Search Commands for Finding Deprecated Code
154
+
155
+ Use these to find all deprecated code for removal:
156
+
157
+ ```bash
158
+ # Find all TODO: Remove in v1.0.0 markers
159
+ grep -r "TODO: Remove in v1.0.0" wry/
160
+
161
+ # Find all DEPRECATED v0.6.0 markers
162
+ grep -r "DEPRECATED v0.6.0" wry/
163
+
164
+ # Find AutoClickParameter usage
165
+ grep -r "AutoClickParameter" wry/ tests/
166
+
167
+ # Find CommaSeparated standalone usage
168
+ grep -r "CommaSeparated" wry/ tests/ | grep -v "comma_separated"
169
+
170
+ # Find old ClassVar names
171
+ grep -r "env_prefix:" wry/ tests/ | grep -v "wry_env_prefix"
172
+ grep -r "comma_separated_lists:" wry/ tests/ | grep -v "wry_comma_separated_lists"
173
+ ```
174
+
175
+ ## Testing Deprecated Features
176
+
177
+ Before removal, ensure all deprecated features have:
178
+
179
+ 1. ✅ Deprecation warnings in place
180
+ 2. ✅ Backwards compatibility tests
181
+ 3. ✅ Migration documented in CHANGELOG
182
+ 4. ✅ Clear TODO markers in code
183
+
184
+ After removal in v1.0.0:
185
+
186
+ 1. Run full test suite
187
+ 2. Update all examples
188
+ 3. Create migration guide
189
+ 4. Update version compatibility matrix