strictcli 0.25.0__tar.gz → 0.26.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 (81) hide show
  1. {strictcli-0.25.0 → strictcli-0.26.0}/.rlsbl/config.json +2 -1
  2. {strictcli-0.25.0 → strictcli-0.26.0}/PKG-INFO +1 -1
  3. {strictcli-0.25.0 → strictcli-0.26.0}/package-lock.json +2 -2
  4. {strictcli-0.25.0 → strictcli-0.26.0}/package.json +1 -1
  5. {strictcli-0.25.0 → strictcli-0.26.0}/pyproject.toml +1 -1
  6. {strictcli-0.25.0 → strictcli-0.26.0}/strictcli/__init__.py +15 -12
  7. strictcli-0.26.0/strictcli/py.typed +0 -0
  8. {strictcli-0.25.0 → strictcli-0.26.0}/uv.lock +1 -1
  9. {strictcli-0.25.0 → strictcli-0.26.0}/.claude/settings.json +0 -0
  10. {strictcli-0.25.0 → strictcli-0.26.0}/.github/workflows/ci-pypi.yml +0 -0
  11. {strictcli-0.25.0 → strictcli-0.26.0}/.github/workflows/ci.yml +0 -0
  12. {strictcli-0.25.0 → strictcli-0.26.0}/.github/workflows/publish.yml +0 -0
  13. {strictcli-0.25.0 → strictcli-0.26.0}/.gitignore +0 -0
  14. {strictcli-0.25.0 → strictcli-0.26.0}/.npmignore +0 -0
  15. {strictcli-0.25.0 → strictcli-0.26.0}/.rlsbl/hashes.json +0 -0
  16. {strictcli-0.25.0 → strictcli-0.26.0}/.rlsbl/managed-files.json +0 -0
  17. {strictcli-0.25.0 → strictcli-0.26.0}/.strictcli/schema.json +0 -0
  18. {strictcli-0.25.0 → strictcli-0.26.0}/CLAUDE.md +0 -0
  19. {strictcli-0.25.0 → strictcli-0.26.0}/LICENSE +0 -0
  20. {strictcli-0.25.0 → strictcli-0.26.0}/README.md +0 -0
  21. {strictcli-0.25.0 → strictcli-0.26.0}/index.js +0 -0
  22. {strictcli-0.25.0 → strictcli-0.26.0}/postinstall.js +0 -0
  23. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_arg_default.py +0 -0
  24. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_arg_default_validation.py +0 -0
  25. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_at_prefix.py +0 -0
  26. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_auto_version.py +0 -0
  27. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_call.py +0 -0
  28. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_check_command.py +0 -0
  29. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_check_discovery.py +0 -0
  30. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_check_public_api.py +0 -0
  31. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_check_runner.py +0 -0
  32. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_check_schema.py +0 -0
  33. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_check_types.py +0 -0
  34. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_choices.py +0 -0
  35. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_choices_none.py +0 -0
  36. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_command_help_suggestion.py +0 -0
  37. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_command_tags.py +0 -0
  38. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_compound_types.py +0 -0
  39. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_config.py +0 -0
  40. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_config_fields.py +0 -0
  41. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_config_file_path.py +0 -0
  42. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_config_set_bugs.py +0 -0
  43. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_context.py +0 -0
  44. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_deep_nesting.py +0 -0
  45. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_dependencies.py +0 -0
  46. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_deprecated.py +0 -0
  47. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_dump_schema.py +0 -0
  48. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_e2e.py +0 -0
  49. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_env.py +0 -0
  50. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_exit_codes.py +0 -0
  51. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_flag_sets.py +0 -0
  52. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_float_type.py +0 -0
  53. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_global_flags.py +0 -0
  54. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_help.py +0 -0
  55. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_hermetic.py +0 -0
  56. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_int_type.py +0 -0
  57. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_invoke.py +0 -0
  58. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_keyword_flags.py +0 -0
  59. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_mcp.py +0 -0
  60. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_mutex.py +0 -0
  61. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_nesting.py +0 -0
  62. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_parser.py +0 -0
  63. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_passthrough.py +0 -0
  64. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_provenance.py +0 -0
  65. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_provenance_phase2.py +0 -0
  66. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_registration.py +0 -0
  67. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_repeatable.py +0 -0
  68. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_reserved_global_flags.py +0 -0
  69. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_tagdsl.py +0 -0
  70. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_toml_loading.py +0 -0
  71. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_tool_export.py +0 -0
  72. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_typed_args.py +0 -0
  73. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_unique.py +0 -0
  74. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_utilities.py +0 -0
  75. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_validate.py +0 -0
  76. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_variadic.py +0 -0
  77. {strictcli-0.25.0 → strictcli-0.26.0}/tests/test_visibility.py +0 -0
  78. {strictcli-0.25.0 → strictcli-0.26.0}/todo/.defer/deferred.md +0 -0
  79. {strictcli-0.25.0 → strictcli-0.26.0}/todo/.done/keyword-collision-in-flag-param-name.md +0 -0
  80. {strictcli-0.25.0 → strictcli-0.26.0}/todo/.done/original-idea.md +0 -0
  81. {strictcli-0.25.0 → strictcli-0.26.0}/todo/.done/public-check-runner-api.md +0 -0
