From 124cd741729120f2aaf2feb30d8e55ea9786c10f Mon Sep 17 00:00:00 2001 From: Hakan Dilek Date: Fri, 17 Jul 2026 10:08:08 +0200 Subject: [PATCH 1/2] feat(parser): serialize to JSON in parser --- siemens_standard_bom/parser.py | 8 +++++- tests/test_v3_parser_write.py | 52 ++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/siemens_standard_bom/parser.py b/siemens_standard_bom/parser.py index e51ad63..1cc756b 100644 --- a/siemens_standard_bom/parser.py +++ b/siemens_standard_bom/parser.py @@ -33,6 +33,12 @@ def save(sbom: StandardBom, output_filename: str, indent: int = 4, with_dependen output_file = Path(output_filename) output_file.parent.mkdir(exist_ok=True, parents=True) + output = StandardBomParser.serialize(sbom, indent=indent, with_dependencies=with_dependencies) + + output_file.write_text(output, encoding='utf-8') + + @staticmethod + def serialize(sbom: StandardBom, indent: int = 4, with_dependencies: bool = True) -> str: writer = JsonV1Dot6(bom=sbom.bom) output = writer.output_as_string(indent=indent) @@ -41,4 +47,4 @@ def save(sbom: StandardBom, output_filename: str, indent: int = 4, with_dependen data.pop('dependencies', None) output = json.dumps(data, indent=indent) - output_file.write_text(output, encoding='utf-8') + return output diff --git a/tests/test_v3_parser_write.py b/tests/test_v3_parser_write.py index f6abd79..358a2ee 100644 --- a/tests/test_v3_parser_write.py +++ b/tests/test_v3_parser_write.py @@ -150,6 +150,58 @@ def counting_write_text( self.assertNotIn("dependencies", data) self.assertEqual(data["components"][0]["name"], "Dummy") + def test_serialize_returns_valid_json_string(self) -> None: + sbom = StandardBomParser.parse("tests/v3/single-dependency.cdx.json") + + output = StandardBomParser.serialize(sbom) + data = json.loads(output) + + self.assertIsInstance(output, str) + self.assertIn("$schema", data) + self.assertEqual("CycloneDX", data["bomFormat"]) + self.assertEqual("1.6", data["specVersion"]) + self.assertEqual(".NET Runtime", data["components"][0]["name"]) + self.assertIn("dependencies", data) + self.assertEqual(1, len(data["dependencies"])) + + def test_serialize_without_dependencies_removes_key_without_mutating_sbom(self) -> None: + sbom = StandardBomParser.parse("tests/v3/single-dependency.cdx.json") + + output = StandardBomParser.serialize(sbom, with_dependencies=False) + data = json.loads(output) + + self.assertNotIn("dependencies", data) + self.assertIn("definitions", data) + self.assertEqual("CycloneDX", data["bomFormat"]) + self.assertEqual("1.6", data["specVersion"]) + self.assertEqual(".NET Runtime", data["components"][0]["name"]) + + data_after_stripping = json.loads(StandardBomParser.serialize(sbom)) + self.assertIn("dependencies", data_after_stripping) + self.assertEqual(1, len(data_after_stripping["dependencies"])) + + def test_serialize_without_dependencies_on_empty_sbom_is_safe(self) -> None: + sbom = StandardBom() + + output = StandardBomParser.serialize(sbom, with_dependencies=False) + data = json.loads(output) + + self.assertNotIn("dependencies", data) + self.assertIn("$schema", data) + self.assertEqual("CycloneDX", data["bomFormat"]) + self.assertEqual("1.6", data["specVersion"]) + + def test_serialize_indent_controls_formatting(self) -> None: + sbom = StandardBomParser.parse("tests/v3/single-dependency.cdx.json") + + two_spaces = StandardBomParser.serialize(sbom, indent=2, with_dependencies=False) + four_spaces = StandardBomParser.serialize(sbom, indent=4, with_dependencies=False) + + self.assertNotEqual(two_spaces, four_spaces) + self.assertEqual(json.loads(two_spaces), json.loads(four_spaces)) + self.assertIn('\n "$schema"', two_spaces) + self.assertIn('\n "$schema"', four_spaces) + def test_write_with_added_license(self) -> None: output_filename = "output/v3/with_added_license.json" From 7b1e72f7f89f44ffb579452f41fb84cde8f827aa Mon Sep 17 00:00:00 2001 From: Hakan Dilek Date: Fri, 17 Jul 2026 10:09:24 +0200 Subject: [PATCH 2/2] chore: bump version to 4.3.0 --- poetry.lock | 12 ++++++------ pyproject.toml | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/poetry.lock b/poetry.lock index a217d29..95e7289 100644 --- a/poetry.lock +++ b/poetry.lock @@ -387,14 +387,14 @@ files = [ [[package]] name = "filelock" -version = "3.29.5" +version = "3.30.2" description = "A platform independent file lock." optional = false python-versions = ">=3.10" groups = ["dev"] files = [ - {file = "filelock-3.29.5-py3-none-any.whl", hash = "sha256:8af830889ba3a0ffcefbd6c7d2af8a54012058103771f2e10848222f476a1693"}, - {file = "filelock-3.29.5.tar.gz", hash = "sha256:6e6034c57a00a020e767f2614a5539863f056de7e7991d6d1473aef7ff73f156"}, + {file = "filelock-3.30.2-py3-none-any.whl", hash = "sha256:a64b58f75048ec39589983e97f5117163f822261dcb6ba843e098f05aac9663f"}, + {file = "filelock-3.30.2.tar.gz", hash = "sha256:1ea7c857465c897a4a6e64c1aace28ff6b83f5bc66c1c06ea148efa65bc2ec5d"}, ] [[package]] @@ -983,14 +983,14 @@ markers = {main = "python_version < \"3.13\""} [[package]] name = "virtualenv" -version = "21.5.1" +version = "21.6.1" description = "Virtual Python Environment builder" optional = false python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "virtualenv-21.5.1-py3-none-any.whl", hash = "sha256:55aa670b67bbfb991b03fda39bd3276d92c419d702376e98c5df1c9989a26783"}, - {file = "virtualenv-21.5.1.tar.gz", hash = "sha256:dca3bf98275a59c652b69d68e73433e597d977c2da9198882479d1a7188009c8"}, + {file = "virtualenv-21.6.1-py3-none-any.whl", hash = "sha256:afe991df855715a2b2f60edfcc0107ef95a79fdfd8cb4cdaa71603d1c12e463b"}, + {file = "virtualenv-21.6.1.tar.gz", hash = "sha256:15f978b7cd329f24855ff4a0c4b4899cc7678589f49adbdcbbb4d3232e641128"}, ] [package.dependencies] diff --git a/pyproject.toml b/pyproject.toml index 65e8380..7d8f8f8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "siemens-standard-bom" -version = "4.2.1" +version = "4.3.0" description = "Standard BOM Format Library" keywords = ["sbom", "software-bill-of-materials", "cyclonedx", "cdx"] authors = [