strictcli 0.8.3__tar.gz → 0.8.5__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 (103) hide show
  1. strictcli-0.8.5/.rlsbl/changes/.validated +1 -0
  2. strictcli-0.8.5/.rlsbl/changes/0.8.4.jsonl +3 -0
  3. strictcli-0.8.5/.rlsbl/changes/0.8.4.md +5 -0
  4. strictcli-0.8.5/.rlsbl/changes/0.8.5.jsonl +7 -0
  5. strictcli-0.8.5/.rlsbl/changes/0.8.5.md +9 -0
  6. strictcli-0.8.5/.rlsbl/releases/unreleased.toml +0 -0
  7. strictcli-0.8.5/.rlsbl/releases/v0.8.5.toml +3 -0
  8. strictcli-0.8.5/.rlsbl/version +1 -0
  9. {strictcli-0.8.3 → strictcli-0.8.5}/CHANGELOG.md +16 -0
  10. {strictcli-0.8.3 → strictcli-0.8.5}/PKG-INFO +1 -1
  11. {strictcli-0.8.3 → strictcli-0.8.5}/package-lock.json +2 -2
  12. {strictcli-0.8.3 → strictcli-0.8.5}/package.json +1 -1
  13. {strictcli-0.8.3 → strictcli-0.8.5}/pyproject.toml +1 -1
  14. {strictcli-0.8.3 → strictcli-0.8.5}/strictcli/__init__.py +32 -13
  15. {strictcli-0.8.3 → strictcli-0.8.5}/tests/test_toml_loading.py +2 -2
  16. {strictcli-0.8.3 → strictcli-0.8.5}/uv.lock +1 -1
  17. strictcli-0.8.3/.rlsbl/changes/.validated +0 -1
  18. strictcli-0.8.3/.rlsbl/version +0 -1
  19. {strictcli-0.8.3 → strictcli-0.8.5}/.claude/settings.json +0 -0
  20. {strictcli-0.8.3 → strictcli-0.8.5}/.github/workflows/ci.yml +0 -0
  21. {strictcli-0.8.3 → strictcli-0.8.5}/.github/workflows/publish.yml +0 -0
  22. {strictcli-0.8.3 → strictcli-0.8.5}/.gitignore +0 -0
  23. {strictcli-0.8.3 → strictcli-0.8.5}/.rlsbl/bases/.claude/settings.json +0 -0
  24. {strictcli-0.8.3 → strictcli-0.8.5}/.rlsbl/bases/.github/workflows/ci.yml +0 -0
  25. {strictcli-0.8.3 → strictcli-0.8.5}/.rlsbl/bases/.github/workflows/publish.yml +0 -0
  26. {strictcli-0.8.3 → strictcli-0.8.5}/.rlsbl/bases/.gitignore +0 -0
  27. {strictcli-0.8.3 → strictcli-0.8.5}/.rlsbl/bases/.rlsbl/hooks/post-release.sh +0 -0
  28. {strictcli-0.8.3 → strictcli-0.8.5}/.rlsbl/bases/.rlsbl/hooks/pre-checks.sh +0 -0
  29. {strictcli-0.8.3 → strictcli-0.8.5}/.rlsbl/bases/.rlsbl/hooks/pre-release.sh +0 -0
  30. {strictcli-0.8.3 → strictcli-0.8.5}/.rlsbl/bases/.rlsbl/lint/go.toml +0 -0
  31. {strictcli-0.8.3 → strictcli-0.8.5}/.rlsbl/bases/.rlsbl/lint/npm.toml +0 -0
  32. {strictcli-0.8.3 → strictcli-0.8.5}/.rlsbl/bases/.rlsbl/lint/python.toml +0 -0
  33. {strictcli-0.8.3 → strictcli-0.8.5}/.rlsbl/bases/CHANGELOG.md +0 -0
  34. {strictcli-0.8.3 → strictcli-0.8.5}/.rlsbl/bases/CLAUDE.md +0 -0
  35. {strictcli-0.8.3 → strictcli-0.8.5}/.rlsbl/bases/LICENSE +0 -0
  36. {strictcli-0.8.3 → strictcli-0.8.5}/.rlsbl/changes/0.4.0.jsonl +0 -0
  37. {strictcli-0.8.3 → strictcli-0.8.5}/.rlsbl/changes/0.4.0.md +0 -0
  38. {strictcli-0.8.3 → strictcli-0.8.5}/.rlsbl/changes/0.4.1.jsonl +0 -0
  39. {strictcli-0.8.3 → strictcli-0.8.5}/.rlsbl/changes/0.4.1.md +0 -0
  40. {strictcli-0.8.3 → strictcli-0.8.5}/.rlsbl/changes/0.5.0.jsonl +0 -0
  41. {strictcli-0.8.3 → strictcli-0.8.5}/.rlsbl/changes/0.5.0.md +0 -0
  42. {strictcli-0.8.3 → strictcli-0.8.5}/.rlsbl/changes/0.6.0.jsonl +0 -0
  43. {strictcli-0.8.3 → strictcli-0.8.5}/.rlsbl/changes/0.6.0.md +0 -0
  44. {strictcli-0.8.3 → strictcli-0.8.5}/.rlsbl/changes/0.6.1.jsonl +0 -0
  45. {strictcli-0.8.3 → strictcli-0.8.5}/.rlsbl/changes/0.6.1.md +0 -0
  46. {strictcli-0.8.3 → strictcli-0.8.5}/.rlsbl/changes/0.7.0.jsonl +0 -0
  47. {strictcli-0.8.3 → strictcli-0.8.5}/.rlsbl/changes/0.7.0.md +0 -0
  48. {strictcli-0.8.3 → strictcli-0.8.5}/.rlsbl/changes/0.7.1.jsonl +0 -0
  49. {strictcli-0.8.3 → strictcli-0.8.5}/.rlsbl/changes/0.7.1.md +0 -0
  50. {strictcli-0.8.3 → strictcli-0.8.5}/.rlsbl/changes/0.8.0.jsonl +0 -0
  51. {strictcli-0.8.3 → strictcli-0.8.5}/.rlsbl/changes/0.8.0.md +0 -0
  52. {strictcli-0.8.3 → strictcli-0.8.5}/.rlsbl/changes/0.8.1.jsonl +0 -0
  53. {strictcli-0.8.3 → strictcli-0.8.5}/.rlsbl/changes/0.8.1.md +0 -0
  54. {strictcli-0.8.3 → strictcli-0.8.5}/.rlsbl/changes/0.8.2.jsonl +0 -0
  55. {strictcli-0.8.3 → strictcli-0.8.5}/.rlsbl/changes/0.8.2.md +0 -0
  56. {strictcli-0.8.3 → strictcli-0.8.5}/.rlsbl/changes/0.8.3.jsonl +0 -0
  57. {strictcli-0.8.3 → strictcli-0.8.5}/.rlsbl/changes/0.8.3.md +0 -0
  58. {strictcli-0.8.3 → strictcli-0.8.5}/.rlsbl/changes/unreleased.jsonl +0 -0
  59. {strictcli-0.8.3 → strictcli-0.8.5}/.rlsbl/config.json +0 -0
  60. {strictcli-0.8.3 → strictcli-0.8.5}/.rlsbl/hashes.json +0 -0
  61. {strictcli-0.8.3 → strictcli-0.8.5}/.rlsbl/hooks/post-release.sh +0 -0
  62. {strictcli-0.8.3 → strictcli-0.8.5}/.rlsbl/hooks/pre-checks.sh +0 -0
  63. {strictcli-0.8.3 → strictcli-0.8.5}/.rlsbl/hooks/pre-release.sh +0 -0
  64. {strictcli-0.8.3 → strictcli-0.8.5}/.rlsbl/lint/go.toml +0 -0
  65. {strictcli-0.8.3 → strictcli-0.8.5}/.rlsbl/lint/npm.toml +0 -0
  66. {strictcli-0.8.3 → strictcli-0.8.5}/.rlsbl/lint/python.toml +0 -0
  67. {strictcli-0.8.3 → strictcli-0.8.5}/CLAUDE.md +0 -0
  68. {strictcli-0.8.3 → strictcli-0.8.5}/LICENSE +0 -0
  69. {strictcli-0.8.3 → strictcli-0.8.5}/README.md +0 -0
  70. {strictcli-0.8.3 → strictcli-0.8.5}/index.js +0 -0
  71. {strictcli-0.8.3 → strictcli-0.8.5}/postinstall.js +0 -0
  72. {strictcli-0.8.3 → strictcli-0.8.5}/tests/test_arg_default.py +0 -0
  73. {strictcli-0.8.3 → strictcli-0.8.5}/tests/test_auto_version.py +0 -0
  74. {strictcli-0.8.3 → strictcli-0.8.5}/tests/test_check_command.py +0 -0
  75. {strictcli-0.8.3 → strictcli-0.8.5}/tests/test_check_discovery.py +0 -0
  76. {strictcli-0.8.3 → strictcli-0.8.5}/tests/test_check_runner.py +0 -0
  77. {strictcli-0.8.3 → strictcli-0.8.5}/tests/test_check_schema.py +0 -0
  78. {strictcli-0.8.3 → strictcli-0.8.5}/tests/test_check_types.py +0 -0
  79. {strictcli-0.8.3 → strictcli-0.8.5}/tests/test_choices.py +0 -0
  80. {strictcli-0.8.3 → strictcli-0.8.5}/tests/test_config.py +0 -0
  81. {strictcli-0.8.3 → strictcli-0.8.5}/tests/test_deep_nesting.py +0 -0
  82. {strictcli-0.8.3 → strictcli-0.8.5}/tests/test_dependencies.py +0 -0
  83. {strictcli-0.8.3 → strictcli-0.8.5}/tests/test_deprecated.py +0 -0
  84. {strictcli-0.8.3 → strictcli-0.8.5}/tests/test_dump_schema.py +0 -0
  85. {strictcli-0.8.3 → strictcli-0.8.5}/tests/test_e2e.py +0 -0
  86. {strictcli-0.8.3 → strictcli-0.8.5}/tests/test_env.py +0 -0
  87. {strictcli-0.8.3 → strictcli-0.8.5}/tests/test_exit_codes.py +0 -0
  88. {strictcli-0.8.3 → strictcli-0.8.5}/tests/test_float_type.py +0 -0
  89. {strictcli-0.8.3 → strictcli-0.8.5}/tests/test_global_flags.py +0 -0
  90. {strictcli-0.8.3 → strictcli-0.8.5}/tests/test_help.py +0 -0
  91. {strictcli-0.8.3 → strictcli-0.8.5}/tests/test_int_type.py +0 -0
  92. {strictcli-0.8.3 → strictcli-0.8.5}/tests/test_mutex.py +0 -0
  93. {strictcli-0.8.3 → strictcli-0.8.5}/tests/test_nesting.py +0 -0
  94. {strictcli-0.8.3 → strictcli-0.8.5}/tests/test_parser.py +0 -0
  95. {strictcli-0.8.3 → strictcli-0.8.5}/tests/test_passthrough.py +0 -0
  96. {strictcli-0.8.3 → strictcli-0.8.5}/tests/test_registration.py +0 -0
  97. {strictcli-0.8.3 → strictcli-0.8.5}/tests/test_repeatable.py +0 -0
  98. {strictcli-0.8.3 → strictcli-0.8.5}/tests/test_tagdsl.py +0 -0
  99. {strictcli-0.8.3 → strictcli-0.8.5}/tests/test_tags.py +0 -0
  100. {strictcli-0.8.3 → strictcli-0.8.5}/tests/test_validate.py +0 -0
  101. {strictcli-0.8.3 → strictcli-0.8.5}/tests/test_variadic.py +0 -0
  102. {strictcli-0.8.3 → strictcli-0.8.5}/todo/.defer/deferred.md +0 -0
  103. {strictcli-0.8.3 → strictcli-0.8.5}/todo/.done/original-idea.md +0 -0
