strictcli 0.18.0__tar.gz → 0.19.0__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 (161) hide show
  1. strictcli-0.19.0/.rlsbl/changes/.validated +1 -0
  2. strictcli-0.19.0/.rlsbl/changes/0.19.0.jsonl +2 -0
  3. strictcli-0.19.0/.rlsbl/changes/0.19.0.md +5 -0
  4. strictcli-0.19.0/.rlsbl/releases/v0.19.0.toml +0 -0
  5. strictcli-0.19.0/.rlsbl/version +1 -0
  6. {strictcli-0.18.0 → strictcli-0.19.0}/CHANGELOG.md +9 -3
  7. {strictcli-0.18.0 → strictcli-0.19.0}/PKG-INFO +7 -7
  8. {strictcli-0.18.0 → strictcli-0.19.0}/README.md +6 -6
  9. {strictcli-0.18.0 → strictcli-0.19.0}/package-lock.json +2 -2
  10. {strictcli-0.18.0 → strictcli-0.19.0}/package.json +1 -1
  11. {strictcli-0.18.0 → strictcli-0.19.0}/pyproject.toml +1 -1
  12. {strictcli-0.18.0 → strictcli-0.19.0}/strictcli/__init__.py +24 -24
  13. {strictcli-0.18.0 → strictcli-0.19.0}/tests/test_e2e.py +8 -8
  14. strictcli-0.18.0/tests/test_tags.py → strictcli-0.19.0/tests/test_flag_sets.py +22 -22
  15. {strictcli-0.18.0 → strictcli-0.19.0}/tests/test_passthrough.py +5 -5
  16. {strictcli-0.18.0 → strictcli-0.19.0}/tests/test_registration.py +4 -4
  17. {strictcli-0.18.0 → strictcli-0.19.0}/uv.lock +1 -1
  18. strictcli-0.18.0/.rlsbl/bases/.rlsbl/lint/go.toml +0 -17
  19. strictcli-0.18.0/.rlsbl/changes/.validated +0 -1
  20. strictcli-0.18.0/.rlsbl/lint/go.toml +0 -17
  21. strictcli-0.18.0/.rlsbl/version +0 -1
  22. {strictcli-0.18.0 → strictcli-0.19.0}/.claude/settings.json +0 -0
  23. {strictcli-0.18.0 → strictcli-0.19.0}/.github/workflows/ci.yml +0 -0
  24. {strictcli-0.18.0 → strictcli-0.19.0}/.github/workflows/publish.yml +0 -0
  25. {strictcli-0.18.0 → strictcli-0.19.0}/.gitignore +0 -0
  26. {strictcli-0.18.0 → strictcli-0.19.0}/.npmignore +0 -0
  27. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/bases/.claude/settings.json +0 -0
  28. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/bases/.github/workflows/ci.yml +0 -0
  29. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/bases/.github/workflows/publish.yml +0 -0
  30. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/bases/.gitignore +0 -0
  31. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/bases/.npmignore +0 -0
  32. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/bases/.rlsbl/hooks/post-release.sh +0 -0
  33. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/bases/.rlsbl/hooks/pre-checks.sh +0 -0
  34. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/bases/.rlsbl/hooks/pre-release.sh +0 -0
  35. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/bases/.rlsbl/lint/npm.toml +0 -0
  36. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/bases/.rlsbl/lint/python.toml +0 -0
  37. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/bases/CHANGELOG.md +0 -0
  38. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/bases/CLAUDE.md +0 -0
  39. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/bases/LICENSE +0 -0
  40. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.10.0.jsonl +0 -0
  41. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.10.0.md +0 -0
  42. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.11.0.jsonl +0 -0
  43. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.11.0.md +0 -0
  44. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.12.0.jsonl +0 -0
  45. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.12.0.md +0 -0
  46. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.13.0.jsonl +0 -0
  47. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.13.0.md +0 -0
  48. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.14.0.jsonl +0 -0
  49. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.14.0.md +0 -0
  50. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.15.0.jsonl +0 -0
  51. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.15.0.md +0 -0
  52. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.15.1.jsonl +0 -0
  53. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.15.1.md +0 -0
  54. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.16.0.jsonl +0 -0
  55. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.16.0.md +0 -0
  56. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.16.1.jsonl +0 -0
  57. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.16.1.md +0 -0
  58. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.17.0.jsonl +0 -0
  59. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.17.0.md +0 -0
  60. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.18.0.jsonl +0 -0
  61. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.18.0.md +0 -0
  62. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.4.0.jsonl +0 -0
  63. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.4.0.md +0 -0
  64. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.4.1.jsonl +0 -0
  65. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.4.1.md +0 -0
  66. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.5.0.jsonl +0 -0
  67. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.5.0.md +0 -0
  68. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.6.0.jsonl +0 -0
  69. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.6.0.md +0 -0
  70. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.6.1.jsonl +0 -0
  71. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.6.1.md +0 -0
  72. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.7.0.jsonl +0 -0
  73. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.7.0.md +0 -0
  74. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.7.1.jsonl +0 -0
  75. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.7.1.md +0 -0
  76. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.8.0.jsonl +0 -0
  77. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.8.0.md +0 -0
  78. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.8.1.jsonl +0 -0
  79. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.8.1.md +0 -0
  80. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.8.2.jsonl +0 -0
  81. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.8.2.md +0 -0
  82. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.8.3.jsonl +0 -0
  83. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.8.3.md +0 -0
  84. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.8.4.jsonl +0 -0
  85. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.8.4.md +0 -0
  86. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.8.5.jsonl +0 -0
  87. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.8.5.md +0 -0
  88. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.8.6.jsonl +0 -0
  89. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.8.6.md +0 -0
  90. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.8.7.jsonl +0 -0
  91. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.8.7.md +0 -0
  92. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.9.0.jsonl +0 -0
  93. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.9.0.md +0 -0
  94. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.9.1.jsonl +0 -0
  95. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/0.9.1.md +0 -0
  96. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/changes/unreleased.jsonl +0 -0
  97. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/config.json +0 -0
  98. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/hashes.json +0 -0
  99. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/hooks/post-release.sh +0 -0
  100. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/hooks/pre-checks.sh +0 -0
  101. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/hooks/pre-release.sh +0 -0
  102. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/lint/npm.toml +0 -0
  103. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/lint/python.toml +0 -0
  104. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/releases/unreleased.toml +0 -0
  105. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/releases/v0.10.0.toml +0 -0
  106. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/releases/v0.11.0.toml +0 -0
  107. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/releases/v0.12.0.toml +0 -0
  108. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/releases/v0.13.0.toml +0 -0
  109. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/releases/v0.15.0.toml +0 -0
  110. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/releases/v0.15.1.toml +0 -0
  111. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/releases/v0.16.0.toml +0 -0
  112. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/releases/v0.16.1.toml +0 -0
  113. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/releases/v0.17.0.toml +0 -0
  114. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/releases/v0.18.0.toml +0 -0
  115. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/releases/v0.8.5.toml +0 -0
  116. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/releases/v0.8.6.toml +0 -0
  117. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/releases/v0.8.7.toml +0 -0
  118. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/releases/v0.9.0.toml +0 -0
  119. {strictcli-0.18.0 → strictcli-0.19.0}/.rlsbl/releases/v0.9.1.toml +0 -0
  120. {strictcli-0.18.0 → strictcli-0.19.0}/.strictcli/schema.json +0 -0
  121. {strictcli-0.18.0 → strictcli-0.19.0}/CLAUDE.md +0 -0
  122. {strictcli-0.18.0 → strictcli-0.19.0}/LICENSE +0 -0
  123. {strictcli-0.18.0 → strictcli-0.19.0}/index.js +0 -0
  124. {strictcli-0.18.0 → strictcli-0.19.0}/postinstall.js +0 -0
  125. {strictcli-0.18.0 → strictcli-0.19.0}/tests/test_arg_default.py +0 -0
  126. {strictcli-0.18.0 → strictcli-0.19.0}/tests/test_at_prefix.py +0 -0
  127. {strictcli-0.18.0 → strictcli-0.19.0}/tests/test_auto_version.py +0 -0
  128. {strictcli-0.18.0 → strictcli-0.19.0}/tests/test_check_command.py +0 -0
  129. {strictcli-0.18.0 → strictcli-0.19.0}/tests/test_check_discovery.py +0 -0
  130. {strictcli-0.18.0 → strictcli-0.19.0}/tests/test_check_public_api.py +0 -0
  131. {strictcli-0.18.0 → strictcli-0.19.0}/tests/test_check_runner.py +0 -0
  132. {strictcli-0.18.0 → strictcli-0.19.0}/tests/test_check_schema.py +0 -0
  133. {strictcli-0.18.0 → strictcli-0.19.0}/tests/test_check_types.py +0 -0
  134. {strictcli-0.18.0 → strictcli-0.19.0}/tests/test_choices.py +0 -0
  135. {strictcli-0.18.0 → strictcli-0.19.0}/tests/test_command_help_suggestion.py +0 -0
  136. {strictcli-0.18.0 → strictcli-0.19.0}/tests/test_config.py +0 -0
  137. {strictcli-0.18.0 → strictcli-0.19.0}/tests/test_config_file_path.py +0 -0
  138. {strictcli-0.18.0 → strictcli-0.19.0}/tests/test_config_set_bugs.py +0 -0
  139. {strictcli-0.18.0 → strictcli-0.19.0}/tests/test_deep_nesting.py +0 -0
  140. {strictcli-0.18.0 → strictcli-0.19.0}/tests/test_dependencies.py +0 -0
  141. {strictcli-0.18.0 → strictcli-0.19.0}/tests/test_deprecated.py +0 -0
  142. {strictcli-0.18.0 → strictcli-0.19.0}/tests/test_dump_schema.py +0 -0
  143. {strictcli-0.18.0 → strictcli-0.19.0}/tests/test_env.py +0 -0
  144. {strictcli-0.18.0 → strictcli-0.19.0}/tests/test_exit_codes.py +0 -0
  145. {strictcli-0.18.0 → strictcli-0.19.0}/tests/test_float_type.py +0 -0
  146. {strictcli-0.18.0 → strictcli-0.19.0}/tests/test_global_flags.py +0 -0
  147. {strictcli-0.18.0 → strictcli-0.19.0}/tests/test_help.py +0 -0
  148. {strictcli-0.18.0 → strictcli-0.19.0}/tests/test_int_type.py +0 -0
  149. {strictcli-0.18.0 → strictcli-0.19.0}/tests/test_mutex.py +0 -0
  150. {strictcli-0.18.0 → strictcli-0.19.0}/tests/test_nesting.py +0 -0
  151. {strictcli-0.18.0 → strictcli-0.19.0}/tests/test_parser.py +0 -0
  152. {strictcli-0.18.0 → strictcli-0.19.0}/tests/test_repeatable.py +0 -0
  153. {strictcli-0.18.0 → strictcli-0.19.0}/tests/test_tagdsl.py +0 -0
  154. {strictcli-0.18.0 → strictcli-0.19.0}/tests/test_toml_loading.py +0 -0
  155. {strictcli-0.18.0 → strictcli-0.19.0}/tests/test_unique.py +0 -0
  156. {strictcli-0.18.0 → strictcli-0.19.0}/tests/test_utilities.py +0 -0
  157. {strictcli-0.18.0 → strictcli-0.19.0}/tests/test_validate.py +0 -0
  158. {strictcli-0.18.0 → strictcli-0.19.0}/tests/test_variadic.py +0 -0
  159. {strictcli-0.18.0 → strictcli-0.19.0}/todo/.defer/deferred.md +0 -0
  160. {strictcli-0.18.0 → strictcli-0.19.0}/todo/.done/original-idea.md +0 -0
  161. {strictcli-0.18.0 → strictcli-0.19.0}/todo/.done/public-check-runner-api.md +0 -0
