-
Notifications
You must be signed in to change notification settings - Fork 144
[Issue 359] Add Json writer for new data model #379
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
armintaenzertng
merged 55 commits into
spdx:refactor-python-tools
from
nicoweidner:issue-359
Jan 3, 2023
Merged
Changes from all commits
Commits
Show all changes
55 commits
Select commit
Hold shift + click to select a range
b750cdf
[bugfix] Fix snippet copyright text type
nicoweidner 72145b0
[issue-359] Recover datetime utils from git history, add tests
nicoweidner 6b892fd
[issue-359][squash] add license header
nicoweidner e2b06dd
[issue-359] Add Json property conversion setup for CreationInfo prope…
nicoweidner f84ef3f
[issue-359] Remove logic from json property enums (will be included i…
nicoweidner cb395c5
[issue-359] Add abstract base converter class and checksum converter
nicoweidner 92c183e
[issue-359][squash] Remove license header from empty __init__.py
nicoweidner aca25d1
[issue-359] Add CreationInfo converter
nicoweidner dad3227
[issue-359] Add external document ref converter
nicoweidner 5f625b9
[issue-359][squash] Rename variable
nicoweidner 1804c21
[issue-359] Enable passing the full document to converters to account…
nicoweidner 70a99bc
[issue-359] Add annotation properties and converter
nicoweidner a33766b
[issue-359] Add external package ref properties and converter
nicoweidner 525d451
[issue-359] Add package verification code properties and converter
nicoweidner 0ae5968
[issue-359] Add __str__ method to LicenseExpression for easy serializ…
nicoweidner e5058b6
[issue-359] add package converter
nicoweidner d0baa7f
[issue-359] add relationship converter
nicoweidner 92e2dc3
[issue-359] add extracted licensing info converter
nicoweidner dbca30a
[issue-359] add file converter
nicoweidner 8f97552
[issue-359] add snippet converter
nicoweidner dd355d4
[issue-359] add document converter
nicoweidner e92d398
[issue-359][squash] Remove deprecated REVIEWEDS property
nicoweidner f3bc25b
[issue-359] json converters no longer set dictionary properties if th…
nicoweidner f4c313f
[issue-359][squash] Fix optional utils return value
nicoweidner dc29f1d
[issue-359] Improve converter typing and some parameter names
nicoweidner 0cf085f
[issue-359] Extract creation info fixture for reuse in tests
nicoweidner 50e0a54
[issue-359] Extract file fixture for reuse in tests
nicoweidner 09a4af5
[issue-359] Extract package fixture for reuse in tests
nicoweidner f669f6b
[issue-359] Extract external document ref fixture for reuse in tests
nicoweidner d640c58
[issue-359] Extract external package ref fixture for reuse in tests
nicoweidner 1aabe99
[issue-359] Extract snippet fixture for reuse in tests
nicoweidner 0adbb75
[issue-359] Add SpdxNoAssertion and SpdxNone tests
nicoweidner c430a0d
[issue-359] Don't write empty lists into the converted dictionary
nicoweidner 976287d
[issue-359] Add json writer
nicoweidner 23894d7
[issue-359][squash] extract variables in test_json_writer.py
nicoweidner 35d235e
[issue-359] Make conversion test assertions more precise by excluding…
nicoweidner 000cd80
[issue-359] Add more test fixtures
nicoweidner fba6e21
[issue-359] Add utility assertion function for mocks
nicoweidner 410dd34
[issue-359] Add tests for annotation writing logic
nicoweidner fbf6e57
[issue-359] Add relationship fixture to test fixtures
nicoweidner f9997da
[issue-359] Add document_describes and has_files tests
nicoweidner fe7b0bd
[issue-359] Add tests for relationship conversion logic in DocumentCo…
nicoweidner c2b9ac0
[issue-359] Fix mock ordering in converter tests
nicoweidner 7aa1b74
[issue-359] Make mock utilities compatible with Python 3.7
nicoweidner 4aac32c
[issue-359] Remove license headers from empty init files
nicoweidner 030b1fc
[issue-359] Move relationship_filters to model package
nicoweidner b371f4c
[issue-359] Add NOASSERTION case to extracted license name
nicoweidner f511d02
[issue-359] Add default implementation of json_property_name to conve…
nicoweidner 57b70af
[issue-359] Allow NOASSERTION and NONE for related element id in conv…
nicoweidner 4727af7
[issue-359] Remove JsonWriter class, convert to plain function
nicoweidner 6c2d577
[issue-359] Add validation to json writer, with the possibility of di…
nicoweidner 03fca1d
[issue-359] Add docstrings to some core files
nicoweidner 3f0f111
[issue-359][squash] Fix docstring
nicoweidner ebae51a
[issue-359] Extract common method to get all spdx element ids inside …
nicoweidner a0a804b
[issue-359] Use extracted relationship filtering methods in document_…
nicoweidner File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# Copyright (c) 2022 spdx contributors | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
from typing import List | ||
|
||
from src.model.document import Document | ||
|
||
|
||
def get_contained_spdx_element_ids(document: Document) -> List[str]: | ||
element_ids = [file.spdx_id for file in document.files] | ||
element_ids.extend([package.spdx_id for package in document.packages]) | ||
element_ids.extend([snippet.spdx_id for snippet in document.snippets]) | ||
return element_ids |
Empty file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
# Copyright (c) 2022 spdx contributors | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
from typing import Type, Any | ||
|
||
from src.datetime_conversions import datetime_to_iso_string | ||
from src.jsonschema.annotation_properties import AnnotationProperty | ||
from src.jsonschema.converter import TypedConverter | ||
from src.jsonschema.json_property import JsonProperty | ||
from src.model.annotation import Annotation | ||
from src.model.document import Document | ||
|
||
|
||
class AnnotationConverter(TypedConverter[Annotation]): | ||
def _get_property_value(self, annotation: Annotation, annotation_property: AnnotationProperty, | ||
document: Document = None) -> Any: | ||
if annotation_property == AnnotationProperty.ANNOTATION_DATE: | ||
return datetime_to_iso_string(annotation.annotation_date) | ||
elif annotation_property == AnnotationProperty.ANNOTATION_TYPE: | ||
return annotation.annotation_type.name | ||
elif annotation_property == AnnotationProperty.ANNOTATOR: | ||
return annotation.annotator.to_serialized_string() | ||
elif annotation_property == AnnotationProperty.COMMENT: | ||
return annotation.annotation_comment | ||
|
||
def get_json_type(self) -> Type[JsonProperty]: | ||
return AnnotationProperty | ||
|
||
def get_data_model_type(self) -> Type[Annotation]: | ||
return Annotation |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# Copyright (c) 2022 spdx contributors | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
from enum import auto | ||
|
||
from src.jsonschema.json_property import JsonProperty | ||
|
||
|
||
class AnnotationProperty(JsonProperty): | ||
ANNOTATION_DATE = auto() | ||
ANNOTATION_TYPE = auto() | ||
ANNOTATOR = auto() | ||
COMMENT = auto() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
# Copyright (c) 2022 spdx contributors | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
from typing import Type | ||
|
||
from src.jsonschema.checksum_properties import ChecksumProperty | ||
from src.jsonschema.converter import TypedConverter | ||
from src.jsonschema.json_property import JsonProperty | ||
from src.model.checksum import Checksum, ChecksumAlgorithm | ||
from src.model.document import Document | ||
|
||
|
||
class ChecksumConverter(TypedConverter[Checksum]): | ||
|
||
def get_data_model_type(self) -> Type[Checksum]: | ||
return Checksum | ||
|
||
def get_json_type(self) -> Type[JsonProperty]: | ||
return ChecksumProperty | ||
|
||
def _get_property_value(self, checksum: Checksum, checksum_property: ChecksumProperty, | ||
_document: Document = None) -> str: | ||
if checksum_property == ChecksumProperty.ALGORITHM: | ||
return algorithm_to_json_string(checksum.algorithm) | ||
elif checksum_property == ChecksumProperty.CHECKSUM_VALUE: | ||
return checksum.value | ||
|
||
|
||
def algorithm_to_json_string(algorithm: ChecksumAlgorithm) -> str: | ||
name_with_dash: str = algorithm.name.replace("_", "-") | ||
if "BLAKE2B" in name_with_dash: | ||
return name_with_dash.replace("BLAKE2B", "BLAKE2b") | ||
return name_with_dash | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
# Copyright (c) 2022 spdx contributors | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
from enum import auto | ||
|
||
from src.jsonschema.json_property import JsonProperty | ||
|
||
|
||
class ChecksumProperty(JsonProperty): | ||
ALGORITHM = auto() | ||
CHECKSUM_VALUE = auto() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
# Copyright (c) 2022 spdx contributors | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
from abc import ABC, abstractmethod | ||
from typing import Any, Type, Dict, TypeVar, Generic | ||
|
||
from src.jsonschema.json_property import JsonProperty | ||
from src.model.document import Document | ||
from src.writer.casing_tools import snake_case_to_camel_case | ||
|
||
MISSING_IMPLEMENTATION_MESSAGE = "Must be implemented" | ||
|
||
T = TypeVar("T") | ||
|
||
|
||
class TypedConverter(ABC, Generic[T]): | ||
""" | ||
Base class for all converters between an instance of the tools-python data model and the corresponding dictionary | ||
representation, following the json schema. The generic type T is the type according to the data model. | ||
Each converter has several methods: | ||
- get_json_type and get_data_model_type: return the data model type and the corresponding JsonProperty subclass. | ||
These methods are abstract in the base class and need to be implemented in subclasses. | ||
- json_property_name: converts an enum value of a JsonProperty subclass to the corresponding property name in the | ||
json schema. The default implementation simply converts from snake case to camel case. Can be overridden in case | ||
of exceptions like "SPDXID". | ||
- convert: converts an instance of type T (one of the data model types) to a dictionary representation. In some | ||
cases, the full document is required (see below). The logic should be generic for all types. | ||
- requires_full_document: indicates whether the full document is required for conversion. Returns False by | ||
default, can be overridden as needed for specific types. | ||
- _get_property_value: Retrieves the value of a specific json property from the data model instance. In some | ||
cases, the full document is required. | ||
""" | ||
|
||
@abstractmethod | ||
def _get_property_value(self, instance: T, json_property: JsonProperty, document: Document = None) -> Any: | ||
raise NotImplementedError(MISSING_IMPLEMENTATION_MESSAGE) | ||
|
||
@abstractmethod | ||
def get_json_type(self) -> Type[JsonProperty]: | ||
raise NotImplementedError(MISSING_IMPLEMENTATION_MESSAGE) | ||
|
||
@abstractmethod | ||
def get_data_model_type(self) -> Type[T]: | ||
raise NotImplementedError(MISSING_IMPLEMENTATION_MESSAGE) | ||
|
||
def json_property_name(self, json_property: JsonProperty) -> str: | ||
return snake_case_to_camel_case(json_property.name) | ||
|
||
def requires_full_document(self) -> bool: | ||
return False | ||
|
||
def convert(self, instance: T, document: Document = None) -> Dict: | ||
if not isinstance(instance, self.get_data_model_type()): | ||
raise TypeError( | ||
f"Converter of type {self.__class__} can only convert objects of type " | ||
f"{self.get_data_model_type()}. Received {type(instance)} instead.") | ||
if self.requires_full_document() and not document: | ||
raise ValueError(f"Converter of type {self.__class__} requires the full document") | ||
|
||
result = {} | ||
for property_name in self.get_json_type(): | ||
property_value = self._get_property_value(instance, property_name, document) | ||
if property_value is None: | ||
armintaenzertng marked this conversation as resolved.
Show resolved
Hide resolved
|
||
continue | ||
result[self.json_property_name(property_name)] = property_value | ||
return result |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
# Copyright (c) 2022 spdx contributors | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
from typing import Type, Any | ||
|
||
from src.datetime_conversions import datetime_to_iso_string | ||
from src.jsonschema.converter import TypedConverter | ||
from src.jsonschema.creation_info_properties import CreationInfoProperty | ||
from src.jsonschema.json_property import JsonProperty | ||
from src.jsonschema.optional_utils import apply_if_present | ||
from src.model.document import CreationInfo, Document | ||
|
||
|
||
class CreationInfoConverter(TypedConverter[CreationInfo]): | ||
def get_data_model_type(self) -> Type[CreationInfo]: | ||
return CreationInfo | ||
|
||
def get_json_type(self) -> Type[JsonProperty]: | ||
return CreationInfoProperty | ||
|
||
def _get_property_value(self, creation_info: CreationInfo, creation_info_property: CreationInfoProperty, | ||
_document: Document = None) -> Any: | ||
if creation_info_property == CreationInfoProperty.CREATED: | ||
return datetime_to_iso_string(creation_info.created) | ||
elif creation_info_property == CreationInfoProperty.CREATORS: | ||
return [creator.to_serialized_string() for creator in creation_info.creators] or None | ||
elif creation_info_property == CreationInfoProperty.LICENSE_LIST_VERSION: | ||
return apply_if_present(str, creation_info.license_list_version) | ||
elif creation_info_property == CreationInfoProperty.COMMENT: | ||
return creation_info.creator_comment |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# Copyright (c) 2022 spdx contributors | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
from enum import auto | ||
|
||
from src.jsonschema.json_property import JsonProperty | ||
|
||
|
||
class CreationInfoProperty(JsonProperty): | ||
CREATED = auto() | ||
CREATORS = auto() | ||
LICENSE_LIST_VERSION = auto() | ||
COMMENT = auto() |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is needed in the tag-value writer, too
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But that isn't merged yet, right? Then once this PR is merged, the other one can be rebased and can extract it