Skip to content

Commit a2e7971

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 a2e7971

3 files changed

Lines changed: 174 additions & 1 deletion

File tree

sw360/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,5 @@
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+
__all__ = ["SW360", "SW360Error", "SW360OAuth2", "Component", "Release"]

sw360/sw360_api.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
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."""
1113

1214
import requests
1315

sw360/sw360_objects.py

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

0 commit comments

Comments
 (0)