@@ -0,0 +1 @@
1
+ 436f8a9ce1b048614cb66e929969dfbcb0791689
@@ -0,0 +1,2 @@
1
+ {"commits":["03d0cd60c4d207b568a19bf6916f58aacdac1450","5a1368de51cbe0abe465f21f3a38f78ba1746fef"],"user_facing":true,"description":"**Breaking.** Renamed `Tag` to `FlagSet` and `tags=` parameter to `flag_sets=` across all API surfaces.","type":"breaking"}
2
+ {"commits":["03782821de6b48073259aa3edb66b141ab70eb3b","232a6e47db207159abfdb81a5e1b93c1cfce82ea","fa29d925446a00a2bddec93cb949f91f13682704"],"user_facing":false}
@@ -0,0 +1,5 @@
1
+ ## 0.19.0
2
+
3
+ ### Breaking
4
+
5
+ - **Breaking.** Renamed `Tag` to `FlagSet` and `tags=` parameter to `flag_sets=` across all API surfaces.
File without changes
@@ -0,0 +1 @@
1
+ 0.69.2
@@ -2,17 +2,23 @@
2
2
 
3
3
  # Changelog
4
4
 
5
- ## 0.18.0
5
+ ## 0.19.0
6
6
 
7
- Public API for running checks programmatically
7
+ Renamed Tag to FlagSet
8
8
 
