dataclass-args 1.4.0__tar.gz → 1.4.2__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 (41) hide show
  1. {dataclass_args-1.4.0 → dataclass_args-1.4.2}/PKG-INFO +1 -1
  2. {dataclass_args-1.4.0 → dataclass_args-1.4.2}/dataclass_args/__init__.py +1 -1
  3. {dataclass_args-1.4.0 → dataclass_args-1.4.2}/dataclass_args/annotations.py +71 -199
  4. {dataclass_args-1.4.0 → dataclass_args-1.4.2}/dataclass_args/builder.py +189 -436
  5. dataclass_args-1.4.2/dataclass_args/config_applicator.py +142 -0
  6. dataclass_args-1.4.2/dataclass_args/nested_processor.py +347 -0
  7. dataclass_args-1.4.2/dataclass_args/type_inspector.py +196 -0
  8. {dataclass_args-1.4.0 → dataclass_args-1.4.2}/dataclass_args.egg-info/PKG-INFO +1 -1
  9. {dataclass_args-1.4.0 → dataclass_args-1.4.2}/dataclass_args.egg-info/SOURCES.txt +8 -0
  10. {dataclass_args-1.4.0 → dataclass_args-1.4.2}/pyproject.toml +1 -1
  11. dataclass_args-1.4.2/tests/test_collisions.py +183 -0
  12. dataclass_args-1.4.2/tests/test_config_applicator.py +202 -0
  13. dataclass_args-1.4.2/tests/test_nested_dict_override.py +240 -0
  14. dataclass_args-1.4.2/tests/test_nested_property_override_bug.py +176 -0
  15. dataclass_args-1.4.2/tests/test_type_inspector.py +168 -0
  16. {dataclass_args-1.4.0 → dataclass_args-1.4.2}/LICENSE +0 -0
  17. {dataclass_args-1.4.0 → dataclass_args-1.4.2}/README.md +0 -0
  18. {dataclass_args-1.4.0 → dataclass_args-1.4.2}/dataclass_args/append_action.py +0 -0
  19. {dataclass_args-1.4.0 → dataclass_args-1.4.2}/dataclass_args/exceptions.py +0 -0
  20. {dataclass_args-1.4.0 → dataclass_args-1.4.2}/dataclass_args/file_loading.py +0 -0
  21. {dataclass_args-1.4.0 → dataclass_args-1.4.2}/dataclass_args/formatter.py +0 -0
  22. {dataclass_args-1.4.0 → dataclass_args-1.4.2}/dataclass_args/utils.py +0 -0
  23. {dataclass_args-1.4.0 → dataclass_args-1.4.2}/dataclass_args.egg-info/dependency_links.txt +0 -0
  24. {dataclass_args-1.4.0 → dataclass_args-1.4.2}/dataclass_args.egg-info/requires.txt +0 -0
  25. {dataclass_args-1.4.0 → dataclass_args-1.4.2}/dataclass_args.egg-info/top_level.txt +0 -0
  26. {dataclass_args-1.4.0 → dataclass_args-1.4.2}/setup.cfg +0 -0
  27. {dataclass_args-1.4.0 → dataclass_args-1.4.2}/tests/test_annotations.py +0 -0
  28. {dataclass_args-1.4.0 → dataclass_args-1.4.2}/tests/test_basic.py +0 -0
  29. {dataclass_args-1.4.0 → dataclass_args-1.4.2}/tests/test_boolean_base_configs.py +0 -0
  30. {dataclass_args-1.4.0 → dataclass_args-1.4.2}/tests/test_boolean_flags.py +0 -0
  31. {dataclass_args-1.4.0 → dataclass_args-1.4.2}/tests/test_builder_advanced.py +0 -0
  32. {dataclass_args-1.4.0 → dataclass_args-1.4.2}/tests/test_cli_append.py +0 -0
  33. {dataclass_args-1.4.0 → dataclass_args-1.4.2}/tests/test_cli_choices.py +0 -0
  34. {dataclass_args-1.4.0 → dataclass_args-1.4.2}/tests/test_cli_nested.py +0 -0
  35. {dataclass_args-1.4.0 → dataclass_args-1.4.2}/tests/test_cli_short.py +0 -0
  36. {dataclass_args-1.4.0 → dataclass_args-1.4.2}/tests/test_combine_annotations.py +0 -0
  37. {dataclass_args-1.4.0 → dataclass_args-1.4.2}/tests/test_config_merging_simple.py +0 -0
  38. {dataclass_args-1.4.0 → dataclass_args-1.4.2}/tests/test_description.py +0 -0
  39. {dataclass_args-1.4.0 → dataclass_args-1.4.2}/tests/test_file_loading.py +0 -0
  40. {dataclass_args-1.4.0 → dataclass_args-1.4.2}/tests/test_positional.py +0 -0
  41. {dataclass_args-1.4.0 → dataclass_args-1.4.2}/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dataclass-args
