Skip to content
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
2 changes: 1 addition & 1 deletion spdx/parsers/rdf.py
Original file line number Diff line number Diff line change
Expand Up @@ -1220,7 +1220,7 @@ def get_relationship(self, subject_term, relation_term):
for sub, pre, rel_ele in self.graph.triples(
(relation_term, self.spdx_namespace["relatedSpdxElement"], None)
):
related_element = str(rel_ele.split("#")[1])
related_element = str(rel_ele.split("#")[1]) if '#' in rel_ele else rel_ele
except:
related_element = None

Expand Down
33 changes: 14 additions & 19 deletions spdx/relationship.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from enum import Enum
from spdx.parsers.loggers import ErrorMessages

# Implement the auto feature that becomes available in 3.6
autoinc = 0

from enum import auto, Enum

def auto():
global autoinc
autoval = autoinc
autoinc += 1
return autoval
from spdx.parsers.loggers import ErrorMessages


class RelationshipType(Enum):
Expand Down Expand Up @@ -82,33 +73,37 @@ def __init__(self, relationship=None, relationship_comment=None):
self.relationship = relationship
self.relationship_comment = relationship_comment

def __eq__(self, other):
return (
isinstance(other, Relationship)
and self.relationship == other.relationship
)

@property
def has_comment(self):
return self.relationship_comment is not None

@property
def spdxelementid(self):
def spdx_element_id(self):
return self.relationship.split(" ")[0]

@property
def relationshiptype(self):
def relationship_type(self):
return self.relationship.split(" ")[1]

@property
def relatedspdxelement(self):
def related_spdx_element(self):
return self.relationship.split(" ")[2]

def validate(self, messages):
def validate(self, messages: ErrorMessages) -> ErrorMessages:
"""
Check that all the fields are valid.
Appends any error messages to messages parameter shall be a ErrorMessages.
"""
self.validate_relationship(messages)