9
9
  <details>
10
10
  <summary>Context</summary>
11
11
 
12
- Adds App.run_checks(), format_check_results(), format_check_results_json(), and CheckRunResult a stable public API replacing the private _filter_checks/_resolve_check_order/_run_checks/_check_format_human functions that consumers like rlsbl were forced to use.
12
+ Breaking: Tag class renamed to FlagSet, tags= parameter renamed to flag_sets= across all API surfaces. The Tag name was misleading — it implied labeling/annotation, but the type is actually a reusable bundle of flags.
13
13
 
14
14
  </details>
15
15
 
16
+ ### Breaking
17
+
18
+ - **Breaking.** Renamed `Tag` to `FlagSet` and `tags=` parameter to `flag_sets=` across all API surfaces.
19
+
20
+ ## 0.18.0
21
+
16
22
  ### Features
17
23
 
18
24
  - **New.** Public API for running checks programmatically: `App.run_checks()`, `format_check_results()`, `format_check_results_json()`, `CheckRunResult`.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: strictcli
3
- Version: 0.18.0
3
+ Version: 0.19.0
4
4
  Summary: A strict, zero-dependency CLI framework for Python
5
5
  Project-URL: Homepage, https://github.com/smm-h/strictcli
6
6
  Project-URL: Repository, https://github.com/smm-h/strictcli