@@ -0,0 +1 @@
1
+ fd52271bcf11157ae4eb47ee9e63d6ed5d9000b9
@@ -0,0 +1,3 @@
1
+ {"commits":["b9de6b57374910b3b7b41f1e28a19cee7430cdd6","2b02693caebcc47a9cf033ccff61d3816450ed4d"],"user_facing":false}
2
+ {"commits":["084096729ab0e737e9c69e57a537c25c4733e794"],"user_facing":true,"description":"**Fix.** Allow empty `tags = []` in `.strictcli/checks.toml`. Checks without tags are valid -- they are addressable by `--name` and included in `--all`.","type":"fix"}
3
+ {"commits":["8dba95c70a17eeea8ce7f6ea1b0da65c35ab7691","2b02693caebcc47a9cf033ccff61d3816450ed4d","b9de6b57374910b3b7b41f1e28a19cee7430cdd6"],"user_facing":false}
@@ -0,0 +1,5 @@
1
+ ## 0.8.4
2
+
3
+ ### Fixes
4
+
5
+ - **Fix.** Allow empty `tags = []` in `.strictcli/checks.toml`. Checks without tags are valid -- they are addressable by `--name` and included in `--all`.
@@ -0,0 +1,7 @@
1
+ {"commits":["eef4bcb494b80009b2e471f2b1465af98aa476e3"],"user_facing":true,"description":"**Fix.** Auto-registered `check` command no longer collides with app-level global flags (e.g., `--dry-run`).","type":"fix"}
2
+ {"commits":["eef4bcb494b80009b2e471f2b1465af98aa476e3"],"user_facing":true,"description":"**New feature.** App-level and command-level help output now includes a 'Global flags' section.","type":"feature"}
3
+ {"commits":["88d7f9e747085d7b1237e39e7f45ccec34c7a3bf","8facbdd35c2b52023005a051d0417ff62878b940"],"user_facing":false}
4
+ {"commits":["00a96ace74f0ccadf55bd5cf6b820102ff504320"],"user_facing":false}
5
+ {"commits":["5df4af02759154eb4cbf3abb2a47950a02b7d3ec"],"user_facing":false}
6
+ {"commits":["b6f72994086bf8ed38dba1550cc1a977d12e988b"],"user_facing":false}
7
+ {"commits":["e2e9804dd8b20925b04bdf7dc7ffbe774d7982df"],"user_facing":false}
@@ -0,0 +1,9 @@
1
+ ## 0.8.5
2
+
3
+ ### Features
4
+
5
+ - **New feature.** App-level and command-level help output now includes a 'Global flags' section.
6
+
7
+ ### Fixes
8
+
9
+ - **Fix.** Auto-registered `check` command no longer collides with app-level global flags (e.g., `--dry-run`).
File without changes
@@ -0,0 +1,3 @@
1
+ bump = "patch"
2
+ include = ["pypi", "npm"]
3
+ exclude = []
@@ -0,0 +1 @@
1
+ 0.39.0
@@ -2,6 +2,22 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ## 0.8.5
6
+
7
+ ### Features
8
+
9
+ - **New feature.** App-level and command-level help output now includes a 'Global flags' section.
10
+
11
+ ### Fixes
12
+
13
+ - **Fix.** Auto-registered `check` command no longer collides with app-level global flags (e.g., `--dry-run`).
14
+
15
+ ## 0.8.4
16
+
17
+ ### Fixes
18
+
19
+ - **Fix.** Allow empty `tags = []` in `.strictcli/checks.toml`. Checks without tags are valid -- they are addressable by `--name` and included in `--all`.
20
+
5
21
  ## 0.8.3