def validate_relationship(self, messages):
r_type = self.relationship.split(" ")[1]
r_type = self.relationship_type
if r_type not in [name for name, _ in RelationshipType.__members__.items()]:
messages.append(
"Relationship type must be one of the constants defined in "
"class spdx.relationship.Relationship"
)
return messages
4 changes: 4 additions & 0 deletions spdx/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
"""
Expand All @@ -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.
Expand Down
10 changes: 9 additions & 1 deletion spdx/writers/json.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@
from spdx.writers.tagvalue import InvalidDocumentError
from spdx.writers.jsonyamlxml import Writer
from spdx.parsers.loggers import ErrorMessages
import datetime


def json_converter(obj):
if isinstance(obj, datetime.datetime):
return str(obj)
else:
raise TypeError("No implementation available to serialize objects of type " + type(obj).__name__)


def write_document(document, out, validate=True):
Expand All @@ -26,4 +34,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)
28 changes: 18 additions & 10 deletions spdx/writers/jsonyamlxml.py
Original file line number Diff line number Diff line change
Expand Up @@ -331,16 +331,16 @@ def create_relationship_info(self):
relationship_objects = []

for relationship_term in self.document.relationships:
if relationship_term.relationshiptype == "DESCRIBES":
if relationship_term.relationship_type == "DESCRIBES":
continue
if relationship_term.relationshiptype == "CONTAINS":
if relationship_term.relationship_type == "CONTAINS":
continue
relationship_object = dict()
relationship_object["spdxElementId"] = relationship_term.spdxelementid
relationship_object["spdxElementId"] = relationship_term.spdx_element_id
relationship_object[
"relatedSpdxElement"
] = relationship_term.relatedspdxelement
relationship_object["relationshipType"] = relationship_term.relationshiptype
] = relationship_term.related_spdx_element
relationship_object["relationshipType"] = relationship_term.relationship_type
if relationship_term.has_comment:
relationship_object["comment"] = relationship_term.relationship_comment

Expand Down Expand Up @@ -398,9 +398,12 @@ def __init__(self, document):

def create_extracted_license(self):
extracted_license_objects = []
extracted_licenses = self.document.extracted_licenses
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):
Expand Down Expand Up @@ -495,8 +498,8 @@ def create_document_describes(self):
document_describes = []
remove_rel = []
for relationship in self.document.relationships:
if relationship.relationshiptype == "DESCRIBES":
document_describes.append(relationship.relatedspdxelement)
if relationship.relationship_type == "DESCRIBES":
document_describes.append(relationship.related_spdx_element)
if not relationship.has_comment:
remove_rel.append(relationship)
for relationship in remove_rel:
Expand All @@ -516,9 +519,14 @@ def create_document(self):
document_describes = self.create_document_describes()
self.document_object["documentDescribes"] = document_describes

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

package_objects = []
file_objects = []
for package in self.document.packages:
for package in unique_doc_packages.values():
package_info_object, files_in_package = self.create_package_info(package)
package_objects.append(package_info_object)
file_objects.extend(file for file in files_in_package if file not in file_objects)
Expand Down
38 changes: 29 additions & 9 deletions spdx/writers/rdf.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from spdx import utils
from spdx.package import Package
from spdx.parsers.loggers import ErrorMessages
from spdx.relationship import Relationship
from spdx.writers.tagvalue import InvalidDocumentError

import warnings
Expand Down Expand Up @@ -536,23 +537,39 @@ class RelationshipInfoWriter(BaseWriter):
def __init__(self, document, out):
super(RelationshipInfoWriter, self).__init__(document, out)

def create_relationship_node(self, relationship):
def transform_relationship_type_to_rdf_model(self, relationship_type: str) -> str:
"""
Return an relationship node.
Transform relationship type from upper snake case to camel case to match rdf-specific output e.g.
COPY_OF -> relationshipType_copyOf.
"""
relationship_node = URIRef(str(relationship.spdxelementid))
return "relationshipType_" + relationship_type[0].lower() + relationship_type.title().replace('_', '')[1:]

def create_relationship_node(self, relationship: Relationship) -> BNode:
"""
Return a relationship node.
"""
relationship_node = BNode()
type_triple = (relationship_node, RDF.type, self.spdx_namespace.Relationship)
self.graph.add(type_triple)

relationship_type_node = Literal(relationship.relationshiptype)
relationship_spdx_element_id = Literal(relationship.spdx_element_id)
self.graph.add(
(
relationship_node,
self.spdx_namespace.spdxElementId,
relationship_spdx_element_id,
)
)
relationship_type = self.transform_relationship_type_to_rdf_model(relationship.relationship_type)
relationship_type_node = self.spdx_namespace[relationship_type]
self.graph.add(
(
relationship_node,
self.spdx_namespace.relationshipType,
relationship_type_node,
)
)
related_spdx_node = Literal(relationship.relatedspdxelement)
related_spdx_node = Literal(relationship.related_spdx_element)
related_spdx_triple = (
relationship_node,
self.spdx_namespace.relatedSpdxElement,
Expand Down Expand Up @@ -1019,6 +1036,7 @@ def write(self, doc_node=None):
for package_node in self.packages():
package_triple = (doc_node, self.spdx_namespace.describesPackage, package_node)
self.graph.add(package_triple)

# Add external package reference
for pkg_ext_ref_node in self.pkg_ext_refs():
pkg_ext_ref_triple = (
Expand All @@ -1027,10 +1045,12 @@ def write(self, doc_node=None):
pkg_ext_ref_node,
)
self.graph.add(pkg_ext_ref_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:
Expand Down
2 changes: 1 addition & 1 deletion spdx/writers/yaml.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')
12 changes: 10 additions & 2 deletions tests/data/doc_write/rdf-simple-plus.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,16 @@
"@rdf:resource": "http://spdx.org/licenses/LGPL-2.1-or-later"
}
}
},
},
"ns1:relationship": {
"ns1:Relationship": {
"ns1:spdxElementId": "SPDXRef-DOCUMENT",
"ns1:relatedSpdxElement": "SPDXRef-Package",
"ns1:relationshipType": {
"@rdf:resource": "http://spdx.org/rdf/terms#relationshipType_describes"
}
}},
"@rdf:about": "http://www.spdx.org/tools#SPDXRef-DOCUMENT"
}
}
}
}
13 changes: 11 additions & 2 deletions tests/data/doc_write/rdf-simple.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,17 @@
},
"ns1:fileName": "./some/path/tofile"
}
},
},
"ns1:relationship": {
"ns1:Relationship": {
"ns1:spdxElementId": "SPDXRef-DOCUMENT",
"ns1:relatedSpdxElement": "SPDXRef-Package",
"ns1:relationshipType": {
"@rdf:resource": "http://spdx.org/rdf/terms#relationshipType_describes"
}
}
},
"@rdf:about": "http://www.spdx.org/tools#SPDXRef-DOCUMENT"
}
}
}
}
78 changes: 36 additions & 42 deletions tests/data/doc_write/xml-simple-plus.xml
Original file line number Diff line number Diff line change
@@ -1,43 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>

<Document>
<spdxVersion>SPDX-2.1</spdxVersion>
<dataLicense>CC0-1.0</dataLicense>
<name>Sample_Document-V2.1</name>
<SPDXID>SPDXRef-DOCUMENT</SPDXID>
<documentNamespace>https://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301</documentNamespace>
<documentDescribes>SPDXRef-Package</documentDescribes>
<packages>
<SPDXID>SPDXRef-Package</SPDXID>
<name>some/path</name>
<downloadLocation>NOASSERTION</downloadLocation>
<copyrightText>Some copyrught</copyrightText>
<packageVerificationCode>
<packageVerificationCodeValue>SOME code</packageVerificationCodeValue>
</packageVerificationCode>
<checksums>
<checksumValue>SOME-SHA1</checksumValue>
<algorithm>SHA1</algorithm>
</checksums>
<licenseDeclared>NOASSERTION</licenseDeclared>
<licenseConcluded>NOASSERTION</licenseConcluded>
<licenseInfoFromFiles>LGPL-2.1-or-later</licenseInfoFromFiles>

<hasFiles>SPDXRef-File</hasFiles>
</packages>
<files>

<fileName>./some/path/tofile</fileName>
<SPDXID>SPDXRef-File</SPDXID>
<checksums>
<checksumValue>SOME-SHA1</checksumValue>
<algorithm>SHA1</algorithm>
</checksums>
<licenseConcluded>NOASSERTION</licenseConcluded>
<copyrightText>NOASSERTION</copyrightText>
<licenseInfoInFiles>LGPL-2.1-or-later</licenseInfoInFiles>

</files>


</Document>
<Document>
<spdxVersion>SPDX-2.1</spdxVersion>
<dataLicense>CC0-1.0</dataLicense>
<name>Sample_Document-V2.1</name>
<SPDXID>SPDXRef-DOCUMENT</SPDXID>
<documentNamespace>https://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301</documentNamespace>
<documentDescribes>SPDXRef-Package</documentDescribes>
<packages>
<SPDXID>SPDXRef-Package</SPDXID>
<name>some/path</name>
<downloadLocation>NOASSERTION</downloadLocation>
<copyrightText>Some copyrught</copyrightText>
<packageVerificationCode>
<packageVerificationCodeValue>SOME code</packageVerificationCodeValue>
</packageVerificationCode>
<checksums>
<checksumValue>SOME-SHA1</checksumValue>
<algorithm>SHA1</algorithm>
</checksums>
<licenseDeclared>NOASSERTION</licenseDeclared>
<licenseConcluded>NOASSERTION</licenseConcluded>
<licenseInfoFromFiles>LGPL-2.1-or-later</licenseInfoFromFiles>
<hasFiles>SPDXRef-File</hasFiles>
</packages>
<files>
<fileName>./some/path/tofile</fileName>
<SPDXID>SPDXRef-File</SPDXID>
<checksums>
<checksumValue>SOME-SHA1</checksumValue>
<algorithm>SHA1</algorithm>
</checksums>
<licenseConcluded>NOASSERTION</licenseConcluded>
<copyrightText>NOASSERTION</copyrightText>
<licenseInfoInFiles>LGPL-2.1-or-later</licenseInfoInFiles>
</files>
</Document>
3 changes: 1 addition & 2 deletions tests/data/doc_write/xml-simple.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
</checksums>
<licenseDeclared>NOASSERTION</licenseDeclared>
<licenseConcluded>NOASSERTION</licenseConcluded>

<licenseInfoFromFiles>LGPL-2.1-only</licenseInfoFromFiles>
<hasFiles>SPDXRef-File</hasFiles>
</packages>
Expand All @@ -35,4 +34,4 @@
<copyrightText>NOASSERTION</copyrightText>
<licenseInfoInFiles>LGPL-2.1-only</licenseInfoInFiles>
</files>
</Document>
</Document>
Loading