@@ -222,12 +222,12 @@ Values resolve in this order: CLI argument > environment variable > default. If
222
222
 
223
223
  Bool flags from env vars accept `1`, `true`, `yes` (case-insensitive) for `True` and `0`, `false`, `no` for `False`. Any other value is an error.
224
224
 
225
- ## Tags
225
+ ## FlagSets
226
226
 
227
- Tags are reusable bundles of flags that can be applied to multiple commands:
227
+ FlagSets are reusable bundles of flags that can be applied to multiple commands:
228
228
 
229
229
  ```python
230
- auth_tag = strictcli.Tag(
230
+ auth_flags = strictcli.FlagSet(
231
231
  name="auth",
232
232
  flags=[
233
233
  strictcli.Flag(name="token", type=str, help="auth token", env="MYAPP_TOKEN", default=""),
@@ -235,16 +235,16 @@ auth_tag = strictcli.Tag(
235
235
  ],
236
236
  )
237
237
 
238
- @app.command("deploy", help="deploy the app", tags=[auth_tag])
238
+ @app.command("deploy", help="deploy the app", flag_sets=[auth_flags])
239
239
  def deploy(token, insecure):
240
240
  print(f"token={'set' if token else 'unset'}, insecure={insecure}")
241
241
 
242
- @app.command("status", help="check status", tags=[auth_tag])
242
+ @app.command("status", help="check status", flag_sets=[auth_flags])
243
243
  def status(token, insecure):
244
244
  print(f"checking status")
245
245
  ```
246
246
 
247
- Both commands now have `--token` and `--insecure` flags. Tag flags appear in help output and are parsed like any other flag.
247
+ Both commands now have `--token` and `--insecure` flags. FlagSet flags appear in help output and are parsed like any other flag.
248
248
 
249
249
  ## Mutex Groups
250
250
 
@@ -204,12 +204,12 @@ Values resolve in this order: CLI argument > environment variable > default. If
204
204
 
205
205
  Bool flags from env vars accept `1`, `true`, `yes` (case-insensitive) for `True` and `0`, `false`, `no` for `False`. Any other value is an error.
206
206
 
207
- ## Tags
207
+ ## FlagSets
208
208
 
209
- Tags are reusable bundles of flags that can be applied to multiple commands:
209
+ FlagSets are reusable bundles of flags that can be applied to multiple commands:
210
210
 
211
211
  ```python
212
- auth_tag = strictcli.Tag(
212
+ auth_flags = strictcli.FlagSet(
213
213
  name="auth",
214
214
  flags=[
215
215
  strictcli.Flag(name="token", type=str, help="auth token", env="MYAPP_TOKEN", default=""),
@@ -217,16 +217,16 @@ auth_tag = strictcli.Tag(
217
217
  ],
218
218
  )
219
219
 
220
- @app.command("deploy", help="deploy the app", tags=[auth_tag])
220
+ @app.command("deploy", help="deploy the app", flag_sets=[auth_flags])
221
221
  def deploy(token, insecure):
222
222
  print(f"token={'set' if token else 'unset'}, insecure={insecure}")
223
223
 
224
- @app.command("status", help="check status", tags=[auth_tag])
224
+ @app.command("status", help="check status", flag_sets=[auth_flags])
225
225
  def status(token, insecure):
226
226
  print(f"checking status")
227
227
  ```
228
228
 
229
- Both commands now have `--token` and `--insecure` flags. Tag flags appear in help output and are parsed like any other flag.
229
+ Both commands now have `--token` and `--insecure` flags. FlagSet flags appear in help output and are parsed like any other flag.
230
230
 
231
231
  ## Mutex Groups
232
232
 
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "strictcli",
3
- "version": "0.18.0",
3
+ "version": "0.19.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "strictcli",
9
- "version": "0.18.0",
9
+ "version": "0.19.0",
10
10
  "hasInstallScript": true,
11
11
  "license": "MIT"
12
12
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "strictcli",
3
- "version": "0.18.0",
3
+ "version": "0.19.0",
4
4
  "description": "A strict, zero-dependency CLI framework for Python (npm wrapper)",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "strictcli"
7
- version = "0.18.0"
7
+ version = "0.19.0"
8
8
  description = "A strict, zero-dependency CLI framework for Python"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -2,10 +2,10 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- __version__ = "0.18.0"
