Skip to content
5 changes: 1 addition & 4 deletions cyclonedx/_internal/compare.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,7 @@
"""

from itertools import zip_longest
from typing import TYPE_CHECKING, Any, Optional

if TYPE_CHECKING: # pragma: no cover
from packageurl import PackageURL
from typing import Any, Optional


class ComparableTuple(tuple[Optional[Any], ...]):
Expand Down
9 changes: 3 additions & 6 deletions cyclonedx/model/bom.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from datetime import datetime
from enum import Enum
from itertools import chain
from typing import TYPE_CHECKING, Optional, Union
from typing import Optional, Union
from uuid import UUID, uuid4
from warnings import warn

Expand Down Expand Up @@ -54,9 +54,6 @@
from .tool import Tool, ToolRepository, _ToolRepositoryHelper
from .vulnerability import Vulnerability

if TYPE_CHECKING: # pragma: no cover
from packageurl import PackageURL


@serializable.serializable_enum
class TlpClassification(str, Enum):
Expand Down Expand Up @@ -694,13 +691,13 @@ def definitions(self) -> Optional[Definitions]:
def definitions(self, definitions: Definitions) -> None:
self._definitions = definitions

def get_component_by_purl(self, purl: Optional['PackageURL']) -> Optional[Component]:
def get_component_by_purl(self, purl: Optional[str]) -> Optional[Component]:
"""
Get a Component already in the Bom by its PURL

Args:
purl:
An instance of `packageurl.PackageURL` to look and find `Component`.
A PURL string to look and find `Component`.

Returns:
`Component` or `None`
Expand Down
25 changes: 11 additions & 14 deletions cyclonedx/model/component.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,11 @@
else:
from typing_extensions import deprecated

# See https://github.com/package-url/packageurl-python/issues/65
import py_serializable as serializable
from packageurl import PackageURL
from sortedcontainers import SortedSet

