|
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