5
+ __version__ = "0.19.0"
6
6
 
7
7
  __all__ = [
8
- "App", "Flag", "Arg", "Tag", "MutexGroup", "CoRequired", "Requires",
8
+ "App", "Flag", "Arg", "FlagSet", "MutexGroup", "CoRequired", "Requires",
9
9
  "Implies", "Passthrough", "DeprecatedCommand", "Result", "flag", "arg",
10
10
  "CheckResult", "CheckContext", "CheckRunResult",
11
11
  "format_check_results", "format_check_results_json",
@@ -677,7 +677,7 @@ class Arg:
677
677
 
678
678
 
679
679
  @dataclass
680
- class Tag:
680
+ class FlagSet:
681
681
  """A reusable bundle of flags."""
682
682
 
683
683
  name: str
@@ -740,7 +740,7 @@ class Command:
740
740
  handler: Callable | None
741
741
  flags: list[Flag] = field(default_factory=list)
742
742
  args: list[Arg] = field(default_factory=list)
743
- tags: list[Tag] = field(default_factory=list)
743
+ flag_sets: list[FlagSet] = field(default_factory=list)
744
744
  mutex: list[MutexGroup] = field(default_factory=list)
745
745
  dependencies: list[CoRequired | Requires | Implies] = field(default_factory=list)
746
746
  passthrough: Passthrough | None = None
@@ -805,7 +805,7 @@ class Group:
805
805
  *,
806
806
  help: str,
807
807
  args: list[Arg] | None = None,
808
- tags: list[Tag] | None = None,
808
+ flag_sets: list[FlagSet] | None = None,
809
809
  mutex: list[MutexGroup] | None = None,
810
810
  dependencies: list[CoRequired | Requires | Implies] | None = None,
811
811
  passthrough: Passthrough | None = None,
@@ -818,7 +818,7 @@ class Group:
818
818
  f'command "{name}" collides with an existing group'
819
819
  )