3
- Version: 1.4.0
3
+ Version: 1.4.2
4
4
  Summary: Zero-boilerplate CLI generation from Python dataclasses with advanced type support and file loading
5
5
  Author-email: Martin Bartlett <martin.j.bartlett@gmail.com>
6
6
  License: MIT
@@ -91,7 +91,7 @@ from .exceptions import ConfigBuilderError, ConfigurationError, FileLoadingError
91
91
  from .file_loading import is_file_loadable_value, load_file_content
92
92
  from .utils import load_structured_file
93
93
 
94
- __version__ = "1.4.0"
94
+ __version__ = "1.4.2"
95
95
 
96
96
  __all__ = [
97
97
  # Main API
@@ -8,6 +8,47 @@ be excluded from CLI argument generation or have special behaviors.
8
8
  from dataclasses import field
9
9
  from typing import Any, Dict, List, Optional
10
10
 
11
+ # ============================================================================
12
+ # Unified Metadata Accessor
13
+ # ============================================================================
14
+
15
+
16
+ class _FieldMetadata:
17
+ """
18
+ Unified accessor for field metadata.
19
+
20
+ Internal class that eliminates duplication across all get_cli_* and is_cli_* functions.
21
+ All these functions share the same pattern: extract field_obj, check metadata, return value.
22
+ """
23
+
24
+ @staticmethod
25
+ def get(field_info: Dict[str, Any], key: str, default: Any = None) -> Any:
26
+ """
27
+ Get metadata value from field_info dict.
28
+
29
+ Args:
30
+ field_info: Field information dictionary from GenericConfigBuilder
31
+ key: Metadata key to retrieve
32
+ default: Default value if key not found
33
+
34
+ Returns:
35
+ Metadata value or default
36
+ """
37
+ field_obj = field_info.get("field_obj")
38
+ if field_obj and hasattr(field_obj, "metadata"):
39
+ return field_obj.metadata.get(key, default)
40
+ return default
41
+
42
+ @staticmethod
43
+ def get_bool(field_info: Dict[str, Any], key: str) -> bool:
44
+ """Get boolean metadata value (defaults to False)."""
45
+ return _FieldMetadata.get(field_info, key, False)
46
+
47
+
48
+ # ============================================================================
49
+ # CLI Annotation Decorators
50
+ # ============================================================================
51
+
11
52
 
12
53
  def cli_exclude(**kwargs) -> Any:
13
54
  """
@@ -595,261 +636,92 @@ def cli_positional(
595
636
 
596
637
 
597
638
  def is_cli_excluded(field_info: Dict[str, Any]) -> bool:
598
- """
599
- Check if a field should be excluded from CLI arguments.
600
-
601
- Args:
602
- field_info: Field information dictionary from GenericConfigBuilder
603
-
604
- Returns:
605
- True if field should be excluded from CLI
606
- """
607
- # Check for explicit CLI exclusion metadata
608
- field_obj = field_info.get("field_obj")
609
- if field_obj and hasattr(field_obj, "metadata"):
610
- return field_obj.metadata.get("cli_exclude", False)
611
-
612
- return False
639
+ """Check if a field should be excluded from CLI arguments."""
640
+ return _FieldMetadata.get_bool(field_info, "cli_exclude")
613
641
 
614
642
 
615
643
  def is_cli_included(field_info: Dict[str, Any]) -> bool:
616
- """
617
- Check if a field is explicitly marked for CLI inclusion.
618
-
619
- Args:
620
- field_info: Field information dictionary from GenericConfigBuilder
621
-
622
- Returns:
623
- True if field is explicitly marked for CLI inclusion
624
- """
625
- field_obj = field_info.get("field_obj")
626
- if field_obj and hasattr(field_obj, "metadata"):
627
- return field_obj.metadata.get("cli_include", False)
628
-
629
- return False
644
+ """Check if a field is explicitly marked for CLI inclusion."""
645
+ return _FieldMetadata.get_bool(field_info, "cli_include")
630
646
 
631
647
 
632
648
  def is_cli_nested(field_info: Dict[str, Any]) -> bool:
633
- """
634
- Check if a field is marked for nested dataclass flattening.
635
-
636
- Args:
637
- field_info: Field information dictionary from GenericConfigBuilder
638
-
639
- Returns:
640
- True if field should be flattened as nested dataclass
641
- """
642
- field_obj = field_info.get("field_obj")
643
- if field_obj and hasattr(field_obj, "metadata"):
644
- return field_obj.metadata.get("cli_nested", False)
645
- return False
649
+ """Check if a field is marked for nested dataclass flattening."""
650
+ return _FieldMetadata.get_bool(field_info, "cli_nested")
646
651
 
647
652
 
648
653
  def get_cli_nested_prefix(field_info: Dict[str, Any]) -> Optional[str]:
649
654
  """
650
655
  Get prefix for nested dataclass CLI arguments.
651
656
 
652
- Args:
653
- field_info: Field information dictionary from GenericConfigBuilder
654
-
655
657
  Returns:
656
- Prefix string if specified:
657
658
  - "" (empty string): No prefix
658
659
  - "custom": Custom prefix
659
660
  - None: Auto-prefix with field name (default)
660
661
  """
661
- field_obj = field_info.get("field_obj")
662
- if field_obj and hasattr(field_obj, "metadata"):
663
- return field_obj.metadata.get("cli_nested_prefix")
664
- return None
662
+ return _FieldMetadata.get(field_info, "cli_nested_prefix")
665
663
 
666
664
 
667
665
  def is_cli_file_loadable(field_info: Dict[str, Any]) -> bool:
668
- """
669
- Check if a field is marked as file-loadable via '@' prefix.
670
-
671
- Args:
672
- field_info: Field information dictionary from GenericConfigBuilder
673
-
674
- Returns:
675
- True if field supports file loading via '@' prefix
676
- """
677
- field_obj = field_info.get("field_obj")
678
- if field_obj and hasattr(field_obj, "metadata"):
679
- return field_obj.metadata.get("cli_file_loadable", False)
680
-
681
- return False
666
+ """Check if a field is marked as file-loadable via '@' prefix."""
667
+ return _FieldMetadata.get_bool(field_info, "cli_file_loadable")
682
668
 
683
669
 
684
670
  def is_cli_append(field_info: Dict[str, Any]) -> bool:
685
- """
686
- Check if a field uses append action for repeated options.
687
-
688
- Args:
689
- field_info: Field information dictionary from GenericConfigBuilder
690
-
691
- Returns:
692
- True if field uses append action
693
- """
694
- field_obj = field_info.get("field_obj")
695
- if field_obj and hasattr(field_obj, "metadata"):
696
- return field_obj.metadata.get("cli_append", False)
697
- return False
671
+ """Check if a field uses append action for repeated options."""
672
+ return _FieldMetadata.get_bool(field_info, "cli_append")
698
673
 
699
674
 
700
675
  def is_cli_positional(field_info: Dict[str, Any]) -> bool:
701
- """
702
- Check if a field is marked as a positional CLI argument.
703
-
704
- Args:
705
- field_info: Field information dictionary from GenericConfigBuilder
706
-
707
- Returns:
708
- True if field is a positional argument
709
- """
710
- field_obj = field_info.get("field_obj")
711
- if field_obj and hasattr(field_obj, "metadata"):
712
- return field_obj.metadata.get("cli_positional", False)
713
- return False
676
+ """Check if a field is marked as a positional CLI argument."""
677
+ return _FieldMetadata.get_bool(field_info, "cli_positional")
714
678
 
715
679
 
716
680
  def get_cli_short(field_info: Dict[str, Any]) -> Optional[str]:
717
- """
718
- Get short option character for a CLI argument.
719
-
720
- Args:
721
- field_info: Field information dictionary from GenericConfigBuilder
722
-
723
- Returns:
724
- Short option character if available, otherwise None
725
- """
726
- field_obj = field_info.get("field_obj")
727
- if field_obj and hasattr(field_obj, "metadata"):
728
- return field_obj.metadata.get("cli_short")
729
- return None
681
+ """Get short option character for a CLI argument."""
682
+ return _FieldMetadata.get(field_info, "cli_short")
730
683
 
731
684
 
732
685
  def get_cli_choices(field_info: Dict[str, Any]) -> Optional[List[Any]]:
733
- """
734
- Get restricted choices for a CLI argument.
735
-
736
- Args:
737
- field_info: Field information dictionary from GenericConfigBuilder
738
-
739
- Returns:
740
- List of valid choices if available, otherwise None
741
- """
742
- field_obj = field_info.get("field_obj")
743
- if field_obj and hasattr(field_obj, "metadata"):
744
- return field_obj.metadata.get("cli_choices")
745
- return None
686
+ """Get restricted choices for a CLI argument."""
687
+ return _FieldMetadata.get(field_info, "cli_choices")
746
688
 
747
689
 
748
690
  def get_cli_append_nargs(field_info: Dict[str, Any]) -> Optional[Any]:
749
- """
750
- Get nargs value for an append CLI argument.
751
-
752
- Args:
753
- field_info: Field information dictionary from GenericConfigBuilder
754
-
755
- Returns:
756
- nargs value if specified, otherwise None (meaning exactly one per occurrence)
757
- """
758
- field_obj = field_info.get("field_obj")
759
- if field_obj and hasattr(field_obj, "metadata"):
760
- return field_obj.metadata.get("cli_append_nargs")
761
- return None
691
+ """Get nargs value for an append CLI argument."""
692
+ return _FieldMetadata.get(field_info, "cli_append_nargs")
762
693
 
763
694
 
764
695
  def get_cli_append_metavar(field_info: Dict[str, Any]) -> Optional[str]:
765
- """
766
- Get metavar for an append CLI argument.
767
-
768
- Args:
769
- field_info: Field information dictionary from GenericConfigBuilder
770
-
771
- Returns:
772
- Metavar string if specified, otherwise None
773
- """
774
- field_obj = field_info.get("field_obj")
775
- if field_obj and hasattr(field_obj, "metadata"):
776
- return field_obj.metadata.get("cli_append_metavar")
777
- return None
696
+ """Get metavar for an append CLI argument."""
697
+ return _FieldMetadata.get(field_info, "cli_append_metavar")
778
698
 
779
699
 
780
700
  def get_cli_append_min_args(field_info: Dict[str, Any]) -> Optional[int]:
781
- """
782
- Get minimum arguments for an append CLI argument.
783
-
784
- Args:
785
- field_info: Field information dictionary from GenericConfigBuilder
786
-
787
- Returns:
788
- Minimum argument count if specified, otherwise None
789
- """
790
- field_obj = field_info.get("field_obj")
791
- if field_obj and hasattr(field_obj, "metadata"):
792
- return field_obj.metadata.get("cli_append_min_args")
793
- return None
701
+ """Get minimum arguments for an append CLI argument."""
702
+ return _FieldMetadata.get(field_info, "cli_append_min_args")
794
703
 
795
704
 
796
705
  def get_cli_append_max_args(field_info: Dict[str, Any]) -> Optional[int]:
797
- """
798
- Get maximum arguments for an append CLI argument.
799
-
800
- Args:
801
- field_info: Field information dictionary from GenericConfigBuilder
802
-
803
- Returns:
804
- Maximum argument count if specified, otherwise None
805
- """
806
- field_obj = field_info.get("field_obj")
807
- if field_obj and hasattr(field_obj, "metadata"):
808
- return field_obj.metadata.get("cli_append_max_args")
809
- return None
706
+ """Get maximum arguments for an append CLI argument."""
707
+ return _FieldMetadata.get(field_info, "cli_append_max_args")
810
708
 
811
709
 
812
710
  def get_cli_positional_nargs(field_info: Dict[str, Any]) -> Optional[Any]:
813
- """
814
- Get nargs value for a positional CLI argument.
815
-
816
- Args:
817
- field_info: Field information dictionary from GenericConfigBuilder
818
-
819
- Returns:
820
- nargs value if specified, otherwise None (meaning exactly one)
821
- """
822
- field_obj = field_info.get("field_obj")
823
- if field_obj and hasattr(field_obj, "metadata"):
824
- return field_obj.metadata.get("cli_positional_nargs")
825
- return None
711
+ """Get nargs value for a positional CLI argument."""
712
+ return _FieldMetadata.get(field_info, "cli_positional_nargs")
826
713
 
827
714
 
828
715
  def get_cli_positional_metavar(field_info: Dict[str, Any]) -> Optional[str]:
829
- """
830
- Get metavar for a positional CLI argument.
831
-
832
- Args:
833
- field_info: Field information dictionary from GenericConfigBuilder
834
-
835
- Returns:
836
- Metavar string if specified, otherwise None
837
- """
838
- field_obj = field_info.get("field_obj")
839
- if field_obj and hasattr(field_obj, "metadata"):
840
- return field_obj.metadata.get("cli_positional_metavar")
841
- return None
716
+ """Get metavar for a positional CLI argument."""
717
+ return _FieldMetadata.get(field_info, "cli_positional_metavar")
842
718
 
843
719
 
844
720
  def get_cli_help(field_info: Dict[str, Any]) -> str:
845
721
  """
846
722
  Get custom help text for a CLI argument.
847
723
 
848
- Args:
849
- field_info: Field information dictionary from GenericConfigBuilder
850
-
851
- Returns:
852
- Custom help text if available, otherwise empty string
724
+ Automatically adds file-loadable hint if applicable.
853
725
  """
854
726
  field_obj = field_info.get("field_obj")
855
727
  if field_obj and hasattr(field_obj, "metadata"):