diff --git a/cyclonedx/model/__init__.py b/cyclonedx/model/__init__.py index ecc39756..9b50d20c 100644 --- a/cyclonedx/model/__init__.py +++ b/cyclonedx/model/__init__.py @@ -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 @@ -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 @@ -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 @@ -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'' - class XsUri: """ @@ -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) @@ -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') @@ -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' @@ -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 @@ -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 @@ -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 @@ -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.' @@ -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( @@ -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 @@ -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( @@ -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 diff --git a/cyclonedx/model/bom.py b/cyclonedx/model/bom.py index 558cc794..24af5d63 100644 --- a/cyclonedx/model/bom.py +++ b/cyclonedx/model/bom.py @@ -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 [] @@ -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. diff --git a/cyclonedx/model/component.py b/cyclonedx/model/component.py index 18825367..9981dedd 100644 --- a/cyclonedx/model/component.py +++ b/cyclonedx/model/component.py @@ -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: @@ -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( @@ -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`.' @@ -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 @@ -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 ' @@ -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 @@ -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, diff --git a/cyclonedx/model/issue.py b/cyclonedx/model/issue.py index b6d176f3..c8d3b672 100644 --- a/cyclonedx/model/issue.py +++ b/cyclonedx/model/issue.py @@ -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.' @@ -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 diff --git a/cyclonedx/model/release_note.py b/cyclonedx/model/release_note.py index 43389e73..c6687fa7 100644 --- a/cyclonedx/model/release_note.py +++ b/cyclonedx/model/release_note.py @@ -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, diff --git a/cyclonedx/model/service.py b/cyclonedx/model/service.py index ced7fd2d..b674ae26 100644 --- a/cyclonedx/model/service.py +++ b/cyclonedx/model/service.py @@ -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, diff --git a/cyclonedx/model/vulnerability.py b/cyclonedx/model/vulnerability.py index 734c0933..e64d040e 100644 --- a/cyclonedx/model/vulnerability.py +++ b/cyclonedx/model/vulnerability.py @@ -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( @@ -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 @@ -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: @@ -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 @@ -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' @@ -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' @@ -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, @@ -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( @@ -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, diff --git a/tests/test_model.py b/tests/test_model.py index 8eb60ac7..eb3f0577 100644 --- a/tests/test_model.py +++ b/tests/test_model.py @@ -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)