820
820
  cmd = _build_and_validate_command(
821
- name, help=help, handler=func, args=args, tags=tags, mutex=mutex,
821
+ name, help=help, handler=func, args=args, flag_sets=flag_sets, mutex=mutex,
822
822
  dependencies=dependencies,
823
823
  env_prefix=self.env_prefix,
824
824
  global_flags=self._global_flags,
@@ -1124,7 +1124,7 @@ class App:
1124
1124
  help="Run project checks",
1125
1125
  handler=_check_handler,
1126
1126
  args=None,
1127
- tags=None,
1127
+ flag_sets=None,
1128
1128
  mutex=None,
1129
1129
  dependencies=None,
1130
1130
  env_prefix=self.env_prefix,
@@ -1140,7 +1140,7 @@ class App:
1140
1140
  *,
1141
1141
  help: str,
1142
1142
  args: list[Arg] | None = None,
1143
- tags: list[Tag] | None = None,
1143
+ flag_sets: list[FlagSet] | None = None,
1144
1144
  mutex: list[MutexGroup] | None = None,
1145
1145
  dependencies: list[CoRequired | Requires | Implies] | None = None,
1146
1146
  passthrough: Passthrough | None = None,
@@ -1153,7 +1153,7 @@ class App:
1153
1153
  help=help,
1154
1154
  handler=func,
1155
1155
  args=args,
1156
- tags=tags,
1156
+ flag_sets=flag_sets,
1157
1157
  mutex=mutex,
1158
1158
  dependencies=dependencies,
1159
1159
  env_prefix=self.env_prefix,
@@ -2483,7 +2483,7 @@ def _build_and_validate_command(
2483
2483
  help: str,
2484
2484
  handler: Callable,
2485
2485
  args: list[Arg] | None,
2486
- tags: list[Tag] | None,
2486
+ flag_sets: list[FlagSet] | None,
2487
2487
  mutex: list[MutexGroup] | None,
2488
2488
  dependencies: list[CoRequired | Requires | Implies] | None = None,
2489
2489
  env_prefix: str | None,
@@ -2495,22 +2495,22 @@ def _build_and_validate_command(
2495
2495
  if not help or not help.strip():
2496
2496
  raise ValueError(f'command "{name}": missing help text')
2497
2497
 
2498
- # Passthrough commands must not have flags, args, tags, or mutex groups
2498
+ # Passthrough commands must not have flags, args, flag sets, or mutex groups
2499
2499
  if passthrough is not None:
2500
2500
  decorator_flags = list(getattr(handler, "_strictcli_flags", []))
2501
2501
  decorator_args = list(getattr(handler, "_strictcli_args", []))
2502
2502
  has_flags = bool(decorator_flags)
2503
2503
  has_args = bool(args) or bool(decorator_args)
2504
- has_tags = bool(tags)
2504
+ has_flag_sets = bool(flag_sets)
2505
2505
  has_mutex = bool(mutex)
2506
- if has_flags or has_args or has_tags or has_mutex:
2506
+ if has_flags or has_args or has_flag_sets or has_mutex:
2507
2507
  parts = []
2508
2508
  if has_flags:
2509
2509
  parts.append("flags")
2510
2510
  if has_args:
2511
2511
  parts.append("args")
2512
- if has_tags:
2513
- parts.append("tags")
2512
+ if has_flag_sets:
2513
+ parts.append("flag sets")
2514
2514
  if has_mutex:
2515
2515
  parts.append("mutex groups")
2516
2516
  raise ValueError(
@@ -2535,11 +2535,11 @@ def _build_and_validate_command(
2535
2535
  all_args = list(args) if args else []
2536
2536
  all_args.extend(decorator_args)
2537
2537
 
2538
- # Merge tags into flags
2539
- resolved_tags = list(tags) if tags else []
2540
- tag_flags: list[Flag] = []
2541
- for tag in resolved_tags:
2542
- tag_flags.extend(tag.flags)
2538
+ # Merge flag sets into flags
2539
+ resolved_flag_sets = list(flag_sets) if flag_sets else []
2540
+ flag_set_flags: list[Flag] = []
2541
+ for flag_set in resolved_flag_sets:
2542
+ flag_set_flags.extend(flag_set.flags)
2543
2543
 
2544
2544
  # Resolve mutex groups and merge their flags
2545
2545
  resolved_mutex = list(mutex) if mutex else []
@@ -2563,13 +2563,13 @@ def _build_and_validate_command(
2563
2563
  )
2564
2564
  mutex_flag_names.add(f.name)
2565
2565
 
2566
- # All flags: decorator flags + tag flags + mutex flags + extra flags
2567
- all_flags = decorator_flags + tag_flags + mutex_flags
2566
+ # All flags: decorator flags + flag set flags + mutex flags + extra flags
2567
+ all_flags = decorator_flags + flag_set_flags + mutex_flags
2568
2568
  if extra_flags:
2569
2569
  all_flags.extend(extra_flags)
2570
2570
 
2571
2571
  # Validate: no duplicate flag names (catches mutex flags overlapping with
2572
- # regular flags or tag flags)
2572
+ # regular flags or flag set flags)
2573
2573
  seen_flag_names: set[str] = set()
2574
2574
  for f in all_flags:
2575
2575
  if f.name in seen_flag_names:
@@ -2745,7 +2745,7 @@ def _build_and_validate_command(
2745
2745
  handler=handler,
2746
2746
  flags=all_flags,
2747
2747
  args=all_args,
2748
- tags=resolved_tags,
2748
+ flag_sets=resolved_flag_sets,
2749
2749
  mutex=resolved_mutex,
2750
2750
  dependencies=resolved_dependencies,
2751
2751
  )
@@ -4,8 +4,8 @@ import strictcli
4
4
 
5
5
 
6
6
  def _build_rlsbl_app():
7
- """Build a mini rlsbl-like CLI app with commands, groups, tags, and env vars."""
8
- auth_tag = strictcli.Tag(
7
+ """Build a mini rlsbl-like CLI app with commands, groups, flag sets, and env vars."""
8
+ auth_flag_set = strictcli.FlagSet(
9
9
  name="auth",
10
10
  flags=[
11
11
  strictcli.Flag(
@@ -26,7 +26,7 @@ def _build_rlsbl_app():
26
26
  )
27
27
 
28
28
  # Top-level commands
29
- @app.command("status", help="show release status", tags=[auth_tag])
29
+ @app.command("status", help="show release status", flag_sets=[auth_flag_set])
30
30
  def status(token):
31
31
  print(f"status: token={'set' if token else 'unset'}")
32
32
 
@@ -34,7 +34,7 @@ def _build_rlsbl_app():
34
34
  "release",
35
35
  help="create a new release",
36
36
  args=[strictcli.Arg(name="bump", help="version bump type")],
37
- tags=[auth_tag],
37
+ flag_sets=[auth_flag_set],
38
38
  )
39
39
  @strictcli.flag("dry-run", type=bool, help="preview without making changes")
40
40
  @strictcli.flag("yes", type=bool, help="non-interactive mode")
@@ -264,9 +264,9 @@ def test_e2e_kwargs_handler_defaults():
264
264
  assert "replicas=1" in r.stdout
265
265
 
266
266
 
267
- def test_e2e_kwargs_handler_with_tags():
268
- """Command with **kwargs handler and tags receives tag flag values."""
269
- auth_tag = strictcli.Tag(
267
+ def test_e2e_kwargs_handler_with_flag_sets():
268
+ """Command with **kwargs handler and flag sets receives flag set flag values."""
269
+ auth_flag_set = strictcli.FlagSet(
270
270
  name="auth",
271
271
  flags=[
272
272
  strictcli.Flag(name="token", type=str, help="auth token", default=""),
@@ -275,7 +275,7 @@ def test_e2e_kwargs_handler_with_tags():
275
275
 
276
276
  app = strictcli.App(name="kw", version="1.0.0", help="kwargs test app")
277
277
 
278
- @app.command("push", help="push changes", tags=[auth_tag])
278
+ @app.command("push", help="push changes", flag_sets=[auth_flag_set])
279
279
  def push_handler(**kwargs):
280
280
  print(f"token={kwargs['token']}")
281
281
  return 0
@@ -1,17 +1,17 @@
1
- """Tests for the tag system."""
1
+ """Tests for the flag set system."""
2
2
 
3
3
  import strictcli
4
4
 
5
5
 
6
- def test_tag_with_single_flag():
7
- """Tag with single flag applied to command."""
8
- verbose_tag = strictcli.Tag(
6
+ def test_flag_set_with_single_flag():
7
+ """FlagSet with single flag applied to command."""
8
+ verbose_flag_set = strictcli.FlagSet(
9
9
  name="verbose",
10
10
  flags=[strictcli.Flag(name="verbose", type=bool, help="verbose output")],
11
11
  )
12
12
  app = strictcli.App(name="test", version="1.0.0", help="test app")
13
13
 
14
- @app.command("cmd", help="a command", tags=[verbose_tag])
14
+ @app.command("cmd", help="a command", flag_sets=[verbose_flag_set])
15
15
  def cmd(verbose):
16
16
  print(f"verbose={verbose}")
17
17
 
@@ -20,9 +20,9 @@ def test_tag_with_single_flag():
20
20
  assert "verbose=True" in r.stdout
21
21
 
22
22
 
23
- def test_tag_with_multiple_flags():
24
- """Tag with multiple flags applied to command."""
25
- output_tag = strictcli.Tag(
23
+ def test_flag_set_with_multiple_flags():
24
+ """FlagSet with multiple flags applied to command."""
25
+ output_flag_set = strictcli.FlagSet(
26
26
  name="output",
27
27
  flags=[
28
28
  strictcli.Flag(name="format", type=str, help="output format", default="text"),
@@ -31,7 +31,7 @@ def test_tag_with_multiple_flags():
31
31
  )
32
32
  app = strictcli.App(name="test", version="1.0.0", help="test app")
33
33
 
34
- @app.command("cmd", help="a command", tags=[output_tag])
34
+ @app.command("cmd", help="a command", flag_sets=[output_flag_set])
35
35
  def cmd(format, color):
36
36
  print(f"format={format} color={color}")
37
37
 
@@ -41,15 +41,15 @@ def test_tag_with_multiple_flags():
41
41
  assert "color=True" in r.stdout
42
42
 
43
43
 
44
- def test_tag_flags_in_command_flags():
45
- """Tag flags appear in command's flags list."""
46
- tag = strictcli.Tag(
44
+ def test_flag_set_flags_in_command_flags():
45
+ """FlagSet flags appear in command's flags list."""
46
+ flag_set = strictcli.FlagSet(
47
47
  name="debug",
48
48
  flags=[strictcli.Flag(name="debug", type=bool, help="enable debug mode")],
49
49
  )
50
50
  app = strictcli.App(name="test", version="1.0.0", help="test app")
51
51
 
52
- @app.command("cmd", help="a command", tags=[tag])
52
+ @app.command("cmd", help="a command", flag_sets=[flag_set])
53
53
  def cmd(debug):
54
54
  pass
55
55
 
@@ -57,15 +57,15 @@ def test_tag_flags_in_command_flags():
57
57
  assert app._commands["cmd"].flags[0].name == "debug"
58
58
 
59
59
 
60
- def test_tag_flags_in_help():
61
- """Tag flags shown in help output."""
62
- tag = strictcli.Tag(
60
+ def test_flag_set_flags_in_help():
61
+ """FlagSet flags shown in help output."""
62
+ flag_set = strictcli.FlagSet(
63
63
  name="debug",
64
64
  flags=[strictcli.Flag(name="debug", type=bool, help="enable debug mode")],
65
65
  )
66
66
  app = strictcli.App(name="test", version="1.0.0", help="test app")
67
67
 
68
- @app.command("cmd", help="a command", tags=[tag])
68
+ @app.command("cmd", help="a command", flag_sets=[flag_set])
69
69
  def cmd(debug):
70
70
  pass
71
71
 
@@ -75,9 +75,9 @@ def test_tag_flags_in_help():
75
75
  assert "enable debug mode" in r.stdout
76
76
 
77
77
 
78
- def test_tag_flag_values_parsed():
79
- """Tag flag values parsed correctly through the full pipeline."""
80
- auth_tag = strictcli.Tag(
78
+ def test_flag_set_flag_values_parsed():
79
+ """FlagSet flag values parsed correctly through the full pipeline."""
80
+ auth_flag_set = strictcli.FlagSet(
81
81
  name="auth",
82
82
  flags=[
83
83
  strictcli.Flag(name="token", type=str, help="auth token", default="none"),
@@ -86,11 +86,11 @@ def test_tag_flag_values_parsed():
86
86
  )
87
87
  app = strictcli.App(name="test", version="1.0.0", help="test app")
88
88
 
89
- @app.command("deploy", help="deploy the app", tags=[auth_tag])
89
+ @app.command("deploy", help="deploy the app", flag_sets=[auth_flag_set])
90
90
  def deploy(token, insecure):
91
91
  print(f"token={token} insecure={insecure}")
92
92
 
93
- # Test with all tag flags provided
93
+ # Test with all flag set flags provided
94
94
  r = app.test(["deploy", "--token", "abc123", "--insecure"])
95
95
  assert r.exit_code == 0
96
96
  assert "token=abc123" in r.stdout
@@ -190,22 +190,22 @@ class TestPassthroughWithArgsRaisesValueError:
190
190
  assert "args" in str(e)
191
191
 
192
192
 
193
- class TestPassthroughWithTagsRaisesValueError:
194
- def test_tags(self):
193
+ class TestPassthroughWithFlagSetsRaisesValueError:
194
+ def test_flag_sets(self):
195
195
  pt = strictcli.Passthrough(handler=lambda n, a, g: 0)
196
- tag = strictcli.Tag(
196
+ flag_set = strictcli.FlagSet(
197
197
  name="auth",
198
198
  flags=[strictcli.Flag(name="token", type=str, help="token", default="")],
199
199
  )
200
200
  app = _build_app()
201
201
  try:
202
- @app.command("exec", help="run", passthrough=pt, tags=[tag])
202
+ @app.command("exec", help="run", passthrough=pt, flag_sets=[flag_set])
203
203
  def exec_cmd(token):
204
204
  pass
205
205
  assert False, "should have raised ValueError"
206
206
  except ValueError as e:
207
207
  assert "passthrough" in str(e)
208
- assert "tags" in str(e)
208
+ assert "flag sets" in str(e)
209
209
 
210
210
 
211
211
  class TestPassthroughWithMutexRaisesValueError:
@@ -115,14 +115,14 @@ def test_env_prefix_correct():
115
115
  assert app._commands["cmd"].flags[0].env == "MYAPP_TARGET"
116
116
 
117
117
 
118
- def test_tag_merging():
119
- """Command inherits tag flags."""
120
- verbose_tag = strictcli.Tag(
118
+ def test_flag_set_merging():
119
+ """Command inherits flag set flags."""
120
+ verbose_flag_set = strictcli.FlagSet(
121
121
  name="verbose", flags=[strictcli.Flag(name="verbose", type=bool, help="verbose output")]
122
122
  )
123
123
  app = strictcli.App(name="test", version="1.0.0", help="test app")
124
124
 
125
- @app.command("cmd", help="a command", tags=[verbose_tag])
125
+ @app.command("cmd", help="a command", flag_sets=[verbose_flag_set])
126
126
  def cmd(verbose):
127
127
  pass
128
128
 
@@ -232,7 +232,7 @@ wheels = [
232
232
 
233
233
  [[package]]
234
234
  name = "strictcli"
235
- version = "0.18.0"
235
+ version = "0.19.0"
236
236
  source = { editable = "." }
237
237
 
238
238
  [package.dev-dependencies]
@@ -1,17 +0,0 @@
1
- [forbidden-imports]
2
- modules = [
3
- "net/http",
4
- "github.com/spf13/cobra",
5
- "github.com/urfave/cli",
6
- ]
7
-
8
- [stdout]
9
- enabled = true
10
- ignore = []
11
-
12
- [entry-point]
13
- enabled = true
14
- ignore = []
15
-
16
- [files]
17
- exclude = []
@@ -1 +0,0 @@
1
- 9fe0fe3a00effc0c9e39704a0bd0cc865542da83
@@ -1,17 +0,0 @@
1
- [forbidden-imports]
2
- modules = [
3
- "net/http",
4
- "github.com/spf13/cobra",
5
- "github.com/urfave/cli",
6
- ]
7
-
8
- [stdout]
9
- enabled = true
10
- ignore = []
11
-
12
- [entry-point]
13
- enabled = true
14
- ignore = []
15
-
16
- [files]
17
- exclude = []
@@ -1 +0,0 @@
1
- 0.67.1
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes