wry 0.3.2.dev0__py3-none-any.whl → 0.3.2.dev2__py3-none-any.whl

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.
wry/__init__.py CHANGED
@@ -55,10 +55,27 @@ try:
55
55
  if __commit_id__:
56
56
  __version_full__ += f"+{__commit_id__}"
57
57
  except ImportError:
58
- # Fallback for development when _version.py is not generated
59
- __version__ = "0.0.0"
60
- __version_full__ = __version__
61
- __commit_id__ = None
58
+ # Fallback for development/editable installs
59
+ try:
60
+ # Try to get version dynamically for editable installs
61
+ from setuptools_scm import get_version
62
+
63
+ __version__ = get_version(root="../..", relative_to=__file__)
64
+ # Extract commit hash from version if present
65
+ if "+" in __version__ and "g" in __version__:
66
+ # Version like "0.0.2+g1234567" or "0.0.2.dev1+g1234567"
67
+ __commit_id__ = __version__.split("+")[-1].split(".")[0]
68
+ __version_full__ = __version__
69
+ else:
70
+ __commit_id__ = None
71
+ __version_full__ = __version__
72
+ # Clean version for consistency
73
+ __version__ = __version__.split("+")[0]
74
+ except Exception:
75
+ # Ultimate fallback
76
+ __version__ = "0.0.1-dev"
77
+ __version_full__ = __version__
78
+ __commit_id__ = None
62
79
 
63
80
  __author__ = "Tyler House"
64
81
  __email__ = "26489166+tahouse@users.noreply.github.com"
wry/_version.py CHANGED
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '0.3.2.dev0'
32
- __version_tuple__ = version_tuple = (0, 3, 2, 'dev0')
31
+ __version__ = version = '0.3.2.dev2'
32
+ __version_tuple__ = version_tuple = (0, 3, 2, 'dev2')
33
33
 
34
34
  __commit_id__ = commit_id = None
