Skip to content

BREAKING CHANGE: adopted PEP-3102 for model classes #158

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 14 additions & 30 deletions cyclonedx/model/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,7 @@ class DataClassification:
https://cyclonedx.org/docs/1.4/xml/#type_dataClassificationType
"""

def __init__(self, flow: DataFlow, classification: str) -> None:
if not flow and not classification:
raise NoPropertiesProvidedException(
'One of `flow` or `classification` must be supplied - neither supplied'
)

def __init__(self, *, flow: DataFlow, classification: str) -> None:
self.flow = flow
self.classification = classification

Expand Down Expand Up @@ -151,7 +146,7 @@ class AttachedText:

DEFAULT_CONTENT_TYPE = 'text/plain'

def __init__(self, content: str, content_type: str = DEFAULT_CONTENT_TYPE,
def __init__(self, *, content: str, content_type: str = DEFAULT_CONTENT_TYPE,
encoding: Optional[Encoding] = None) -> None:
self.content_type = content_type
self.encoding = encoding
Expand Down Expand Up @@ -282,7 +277,7 @@ def from_composite_str(composite_hash: str) -> 'HashType':

raise UnknownHashTypeException(f"Unable to determine hash type from '{composite_hash}'")

def __init__(self, algorithm: HashAlgorithm, hash_value: str) -> None:
def __init__(self, *, algorithm: HashAlgorithm, hash_value: str) -> None:
self._alg = algorithm
self._content = hash_value

Expand Down Expand Up @@ -329,17 +324,6 @@ class ExternalReferenceType(Enum):
VCS = 'vcs'
WEBSITE = 'website'

# def __eq__(self, other: object) -> bool:
# if isinstance(other, ExternalReferenceType):
# return hash(other) == hash(self)
# return False
#
# def __hash__(self) -> int:
# return hash(self.value)
#
# def __repr__(self) -> str:
# return f'<ExternalReferenceType name={self.name}, value={self.value}>'


class XsUri:
"""
Expand Down Expand Up @@ -382,7 +366,7 @@ class ExternalReference:
See the CycloneDX Schema definition: https://cyclonedx.org/docs/1.3/#type_externalReference
"""

def __init__(self, reference_type: ExternalReferenceType, url: Union[str, XsUri], comment: str = '',
def __init__(self, *, reference_type: ExternalReferenceType, url: Union[str, XsUri], comment: str = '',
hashes: Optional[List[HashType]] = None) -> None:
self._type: ExternalReferenceType = reference_type
self._url = str(url)
Expand Down Expand Up @@ -459,7 +443,7 @@ class License:
See the CycloneDX Schema definition: https://cyclonedx.org/docs/1.4/xml/#type_licenseType
"""

