Skip to content

Commit 5967310

Browse files
committed
feat: basic abstraction for Release and Component
Start a high level API with classes for Release and Component.
1 parent cfc8cfc commit 5967310

3 files changed

Lines changed: 175 additions & 1 deletion

File tree

sw360/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,6 @@
1212
from .sw360_api import SW360 # noqa: F401
1313
from .sw360error import SW360Error # noqa: F401
1414
from .sw360oauth2 import SW360OAuth2 # noqa: F401
15+
from .sw360_objects import Component, Release
16+
17+
__all__ = ["SW360", "SW360Error", "Component", "Release"]

sw360/sw360_api.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@
77
# SPDX-License-Identifier: MIT
88
# -------------------------------------------------------------------------------
99

10-
"""Python interface to the Siemens SW360 platform"""
10+
"""Low-Level Python interface to the SW360 REST API. This provides a low-level
11+
abstraction of the REST API endpoints. In most cases, JSON objects are just
12+
passed through unchanged from/to the SW360 REST API."""
13+
1114

1215
import requests
1316

sw360/sw360_objects.py

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
# -------------------------------------------------------------------------------
2+
# (c) 2019-2020 Siemens AG
3+
# All Rights Reserved.
4+
# Author: gernot.hillier@siemens.com
5+
#
6+
# Licensed as Siemens Inner Source, see top-level License.md file for details.
7+
# -------------------------------------------------------------------------------
8+
9+
"""High-Level Python interface to the SW360 REST API. This is a set of Python
10+
classes abstracting most important aspects of the SW360 REST API. For now, this
11+
does NOT strive to provide a complete API abstraction, just provide a more
12+
convenient abstraction for some (important) objects."""
13+
14+
15+
class Release:
16+
"""A release is the SW360 abstraction for a single version of a component.
17+
18+
You can either create it from a SW360 `json` object or by specifying the
19+
details via the constructor parameters, see list below. Only the most
20+
important attributes are supported, rest hast be provided via `kwargs` and
21+
is stored in the `details` attribute of instances.
22+
23+
For JSON parsing, please read documentation of from_json() method.
24+
25+
:param json: create release from SW360 JSON object by calling from_json()
26+
:param component_id: SW360 id of the component the release belongs to
27+
:param version: the actual version
28+
:param downloadurl: URL the release was downloaded from
29+
:param kwargs: additional relase details as specified in the SW360 REST API
30+
:type json: SW360 JSON object
31+
:type component_id: string
32+
:type version: string
33+
:type downloadurl: string
34+
:type kwargs: dictionary
35+
36+
"""
37+
def __init__(self, json=None, component_id=None, version=None,
38+
downloadurl=None, **kwargs):
39+
self.details = {}
40+
"""All release details which are not explicitely supported by the
41+
constructor parameters are stored in the `details` attribute. Shall use
42+
names and types as specified in SW360 REST API."""
43+
44+
if json is not None:
45+
self.from_json(json)
46+
else:
47+
self.component_id = component_id
48+
self.version = version
49+
self.downloadurl = downloadurl
50+
for key, value in kwargs:
51+
self.details[key] = value
52+
53+
def from_json(self, json):
54+
"""Parse release JSON object from SW360 REST API. The component it
55+
belongs to will be extracted and stored in the `component_id`
56+
attribute.
57+
58+
All details not directly supported by this class will be stored as-is
59+
in the `details` instance attribute. For now, this also includes
60+
attachment information and external ids which will be stored as-is in
61+
`details['_embedded']['sw360:attachments']` and
62+
`details['externalIds']. Please note that this might change in future
63+
if better abstractions will be added in this Python library."""
64+
for key, value in json.items():
65+
if key in ("name", "version", "downloadurl"):
66+
self.__setattr__(key, value)
67+
elif key == "_links":
68+
for links_key, links_value in value.items():
69+
if links_key == "sw360:component":
70+
self.component_id = links_value["href"].split("/")[-1]
71+
elif links_key == "self":
72+
self.id = links_value["href"].split("/")[-1]
73+
else:
74+
self.details.setdefault(key, {})
75+
self.details[key][links_key] = links_value
76+
else:
77+
self.details[key] = value
78+
79+
def __repr__(self):
80+
"""Representation string."""
81+
return "<Release %s %s id:%s>" % (self.name, self.version, self.id)
82+
83+
84+
class Component:
85+
"""A component is the SW360 abstraction for a single software
86+
package/library/program/etc.
87+
88+
You can either create it from a SW360 `json` object or by specifying the
89+
details via the constructor parameters, see list below. Only the most
90+
important attributes are supported, rest hast be provided via `kwargs` and
91+
is stored in the `details` attribute of instances.
92+
93+
For JSON parsing, please read documentation of from_json() method.
94+
95+
:param json: create component from SW360 JSON object by calling from_json()
96+
:param name: name of the component
97+
:param description: short description for component
98+
:param homepage: homepage of the component
99+
:param component_type: one of "INTERNAL", "OSS", "COTS", "FREESOFTWARE",
100+
"INNER_SOURCE", "SERVICE", "CODE_SNIPPET"
101+
:param kwargs: additional component details as specified in the SW360 REST API
102+
:type json: SW360 JSON object
103+
:type name: string
104+
:type description: string
105+
:type homepage: string
106+
:type component_type: string
107+
:type kwargs: dictionary
108+
"""
109+
def __init__(self, json=None, name=None, description=None, homepage=None,
110+
component_type=None, **kwargs):
111+
self.details = {}
112+
"""All release details which are not explicitely supported by the
113+
constructor parameters are stored in the `details` attribute. Shall use
114+
names and types as specified in SW360 REST API."""
115+
116+
self.releases = {}
117+
118+
if json is not None:
119+
self.from_json(json)
120+
else:
121+
self.name = name
122+
self.description = description
123+
self.homepage = homepage
124+
self.component_type = component_type
125+
for key, value in kwargs:
126+
self.details[key] = value
127+
128+
def from_json(self, json):
129+
"""Parse component JSON object from SW360 REST API. Information for
130+
its releases will be extracted, Release() objects created for them
131+
and stored in the `releases` instance attribue. Please note that
132+
the REST API will only provide basic information for the releases.
133+
134+
All details not directly supported by this class will be
135+
stored as-is in the `details` instance attribute. For now, this also
136+
includes vendor information and external ids which will be stored
137+
as-is in `details['_embedded']['sw360:vendors']` and
138+
`details['externalIds']. Please note that this might change in future
139+
if better abstractions will be added in this Python library."""
140+
releases = None
141+
for key, value in json.items():
142+
if key in ("name", "description", "homepage"):
143+
self.__setattr__(key, value)
144+
elif key == "componentType":
145+
self.component_type = value
146+
elif key in ("_links", "_embedded"):
147+
for links_key, links_value in value.items():
148+
if key == "_links" and links_key == "self":
149+
self.id = links_value["href"].split("/")[-1]
150+
elif links_key == "sw360:releases":
151+
releases = links_value
152+
else:
153+
self.details.setdefault(key, {})
154+
self.details[key][links_key] = links_value
155+
else:
156+
self.details[key] = value
157+
158+
if releases is None:
159+
return
160+
161+
for release_json in releases:
162+
release = Release(component_id=self.id)
163+
release.from_json(release_json)
164+
self.releases[release.id] = release
165+
166+
def __repr__(self):
167+
"""Representation string."""
168+
return "<Component %s id:%s>" % (self.name, self.id)

0 commit comments

Comments
 (0)