diff --git a/setup.cfg b/setup.cfg index 8ba2b06da..147347759 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,8 +1,5 @@ [metadata] license_file = LICENSE -[bdist_wheel] -universal=1 - [aliases] release = clean --all sdist --formats=gztar bdist_wheel diff --git a/setup.py b/setup.py index ba48f80c6..46be23a9a 100755 --- a/setup.py +++ b/setup.py @@ -12,8 +12,8 @@ def test_suite(): long_description = fh.read() setup( - name='spdx-tools', - version='0.7.0a1', + name='ws-spdx-tools', + version='0.7.0a3.post7', description='SPDX parser and tools.', long_description=long_description, long_description_content_type='text/markdown', @@ -51,9 +51,9 @@ def test_suite(): classifiers=[ 'Intended Audience :: Developers', 'License :: OSI Approved :: Apache Software License', - 'Programming Language :: Python :: 3.6' - 'Programming Language :: Python :: 3.7' - 'Programming Language :: Python :: 3.8' - 'Programming Language :: Python :: 3.9' + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', ] ) diff --git a/spdx/package.py b/spdx/package.py index 32279d2d5..06fd84347 100644 --- a/spdx/package.py +++ b/spdx/package.py @@ -271,11 +271,17 @@ def validate_str_fields(self, fields, optional, messages): return messages def validate_checksum(self, messages): - if self.check_sum is not None: - if not isinstance(self.check_sum, checksum.Algorithm): - messages.append( - "Package checksum must be instance of spdx.checksum.Algorithm" - ) + try: + if self.check_sum is not None: + if not isinstance(self.check_sum, checksum.Algorithm): + messages.append( + "Package checksum must be instance of spdx.checksum.Algorithm" + ) + # this check was added by the WhiteSouse PS Team ( for cases where SHA1 is not available at WhiteSource ) + if not self.check_sum.value: + delattr(self, 'check_sum') + except: + pass return messages diff --git a/spdx/parsers/tagvalue.py b/spdx/parsers/tagvalue.py index f3962b8e6..eda58fa70 100644 --- a/spdx/parsers/tagvalue.py +++ b/spdx/parsers/tagvalue.py @@ -86,7 +86,7 @@ "FILE_CHKSUM_VALUE": "FileChecksum must be a single line of text starting with 'SHA1:', line:{0}", "FILE_LICS_CONC_VALUE": "LicenseConcluded must be NOASSERTION, NONE, license identifier or license list, line:{0}", "FILE_LICS_INFO_VALUE": "LicenseInfoInFile must be NOASSERTION, NONE or license identifier, line: {0}", - "FILE_LICS_COMMENT_VALUE": "LicenseComments must be free form lext, line: {0}", + "FILE_LICS_COMMENT_VALUE": "LicenseComments must be free form text, line: {0}", "FILE_CR_TEXT_VALUE": "FileCopyrightText must be one of NOASSERTION, NONE or free form text, line: {0}", "FILE_NOTICE_VALUE": "FileNotice must be free form text, line: {0}", "FILE_CONTRIB_VALUE": "FileContributor must be a single line, line: {0}", diff --git a/spdx/relationship.py b/spdx/relationship.py index b0dcbab68..20fae0408 100644 --- a/spdx/relationship.py +++ b/spdx/relationship.py @@ -82,6 +82,9 @@ def __init__(self, relationship=None, relationship_comment=None): self.relationship = relationship self.relationship_comment = relationship_comment + def __eq__(self, other): + return True if self.relationship == other.relationship else False + @property def has_comment(self): return self.relationship_comment is not None @@ -103,7 +106,7 @@ def validate(self, messages): Check that all the fields are valid. Appends any error messages to messages parameter shall be a ErrorMessages. """ - self.validate_relationship(messages) + return self.validate_relationship(messages) def validate_relationship(self, messages): r_type = self.relationship.split(" ")[1] @@ -112,3 +115,5 @@ def validate_relationship(self, messages): "Relationship type must be one of the constants defined in " "class spdx.relationship.Relationship" ) + + return messages diff --git a/spdx/utils.py b/spdx/utils.py index ca8ab6fef..e245b3981 100644 --- a/spdx/utils.py +++ b/spdx/utils.py @@ -73,6 +73,9 @@ def to_value(self): def __str__(self): return self.to_value() + def __repr__(self): + return self.to_value() + class UnKnown(object): """ @@ -91,6 +94,7 @@ def __repr__(self): def __eq__(self, other): return self.to_value() == other.to_value() + class SPDXNone(object): """ Represent SPDX None value. diff --git a/spdx/writers/json.py b/spdx/writers/json.py index 0177cd104..c9e257d04 100644 --- a/spdx/writers/json.py +++ b/spdx/writers/json.py @@ -14,6 +14,20 @@ from spdx.writers.tagvalue import InvalidDocumentError from spdx.writers.jsonyamlxml import Writer from spdx.parsers.loggers import ErrorMessages +import numpy as np +import datetime + + +# this method has been added by the WhiteSouse PS Team. +def json_converter(obj): + if isinstance(obj, np.integer): + return int(obj) + elif isinstance(obj, np.floating): + return float(obj) + elif isinstance(obj, np.ndarray): + return obj.tolist() + elif isinstance(obj, datetime.datetime): + return obj.__str__() def write_document(document, out, validate=True): @@ -26,4 +40,4 @@ def write_document(document, out, validate=True): writer = Writer(document) document_object = writer.create_document() - json.dump(document_object, out, indent=4) + json.dump(document_object, out, indent=4, default=json_converter) diff --git a/spdx/writers/jsonyamlxml.py b/spdx/writers/jsonyamlxml.py index faac513dd..f89352ebe 100644 --- a/spdx/writers/jsonyamlxml.py +++ b/spdx/writers/jsonyamlxml.py @@ -47,7 +47,9 @@ def checksum(self, checksum_field): """ checksum_object = dict() checksum_object["algorithm"] = ( - "checksumAlgorithm_" + checksum_field.identifier.lower() + #"checksumAlgorithm_" + checksum_field.identifier.lower() + # Changed by the WhiteSouse PS Team. + checksum_field.identifier ) checksum_object["checksumValue"] = checksum_field.value return checksum_object @@ -112,9 +114,6 @@ def create_package_info(self, package): package_object["SPDXID"] = self.spdx_id(package.spdx_id) package_object["name"] = package.name package_object["downloadLocation"] = package.download_location.__str__() - package_object["packageVerificationCode"] = self.package_verification_code( - package - ) package_object["licenseConcluded"] = self.license(package.conc_lics) package_object["licenseInfoFromFiles"] = list( map(self.license, package.licenses_from_files) @@ -122,6 +121,9 @@ def create_package_info(self, package): package_object["licenseDeclared"] = self.license(package.license_declared) package_object["copyrightText"] = package.cr_text.__str__() + if package.verif_code is not None: + package_object["packageVerificationCode"] = self.package_verification_code(package) + if package.has_optional_field("version"): package_object["versionInfo"] = package.version @@ -145,7 +147,8 @@ def create_package_info(self, package): if package.has_optional_field("check_sum"): package_object["checksums"] = [self.checksum(package.check_sum)] - package_object["sha1"] = package.check_sum.value + # package_object["sha1"] = package.check_sum.value + # commented by the WS PS Team, sha1 is already exist in check_sum if package.has_optional_field("description"): package_object["description"] = package.description @@ -156,6 +159,9 @@ def create_package_info(self, package): if package.has_optional_field("homepage"): package_object["homepage"] = package.homepage.__str__() + if package.has_optional_field("files_analyzed"): + package_object["filesAnalyzed"] = package.files_analyzed + return package_object @@ -371,9 +377,16 @@ def __init__(self, document): def create_extracted_license(self): extracted_license_objects = [] - extracted_licenses = self.document.extracted_licenses + # commented by the WS PS Team + # extracted_licenses = self.document.extracted_licenses + + # filter by unique identifier attribute in ExtractedLicense object, added by the WhiteSouse PS Team + unique_extracted_licenses = {} + for lic in self.document.extracted_licenses: + if lic.identifier not in unique_extracted_licenses.keys(): + unique_extracted_licenses[lic.identifier] = lic - for extracted_license in extracted_licenses: + for extracted_license in unique_extracted_licenses.values(): extracted_license_object = dict() if isinstance(extracted_license.identifier, Literal): @@ -471,13 +484,37 @@ def create_document(self): self.document_object["SPDXID"] = self.spdx_id(self.document.spdx_id) self.document_object["name"] = self.document.name + # filter by unique spdx_id attribute in Package object, added by the WhiteSouse PS Team + unique_doc_packages = {} + for doc_package in self.document.packages: + if doc_package.spdx_id not in unique_doc_packages.keys(): + unique_doc_packages[doc_package.spdx_id] = doc_package + + # commented by the WS PS Team + # package_objects = [] + # for package in self.document.packages: + # package_info_object = self.create_package_info(package) + # package_info_object["files"] = self.create_file_info(package) + # package_objects.append({"Package": package_info_object}) + # + # self.document_object["documentDescribes"] = package_objects + + # the previous code block has been adjusted by the WhiteSouse PS Team. + # adding documentDescribes and packages sections. package_objects = [] - for package in self.document.packages: + document_describes_objects = [] + for package in unique_doc_packages.values(): package_info_object = self.create_package_info(package) - package_info_object["files"] = self.create_file_info(package) - package_objects.append({"Package": package_info_object}) + if package.files: + package_info_object["files"] = self.create_file_info(package) + # create a list of the packages' names for the 'documentDescribes' field + package_spdxid = package_info_object.get("SPDXID") + document_describes_objects.append(package_spdxid) + package_objects.append(package_info_object) - self.document_object["documentDescribes"] = package_objects + self.document_object["documentDescribes"] = document_describes_objects + self.document_object["packages"] = package_objects + # end if self.document.has_comment: self.document_object["comment"] = self.document.comment @@ -504,4 +541,6 @@ def create_document(self): if self.document.relationships: self.document_object["relationships"] = self.create_relationship_info() - return {"Document": self.document_object} + # return {"Document": self.document_object}. No need in "Document" key for json and tv format. + # Changed by the WhiteSouse PS Team. + return self.document_object diff --git a/spdx/writers/rdf.py b/spdx/writers/rdf.py index b5bb6a458..a7cfcff48 100644 --- a/spdx/writers/rdf.py +++ b/spdx/writers/rdf.py @@ -569,7 +569,7 @@ def relationships(self): """ Return a list of relationship nodes """ - return map(self.create_relationship_node, self.document.relationships) + return list(map(self.create_relationship_node, self.document.relationships)) class CreationInfoWriter(BaseWriter): @@ -1016,10 +1016,11 @@ def write(self): for package_node in self.packages(): package_triple = (doc_node, self.spdx_namespace.describesPackage, package_node) self.graph.add(package_triple) - """# Add relationship - relate_node = self.relationships() - relate_triple = (doc_node, self.spdx_namespace.relationship, relate_node) - self.graph.add(relate_triple)""" + # Add relationship + for relate_node in self.relationships(): + relate_triple = (doc_node, self.spdx_namespace.relationship, relate_node) + self.graph.add(relate_triple) + # Add snippet snippet_nodes = self.snippets() for snippet in snippet_nodes: diff --git a/spdx/writers/xml.py b/spdx/writers/xml.py index 43e28f8cf..c2b18d999 100644 --- a/spdx/writers/xml.py +++ b/spdx/writers/xml.py @@ -25,6 +25,8 @@ def write_document(document, out, validate=True): raise InvalidDocumentError(messages) writer = Writer(document) - document_object = {"SpdxDocument": writer.create_document()} + # document_object = {"SpdxDocument": writer.create_document()}. + # hanged by the WhiteSouse PS Team + document_object = {"Document": writer.create_document()} xmltodict.unparse(document_object, out, encoding="utf-8", pretty=True) diff --git a/spdx/writers/yaml.py b/spdx/writers/yaml.py index 24600d8a7..2ccc6884d 100644 --- a/spdx/writers/yaml.py +++ b/spdx/writers/yaml.py @@ -27,4 +27,4 @@ def write_document(document, out, validate=True): writer = Writer(document) document_object = writer.create_document() - yaml.safe_dump(document_object, out, indent=2, explicit_start=True) + yaml.safe_dump(document_object, out, indent=2, explicit_start=True, encoding='utf-8')