def __init__(self, spxd_license_id: Optional[str] = None, license_name: Optional[str] = None,
def __init__(self, *, spxd_license_id: Optional[str] = None, license_name: Optional[str] = None,
license_text: Optional[AttachedText] = None, license_url: Optional[XsUri] = None) -> None:
if not spxd_license_id and not license_name:
raise MutuallyExclusivePropertiesException('Either `spxd_license_id` or `license_name` MUST be supplied')
Expand Down Expand Up @@ -554,7 +538,7 @@ class LicenseChoice:
See the CycloneDX Schema definition: https://cyclonedx.org/docs/1.4/xml/#type_licenseChoiceType
"""

def __init__(self, license: Optional[License] = None, license_expression: Optional[str] = None) -> None:
def __init__(self, *, license: Optional[License] = None, license_expression: Optional[str] = None) -> None:
if not license and not license_expression:
raise NoPropertiesProvidedException(
'One of `license` or `license_expression` must be supplied - neither supplied'
Expand Down Expand Up @@ -623,7 +607,7 @@ class Property:
Specifies an individual property with a name and value.
"""

def __init__(self, name: str, value: str) -> None:
def __init__(self, *, name: str, value: str) -> None:
self._name = name
self._value = value

Expand Down Expand Up @@ -668,7 +652,7 @@ class NoteText:

DEFAULT_CONTENT_TYPE: str = 'text/plain'

def __init__(self, content: str, content_type: Optional[str] = None,
def __init__(self, *, content: str, content_type: Optional[str] = None,
content_encoding: Optional[Encoding] = None) -> None:
self.content = content
self.content_type = content_type or NoteText.DEFAULT_CONTENT_TYPE
Expand Down Expand Up @@ -741,7 +725,7 @@ class Note:

_LOCALE_TYPE_REGEX = re.compile(r'^[a-z]{2}(?:\-[A-Z]{2})?$')

def __init__(self, text: NoteText, locale: Optional[str] = None) -> None:
def __init__(self, *, text: NoteText, locale: Optional[str] = None) -> None:
self.text = text
self.locale = locale

Expand Down Expand Up @@ -806,7 +790,7 @@ class OrganizationalContact:
See the CycloneDX Schema definition: https://cyclonedx.org/docs/1.4/xml/#type_organizationalContact
"""

def __init__(self, name: Optional[str] = None, phone: Optional[str] = None, email: Optional[str] = None) -> None:
def __init__(self, *, name: Optional[str] = None, phone: Optional[str] = None, email: Optional[str] = None) -> None:
if not name and not phone and not email:
raise NoPropertiesProvidedException(
'One of name, email or phone must be supplied for an OrganizationalContact - none supplied.'
Expand Down Expand Up @@ -866,7 +850,7 @@ class OrganizationalEntity:
See the CycloneDX Schema definition: https://cyclonedx.org/docs/1.4/xml/#type_organizationalEntity
"""

def __init__(self, name: Optional[str] = None, urls: Optional[List[XsUri]] = None,
def __init__(self, *, name: Optional[str] = None, urls: Optional[List[XsUri]] = None,
contacts: Optional[List[OrganizationalContact]] = None) -> None:
if not name and not urls and not contacts:
raise NoPropertiesProvidedException(
Expand Down Expand Up @@ -932,7 +916,7 @@ class Tool:
See the CycloneDX Schema for toolType: https://cyclonedx.org/docs/1.3/#type_toolType
"""

def __init__(self, vendor: Optional[str] = None, name: Optional[str] = None, version: Optional[str] = None,
def __init__(self, *, vendor: Optional[str] = None, name: Optional[str] = None, version: Optional[str] = None,
hashes: Optional[List[HashType]] = None,
external_references: Optional[List[ExternalReference]] = None) -> None:
self._vendor = vendor
Expand Down Expand Up @@ -1037,7 +1021,7 @@ class IdentifiableAction:
See the CycloneDX specification: https://cyclonedx.org/docs/1.4/xml/#type_identifiableActionType
"""

def __init__(self, timestamp: Optional[datetime] = None, name: Optional[str] = None,
def __init__(self, *, timestamp: Optional[datetime] = None, name: Optional[str] = None,
email: Optional[str] = None) -> None:
if not timestamp and not name and not email:
raise NoPropertiesProvidedException(
Expand Down Expand Up @@ -1110,7 +1094,7 @@ class Copyright:
See the CycloneDX specification: https://cyclonedx.org/docs/1.4/xml/#type_copyrightsType
"""

def __init__(self, text: str) -> None:
def __init__(self, *, text: str) -> None:
self.text = text

@property
Expand Down
4 changes: 2 additions & 2 deletions cyclonedx/model/bom.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class BomMetaData:
See the CycloneDX Schema for Bom metadata: https://cyclonedx.org/docs/1.3/#type_metadata
"""

def __init__(self, tools: Optional[List[Tool]] = None) -> None:
def __init__(self, *, tools: Optional[List[Tool]] = None) -> None:
self.timestamp = datetime.now(tz=timezone.utc)
self.tools = tools if tools else []

Expand Down Expand Up @@ -149,7 +149,7 @@ def from_parser(parser: BaseParser) -> 'Bom':
bom.add_components(parser.get_components())
return bom

def __init__(self, components: Optional[List[Component]] = None, services: Optional[List[Service]] = None,
def __init__(self, *, components: Optional[List[Component]] = None, services: Optional[List[Service]] = None,
external_references: Optional[List[ExternalReference]] = None) -> None:
"""
Create a new Bom that you can manually/programmatically add data to later.
Expand Down
19 changes: 10 additions & 9 deletions cyclonedx/model/component.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class Commit:
See the CycloneDX Schema definition: https://cyclonedx.org/docs/1.4/xml/#type_commitType
"""

def __init__(self, uid: Optional[str] = None, url: Optional[XsUri] = None,
def __init__(self, *, uid: Optional[str] = None, url: Optional[XsUri] = None,
author: Optional[IdentifiableAction] = None, committer: Optional[IdentifiableAction] = None,
message: Optional[str] = None) -> None:
if not uid and not url and not author and not committer and not message:
Expand Down Expand Up @@ -149,7 +149,7 @@ class ComponentEvidence:
See the CycloneDX Schema definition: https://cyclonedx.org/docs/1.4/xml/#type_componentEvidenceType
"""

def __init__(self, licenses: Optional[List[LicenseChoice]] = None,
def __init__(self, *, licenses: Optional[List[LicenseChoice]] = None,
copyright_: Optional[List[Copyright]] = None) -> None:
if not licenses and not copyright_:
raise NoPropertiesProvidedException(
Expand Down Expand Up @@ -240,7 +240,7 @@ class Diff:
See the CycloneDX Schema definition: https://cyclonedx.org/docs/1.4/xml/#type_diffType
"""

def __init__(self, text: Optional[AttachedText] = None, url: Optional[XsUri] = None) -> None:
def __init__(self, *, text: Optional[AttachedText] = None, url: Optional[XsUri] = None) -> None:
if not text and not url:
raise NoPropertiesProvidedException(
'At least one of `text` or `url` must be provided for a `Diff`.'
Expand Down Expand Up @@ -310,7 +310,7 @@ class Patch:
See the CycloneDX Schema definition: https://cyclonedx.org/docs/1.4/xml/#type_patchType
"""

def __init__(self, type_: PatchClassification, diff: Optional[Diff] = None,
def __init__(self, *, type_: PatchClassification, diff: Optional[Diff] = None,
resolves: Optional[List[IssueType]] = None) -> None:
self.type = type_
self.diff = diff
Expand Down Expand Up @@ -400,9 +400,10 @@ class Pedigree:
See the CycloneDX Schema definition: https://cyclonedx.org/docs/1.4/xml/#type_pedigreeType
"""

def __init__(self, ancestors: Optional[List['Component']] = None, descendants: Optional[List['Component']] = None,
variants: Optional[List['Component']] = None, commits: Optional[List[Commit]] = None,
patches: Optional[List[Patch]] = None, notes: Optional[str] = None) -> None:
def __init__(self, *, ancestors: Optional[List['Component']] = None,
descendants: Optional[List['Component']] = None, variants: Optional[List['Component']] = None,
commits: Optional[List[Commit]] = None, patches: Optional[List[Patch]] = None,
notes: Optional[str] = None) -> None:
if not ancestors and not descendants and not variants and not commits and not patches and not notes:
raise NoPropertiesProvidedException(
'At least one of `ancestors`, `descendants`, `variants`, `commits`, `patches` or `notes` must be '
Expand Down Expand Up @@ -589,7 +590,7 @@ class Swid:
See the CycloneDX Schema definition: https://cyclonedx.org/docs/1.4/xml/#type_swidType
"""

def __init__(self, tag_id: str, name: str, version: Optional[str] = None,
def __init__(self, *, tag_id: str, name: str, version: Optional[str] = None,
tag_version: Optional[int] = None, patch: Optional[bool] = None,
text: Optional[AttachedText] = None, url: Optional[XsUri] = None) -> None:
self.tag_id = tag_id
Expand Down Expand Up @@ -750,7 +751,7 @@ def for_file(absolute_file_path: str, path_for_bom: Optional[str]) -> 'Component
)
)

def __init__(self, name: str, component_type: ComponentType = ComponentType.LIBRARY,
def __init__(self, *, name: str, component_type: ComponentType = ComponentType.LIBRARY,
mime_type: Optional[str] = None, bom_ref: Optional[str] = None,
supplier: Optional[OrganizationalEntity] = None, author: Optional[str] = None,
publisher: Optional[str] = None, group: Optional[str] = None, version: Optional[str] = None,
Expand Down
4 changes: 2 additions & 2 deletions cyclonedx/model/issue.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class IssueTypeSource:
See the CycloneDX Schema definition: https://cyclonedx.org/docs/1.4/xml/#type_issueType
"""

def __init__(self, name: Optional[str] = None, url: Optional[XsUri] = None) -> None:
def __init__(self, *, name: Optional[str] = None, url: Optional[XsUri] = None) -> None:
if not name and not url:
raise NoPropertiesProvidedException(
'Neither `name` nor `url` were provided - at least one must be provided.'
Expand Down Expand Up @@ -99,7 +99,7 @@ class IssueType:
See the CycloneDX Schema definition: https://cyclonedx.org/docs/1.4/xml/#type_issueType
"""

def __init__(self, classification: IssueClassification, id: Optional[str] = None, name: Optional[str] = None,
def __init__(self, *, classification: IssueClassification, id: Optional[str] = None, name: Optional[str] = None,
description: Optional[str] = None, source_name: Optional[str] = None,
source_url: Optional[XsUri] = None, references: Optional[List[XsUri]] = None) -> None:
self._type: IssueClassification = classification
Expand Down
2 changes: 1 addition & 1 deletion cyclonedx/model/release_note.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class ReleaseNotes:
See the CycloneDX Schema definition: https://cyclonedx.org/docs/1.4/#type_releaseNotesType
"""

def __init__(self, type: str, title: Optional[str] = None, featured_image: Optional[XsUri] = None,
def __init__(self, *, type: str, title: Optional[str] = None, featured_image: Optional[XsUri] = None,
social_image: Optional[XsUri] = None, description: Optional[str] = None,
timestamp: Optional[datetime] = None, aliases: Optional[List[str]] = None,
tags: Optional[List[str]] = None, resolves: Optional[List[IssueType]] = None,
Expand Down
2 changes: 1 addition & 1 deletion cyclonedx/model/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class Service:
See the CycloneDX schema: https://cyclonedx.org/docs/1.4/xml/#type_service
"""

def __init__(self, name: str, bom_ref: Optional[str] = None, provider: Optional[OrganizationalEntity] = None,
def __init__(self, *, name: str, bom_ref: Optional[str] = None, provider: Optional[OrganizationalEntity] = None,
group: Optional[str] = None, version: Optional[str] = None, description: Optional[str] = None,
endpoints: Optional[List[XsUri]] = None, authenticated: Optional[bool] = None,
x_trust_boundary: Optional[bool] = None, data: Optional[List[DataClassification]] = None,
Expand Down
18 changes: 9 additions & 9 deletions cyclonedx/model/vulnerability.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class BomTargetVersionRange:
See the CycloneDX schema: https://cyclonedx.org/docs/1.4/#type_vulnerabilityType
"""

def __init__(self, version: Optional[str] = None, version_range: Optional[str] = None,
def __init__(self, *, version: Optional[str] = None, version_range: Optional[str] = None,
status: Optional[ImpactAnalysisAffectedStatus] = None) -> None:
if not version and not version_range:
raise NoPropertiesProvidedException(
Expand Down Expand Up @@ -131,7 +131,7 @@ class BomTarget:
See the CycloneDX schema: https://cyclonedx.org/docs/1.4/#type_vulnerabilityType
"""

def __init__(self, ref: str, versions: Optional[List[BomTargetVersionRange]] = None) -> None:
def __init__(self, *, ref: str, versions: Optional[List[BomTargetVersionRange]] = None) -> None:
self.ref = ref
self.versions = versions

Expand Down Expand Up @@ -180,7 +180,7 @@ class VulnerabilityAnalysis:
See the CycloneDX schema: https://cyclonedx.org/docs/1.4/#type_vulnerabilityType
"""

def __init__(self, state: Optional[ImpactAnalysisState] = None,
def __init__(self, *, state: Optional[ImpactAnalysisState] = None,
justification: Optional[ImpactAnalysisJustification] = None,
responses: Optional[List[ImpactAnalysisResponse]] = None,
detail: Optional[str] = None) -> None:
Expand Down Expand Up @@ -267,7 +267,7 @@ class VulnerabilityAdvisory:
See the CycloneDX schema: https://cyclonedx.org/docs/1.4/#type_advisoryType
"""

def __init__(self, url: XsUri, title: Optional[str] = None) -> None:
def __init__(self, *, url: XsUri, title: Optional[str] = None) -> None:
self.title = title
self.url = url

Expand Down Expand Up @@ -315,7 +315,7 @@ class VulnerabilitySource:
See the CycloneDX schema: https://cyclonedx.org/docs/1.4/#type_vulnerabilitySourceType
"""

def __init__(self, name: Optional[str] = None, url: Optional[XsUri] = None) -> None:
def __init__(self, *, name: Optional[str] = None, url: Optional[XsUri] = None) -> None:
if not name and not url:
raise NoPropertiesProvidedException(
'Either name or url must be provided for a VulnerabilitySource - neither provided'
Expand Down Expand Up @@ -370,7 +370,7 @@ class VulnerabilityReference:
See the CycloneDX schema: https://cyclonedx.org/docs/1.4/#type_vulnerabilityType
"""

def __init__(self, id: Optional[str] = None, source: Optional[VulnerabilitySource] = None) -> None:
def __init__(self, *, id: Optional[str] = None, source: Optional[VulnerabilitySource] = None) -> None:
if not id and not source:
raise NoPropertiesProvidedException(
'Either id or source must be provided for a VulnerabilityReference - neither provided'
Expand Down Expand Up @@ -549,7 +549,7 @@ class VulnerabilityRating:
they are redundant if you have the vector (the vector allows you to calculate the scores).
"""

def __init__(self, source: Optional[VulnerabilitySource] = None, score: Optional[Decimal] = None,
def __init__(self, *, source: Optional[VulnerabilitySource] = None, score: Optional[Decimal] = None,
severity: Optional[VulnerabilitySeverity] = None,
method: Optional[VulnerabilityScoreSource] = None, vector: Optional[str] = None,
justification: Optional[str] = None,
Expand Down Expand Up @@ -669,7 +669,7 @@ class VulnerabilityCredits:
See the CycloneDX schema: https://cyclonedx.org/docs/1.4/#type_vulnerabilityType
"""

def __init__(self, organizations: Optional[List[OrganizationalEntity]] = None,
def __init__(self, *, organizations: Optional[List[OrganizationalEntity]] = None,
individuals: Optional[List[OrganizationalContact]] = None) -> None:
if not organizations and not individuals:
raise NoPropertiesProvidedException(
Expand Down Expand Up @@ -732,7 +732,7 @@ class Vulnerability:
See the CycloneDX schema: https://cyclonedx.org/docs/1.4/#type_vulnerabilityType
"""

def __init__(self, bom_ref: Optional[str] = None, id: Optional[str] = None,
def __init__(self, *, bom_ref: Optional[str] = None, id: Optional[str] = None,
source: Optional[VulnerabilitySource] = None,
references: Optional[List[VulnerabilityReference]] = None,
ratings: Optional[List[VulnerabilityRating]] = None, cwes: Optional[List[int]] = None,
Expand Down
2 changes: 1 addition & 1 deletion tests/test_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ def test_issue_type(self) -> None:
class TestModelNote(TestCase):

def test_note_plain_text(self) -> None:
n = Note(text=NoteText('Some simple plain text'))
n = Note(text=NoteText(content='Some simple plain text'))
self.assertEqual(n.text.content, 'Some simple plain text')
self.assertEqual(n.text.content_type, NoteText.DEFAULT_CONTENT_TYPE)
self.assertIsNone(n.locale)
Expand Down