@@ -14,5 +14,6 @@
14
14
  "type": "npm",
15
15
  "local": false
16
16
  }
17
- }
17
+ },
18
+ "coverage_unit": "commit"
18
19
  }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: strictcli
3
- Version: 0.25.0
3
+ Version: 0.26.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
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "strictcli",
3
- "version": "0.25.0",
3
+ "version": "0.26.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "strictcli",
9
- "version": "0.25.0",
9
+ "version": "0.26.0",
10
10
  "hasInstallScript": true,
11
11
  "license": "MIT"
12
12
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "strictcli",
3
- "version": "0.25.0",
3
+ "version": "0.26.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.25.0"
7
+ version = "0.26.0"
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.25.0"
5
+ __version__ = "0.26.0"
6
6
 
7
7
  __all__ = [
8
8
  "App", "Flag", "Arg", "FlagSet", "MutexGroup", "CoRequired", "Requires",
@@ -30,7 +30,10 @@ import tomllib
30
30
  from collections import deque
31
31
  from dataclasses import dataclass, field
32
32
  from pathlib import Path
33
- from typing import Callable, Protocol, get_args, get_origin, runtime_checkable
33
+ from typing import Any, Callable, Protocol, TypeVar, get_args, get_origin, runtime_checkable
34
+
35
+ # TypeVar for decorator return types — preserves the decorated function's type
36
+ F = TypeVar("F", bound=Callable[..., Any])
34
37
 
35
38
 
36
39
  # Sentinel for distinguishing "not provided" from actual values
@@ -1904,10 +1907,10 @@ class Group:
1904
1907
  hidden: bool = False,
1905
1908
  interactive: bool = False,
1906
1909
  config_fields: list[str] | None = None,
1907
- ) -> Callable:
1910
+ ) -> Callable[[F], F]:
1908
1911
  """Decorator to register a command within this group."""
1909
1912
 
1910
- def decorator(func: Callable) -> Callable:
1913
+ def decorator(func: F) -> F:
1911
1914
  if name in self._groups:
1912
1915
  raise ValueError(
1913
1916
  f'command "{name}" collides with an existing group'
@@ -2202,9 +2205,9 @@ class App:
2202
2205
  self._framework_fields[name] = cf
2203
2206
  return cf
2204
2207
 
2205
- def check(self, name: str):
2208
+ def check(self, name: str) -> Callable[[F], F]:
2206
2209
  """Decorator to register a check implementation."""
2207
- def decorator(fn):
2210
+ def decorator(fn: F) -> F:
2208
2211
  if not self._checks_enabled:
2209
2212
  raise ValueError(
2210
2213
  f'cannot register check "{name}": '
@@ -2508,10 +2511,10 @@ class App:
2508
2511
  hidden: bool = False,
2509
2512
  interactive: bool = False,
2510
2513
  config_fields: list[str] | None = None,
2511
- ) -> Callable:
2514
+ ) -> Callable[[F], F]:
2512
2515
  """Decorator to register a top-level command."""
2513
2516
 
2514
- def decorator(func: Callable) -> Callable:
2517
+ def decorator(func: F) -> F:
2515
2518
  cmd = _build_and_validate_command(
2516
2519
  name,
2517
2520
  help=help,
@@ -5114,10 +5117,10 @@ def flag(
5114
5117
  validate: Callable | None = None,
5115
5118
  repeatable: bool = False,
5116
5119
  unique: object = _MISSING,
5117
- ) -> Callable:
5120
+ ) -> Callable[[F], F]:
5118
5121
  """Module-level decorator to attach a Flag to a command handler."""
5119
5122
 
5120
- def decorator(func: Callable) -> Callable:
5123
+ def decorator(func: F) -> F:
5121
5124
  f = Flag(
5122
5125
  name=name,
5123
5126
  short=short,
@@ -5150,10 +5153,10 @@ def arg(
5150
5153
  variadic: bool = False,
5151
5154
  type: type = str,
5152
5155
  choices: list | None = None,
5153
- ) -> Callable:
5156
+ ) -> Callable[[F], F]:
5154
5157
  """Module-level decorator to attach an Arg to a command handler."""
5155
5158
 
5156
- def decorator(func: Callable) -> Callable:
5159
+ def decorator(func: F) -> F:
5157
5160
  a = Arg(
5158
5161
  name=name, help=help, required=required, default=default,
5159
5162
  variadic=variadic, type=type, choices=choices,
File without changes
@@ -232,7 +232,7 @@ wheels = [
232
232
 
233
233
  [[package]]
234
234
  name = "strictcli"
235
- version = "0.25.0"
235
+ version = "0.26.0"
236
236
  source = { editable = "." }
237
237
 
238
238
  [package.dev-dependencies]
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