6
22
 
7
23
  - No user-facing changes.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: strictcli
3
- Version: 0.8.3
3
+ Version: 0.8.5
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
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "strictcli",
3
- "version": "0.8.3",
3
+ "version": "0.8.5",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "strictcli",
9
- "version": "0.8.3",
9
+ "version": "0.8.5",
10
10
  "hasInstallScript": true,
11
11
  "license": "MIT"
12
12
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "strictcli",
3
- "version": "0.8.3",
3
+ "version": "0.8.5",
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.8.3"
7
+ version = "0.8.5"
8
8
  description = "A strict, zero-dependency CLI framework for Python"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -2,7 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- __version__ = "0.8.3"
5
+ __version__ = "0.8.5"
6
6
 
7
7
  __all__ = [
8
8
  "App", "Flag", "Arg", "Tag", "MutexGroup", "CoRequired", "Requires",
@@ -143,9 +143,9 @@ def _load_checks_toml(path: str | Path) -> dict[str, _CheckDef]:
143
143
 
144
144
  # Validate tags
145
145
  tags = fields["tags"]
146
- if not isinstance(tags, list) or len(tags) == 0:
146
+ if not isinstance(tags, list):
147
147
  raise ValueError(
148
- f'checks.toml: check "{name}": "tags" must be a non-empty list of strings'
148
+ f'checks.toml: check "{name}": "tags" must be a list of strings'
149
149
  )
150
150
  for tag in tags:
151
151
  if not isinstance(tag, str) or not tag.strip():
@@ -714,6 +714,20 @@ class App:
714
714
 
715
715
  return exit_code
716
716
 
717
+ # Filter out extra flags that already exist as global flags to avoid
718
+ # collisions -- the handler receives global flag values automatically.
719
+ global_flag_names = {gf.name for gf in self._global_flags}
720
+ candidate_extra_flags = [
721
+ Flag(name="all", type=bool, help="Run all checks"),
722
+ Flag(name="tag", type=str, default="", help="Tag DSL expression to filter checks"),
723
+ Flag(name="name", type=str, default="", help="Glob pattern to filter by check name"),
724
+ Flag(name="list", type=bool, help="List all checks and their tags"),
725
+ Flag(name="json", type=bool, help="Output results as JSON"),
726
+ Flag(name="ignore-warnings", type=bool, help="Warn severity does not cause nonzero exit"),
727
+ Flag(name="verbose", type=bool, help="Show details for passing checks too"),
728
+ Flag(name="dry-run", type=bool, help="Show which checks would run without running them"),
729
+ ]
730
+ extra_flags = [f for f in candidate_extra_flags if f.name not in global_flag_names]
717
731
  check_cmd = _build_and_validate_command(
718
732
  "check",
719
733
  help="Run project checks",
@@ -725,16 +739,7 @@ class App:
725
739
  env_prefix=self.env_prefix,
726
740
  global_flags=self._global_flags,
727
741
  passthrough=None,
728
- extra_flags=[
729
- Flag(name="all", type=bool, help="Run all checks"),
730
- Flag(name="tag", type=str, default="", help="Tag DSL expression to filter checks"),
731
- Flag(name="name", type=str, default="", help="Glob pattern to filter by check name"),
732
- Flag(name="list", type=bool, help="List all checks and their tags"),
733
- Flag(name="json", type=bool, help="Output results as JSON"),
734
- Flag(name="ignore-warnings", type=bool, help="Warn severity does not cause nonzero exit"),
735
- Flag(name="verbose", type=bool, help="Show details for passing checks too"),
736
- Flag(name="dry-run", type=bool, help="Show which checks would run without running them"),
737
- ],
742
+ extra_flags=extra_flags,
738
743
  )
739
744
  self._commands["check"] = check_cmd
740
745
 
@@ -2100,6 +2105,20 @@ def _format_app_help(app: App) -> str:
2100
2105
  padding = max_len - len(name) + 4
2101
2106
  lines.append(f" {name}{' ' * padding}{dep.message}")
2102
2107
 
2108
+ if app._global_flags:
2109
+ lines.append("")
2110
+ lines.append("Global flags:")
2111
+ flag_strs = []
2112
+ for f in app._global_flags:
2113
+ parts = [f"--{f.name}"]
2114
+ if f.short:
2115
+ parts.append(f"-{f.short}")
2116
+ flag_strs.append((", ".join(parts), f.help))
2117
+ max_flag_len = max(len(s[0]) for s in flag_strs)
2118
+ for flag_str, help_text in flag_strs:
2119
+ padding = max_flag_len - len(flag_str) + 4
2120
+ lines.append(f" {flag_str}{' ' * padding}{help_text}")
2121
+
2103
2122
  lines.append("")
2104
2123
  lines.append(f"Use '{app.name} <command> --help' for more information.")
2105
2124
 
@@ -211,8 +211,8 @@ depends_on = []
211
211
  """
212
212
  f = tmp_path / "checks.toml"
213
213
  f.write_text(toml)
214
- with pytest.raises(ValueError, match='"tags" must be a non-empty list'):
215
- _load_checks_toml(f)
214
+ defs = _load_checks_toml(f)
215
+ assert defs["my-check"].tags == []
216
216
 
217
217
  def test_tags_with_empty_string(self, tmp_path):
218
218
  toml = """\
@@ -232,7 +232,7 @@ wheels = [
232
232
 
233
233
  [[package]]
234
234
  name = "strictcli"
235
- version = "0.8.3"
235
+ version = "0.8.5"
236
236
  source = { editable = "." }
237
237
 
238
238
  [package.dev-dependencies]
@@ -1 +0,0 @@
1
- d3c987f9ee7ca4844f3fa1f3760e0d8b9c07fd07
@@ -1 +0,0 @@
1
- 0.38.0
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes