Skip to content

Commit a19fd28

Browse files
authored
docs: update architecture description and examples (#550)
Signed-off-by: Jan Kowalleck <[email protected]>
1 parent 63cff7e commit a19fd28

8 files changed

+288
-29
lines changed

Diff for: .isort.cfg

-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ skip_glob =
99
.git/*,.tox/*,.venv/*,venv/*,.venv*/*,venv*/*,
1010
_OLD/*,_TEST/*,
1111
docs/*
12-
examples/*
1312
combine_as_imports = true
1413
default_section = THIRDPARTY
1514
ensure_newline_before_comments = true

Diff for: docs/architecture.rst

+1-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ Architecture
1717

1818
This library broadly is separated into three key functional areas:
1919

20-
1. **Model**: Internal models used to unify data from different parsers
20+
1. **Model**: Internal models used to unify data.
2121

2222
**Note:** As of version 4.0.0 of this library we support deserialization from JSON and XML as well as
2323
serialization to JSON and XML.
@@ -30,7 +30,6 @@ When wishing to generate a BOM, the process is as follows:
3030
1. Generate a Model by either:
3131
1. Programmatically using this library
3232
2. By deserializing from an existing CycloneDX BOM document
33-
3. From a :py:mod:`cyclonedx.parser`
3433
2. Output the Model using an :py:mod:`cyclonedx.output` instance that reflects the schema version and format you require
3534

3635
.. toctree::

Diff for: docs/examples.rst

+11-3
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,17 @@
1515
Examples
1616
========
1717

18-
Complex
19-
-------
18+
Complex Serialize
19+
-----------------
2020

21-
.. literalinclude:: ../examples/complex.py
21+
.. literalinclude:: ../examples/complex_serialize.py
22+
:language: python
23+
:linenos:
24+
25+
26+
Complex Deserialize
27+
-------------------
28+
29+
.. literalinclude:: ../examples/complex_deserialize.py
2230
:language: python
2331
:linenos:

Diff for: docs/modelling.rst

+3-17
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@
1515
Modelling
1616
=========
1717

18-
You can create a BOM Model from either a :py:mod:`cyclonedx.parser` instance or manually using the methods available
19-
directly on the :py:mod:`cyclonedx.model.bom.Bom` class.
18+
You can create a BOM Model from either manually using the methods available
19+
directly on the :py:class:`cyclonedx.model.bom.Bom` class,
20+
or deserialize a JSON/XML via :py:meth:`cyclonedx.model.bom.Bom.from_json`/:py:meth:`cyclonedx.model.bom.Bom.from_xml`
2021

2122
Vulnerabilities are supported by the Model as of version 0.3.0.
2223

@@ -76,21 +77,6 @@ you use a library such as `defusedxml` instead of the native `xml.etree.ElementT
7677
deserialized_bom = cast(Bom, Bom.from_xml(data=ElementTree.fromstring(input_xml.read())))
7778
7879
79-
Example BOM using a Parser
80-
--------------------------
81-
82-
**Note:** Concreate parser implementations were moved out of this library and into `CycloneDX Python`_ as of version
83-
``1.0.0``.
84-
85-
.. code-block:: python
86-
87-
from cyclonedx.model.bom import Bom
88-
from cyclonedx_py.parser.environment import EnvironmentParser
89-
90-
parser = EnvironmentParser()
91-
bom = Bom.from_parser(parser=parser)
92-
93-
9480
9581
9682
.. _CycloneDX Python: https://github.com/CycloneDX/cyclonedx-python

Diff for: examples/README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Examples
22

3-
* [Build & Serialize](build_and_serialize.py)
3+
* [Build & Serialize](complex_serialize.py)
4+
* [Deserialize](complex_deserialize.py)
45

56
----
67

Diff for: examples/complex_deserialize.py

+267
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,267 @@
1+
# This file is part of CycloneDX Python Lib
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
#
15+
# SPDX-License-Identifier: Apache-2.0
16+
# Copyright (c) OWASP Foundation. All Rights Reserved.
17+
18+
import sys
19+
from json import loads as json_loads
20+
from typing import TYPE_CHECKING
21+
22+
from defusedxml import ElementTree as SafeElementTree # type:ignore[import-untyped]
23+
24+
from cyclonedx.exception import MissingOptionalDependencyException
25+
from cyclonedx.model.bom import Bom
26+
from cyclonedx.schema import OutputFormat, SchemaVersion
27+
from cyclonedx.validation import make_schemabased_validator
28+
from cyclonedx.validation.json import JsonStrictValidator
29+
30+
if TYPE_CHECKING:
31+
from cyclonedx.validation.xml import XmlValidator
32+
33+
# region JSON
34+
35+
json_data = """{
36+
"$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json",
37+
"bomFormat": "CycloneDX",
38+
"specVersion": "1.5",
39+
"serialNumber": "urn:uuid:88fabcfa-7529-4ba2-8256-29bec0c03900",
40+
"version": 1,
41+
"metadata": {
42+
"timestamp": "2024-02-10T21:38:53.313120+00:00",
43+
"tools": [
44+
{
45+
"vendor": "CycloneDX",
46+
"name": "cyclonedx-python-lib",
47+
"version": "6.4.1",
48+
"externalReferences": [
49+
{
50+
"type": "build-system",
51+
"url": "https://github.com/CycloneDX/cyclonedx-python-lib/actions"
52+
},
53+
{
54+
"type": "distribution",
55+
"url": "https://pypi.org/project/cyclonedx-python-lib/"
56+
},
57+
{
58+
"type": "documentation",
59+
"url": "https://cyclonedx-python-library.readthedocs.io/"
60+
},
61+
{
62+
"type": "issue-tracker",
63+
"url": "https://github.com/CycloneDX/cyclonedx-python-lib/issues"
64+
},
65+
{
66+
"type": "license",
67+
"url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE"
68+
},
69+
{
70+
"type": "release-notes",
71+
"url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md"
72+
},
73+
{
74+
"type": "vcs",
75+
"url": "https://github.com/CycloneDX/cyclonedx-python-lib"
76+
},
77+
{
78+
"type": "website",
79+
"url": "https://github.com/CycloneDX/cyclonedx-python-lib/#readme"
80+
}
81+
]
82+
}
83+
],
84+
"component": {
85+
"bom-ref": "myApp",
86+
"name": "myApp",
87+
"type": "application",
88+
"licenses": [
89+
{
90+
"license": {
91+
"id": "MIT"
92+
}
93+
}
94+
]
95+
}
96+
},
97+
"components": [
98+
{
99+
"bom-ref": "[email protected]",
100+
"type": "library",
101+
"group": "acme",
102+
"name": "some-component",
103+
"version": "1.33.7-beta.1",
104+
"purl": "pkg:generic/acme/[email protected]",
105+
"licenses": [
106+
{
107+
"license": {
108+
"name": "(c) 2021 Acme inc."
109+
}
110+
}
111+
],
112+
"supplier": {
113+
"name": "Acme Inc",
114+
"url": [
115+
"https://www.acme.org"
116+
]
117+
}
118+
},
119+
{
120+
"bom-ref": "some-lib",
121+
"type": "library",
122+
"name": "some-library",
123+
"licenses": [
124+
{
125+
"expression": "GPL-3.0-only WITH Classpath-exception-2.0"
126+
}
127+
]
128+
}
129+
],
130+
"dependencies": [
131+
{
132+
"ref": "some-lib"
133+
},
134+
{
135+
"dependsOn": [
136+
137+
],
138+
"ref": "myApp"
139+
},
140+
{
141+
"dependsOn": [
142+
"some-lib"
143+
],
144+
145+
}
146+
]
147+
}"""
148+
my_json_validator = JsonStrictValidator(SchemaVersion.V1_5)
149+
try:
150+
validation_errors = my_json_validator.validate_str(json_data)
151+
if validation_errors:
152+
print('JSON invalid', 'ValidationError:', repr(validation_errors), sep='\n', file=sys.stderr)
153+
sys.exit(2)
154+
print('JSON valid')
155+
except MissingOptionalDependencyException as error:
156+
print('JSON-validation was skipped due to', error)
157+
bom_from_json = Bom.from_json( # type: ignore[attr-defined]
158+
json_loads(json_data))
159+
print('bom_from_json', repr(bom_from_json))
160+
161+
# endregion JSON
162+
163+
print('', '=' * 30, '', sep='\n')
164+
165+
# endregion XML
166+
167+
xml_data = """<?xml version="1.0" ?>
168+
<bom xmlns="http://cyclonedx.org/schema/bom/1.5"
169+
serialNumber="urn:uuid:88fabcfa-7529-4ba2-8256-29bec0c03900"
170+
version="1"
171+
>
172+
<metadata>
173+
<timestamp>2024-02-10T21:38:53.313120+00:00</timestamp>
174+
<tools>
175+
<tool>
176+
<vendor>CycloneDX</vendor>
177+
<name>cyclonedx-python-lib</name>
178+
<version>6.4.1</version>
179+
<externalReferences>
180+
<reference type="build-system">
181+
<url>https://github.com/CycloneDX/cyclonedx-python-lib/actions</url>
182+
</reference>
183+
<reference type="distribution">
184+
<url>https://pypi.org/project/cyclonedx-python-lib/</url>
185+
</reference>
186+
<reference type="documentation">
187+
<url>https://cyclonedx-python-library.readthedocs.io/</url>
188+
</reference>
189+
<reference type="issue-tracker">
190+
<url>https://github.com/CycloneDX/cyclonedx-python-lib/issues</url>
191+
</reference>
192+
<reference type="license">
193+
<url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE</url>
194+
</reference>
195+
<reference type="release-notes">
196+
<url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md</url>
197+
</reference>
198+
<reference type="vcs">
199+
<url>https://github.com/CycloneDX/cyclonedx-python-lib</url>
200+
</reference>
201+
<reference type="website">
202+
<url>https://github.com/CycloneDX/cyclonedx-python-lib/#readme</url>
203+
</reference>
204+
</externalReferences>
205+
</tool>
206+
</tools>
207+
<component type="application" bom-ref="myApp">
208+
<name>myApp</name>
209+
<licenses>
210+
<license>
211+
<id>MIT</id>
212+
</license>
213+
</licenses>
214+
</component>
215+
</metadata>
216+
<components>
217+
<component type="library" bom-ref="[email protected]">
218+
<supplier>
219+
<name>Acme Inc</name>
220+
<url>https://www.acme.org</url>
221+
</supplier>
222+
<group>acme</group>
223+
<name>some-component</name>
224+
<version>1.33.7-beta.1</version>
225+
<licenses>
226+
<license>
227+
<name>(c) 2021 Acme inc.</name>
228+
</license>
229+
</licenses>
230+
<purl>pkg:generic/acme/[email protected]</purl>
231+
</component>
232+
<component type="library" bom-ref="some-lib">
233+
<name>some-library</name>
234+
<licenses>
235+
<expression>GPL-3.0-only WITH Classpath-exception-2.0</expression>
236+
</licenses>
237+
</component>
238+
</components>
239+
<dependencies>
240+
<dependency ref="some-lib"/>
241+
<dependency ref="myApp">
242+
<dependency ref="[email protected]"/>
243+
</dependency>
244+
<dependency ref="[email protected]">
245+
<dependency ref="some-lib"/>
246+
</dependency>
247+
</dependencies>
248+
</bom>"""
249+
my_xml_validator: 'XmlValidator' = make_schemabased_validator(OutputFormat.XML, SchemaVersion.V1_5)
250+
try:
251+
validation_errors = my_xml_validator.validate_str(xml_data)
252+
if validation_errors:
253+
print('XML invalid', 'ValidationError:', repr(validation_errors), sep='\n', file=sys.stderr)
254+
sys.exit(2)
255+
print('XML valid')
256+
except MissingOptionalDependencyException as error:
257+
print('XML-validation was skipped due to', error)
258+
bom_from_xml = Bom.from_xml( # type: ignore[attr-defined]
259+
SafeElementTree.fromstring(xml_data))
260+
print('bom_from_xml', repr(bom_from_xml))
261+
262+
# endregion XML
263+
264+
print('', '=' * 30, '', sep='\n')
265+
266+
print('assert bom_from_json equals bom_from_xml')
267+
assert bom_from_json == bom_from_xml, 'expected to have equal BOMs from JSON and XML'

Diff for: examples/complex.py renamed to examples/complex_serialize.py

+3-4
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
# Copyright (c) OWASP Foundation. All Rights Reserved.
1717

1818
import sys
19+
from typing import TYPE_CHECKING
1920

2021
from packageurl import PackageURL
2122

@@ -26,11 +27,9 @@
2627
from cyclonedx.model.component import Component, ComponentType
2728
from cyclonedx.output import make_outputter
2829
from cyclonedx.output.json import JsonV1Dot5
29-
from cyclonedx.schema import SchemaVersion, OutputFormat
30-
from cyclonedx.validation.json import JsonStrictValidator
30+
from cyclonedx.schema import OutputFormat, SchemaVersion
3131
from cyclonedx.validation import make_schemabased_validator
32-
33-
from typing import TYPE_CHECKING
32+
from cyclonedx.validation.json import JsonStrictValidator
3433

3534
if TYPE_CHECKING:
3635
from cyclonedx.output.json import Json as JsonOutputter

Diff for: pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ include = [
2727
{ path="README.md", format =["sdist","wheel"] },
2828
{ path="LICENSE", format=["sdist","wheel"] },
2929
{ path="NOTICE", format=["sdist","wheel"] },
30-
{ path="tests", format=["sdist"] },
3130
{ path="CHANGELOG.md", format=["sdist"] },
3231
{ path="docs", format=["sdist"] },
3332
{ path="examples", format=["sdist"] },
33+
{ path="tests", format=["sdist"] },
3434
]
3535
exclude = [
3636
# exclude dotfiles and dotfolders

0 commit comments

Comments
 (0)