from .._internal.bom_ref import bom_ref_from_str as _bom_ref_from_str
from .._internal.compare import ComparablePackageURL as _ComparablePackageURL, ComparableTuple as _ComparableTuple
from .._internal.compare import ComparableTuple as _ComparableTuple
from ..exception.model import InvalidOmniBorIdException, InvalidSwhidException
from ..exception.serialization import (
CycloneDxDeserializationException,
Expand Down Expand Up @@ -974,11 +972,10 @@ def for_file(absolute_file_path: str, path_for_bom: Optional[str]) -> 'Component
component = ComponentBuilder().make_for_file(absolute_file_path, name=path_for_bom)
sha1_hash = next((h.content for h in component.hashes if h.alg is HashAlgorithm.SHA_1), None)
assert sha1_hash is not None
component.version = f'0.0.0-{sha1_hash[0:12]}'
component.purl = PackageURL( # DEPRECATED: a file has no PURL!
type='generic', name=path_for_bom if path_for_bom else absolute_file_path,
version=f'0.0.0-{sha1_hash[0:12]}'
)
version = f'0.0.0-{sha1_hash[0:12]}'
name = path_for_bom if path_for_bom else absolute_file_path
component.version = version
component.purl = f'pkg:generic/{name}@{version}' # DEPRECATED: a file has no PURL!
return component

def __init__(
Expand All @@ -997,7 +994,7 @@ def __init__(
hashes: Optional[Iterable[HashType]] = None,
licenses: Optional[Iterable[License]] = None,
copyright: Optional[str] = None,
purl: Optional[PackageURL] = None,
purl: Optional[str] = None,
external_references: Optional[Iterable[ExternalReference]] = None,
properties: Optional[Iterable[Property]] = None,
release_notes: Optional[ReleaseNotes] = None,
Expand Down Expand Up @@ -1402,22 +1399,22 @@ def cpe(self, cpe: Optional[str]) -> None:
self._cpe = cpe

@property
@serializable.type_mapping(PackageUrlSH)
@serializable.xml_sequence(15)
def purl(self) -> Optional[PackageURL]:
@serializable.xml_string(serializable.XmlStringSerializationType.NORMALIZED_STRING)
def purl(self) -> Optional[str]:
"""
Specifies the package-url (PURL).

The purl, if specified, must be valid and conform to the specification defined at:
https://github.com/package-url/purl-spec

Returns:
`PackageURL` or `None`
`str` or `None`
"""
return self._purl

@purl.setter
def purl(self, purl: Optional[PackageURL]) -> None:
def purl(self, purl: Optional[str]) -> None:
self._purl = purl

@property
Expand Down Expand Up @@ -1718,7 +1715,7 @@ def __comparable_tuple(self) -> _ComparableTuple:
return _ComparableTuple((
self.type, self.group, self.name, self.version,
self.bom_ref.value,
None if self.purl is None else _ComparablePackageURL(self.purl),
self.purl,
self.swid, self.cpe, _ComparableTuple(self.swhids),
self.supplier, self.author, self.publisher,
self.description,
Expand Down
1 change: 0 additions & 1 deletion cyclonedx/model/component_evidence.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
from warnings import warn
from xml.etree.ElementTree import Element as XmlElement # nosec B405

# See https://github.com/package-url/packageurl-python/issues/65
import py_serializable as serializable
from sortedcontainers import SortedSet

Expand Down
21 changes: 0 additions & 21 deletions cyclonedx/serialization/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@
from typing import Any, Optional
from uuid import UUID

# See https://github.com/package-url/packageurl-python/issues/65
from packageurl import PackageURL
from py_serializable.helpers import BaseHelper

if sys.version_info >= (3, 13):
Expand Down Expand Up @@ -57,25 +55,6 @@ def deserialize(cls, o: Any) -> BomRef:
return BomRef.deserialize(o)


class PackageUrl(BaseHelper):

@classmethod
def serialize(cls, o: Any, ) -> str:
if isinstance(o, PackageURL):
return str(o.to_string())
raise SerializationOfUnexpectedValueException(
f'Attempt to serialize a non-PackageURL: {o!r}')

@classmethod
def deserialize(cls, o: Any) -> PackageURL:
try:
return PackageURL.from_string(purl=str(o))
except ValueError as err:
raise CycloneDxDeserializationException(
f'PURL string supplied does not parse: {o!r}'
) from err


class UrnUuidHelper(BaseHelper):

@classmethod
Expand Down
4 changes: 1 addition & 3 deletions examples/complex_serialize.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@
import sys
from typing import TYPE_CHECKING

from packageurl import PackageURL

from cyclonedx.contrib.license.factories import LicenseFactory
from cyclonedx.contrib.this.builders import this_component as cdx_lib_component
from cyclonedx.exception import MissingOptionalDependencyException
Expand Down Expand Up @@ -68,7 +66,7 @@
urls=[XsUri('https://www.acme.org')]
),
bom_ref='myComponent@1.33.7-beta.1',
purl=PackageURL('generic', 'acme', 'some-component', '1.33.7-beta.1')
purl='pkg:generic/acme/some-component@1.33.7-beta.1'
)
bom.components.add(component1)
bom.register_dependency(root_component, [component1])
Expand Down
1 change: 0 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ keywords = [

[tool.poetry.dependencies]
python = "^3.9"
packageurl-python = ">=0.11, <2"
py-serializable = "^2.1.0"
sortedcontainers = "^2.4.0"
license-expression = "^30"
Expand Down
35 changes: 9 additions & 26 deletions tests/_data/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,6 @@
from typing import Any, Optional
from uuid import UUID

# See https://github.com/package-url/packageurl-python/issues/65
from packageurl import PackageURL

from cyclonedx.builder.this import this_component, this_tool
from cyclonedx.model import (
AttachedText,
Expand Down Expand Up @@ -488,9 +485,7 @@ def get_bom_with_component_evidence() -> Bom:
component = Component(
name='setuptools', version='50.3.2',
bom_ref='pkg:pypi/setuptools@50.3.2?extension=tar.gz',
purl=PackageURL(
type='pypi', name='setuptools', version='50.3.2', qualifiers='extension=tar.gz'
),
purl='pkg:pypi/setuptools@50.3.2?extension=tar.gz',
licenses=[DisjunctiveLicense(id='MIT')],
author='Test Author'
)
Expand Down Expand Up @@ -556,7 +551,7 @@ def get_bom_with_component_setuptools_with_vulnerability() -> Bom:
),
affects=[
BomTarget(
ref=component.purl.to_string(),
ref=component.purl,
versions=[BomTargetVersionRange(
range='49.0.0 - 54.0.0', status=ImpactAnalysisAffectedStatus.AFFECTED
)]
Expand Down Expand Up @@ -856,9 +851,7 @@ def get_component_setuptools_simple(
return Component(
name='setuptools', version='50.3.2',
bom_ref=bom_ref,
purl=PackageURL(
type='pypi', name='setuptools', version='50.3.2', qualifiers='extension=tar.gz'
),
purl='pkg:pypi/setuptools@50.3.2?extension=tar.gz',
licenses=[DisjunctiveLicense(id='MIT')],
author='Test Author'
)
Expand All @@ -877,9 +870,7 @@ def get_component_external() -> Component:
def get_component_setuptools_simple_no_version(bom_ref: Optional[str] = None) -> Component:
return Component(
name='setuptools', bom_ref=bom_ref or 'pkg:pypi/setuptools?extension=tar.gz',
purl=PackageURL(
type='pypi', name='setuptools', qualifiers='extension=tar.gz'
),
purl='pkg:pypi/setuptools?extension=tar.gz',
licenses=[DisjunctiveLicense(id='MIT')],
author='Test Author'
)
Expand All @@ -888,9 +879,7 @@ def get_component_setuptools_simple_no_version(bom_ref: Optional[str] = None) ->
def get_component_toml_with_hashes_with_references(bom_ref: Optional[str] = None) -> Component:
return Component(
name='toml', version='0.10.2', bom_ref=bom_ref or 'pkg:pypi/toml@0.10.2?extension=tar.gz',
purl=PackageURL(
type='pypi', name='toml', version='0.10.2', qualifiers='extension=tar.gz'
), hashes=[
purl='pkg:pypi/toml@0.10.2?extension=tar.gz', hashes=[
HashType.from_composite_str('sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b')
], external_references=[
get_external_reference_1()
Expand Down Expand Up @@ -1400,19 +1389,13 @@ def get_bom_for_issue_598_multiple_components_with_purl_qualifiers() -> Bom:
return _make_bom(components=[
Component(
name='dummy', version='2.3.5', bom_ref='dummy-a',
purl=PackageURL(
type='pypi', namespace=None, name='pathlib2', version='2.3.5', subpath=None,
qualifiers={}
)
purl='pkg:pypi/pathlib2@2.3.5'
),
Component(
name='dummy', version='2.3.5', bom_ref='dummy-b',
purl=PackageURL(
type='pypi', namespace=None, name='pathlib2', version='2.3.5', subpath=None,
qualifiers={
'vcs_url': 'git+https://github.com/jazzband/pathlib2.git@5a6a88db3cc1d08dbc86fbe15edfb69fb5f5a3d6'
}
)
purl='pkg:pypi/pathlib2@2.3.5'
'?vcs_url=git%2Bhttps:%2F%2Fgithub.com%2Fjazzband%2Fpathlib2.git'
'%405a6a88db3cc1d08dbc86fbe15edfb69fb5f5a3d6'
)
])

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<component type="library">
<name>dummy</name>
<version>2.3.5</version>
<purl>pkg:pypi/pathlib2@2.3.5?vcs_url=git%2Bhttps://github.com/jazzband/pathlib2.git%405a6a88db3cc1d08dbc86fbe15edfb69fb5f5a3d6</purl>
<purl>pkg:pypi/pathlib2@2.3.5?vcs_url=git%2Bhttps:%2F%2Fgithub.com%2Fjazzband%2Fpathlib2.git%405a6a88db3cc1d08dbc86fbe15edfb69fb5f5a3d6</purl>
<modified>false</modified>
</component>
</components>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<component type="library" bom-ref="dummy-b">
<name>dummy</name>
<version>2.3.5</version>
<purl>pkg:pypi/pathlib2@2.3.5?vcs_url=git%2Bhttps://github.com/jazzband/pathlib2.git%405a6a88db3cc1d08dbc86fbe15edfb69fb5f5a3d6</purl>
<purl>pkg:pypi/pathlib2@2.3.5?vcs_url=git%2Bhttps:%2F%2Fgithub.com%2Fjazzband%2Fpathlib2.git%405a6a88db3cc1d08dbc86fbe15edfb69fb5f5a3d6</purl>
</component>
</components>
</bom>
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
{
"bom-ref": "dummy-b",
"name": "dummy",
"purl": "pkg:pypi/pathlib2@2.3.5?vcs_url=git%2Bhttps://github.com/jazzband/pathlib2.git%405a6a88db3cc1d08dbc86fbe15edfb69fb5f5a3d6",
"purl": "pkg:pypi/pathlib2@2.3.5?vcs_url=git%2Bhttps:%2F%2Fgithub.com%2Fjazzband%2Fpathlib2.git%405a6a88db3cc1d08dbc86fbe15edfb69fb5f5a3d6",
"type": "library",
"version": "2.3.5"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<component type="library" bom-ref="dummy-b">
<name>dummy</name>
<version>2.3.5</version>
<purl>pkg:pypi/pathlib2@2.3.5?vcs_url=git%2Bhttps://github.com/jazzband/pathlib2.git%405a6a88db3cc1d08dbc86fbe15edfb69fb5f5a3d6</purl>
<purl>pkg:pypi/pathlib2@2.3.5?vcs_url=git%2Bhttps:%2F%2Fgithub.com%2Fjazzband%2Fpathlib2.git%405a6a88db3cc1d08dbc86fbe15edfb69fb5f5a3d6</purl>
</component>
</components>
<dependencies>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
{
"bom-ref": "dummy-b",
"name": "dummy",
"purl": "pkg:pypi/pathlib2@2.3.5?vcs_url=git%2Bhttps://github.com/jazzband/pathlib2.git%405a6a88db3cc1d08dbc86fbe15edfb69fb5f5a3d6",
"purl": "pkg:pypi/pathlib2@2.3.5?vcs_url=git%2Bhttps:%2F%2Fgithub.com%2Fjazzband%2Fpathlib2.git%405a6a88db3cc1d08dbc86fbe15edfb69fb5f5a3d6",
"type": "library",
"version": "2.3.5"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<component type="library" bom-ref="dummy-b">
<name>dummy</name>
<version>2.3.5</version>
<purl>pkg:pypi/pathlib2@2.3.5?vcs_url=git%2Bhttps://github.com/jazzband/pathlib2.git%405a6a88db3cc1d08dbc86fbe15edfb69fb5f5a3d6</purl>
<purl>pkg:pypi/pathlib2@2.3.5?vcs_url=git%2Bhttps:%2F%2Fgithub.com%2Fjazzband%2Fpathlib2.git%405a6a88db3cc1d08dbc86fbe15edfb69fb5f5a3d6</purl>
</component>
</components>
<dependencies>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
{
"bom-ref": "dummy-b",
"name": "dummy",
"purl": "pkg:pypi/pathlib2@2.3.5?vcs_url=git%2Bhttps://github.com/jazzband/pathlib2.git%405a6a88db3cc1d08dbc86fbe15edfb69fb5f5a3d6",
"purl": "pkg:pypi/pathlib2@2.3.5?vcs_url=git%2Bhttps:%2F%2Fgithub.com%2Fjazzband%2Fpathlib2.git%405a6a88db3cc1d08dbc86fbe15edfb69fb5f5a3d6",
"type": "library",
"version": "2.3.5"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<component type="library" bom-ref="dummy-b">
<name>dummy</name>
<version>2.3.5</version>
<purl>pkg:pypi/pathlib2@2.3.5?vcs_url=git%2Bhttps://github.com/jazzband/pathlib2.git%405a6a88db3cc1d08dbc86fbe15edfb69fb5f5a3d6</purl>
<purl>pkg:pypi/pathlib2@2.3.5?vcs_url=git%2Bhttps:%2F%2Fgithub.com%2Fjazzband%2Fpathlib2.git%405a6a88db3cc1d08dbc86fbe15edfb69fb5f5a3d6</purl>
</component>
</components>
<dependencies>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
{
"bom-ref": "dummy-b",
"name": "dummy",
"purl": "pkg:pypi/pathlib2@2.3.5?vcs_url=git%2Bhttps://github.com/jazzband/pathlib2.git%405a6a88db3cc1d08dbc86fbe15edfb69fb5f5a3d6",
"purl": "pkg:pypi/pathlib2@2.3.5?vcs_url=git%2Bhttps:%2F%2Fgithub.com%2Fjazzband%2Fpathlib2.git%405a6a88db3cc1d08dbc86fbe15edfb69fb5f5a3d6",
"type": "library",
"version": "2.3.5"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<component type="library" bom-ref="dummy-b">
<name>dummy</name>
<version>2.3.5</version>
<purl>pkg:pypi/pathlib2@2.3.5?vcs_url=git%2Bhttps://github.com/jazzband/pathlib2.git%405a6a88db3cc1d08dbc86fbe15edfb69fb5f5a3d6</purl>
<purl>pkg:pypi/pathlib2@2.3.5?vcs_url=git%2Bhttps:%2F%2Fgithub.com%2Fjazzband%2Fpathlib2.git%405a6a88db3cc1d08dbc86fbe15edfb69fb5f5a3d6</purl>
</component>
</components>
<dependencies>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
{
"bom-ref": "dummy-b",
"name": "dummy",
"purl": "pkg:pypi/pathlib2@2.3.5?vcs_url=git%2Bhttps://github.com/jazzband/pathlib2.git%405a6a88db3cc1d08dbc86fbe15edfb69fb5f5a3d6",
"purl": "pkg:pypi/pathlib2@2.3.5?vcs_url=git%2Bhttps:%2F%2Fgithub.com%2Fjazzband%2Fpathlib2.git%405a6a88db3cc1d08dbc86fbe15edfb69fb5f5a3d6",
"type": "library",
"version": "2.3.5"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<component type="library" bom-ref="dummy-b">
<name>dummy</name>
<version>2.3.5</version>
<purl>pkg:pypi/pathlib2@2.3.5?vcs_url=git%2Bhttps://github.com/jazzband/pathlib2.git%405a6a88db3cc1d08dbc86fbe15edfb69fb5f5a3d6</purl>
<purl>pkg:pypi/pathlib2@2.3.5?vcs_url=git%2Bhttps:%2F%2Fgithub.com%2Fjazzband%2Fpathlib2.git%405a6a88db3cc1d08dbc86fbe15edfb69fb5f5a3d6</purl>
</component>
</components>
<dependencies>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
{
"bom-ref": "dummy-b",
"name": "dummy",
"purl": "pkg:pypi/pathlib2@2.3.5?vcs_url=git%2Bhttps://github.com/jazzband/pathlib2.git%405a6a88db3cc1d08dbc86fbe15edfb69fb5f5a3d6",
"purl": "pkg:pypi/pathlib2@2.3.5?vcs_url=git%2Bhttps:%2F%2Fgithub.com%2Fjazzband%2Fpathlib2.git%405a6a88db3cc1d08dbc86fbe15edfb69fb5f5a3d6",
"type": "library",
"version": "2.3.5"
}
Expand Down
Loading