|
20 | 20 | from decimal import Decimal |
21 | 21 | from enum import Enum |
22 | 22 | from json import loads as json_loads |
23 | | -from typing import Any, Optional, Union |
| 23 | +from typing import Any, Optional, Union, Type |
| 24 | +from warnings import warn |
24 | 25 | from xml.etree.ElementTree import Element as XmlElement # nosec B405 |
25 | 26 |
|
26 | 27 | # See https://github.com/package-url/packageurl-python/issues/65 |
@@ -623,30 +624,6 @@ def __repr__(self) -> str: |
623 | 624 | return f'<CallStack frames={len(self.frames)}>' |
624 | 625 |
|
625 | 626 |
|
626 | | -class _IdentityRepositorySerializationHelper(serializable.helpers.BaseHelper): |
627 | | - """THIS CLASS IS NON-PUBLIC API""" |
628 | | - |
629 | | - @classmethod |
630 | | - def json_normalize(cls, o: SortedSet[Identity], *, |
631 | | - view: Optional[type[serializable.ViewType]], |
632 | | - **__: Any) -> Union[dict,list[dict],None]: |
633 | | - if not o: |
634 | | - return None |
635 | | - if view and view is SchemaVersion1Dot5: |
636 | | - # For Schema 1.5 JSON, return first identity as a single object |
637 | | - first_identity = o[0] |
638 | | - return json_loads(first_identity.as_json(view_=view)) # type: ignore[attr-defined] |
639 | | - # For Schema 1.6 and others, return array of all identities |
640 | | - return [json_loads(identity.as_json(view_=view)) for identity in o] # type: ignore[attr-defined] |
641 | | - |
642 | | - @classmethod |
643 | | - def json_denormalize(cls, o: Any, **__: Any) -> Optional[list[Identity]]: |
644 | | - if isinstance(o, dict): # Single Identity object (Schema 1.5) |
645 | | - return [Identity.from_json(o)] # type: ignore[attr-defined] |
646 | | - elif isinstance(o, (list, tuple)): # Array of Identity objects (Schema 1.6) |
647 | | - return [Identity.from_json(i) for i in o] # type: ignore[attr-defined] |
648 | | - return None |
649 | | - |
650 | 627 |
|
651 | 628 | @serializable.serializable_class |
652 | 629 | class ComponentEvidence: |
@@ -677,7 +654,6 @@ def __init__( |
677 | 654 | @serializable.view(SchemaVersion1Dot5) |
678 | 655 | @serializable.view(SchemaVersion1Dot6) |
679 | 656 | @serializable.xml_sequence(1) |
680 | | - @serializable.type_mapping(_IdentityRepositorySerializationHelper) |
681 | 657 | @serializable.xml_array(serializable.XmlArraySerializationType.FLAT, 'identity') |
682 | 658 | # TODO: CDX 1.5 knows only one identity, all versions later known multiple ... |
683 | 659 | # TODO: need to fix the serialization/normalization |
@@ -774,3 +750,44 @@ def __hash__(self) -> int: |
774 | 750 |
|
775 | 751 | def __repr__(self) -> str: |
776 | 752 | return f'<ComponentEvidence id={id(self)}>' |
| 753 | + |
| 754 | +class _ComponentEvidenceSerializationHelper(serializable.helpers.BaseHelper): |
| 755 | + """THIS CLASS IS NON-PUBLIC API""" |
| 756 | + |
| 757 | + @classmethod |
| 758 | + def json_normalize(cls, o: ComponentEvidence, *, |
| 759 | + view: Optional[type[serializable.ViewType]], |
| 760 | + **__: Any) -> Union[dict,list[dict],None]: |
| 761 | + data:dict[str, Any] = json_loads( o.as_json(view)) |
| 762 | + if view is SchemaVersion1Dot5: |
| 763 | + identities = data.get('identity', []) |
| 764 | + if il:=len(identities) > 1: |
| 765 | + warn(f'CycloneDX 1.5 does not support multiple identity items; dropping {il-1} items.') |
| 766 | + data['identity'] = identities[0] |
| 767 | + return data |
| 768 | + |
| 769 | + @classmethod |
| 770 | + def json_denormalize(cls, o: dict[str, Any], **__: Any) -> Optional[list[Identity]]: |
| 771 | + return ComponentEvidence.from_json(o) |
| 772 | + |
| 773 | + @classmethod |
| 774 | + def xml_normalize(cls, o: ComponentEvidence, *, |
| 775 | + element_name: str, |
| 776 | + view: Optional[Type['serializable.ViewType']], |
| 777 | + xmlns: Optional[str], |
| 778 | + **__: Any) -> Optional['XmlElement']: |
| 779 | + normalized: 'XmlElement' = o.as_xml(view, False, element_name, xmlns) |
| 780 | + if view is SchemaVersion1Dot5: |
| 781 | + identities = normalized.findall(f'./{{{xmlns}}}identity' if xmlns else './identity') |
| 782 | + if il:=len(identities) > 1: |
| 783 | + warn(f'CycloneDX 1.5 does not support multiple identity items; dropping {il-1} items.') |
| 784 | + for i in identities[1:]: |
| 785 | + normalized.remove(i) |
| 786 | + return normalized |
| 787 | + |
| 788 | + @classmethod |
| 789 | + def xml_denormalize(cls, o: 'XmlElement', *, |
| 790 | + default_ns: Optional[str], |
| 791 | + **__: Any) -> Any: |
| 792 | + return ComponentEvidence.from_xml(o, default_ns) |
| 793 | + |
0 commit comments