wry/auto_model.py CHANGED
@@ -138,7 +138,7 @@ def create_auto_model(name: str, fields: dict[str, Any], **kwargs: Any) -> type[
138
138
  # Use it with Click
139
139
  @click.command()
140
140
  @generate_click_parameters(MyConfig)
141
- def my_command(**kwargs):
141
+ def my_command(**kwargs: Any):
142
142
  config = MyConfig.from_click_context(**kwargs)
143
143
  print(f"Connecting to {config.host}:{config.port}")
144
144
  ```
wry/click_integration.py CHANGED
@@ -378,7 +378,9 @@ def generate_click_parameters(
378
378
 
379
379
  if field_type == AutoClickParameter.OPTION or field_type == AutoClickParameter.REQUIRED_OPTION:
380
380
  # Auto-generate Click option from Field info
381
- option_name = f"--{field_name.replace('_', '-')}"
381
+ # Use alias if available, otherwise use field name
382
+ name_for_option = field_info.alias if field_info.alias else field_name
383
+ option_name = f"--{name_for_option.replace('_', '-')}"
382
384
 
383
385
  # Check if field is required first (needed to decide on default handling)
384
386
  is_required = field_info.is_required() or field_type == AutoClickParameter.REQUIRED_OPTION
@@ -457,7 +459,9 @@ def generate_click_parameters(
457
459
 
458
460
  # Get the environment variable prefix
459
461
  env_prefix = getattr(model_class, "env_prefix", "DRYCLI_")
460
- env_var_name = f"{env_prefix}{field_name.upper()}"
462
+ # Use alias for env var name if available, otherwise use field name
463
+ name_for_env = field_info.alias if field_info.alias else field_name
464
+ env_var_name = f"{env_prefix}{name_for_env.upper()}"
461
465
 
462
466
  env_var_set = env_var_name in os.environ
463
467
 
@@ -508,8 +512,18 @@ def generate_click_parameters(
508
512
  elif base_type is not str: # Only specify type if not string (Click default)
509
513
  click_kwargs["type"] = base_type
510
514
 
511
- # Note: required=False to allow --config to replace arg
512
- arguments.append(click.argument(argument_name, **click_kwargs, required=False))
515
+ # Check if field has a default or if env var is set
516
+ import os
517
+
518
+ env_prefix = getattr(model_class, "env_prefix", "")
519
+ name_for_env = field_info.alias if field_info.alias else field_name
520
+ env_var_name = f"{env_prefix}{name_for_env.upper()}"
521
+ env_var_set = env_var_name in os.environ
522
+
523
+ # Mark as not required if field has default or env var is set
524
+ is_required_arg = field_info.is_required() and not env_var_set
525
+
526
+ arguments.append(click.argument(argument_name, **click_kwargs, required=is_required_arg))
513
527
 
514
528
  # Track argument description for docstring injection
515
529
  if field_info.description:
@@ -633,7 +647,7 @@ def extract_and_modify_argument_decorator(
633
647
  """
634
648
  # Default values - use a safe fallback
635
649
  param_decls: list[str] = ["argument"]
636
- attrs: dict[str, Any] = {"required": False}
650
+ attrs: dict[str, Any] = {} # Don't override required - let Click handle it
637
651
 
638
652
  # Try to extract from closure, but don't rely on it
639
653
  try:
@@ -658,7 +672,7 @@ def extract_and_modify_argument_decorator(
658
672
  for k, v in dict_contents.items():
659
673
  if isinstance(k, str):
660
674
  attrs[k] = v
661
- attrs["required"] = False # Always override to make optional
675
+ # Don't override required - preserve original setting
662
676
 
663
677
  # Handle Click parameter classes
664
678
  elif isinstance(contents, type):
wry/core/env_utils.py CHANGED
@@ -23,8 +23,10 @@ def get_env_var_names(model_class: type[T]) -> dict[str, str]:
23
23
  prefix = getattr(model_class, "env_prefix", "")
24
24
  env_vars = {}
25
25
 
26
- for field_name in model_class.model_fields:
27
- env_name = f"{prefix}{field_name.upper()}"
26
+ for field_name, field_info in model_class.model_fields.items():
27
+ # Use alias if available, otherwise use field name
28
+ name_for_env = field_info.alias if field_info.alias else field_name
29
+ env_name = f"{prefix}{name_for_env.upper()}"
28
30
  env_vars[field_name] = env_name
29
31
 
30
32
  return env_vars
@@ -46,9 +48,24 @@ def print_env_vars(model_class: type[T]) -> None:
46
48
  field_info = model_class.model_fields[field_name]
47
49
  field_type = type_hints.get(field_name, Any)
48
50
 
49
- # Format type for display
51
+ # Extract base type from Annotated types
52
+ from typing import Annotated, get_args, get_origin
53
+
54
+ # Handle Annotated[Type, ...] - extract the actual type
55
+ origin = get_origin(field_type)
56
+ if origin is not None and str(origin) == str(Annotated):
57
+ args = get_args(field_type)
58
+ if args:
59
+ # First arg is the actual type (might be a Union)
60
+ field_type = args[0]
61
+
62
+ # Format type for display (preserve Union types like str | None)
50
63
  type_str = getattr(field_type, "__name__", str(field_type))
51
64
 
65
+ # Clean up type string representation for display
66
+ if "typing." in type_str:
67
+ type_str = type_str.replace("typing.", "")
68
+
52
69
  # Check if field is required
53
70
  required = field_info.default is PydanticUndefined and field_info.default_factory is None
54
71
 
wry/core/model.py CHANGED
@@ -52,7 +52,7 @@ class WryModel(BaseModel):
52
52
  ```
53
53
  """
54
54
 
55
- model_config = ConfigDict(arbitrary_types_allowed=True)
55
+ model_config = ConfigDict(arbitrary_types_allowed=True, validate_by_name=True, validate_by_alias=True)
56
56
 
57
57
  # Class variables that should not trigger Pydantic warnings
58
58
  env_prefix: ClassVar[str] = ""
@@ -450,7 +450,7 @@ class WryModel(BaseModel):
450
450
  @click.command()
451
451
  @generate_click_parameters(MyConfig)
452
452
  @click.pass_context
453
- def my_command(ctx, **kwargs):
453
+ def my_command(ctx: click.Context, **kwargs: Any):
454
454
  config = MyConfig.from_click_context(ctx, **kwargs)
455
455
  print(f"Hello {config.name}")
456
456
  print(f"Source: {config.source.name}") # Accurate source
@@ -474,18 +474,41 @@ class WryModel(BaseModel):
474
474
  strict = cls.model_config.get("extra", "ignore") == "forbid"
475
475
 
476
476
  if strict:
477
- # Check for extra fields
478
- extra_fields = set(kwargs.keys()) - set(cls.model_fields.keys())
477
+ # Build alias set for validation
478
+ valid_aliases = {field_info.alias for field_info in cls.model_fields.values() if field_info.alias}
479
+ # Check for extra fields (allow both field names and aliases)
480
+ valid_keys = set(cls.model_fields.keys()) | valid_aliases
481
+ extra_fields = set(kwargs.keys()) - valid_keys
479
482
  if extra_fields:
480
483
  raise ValueError(f"Extra fields not allowed: {extra_fields}")
481
484
 
482
- # Filter kwargs to only include model fields
485
+ # Build alias-to-field mapping for handling Pydantic aliases
486
+ alias_to_field: dict[str, str] = {}
487
+ for field_name, field_info in cls.model_fields.items():
488
+ if field_info.alias:
489
+ alias_to_field[field_info.alias] = field_name
490
+
491
+ # Filter kwargs to include both field names AND aliases
483
492
  model_fields = set(cls.model_fields.keys())
484
- filtered_kwargs = {k: v for k, v in kwargs.items() if k in model_fields}
493
+ filtered_kwargs: dict[str, Any] = {}
494
+
495
+ for k, v in kwargs.items():
496
+ if k in model_fields:
497
+ # Direct field name match
498
+ filtered_kwargs[k] = v
499
+ elif k in alias_to_field:
500
+ # Alias match - map to field name
501
+ field_name = alias_to_field[k]
502
+ filtered_kwargs[field_name] = v
485
503
 
486
504
  # If kwargs are empty but ctx.params has values, use those (for test compatibility)
487
505
  if not filtered_kwargs and hasattr(ctx, "params") and ctx.params:
488
- filtered_kwargs = {k: v for k, v in ctx.params.items() if k in model_fields}
506
+ for k, v in ctx.params.items():
507
+ if k in model_fields:
508
+ filtered_kwargs[k] = v
509
+ elif k in alias_to_field:
510
+ field_name = alias_to_field[k]
511
+ filtered_kwargs[field_name] = v
489
512
 
490
513
  # Get JSON data from context if available
491
514
  json_data = ctx.obj.get("json_data", {}) if ctx.obj else {}
@@ -508,19 +531,33 @@ class WryModel(BaseModel):
508
531
  for field_name, value in env_values.items():
509
532
  config_data[field_name] = TrackedValue(value, ValueSource.ENV)
510
533
 
511
- # 3. Override with JSON values
512
- for field_name, value in json_data.items():
513
- if field_name in cls.model_fields:
534
+ # 3. Override with JSON values (handle both field names and aliases)
535
+ for key, value in json_data.items():
536
+ if key in cls.model_fields:
537
+ # Direct field name match
538
+ config_data[key] = TrackedValue(value, ValueSource.JSON)
539
+ elif key in alias_to_field:
540
+ # Alias match - map to field name
541
+ field_name = alias_to_field[key]
514
542
  config_data[field_name] = TrackedValue(value, ValueSource.JSON)
515
543
 
516
544
  # 4. Override with CLI values from kwargs (but respect Click's source info)
517
545
  for field_name in cls.model_fields:
518
546
  if field_name in filtered_kwargs:
519
547
  value = filtered_kwargs[field_name]
548
+ field_info = cls.model_fields[field_name]
520
549
 
521
550
  # Check Click's parameter source if available
551
+ # Try both alias and field name since Click might know it by either
522
552
  try:
523
- param_source = ctx.get_parameter_source(field_name)
553
+ # First try the alias if it exists (for explicit click.option with custom names)
554
+ param_name = field_info.alias if field_info.alias else field_name
555
+ param_source = ctx.get_parameter_source(param_name)
556
+
557
+ # If alias didn't work, try field name
558
+ if param_source is None and field_info.alias:
559
+ param_source = ctx.get_parameter_source(field_name)
560
+
524
561
  if param_source is not None:
525
562
  source_str = str(param_source)
526
563
  # Only override if it's actually from CLI
@@ -648,7 +685,7 @@ class WryModel(BaseModel):
648
685
  @click.command()
649
686
  @MyConfig.generate_click_parameters()
650
687
  @click.pass_context
651
- def cli(ctx, **kwargs):
688
+ def cli(ctx: click.Context, **kwargs: Any):
652
689
  config = MyConfig.from_click_context(ctx, **kwargs)
653
690
  ```
654
691
 
wry/multi_model.py CHANGED
@@ -39,7 +39,7 @@ def split_kwargs_by_model(
39
39
  @click.command()
40
40
  @generate_click_parameters(ServerConfig)
41
41
  @generate_click_parameters(DatabaseConfig)
42
- def cmd(**kwargs):
42
+ def cmd(**kwargs: Any):
43
43
  configs = split_kwargs_by_model(kwargs, ServerConfig, DatabaseConfig)
44
44
  server_config = ServerConfig(**configs[ServerConfig])
45
45
  db_config = DatabaseConfig(**configs[DatabaseConfig])
@@ -89,7 +89,7 @@ def create_models(
89
89
  @generate_click_parameters(ServerModel)
90
90
  @generate_click_parameters(DatabaseModel)
91
91
  @click.pass_context
92
- def cmd(ctx, **kwargs):
92
+ def cmd(ctx: click.Context, **kwargs: Any):
93
93
  models = create_models(ctx, kwargs, ServerModel, DatabaseModel)
94
94
  server = models[ServerModel]
95
95
  db = models[DatabaseModel]
@@ -127,7 +127,7 @@ def multi_model(*model_classes: type[BaseModel], strict: bool = False) -> Any:
127
127
  @click.command()
128
128
  @multi_model(ServerModel, DatabaseModel)
129
129
  @click.pass_context # Add this for source tracking
130
- def my_command(ctx, **kwargs):
130
+ def my_command(ctx: click.Context, **kwargs: Any):
131
131
  models = create_models(ctx, kwargs, ServerModel, DatabaseModel)
132
132
  server = models[ServerModel]
133
133
  database = models[DatabaseModel]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wry
3
- Version: 0.3.2.dev0
3
+ Version: 0.3.2.dev2
4
4
  Summary: Why Repeat Yourself? - Define your CLI once with Pydantic models
5
5
  Author-email: Tyler House <26489166+tahouse@users.noreply.github.com>
6
6
  License: MIT
@@ -90,7 +90,7 @@ class AppArgs(AutoWryModel):
90
90
 
91
91
  @click.command()
92
92
  @AppArgs.generate_click_parameters()
93
- def main(**kwargs):
93
+ def main(**kwargs: Any):
94
94
  """My simple CLI application."""
95
95
  # Create the model instance from kwargs
96
96
  config = AppArgs(**kwargs)
@@ -100,7 +100,10 @@ if __name__ == "__main__":
100
100
  main()
101
101
  ```
102
102
 
103
- **Note**: Currently, `generate_click_parameters()` passes individual parameters as kwargs to your function. You need to instantiate the model yourself. See the [Future Features](#future-features) section for a potential cleaner API.
103
+ **See comprehensive examples:**
104
+ - `examples/autowrymodel_comprehensive.py` - All AutoWryModel features including aliases
105
+ - `examples/wrymodel_comprehensive.py` - WryModel with source tracking
106
+ - `examples/multimodel_comprehensive.py` - Multi-model usage
104
107
 
105
108
  Run it:
106
109
 
@@ -129,7 +132,7 @@ wry tracks where each configuration value came from, supporting all four sources
129
132
  ```python
130
133
  @click.command()
131
134
  @AppArgs.generate_click_parameters()
132
- def main(**kwargs):
135
+ def main(**kwargs: Any):
133
136
  # Simple instantiation - no source tracking
134
137
  config = AppArgs(**kwargs)
135
138
  # Works fine, but config.source.* will always show CLI
@@ -143,7 +146,7 @@ To enable accurate source tracking, use `@click.pass_context` and `from_click_co
143
146
  @click.command()
144
147
  @AppArgs.generate_click_parameters()
145
148
  @click.pass_context
146
- def main(ctx, **kwargs):
149
+ def main(ctx: click.Context, **kwargs: Any):
147
150
  # Full source tracking with context
148
151
  config = AppArgs.from_click_context(ctx, **kwargs)
149
152
 
@@ -181,7 +184,8 @@ python examples/source_tracking_comprehensive.py --config examples/sample_config
181
184
  ```
182
185
 
183
186
  **Output shows source for each field:**
184
- ```
187
+
188
+ ```text
185
189
  host = json-server.com [from JSON]
186
190
  port = 3000 [from CLI] ← CLI overrides JSON
187
191
  debug = True [from ENV]
@@ -257,7 +261,7 @@ class DatabaseArgs(WryModel):
257
261
  @click.command()
258
262
  @multi_model(ServerConfig, DatabaseConfig)
259
263
  @click.pass_context
260
- def serve(ctx, **kwargs):
264
+ def serve(ctx: click.Context, **kwargs: Any):
261
265
  # Create model instances
262
266
  configs = create_models(ctx, kwargs, ServerConfig, DatabaseConfig)
263
267
  server = configs[ServerConfig]
@@ -330,7 +334,7 @@ class AppArgs(WryModel):
330
334
  @click.command()
331
335
  @multi_model(DatabaseConfig, AppArgs)
332
336
  @click.pass_context
333
- def main(ctx, **kwargs):
337
+ def main(ctx: click.Context, **kwargs: Any):
334
338
  # Automatically splits kwargs between models
335
339
  configs = create_models(ctx, kwargs, DatabaseConfig, AppArgs)
336
340
 
@@ -349,7 +353,7 @@ By default, `generate_click_parameters` runs in strict mode to prevent common mi
349
353
  @click.command()
350
354
  @Config.generate_click_parameters() # strict=True by default
351
355
  @Config.generate_click_parameters() # ERROR: Duplicate decorator detected!
352
- def main(**kwargs):
356
+ def main(**kwargs: Any):
353
357
  pass
354
358
  ```
355
359
 
@@ -391,6 +395,76 @@ class Config(WryModel):
391
395
  )
392
396
  ```
393
397
 
398
+ ### Using Pydantic Aliases for Custom CLI Names
399
+
400
+ **New in v0.3.2+**: Pydantic field aliases automatically control the generated CLI option names and environment variable names!
401
+
402
+ This allows you to have concise Python field names while exposing descriptive CLI options:
403
+
404
+ ```python
405
+ from pydantic import Field
406
+ from wry import AutoWryModel
407
+
408
+ class DatabaseConfig(AutoWryModel):
409
+ env_prefix = "DB_"
410
+
411
+ # Concise Python field name: db_url
412
+ # Alias controls CLI option: --database-url
413
+ # Environment variable: DB_DATABASE_URL
414
+ db_url: str = Field(
415
+ alias="database_url",
416
+ default="sqlite:///app.db",
417
+ description="Database connection URL"
418
+ )
419
+
420
+ pool_size: int = Field(
421
+ alias="connection_pool_size",
422
+ default=5,
423
+ description="Maximum connection pool size"
424
+ )
425
+ ```
426
+
427
+ **How it works:**
428
+
429
+ - **Python field**: `db_url` (concise, easy to type)
430
+ - **CLI option**: `--database-url` (descriptive, user-friendly)
431
+ - **Environment variable**: `DB_DATABASE_URL` (consistent with CLI)
432
+ - **JSON config**: Accepts both `db_url` and `database_url`
433
+
434
+ **Requirements:**
435
+
436
+ - **None!** `WryModel` automatically sets `validate_by_name=True` and `validate_by_alias=True`
437
+ - This tells Pydantic to accept both field names and aliases
438
+ - No need to configure anything - it just works!
439
+ - Aliases automatically control option names, env var names, and help text
440
+
441
+ **Full support (v0.3.2+):**
442
+
443
+ - ✅ Aliases automatically control auto-generated option names
444
+ - ✅ Environment variables use alias names (consistent with CLI)
445
+ - ✅ Source tracking works correctly
446
+ - ✅ JSON config accepts both field names and aliases
447
+
448
+ **Why this feature exists:**
449
+
450
+ Before v0.3.2, if you wanted custom CLI option names, you had to use explicit `click.option()` decorators for every field. The alias feature eliminates this boilerplate for the common case where you just want different names.
451
+
452
+ **For advanced use cases** (short options, custom Click types):
453
+
454
+ You can still combine aliases with explicit `click.option()` decorators:
455
+
456
+ ```python
457
+ class Config(AutoWryModel):
458
+ # Explicit click.option for short option support
459
+ verbose: Annotated[int, click.option("-v", "--verbose", count=True)] = Field(default=0)
460
+ ```
461
+
462
+ See `examples/autowrymodel_comprehensive.py` for examples of explicit Click decorators.
463
+
464
+ **See also:**
465
+ - `examples/autowrymodel_comprehensive.py` - Complete AutoWryModel example with aliases
466
+ - `examples/wrymodel_comprehensive.py` - WryModel with aliases and source tracking
467
+
394
468
  ## Development
395
469
 
396
470
  ### Prerequisites
@@ -0,0 +1,18 @@
1
+ wry/__init__.py,sha256=BI1sXr3d2q6wm4LdFSjgpatETyhv4RruVKN3auO7WH8,4203
2
+ wry/_version.py,sha256=ZmNNN5KY7zagAfK_ReGsNVBfLtZ1xBk0-Q-QqXvizhI,717
3
+ wry/auto_model.py,sha256=TC3I8r00Yv870bG3zZ5qa2Iet1rSCZ1cRWSkZSvZhco,6932
4
+ wry/click_integration.py,sha256=vo8Ajv-nD-YvTbBQsdW2txhTrUc_pdGXIghjswNtZaU,32554
5
+ wry/help_system.py,sha256=zSryjsOXAWz9HyCpybwuFWrlaP9gwbMNIexuAWTcCns,5731
6
+ wry/multi_model.py,sha256=-72Eder564guz5nwFW3te5MRVWbBmGUI8V6ig1axgtw,6023
7
+ wry/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ wry/core/__init__.py,sha256=24Mu7qGzaFde8tAnyJOPPkD1ScZq-iSXNlDdAWSw_mg,894
9
+ wry/core/accessors.py,sha256=Kn5dziklgcMWClOjbeJSwWNHOCQkpAWV9b1uH9ZGUPI,3708
10
+ wry/core/env_utils.py,sha256=_yZDUPlzjIdyk-BbsX-sBfLCLmRsUlk8_la4zkg5mkI,4838
11
+ wry/core/field_utils.py,sha256=nDFkbzfIf7mNJm6T5BuqcZ1mYUVIKinXfw77xpK_FK0,4134
12
+ wry/core/model.py,sha256=tP0dyt0rsCDMxM9ULMLhHcaoOF3s9xd96iMkGbQ4uFE,27056
13
+ wry/core/sources.py,sha256=4uboTc23f_CXiD3ql767-TvrGfe6xXN5NhXEIfNxD2U,1171
14
+ wry-0.3.2.dev2.dist-info/licenses/LICENSE,sha256=0EfVapSdYZQRHpfqCVAO5OeyT2xMu8cxPKaRkWWdb2g,1068
15
+ wry-0.3.2.dev2.dist-info/METADATA,sha256=E_0Sux0uGD5MC0BExttbkPT0a9P8SMAO_PD0j6aaPE0,24030
16
+ wry-0.3.2.dev2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
17
+ wry-0.3.2.dev2.dist-info/top_level.txt,sha256=ytpYWd5uCeQpPCdTYaB1Vjzp4C5em03WpUKn3SiDDY8,4
18
+ wry-0.3.2.dev2.dist-info/RECORD,,
@@ -1,18 +0,0 @@
1
- wry/__init__.py,sha256=r42j1WbOhUjsB3lXyhX7H1vZATs2glLoeoxw69uAB_U,3496
2
- wry/_version.py,sha256=F2rbIVsiqBoq-pirIKA3f5y7JD5arTtBiGUAlm59LGg,717
3
- wry/auto_model.py,sha256=YY71mkYr46P3O4cjY8fN0AmothtPcvsDqvk1eQM4VbE,6927
4
- wry/click_integration.py,sha256=XDeNDHGh99Now77vrGMo151xp0KjWZYm7nTuIHh6CU4,31775
5
- wry/help_system.py,sha256=zSryjsOXAWz9HyCpybwuFWrlaP9gwbMNIexuAWTcCns,5731
6
- wry/multi_model.py,sha256=f6Hf5NMfIZtdXc6t00iTPtUEbiWnQZiC7NKVchQ7QU4,5978
7
- wry/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
- wry/core/__init__.py,sha256=24Mu7qGzaFde8tAnyJOPPkD1ScZq-iSXNlDdAWSw_mg,894
9
- wry/core/accessors.py,sha256=Kn5dziklgcMWClOjbeJSwWNHOCQkpAWV9b1uH9ZGUPI,3708
10
- wry/core/env_utils.py,sha256=8TCgVPr7n5-YNThEVC5MvAG6qB0TW5MJkO1YT5yHZYI,4051
11
- wry/core/field_utils.py,sha256=nDFkbzfIf7mNJm6T5BuqcZ1mYUVIKinXfw77xpK_FK0,4134
12
- wry/core/model.py,sha256=CP0zElttAqpFHj2yD8O8CgMSm9VpSAT46nXcnCHw38U,25150
13
- wry/core/sources.py,sha256=4uboTc23f_CXiD3ql767-TvrGfe6xXN5NhXEIfNxD2U,1171
14
- wry-0.3.2.dev0.dist-info/licenses/LICENSE,sha256=0EfVapSdYZQRHpfqCVAO5OeyT2xMu8cxPKaRkWWdb2g,1068
15
- wry-0.3.2.dev0.dist-info/METADATA,sha256=8EJZPjxs48klq0rrJpTOoY00zcU7T8kqHcPMpKhs6_U,21429
16
- wry-0.3.2.dev0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
17
- wry-0.3.2.dev0.dist-info/top_level.txt,sha256=ytpYWd5uCeQpPCdTYaB1Vjzp4C5em03WpUKn3SiDDY8,4
18
- wry-0.3.2.dev0.dist-info/RECORD,,