wry 0.2.1__tar.gz → 0.2.2.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wry
3
- Version: 0.2.1
3
+ Version: 0.2.2.dev1
4
4
  Summary: Why Repeat Yourself? - Define your CLI once with Pydantic models
5
5
  License: MIT
6
6
  License-File: LICENSE
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "wry"
3
- version = "0.2.1" # Placeholder - actual version comes from git tags via poetry-dynamic-versioning
3
+ version = "0.2.2.dev1" # Placeholder - actual version comes from git tags via poetry-dynamic-versioning
4
4
  description = "Why Repeat Yourself? - Define your CLI once with Pydantic models"
5
5
  authors = ["Tyler House <26489166+tahouse@users.noreply.github.com>"]
6
6
  readme = "README.md"
@@ -1,8 +1,8 @@
1
1
  # file generated by poetry-dynamic-versioning
2
2
  from typing import TYPE_CHECKING
3
3
 
4
- __version__: str = "0.2.1" # This will be replaced during build
5
- __version_tuple__: tuple[int, ...] = (0, 2, 1) # This will be replaced during build
4
+ __version__: str = "0.2.2.dev1" # This will be replaced during build
5
+ __version_tuple__: tuple[int, ...] = (0, 2, 2, "dev1") # This will be replaced during build
6
6
  __commit_id__: str | None = None # This will be replaced during build
7
7
 
8
8
  # For compatibility with setuptools-scm test expectations
@@ -380,14 +380,22 @@ def generate_click_parameters(
380
380
  # Auto-generate Click option from Field info
381
381
  option_name = f"--{field_name.replace('_', '-')}"
382
382
 
383
+ # Check if field is required first (needed to decide on default handling)
384
+ is_required = field_info.is_required() or field_type == AutoClickParameter.REQUIRED_OPTION
385
+
383
386
  click_kwargs: dict[str, Any] = {
384
- "default": (field_info.default if field_info.default is not PydanticUndefined else None),
385
387
  "help": field_info.description or f"{field_name.replace('_', ' ').title()}",
386
388
  "show_default": True,
387
389
  }
388
390
 
389
- # Check if field is required
390
- is_required = field_info.is_required() or field_type == AutoClickParameter.REQUIRED_OPTION
391
+ # Only set default if field has one, or if field is not required
392
+ # For required fields without a default, we must NOT set default=None
393
+ # or Click will think there IS a default and won't enforce the requirement
394
+ if field_info.default is not PydanticUndefined:
395
+ click_kwargs["default"] = field_info.default
396
+ elif not is_required:
397
+ # Optional field without explicit default gets None
398
+ click_kwargs["default"] = None
391
399
 
392
400
  # Determine Click type from annotation
393
401
  base_type = get_args(annotation)[0]
@@ -740,23 +748,15 @@ def eager_json_config(ctx: click.Context, param: click.Parameter, value: Any) ->
740
748
  with open(value) as f:
741
749
  json_data = json.load(f)
742
750
 
743
- # Pre-fill missing required parameters from JSON
744
- # This prevents Click from throwing MissingParameter errors
745
- for json_key, json_value in json_data.items():
746
- param_key = json_key.replace("-", "_") # Handle kebab-case
747
- if param_key not in ctx.params:
748
- ctx.params[param_key] = json_value
749
-
750
- # Store for later merging
751
+ # Store JSON data for later merging in from_click_context
751
752
  ctx.ensure_object(dict)["json_data"] = json_data
752
753
 
753
- # Also modify Click argument requirements if they exist
754
- # This allows JSON to satisfy required arguments
754
+ # Mark parameters from JSON as not required
755
+ # This allows JSON to satisfy required arguments without modifying defaults
755
756
  if hasattr(ctx, "command") and ctx.command:
756
757
  for p in ctx.command.params:
757
758
  if (isinstance(p, click.Argument) or isinstance(p, click.Option)) and p.name in json_data:
758
759
  p.required = False
759
- p.default = json_data[p.name]
760
760
 
761
761
  return value
762
762
 
@@ -66,7 +66,7 @@ class WryModel(BaseModel):
66
66
  if "_value_sources" not in data:
67
67
  # Only initialize sources if not already provided
68
68
  self._value_sources = {}
69
- for field_name in self.model_fields:
69
+ for field_name in self.__class__.model_fields:
70
70
  # Mark non-default values as programmatic
71
71
  if field_name in data:
72
72
  self._value_sources[field_name] = ValueSource.CLI
@@ -526,6 +526,7 @@ class WryModel(BaseModel):
526
526
  # Only override if it's actually from CLI
527
527
  if "COMMANDLINE" in source_str:
528
528
  config_data[field_name] = TrackedValue(value, ValueSource.CLI)
529
+ continue
529
530
  # Skip if it's DEFAULT or ENVIRONMENT - already handled above
530
531
  continue
531
532
  except (AttributeError, RuntimeError):
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