@@ -41,10 +41,10 @@ def __init_subclass__(*_args, **_kwargs):
41
41
42
42
43
43
try :
44
- ExceptionGroup = __builtins__ . ExceptionGroup # type: ignore[attr-defined]
45
- except AttributeError :
44
+ ExceptionGroup
45
+ except NameError : # pragma: no cover
46
46
47
- class ExceptionGroup (Exception ): # type: ignore[no-redef] # noqa: N818
47
+ class ExceptionGroup (Exception ): # noqa: N818
48
48
"""A minimal implementation of :external:exc:`ExceptionGroup` from Python 3.11.
49
49
50
50
If :external:exc:`ExceptionGroup` is already defined by Python itself,
@@ -61,6 +61,9 @@ def __init__(self, message: str, exceptions: List[Exception]) -> None:
61
61
def __repr__ (self ) -> str :
62
62
return f"{ self .__class__ .__name__ } ({ self .message !r} , { self .exceptions !r} )"
63
63
64
+ else : # pragma: no cover
65
+ ExceptionGroup = ExceptionGroup
66
+
64
67
65
68
class InvalidMetadata (ValueError ):
66
69
"""A metadata field contains invalid data."""
@@ -505,24 +508,19 @@ def __get__(self, instance: "Metadata", _owner: Type["Metadata"]) -> T:
505
508
# No need to check the cache as attribute lookup will resolve into the
506
509
# instance's __dict__ before __get__ is called.
507
510
cache = instance .__dict__
508
- try :
509
- value = instance ._raw [self .name ] # type: ignore[literal-required]
510
- except KeyError :
511
- if self .name in _STRING_FIELDS :
512
- value = ""
513
- elif self .name in _LIST_FIELDS :
514
- value = []
515
- elif self .name in _DICT_FIELDS :
516
- value = {}
517
- else : # pragma: no cover
518
- assert False
511
+ value = instance ._raw .get (self .name )
519
512
520
- try :
521
- converter : Callable [[Any ], T ] = getattr (self , f"_process_{ self .name } " )
522
- except AttributeError :
523
- pass
524
- else :
525
- value = converter (value )
513
+ # To make the _process_* methods easier, we'll check if the value is None
514
+ # and if this field is NOT a required attribute, and if both of those
515
+ # things are true, we'll skip the the converter. This will mean that the
516
+ # converters never have to deal with the None union.
517
+ if self .name in _REQUIRED_ATTRS or value is not None :
518
+ try :
519
+ converter : Callable [[Any ], T ] = getattr (self , f"_process_{ self .name } " )
520
+ except AttributeError :
521
+ pass
522
+ else :
523
+ value = converter (value )
526
524
527
525
cache [self .name ] = value
528
526
try :
@@ -677,7 +675,7 @@ def from_raw(cls, data: RawMetadata, *, validate: bool = True) -> "Metadata":
677
675
ins ._raw = data .copy () # Mutations occur due to caching enriched values.
678
676
679
677
if validate :
680
- exceptions : List [InvalidMetadata ] = []
678
+ exceptions : List [Exception ] = []
681
679
try :
682
680
metadata_version = ins .metadata_version
683
681
metadata_age = _VALID_METADATA_VERSIONS .index (metadata_version )
@@ -732,10 +730,10 @@ def from_email(
732
730
If *validate* is true, the metadata will be validated. All exceptions
733
731
related to validation will be gathered and raised as an :class:`ExceptionGroup`.
734
732
"""
735
- exceptions : list [InvalidMetadata ] = []
736
733
raw , unparsed = parse_email (data )
737
734
738
735
if validate :
736
+ exceptions : list [Exception ] = []
739
737
for unparsed_key in unparsed :
740
738
if unparsed_key in _EMAIL_TO_RAW_MAPPING :
741
739
message = f"{ unparsed_key !r} has invalid data"
@@ -749,8 +747,9 @@ def from_email(
749
747
try :
750
748
return cls .from_raw (raw , validate = validate )
751
749
except ExceptionGroup as exc_group :
752
- exceptions .extend (exc_group .exceptions )
753
- raise ExceptionGroup ("invalid or unparsed metadata" , exceptions ) from None
750
+ raise ExceptionGroup (
751
+ "invalid or unparsed metadata" , exc_group .exceptions
752
+ ) from None
754
753
755
754
metadata_version : _Validator [_MetadataVersion ] = _Validator ()
756
755
""":external:ref:`core-metadata-metadata-version`
@@ -761,62 +760,66 @@ def from_email(
761
760
*validate* parameter)"""
762
761
version : _Validator [version_module .Version ] = _Validator ()
763
762
""":external:ref:`core-metadata-version` (required)"""
764
- dynamic : _Validator [List [str ]] = _Validator (
763
+ dynamic : _Validator [Optional [ List [str ] ]] = _Validator (
765
764
added = "2.2" ,
766
765
)
767
766
""":external:ref:`core-metadata-dynamic`
768
767
(validated against core metadata field names and lowercased)"""
769
- platforms : _Validator [List [str ]] = _Validator ()
768
+ platforms : _Validator [Optional [ List [str ] ]] = _Validator ()
770
769
""":external:ref:`core-metadata-platform`"""
771
- supported_platforms : _Validator [List [str ]] = _Validator (added = "1.1" )
770
+ supported_platforms : _Validator [Optional [ List [str ] ]] = _Validator (added = "1.1" )
772
771
""":external:ref:`core-metadata-supported-platform`"""
773
- summary : _Validator [str ] = _Validator ()
772
+ summary : _Validator [Optional [ str ] ] = _Validator ()
774
773
""":external:ref:`core-metadata-summary` (validated to contain no newlines)"""
775
- description : _Validator [str ] = _Validator () # TODO 2.1: can be in body
774
+ description : _Validator [Optional [ str ] ] = _Validator () # TODO 2.1: can be in body
776
775
""":external:ref:`core-metadata-description`"""
777
- description_content_type : _Validator [str ] = _Validator (added = "2.1" )
776
+ description_content_type : _Validator [Optional [ str ] ] = _Validator (added = "2.1" )
778
777
""":external:ref:`core-metadata-description-content-type` (validated)"""
779
- keywords : _Validator [List [str ]] = _Validator ()
778
+ keywords : _Validator [Optional [ List [str ] ]] = _Validator ()
780
779
""":external:ref:`core-metadata-keywords`"""
781
- home_page : _Validator [str ] = _Validator ()
780
+ home_page : _Validator [Optional [ str ] ] = _Validator ()
782
781
""":external:ref:`core-metadata-home-page`"""
783
- download_url : _Validator [str ] = _Validator (added = "1.1" )
782
+ download_url : _Validator [Optional [ str ] ] = _Validator (added = "1.1" )
784
783
""":external:ref:`core-metadata-download-url`"""
785
- author : _Validator [str ] = _Validator ()
784
+ author : _Validator [Optional [ str ] ] = _Validator ()
786
785
""":external:ref:`core-metadata-author`"""
787
- author_email : _Validator [str ] = _Validator ()
786
+ author_email : _Validator [Optional [ str ] ] = _Validator ()
788
787
""":external:ref:`core-metadata-author-email`"""
789
- maintainer : _Validator [str ] = _Validator (added = "1.2" )
788
+ maintainer : _Validator [Optional [ str ] ] = _Validator (added = "1.2" )
790
789
""":external:ref:`core-metadata-maintainer`"""
791
- maintainer_email : _Validator [str ] = _Validator (added = "1.2" )
790
+ maintainer_email : _Validator [Optional [ str ] ] = _Validator (added = "1.2" )
792
791
""":external:ref:`core-metadata-maintainer-email`"""
793
- license : _Validator [str ] = _Validator ()
792
+ license : _Validator [Optional [ str ] ] = _Validator ()
794
793
""":external:ref:`core-metadata-license`"""
795
- classifiers : _Validator [List [str ]] = _Validator (added = "1.1" )
794
+ classifiers : _Validator [Optional [ List [str ] ]] = _Validator (added = "1.1" )
796
795
""":external:ref:`core-metadata-classifier`"""
797
- requires_dist : _Validator [List [requirements .Requirement ]] = _Validator (added = "1.2" )
796
+ requires_dist : _Validator [Optional [List [requirements .Requirement ]]] = _Validator (
797
+ added = "1.2"
798
+ )
798
799
""":external:ref:`core-metadata-requires-dist`"""
799
- requires_python : _Validator [specifiers .SpecifierSet ] = _Validator (added = "1.2" )
800
+ requires_python : _Validator [Optional [specifiers .SpecifierSet ]] = _Validator (
801
+ added = "1.2"
802
+ )
800
803
""":external:ref:`core-metadata-requires-python`"""
801
804
# Because `Requires-External` allows for non-PEP 440 version specifiers, we
802
805
# don't do any processing on the values.
803
- requires_external : _Validator [List [str ]] = _Validator (added = "1.2" )
806
+ requires_external : _Validator [Optional [ List [str ] ]] = _Validator (added = "1.2" )
804
807
""":external:ref:`core-metadata-requires-external`"""
805
- project_urls : _Validator [Dict [str , str ]] = _Validator (added = "1.2" )
808
+ project_urls : _Validator [Optional [ Dict [str , str ] ]] = _Validator (added = "1.2" )
806
809
""":external:ref:`core-metadata-project-url`"""
807
810
# PEP 685 lets us raise an error if an extra doesn't pass `Name` validation
808
811
# regardless of metadata version.
809
- provides_extra : _Validator [List [utils .NormalizedName ]] = _Validator (
812
+ provides_extra : _Validator [Optional [ List [utils .NormalizedName ] ]] = _Validator (
810
813
added = "2.1" ,
811
814
)
812
815
""":external:ref:`core-metadata-provides-extra`"""
813
- provides_dist : _Validator [List [str ]] = _Validator (added = "1.2" )
816
+ provides_dist : _Validator [Optional [ List [str ] ]] = _Validator (added = "1.2" )
814
817
""":external:ref:`core-metadata-provides-dist`"""
815
- obsoletes_dist : _Validator [List [str ]] = _Validator (added = "1.2" )
818
+ obsoletes_dist : _Validator [Optional [ List [str ] ]] = _Validator (added = "1.2" )
816
819
""":external:ref:`core-metadata-obsoletes-dist`"""
817
- requires : _Validator [List [str ]] = _Validator (added = "1.1" )
820
+ requires : _Validator [Optional [ List [str ] ]] = _Validator (added = "1.1" )
818
821
"""``Requires`` (deprecated)"""
819
- provides : _Validator [List [str ]] = _Validator (added = "1.1" )
822
+ provides : _Validator [Optional [ List [str ] ]] = _Validator (added = "1.1" )
820
823
"""``Provides`` (deprecated)"""
821
- obsoletes : _Validator [List [str ]] = _Validator (added = "1.1" )
824
+ obsoletes : _Validator [Optional [ List [str ] ]] = _Validator (added = "1.1" )
822
825
"""``Obsoletes`` (deprecated)"""
0 commit comments