robotframework-prometheus 0.6.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- robotframework-prometheus-0.6.1/PKG-INFO +78 -0
- robotframework-prometheus-0.6.1/PrometheusInterface/PrometheusInterface.pdf +0 -0
- robotframework-prometheus-0.6.1/PrometheusInterface/__init__.py +13 -0
- robotframework-prometheus-0.6.1/PrometheusInterface/prometheus_interface.py +697 -0
- robotframework-prometheus-0.6.1/README.rst +73 -0
- robotframework-prometheus-0.6.1/robotframework_prometheus.egg-info/PKG-INFO +78 -0
- robotframework-prometheus-0.6.1/robotframework_prometheus.egg-info/SOURCES.txt +10 -0
- robotframework-prometheus-0.6.1/robotframework_prometheus.egg-info/dependency_links.txt +1 -0
- robotframework-prometheus-0.6.1/robotframework_prometheus.egg-info/requires.txt +3 -0
- robotframework-prometheus-0.6.1/robotframework_prometheus.egg-info/top_level.txt +1 -0
- robotframework-prometheus-0.6.1/setup.cfg +4 -0
- robotframework-prometheus-0.6.1/setup.py +224 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: robotframework-prometheus
|
|
3
|
+
Version: 0.6.1
|
|
4
|
+
Summary: Additional Robot Framework keywords
|
|
5
|
+
Home-page: https://github.com/test-fullautomation/robotframework-prometheus
|
|
6
|
+
Author: Holger Queckenstedt
|
|
7
|
+
Author-email: Holger.Queckenstedt@de.bosch.com
|
|
8
|
+
License: UNKNOWN
|
|
9
|
+
Platform: UNKNOWN
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Topic :: Software Development
|
|
16
|
+
Requires-Python: >=3.0
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
|
|
19
|
+
Package Description
|
|
20
|
+
===================
|
|
21
|
+
|
|
22
|
+
The interface library **prometheus\_interface** provides Robot Framework
|
|
23
|
+
keywords to communicate with the monitoring system **Prometheus**.
|
|
24
|
+
|
|
25
|
+
Currently this library is under development. We work on it. But what is
|
|
26
|
+
available up to now, is not ready for being used in productive systems
|
|
27
|
+
(but hopefully will be in near future).
|
|
28
|
+
|
|
29
|
+
Package Documentation
|
|
30
|
+
---------------------
|
|
31
|
+
|
|
32
|
+
A (growing) detailed documentation of the **prometheus\_interface** can
|
|
33
|
+
be found here:
|
|
34
|
+
|
|
35
|
+
[PrometheusInterface.pdf](https://github.com/test-fullautomation/robotframework-prometheus/blob/develop/PrometheusInterface/PrometheusInterface.pdf)
|
|
36
|
+
|
|
37
|
+
Feedback
|
|
38
|
+
--------
|
|
39
|
+
|
|
40
|
+
To give us a feedback, you can send an email to [Thomas
|
|
41
|
+
Pollerspöck](mailto:Thomas.Pollerspoeck@de.bosch.com)
|
|
42
|
+
|
|
43
|
+
In case you want to report a bug or request any interesting feature,
|
|
44
|
+
please don\'t hesitate to raise a ticket.
|
|
45
|
+
|
|
46
|
+
Maintainers
|
|
47
|
+
-----------
|
|
48
|
+
|
|
49
|
+
[Holger Queckenstedt](mailto:Holger.Queckenstedt@de.bosch.com)
|
|
50
|
+
|
|
51
|
+
[Thomas Pollerspöck](mailto:Thomas.Pollerspoeck@de.bosch.com)
|
|
52
|
+
|
|
53
|
+
Contributors
|
|
54
|
+
------------
|
|
55
|
+
|
|
56
|
+
[Holger Queckenstedt](mailto:Holger.Queckenstedt@de.bosch.com)
|
|
57
|
+
|
|
58
|
+
[Thomas Pollerspöck](mailto:Thomas.Pollerspoeck@de.bosch.com)
|
|
59
|
+
|
|
60
|
+
License
|
|
61
|
+
-------
|
|
62
|
+
|
|
63
|
+
Copyright 2020-2024 Robert Bosch GmbH
|
|
64
|
+
|
|
65
|
+
Licensed under the Apache License, Version 2.0 (the \"License\"); you
|
|
66
|
+
may not use this file except in compliance with the License. You may
|
|
67
|
+
obtain a copy of the License at
|
|
68
|
+
|
|
69
|
+
> [](http://www.apache.org/licenses/LICENSE-2.0.html)
|
|
71
|
+
|
|
72
|
+
Unless required by applicable law or agreed to in writing, software
|
|
73
|
+
distributed under the License is distributed on an \"AS IS\" BASIS,
|
|
74
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
75
|
+
See the License for the specific language governing permissions and
|
|
76
|
+
limitations under the License.
|
|
77
|
+
|
|
78
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Copyright 2020-2024 Robert Bosch GmbH
|
|
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.
|
|
@@ -0,0 +1,697 @@
|
|
|
1
|
+
# Copyright 2020-2024 Robert Bosch GmbH
|
|
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
|
+
# XC-HWP/ESW3-Queckenstedt
|
|
16
|
+
|
|
17
|
+
# -- import standard Python modules
|
|
18
|
+
import pickle, os, time, random
|
|
19
|
+
import dotdict
|
|
20
|
+
|
|
21
|
+
# -- import Prometheus interface
|
|
22
|
+
from prometheus_client import start_http_server, Gauge, Counter, Info
|
|
23
|
+
|
|
24
|
+
# -- import Robotframework API
|
|
25
|
+
from robot.api.deco import keyword, library # required when using @keyword, @library decorators
|
|
26
|
+
from robot.libraries.BuiltIn import BuiltIn
|
|
27
|
+
|
|
28
|
+
# -- import some helpers
|
|
29
|
+
from PythonExtensionsCollection.String.CString import CString
|
|
30
|
+
from PythonExtensionsCollection.Utils.CUtils import *
|
|
31
|
+
|
|
32
|
+
# --------------------------------------------------------------------------------------------------------------
|
|
33
|
+
# this interface library
|
|
34
|
+
#
|
|
35
|
+
LIBRARY_VERSION = "0.6.1"
|
|
36
|
+
LIBRARY_VERSION_DATE = "17.06.2024"
|
|
37
|
+
#
|
|
38
|
+
THISMODULENAME = "prometheus_interface.py"
|
|
39
|
+
THISMODULE = f"{THISMODULENAME} v. {LIBRARY_VERSION} / {LIBRARY_VERSION_DATE}"
|
|
40
|
+
#
|
|
41
|
+
DEFAULT_PORT = 8000
|
|
42
|
+
#
|
|
43
|
+
DEFAULT_MESSAGE_LEVEL = "INFO"
|
|
44
|
+
#
|
|
45
|
+
# --------------------------------------------------------------------------------------------------------------
|
|
46
|
+
#
|
|
47
|
+
@library
|
|
48
|
+
class prometheus_interface():
|
|
49
|
+
"""The class 'prometheus_interface' provides to communicate with the monitoring system Prometheus.
|
|
50
|
+
For this purpose the 'Prometheus Python client library' is used.
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
ROBOT_AUTO_KEYWORDS = False # only decorated methods are keywords
|
|
54
|
+
ROBOT_LIBRARY_VERSION = LIBRARY_VERSION
|
|
55
|
+
ROBOT_LIBRARY_SCOPE = 'GLOBAL'
|
|
56
|
+
|
|
57
|
+
# --------------------------------------------------------------------------------------------------------------
|
|
58
|
+
#TM***
|
|
59
|
+
|
|
60
|
+
def __init__(self, port_number=DEFAULT_PORT, message_level=DEFAULT_MESSAGE_LEVEL):
|
|
61
|
+
self.__sMessageLevel = message_level
|
|
62
|
+
self.__port_number = port_number
|
|
63
|
+
|
|
64
|
+
# prometheus metric types
|
|
65
|
+
self.__dictCounter = {}
|
|
66
|
+
self.__dictGauges = {}
|
|
67
|
+
self.__dictInfos = {}
|
|
68
|
+
|
|
69
|
+
start_http_server(self.__port_number)
|
|
70
|
+
|
|
71
|
+
# default info metric about this interface library
|
|
72
|
+
oInfo = Info("Prometheus_interface", "Prometheus interface info")
|
|
73
|
+
dictInfo = {}
|
|
74
|
+
dictInfo['file name'] = THISMODULENAME
|
|
75
|
+
dictInfo['version'] = LIBRARY_VERSION
|
|
76
|
+
dictInfo['date'] = LIBRARY_VERSION_DATE
|
|
77
|
+
dictInfo['location'] = self.where_am_i()
|
|
78
|
+
oInfo.info(dictInfo)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def __del__(self):
|
|
82
|
+
del self.__dictCounter
|
|
83
|
+
del self.__dictGauges
|
|
84
|
+
del self.__dictInfos
|
|
85
|
+
|
|
86
|
+
# --------------------------------------------------------------------------------------------------------------
|
|
87
|
+
# -- library informations
|
|
88
|
+
# --------------------------------------------------------------------------------------------------------------
|
|
89
|
+
#TM***
|
|
90
|
+
|
|
91
|
+
@keyword
|
|
92
|
+
def get_version(self):
|
|
93
|
+
"""Returns the version of this interface library
|
|
94
|
+
"""
|
|
95
|
+
return LIBRARY_VERSION
|
|
96
|
+
|
|
97
|
+
@keyword
|
|
98
|
+
def who_am_i(self):
|
|
99
|
+
"""Returns the full name of this interface library
|
|
100
|
+
"""
|
|
101
|
+
return THISMODULE
|
|
102
|
+
|
|
103
|
+
@keyword
|
|
104
|
+
def where_am_i(self):
|
|
105
|
+
"""Returns path to this interface library
|
|
106
|
+
"""
|
|
107
|
+
location = CString.NormalizePath(os.path.dirname(os.path.abspath(__file__)))
|
|
108
|
+
return location
|
|
109
|
+
|
|
110
|
+
@keyword
|
|
111
|
+
def get_port_number(self):
|
|
112
|
+
"""Returns the port number assigned to this instance of the library
|
|
113
|
+
"""
|
|
114
|
+
return self.__port_number
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
# --------------------------------------------------------------------------------------------------------------
|
|
118
|
+
# -- prometheus metric type 'Info'
|
|
119
|
+
# --------------------------------------------------------------------------------------------------------------
|
|
120
|
+
#TM***
|
|
121
|
+
|
|
122
|
+
@keyword
|
|
123
|
+
def add_info(self, name=None, description=None, labels=None):
|
|
124
|
+
"""add_info
|
|
125
|
+
"""
|
|
126
|
+
success = False
|
|
127
|
+
result = "UNKNOWN"
|
|
128
|
+
if name is None:
|
|
129
|
+
result = "Parameter 'name' not defined"
|
|
130
|
+
return success, result
|
|
131
|
+
if description is None:
|
|
132
|
+
result = "Parameter 'description' not defined"
|
|
133
|
+
return success, result
|
|
134
|
+
if name in self.__dictInfos:
|
|
135
|
+
result = f"An info with name '{name}' is already defined"
|
|
136
|
+
return success, result
|
|
137
|
+
oInfo = None
|
|
138
|
+
if labels is None:
|
|
139
|
+
oInfo = Info(name, description)
|
|
140
|
+
else:
|
|
141
|
+
labellist = labels.split(';')
|
|
142
|
+
listLabelNames = []
|
|
143
|
+
for label in labellist:
|
|
144
|
+
label = label.strip()
|
|
145
|
+
listLabelNames.append(label)
|
|
146
|
+
oInfo = Info(name, description, listLabelNames)
|
|
147
|
+
self.__dictInfos[name] = oInfo
|
|
148
|
+
success = True
|
|
149
|
+
listResults = []
|
|
150
|
+
listResults.append(f"Info '{name}' added")
|
|
151
|
+
if labels is not None:
|
|
152
|
+
listResults.append(f"with labels: '{labels}'")
|
|
153
|
+
result = " ".join(listResults)
|
|
154
|
+
return success, result
|
|
155
|
+
|
|
156
|
+
@keyword
|
|
157
|
+
def set_info(self, name=None, info=None, labels=None):
|
|
158
|
+
"""set_info
|
|
159
|
+
"""
|
|
160
|
+
success = False
|
|
161
|
+
result = "UNKNOWN"
|
|
162
|
+
if name is None:
|
|
163
|
+
result = "Parameter 'name' not defined"
|
|
164
|
+
return success, result
|
|
165
|
+
if info is None:
|
|
166
|
+
result = "Parameter 'info' not defined"
|
|
167
|
+
return success, result
|
|
168
|
+
if name not in self.__dictInfos:
|
|
169
|
+
result = f"Info '{name}' not defined"
|
|
170
|
+
return success, result
|
|
171
|
+
dictInfo = {}
|
|
172
|
+
list_splitparts = info.split(';')
|
|
173
|
+
for splitpart in list_splitparts:
|
|
174
|
+
splitpart = splitpart.strip()
|
|
175
|
+
list_splitparts2 = splitpart.split(':')
|
|
176
|
+
if len(list_splitparts2) != 2:
|
|
177
|
+
success = False
|
|
178
|
+
result = "Syntax error in parameter 'info' of '{name}': missing delimiter"
|
|
179
|
+
return success, result
|
|
180
|
+
param_name = list_splitparts2[0].strip()
|
|
181
|
+
if param_name == "":
|
|
182
|
+
success = False
|
|
183
|
+
result = "Syntax error in parameter 'info' of '{name}': parameter name is empty"
|
|
184
|
+
return success, result
|
|
185
|
+
param_value = list_splitparts2[1].strip()
|
|
186
|
+
if param_value == "":
|
|
187
|
+
success = False
|
|
188
|
+
result = "Syntax error in parameter 'info' of '{name}': parameter value is empty"
|
|
189
|
+
return success, result
|
|
190
|
+
dictInfo[param_name] = str(param_value)
|
|
191
|
+
oInfo = self.__dictInfos[name]
|
|
192
|
+
if labels is None:
|
|
193
|
+
oInfo.info(dictInfo)
|
|
194
|
+
else:
|
|
195
|
+
labellist = labels.split(';')
|
|
196
|
+
listLabelValues = []
|
|
197
|
+
for label in labellist:
|
|
198
|
+
label = label.strip()
|
|
199
|
+
listLabelValues.append(label)
|
|
200
|
+
oInfo.labels(*listLabelValues).info(dictInfo)
|
|
201
|
+
success = True
|
|
202
|
+
listResults = []
|
|
203
|
+
listResults.append(f"Info '{name}' set to'{info}'")
|
|
204
|
+
if labels is not None:
|
|
205
|
+
listResults.append(f"with labels: '{labels}'")
|
|
206
|
+
result = " ".join(listResults)
|
|
207
|
+
return success, result
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
# TODO lighting reaktivieren (as example)
|
|
211
|
+
|
|
212
|
+
# # @keyword
|
|
213
|
+
# # def add_lighting(self):
|
|
214
|
+
# # """add_lighting (experimental only)
|
|
215
|
+
# # """
|
|
216
|
+
# # self.__oLighting = Info('lighting', ': kind of lighting')
|
|
217
|
+
|
|
218
|
+
# # @keyword
|
|
219
|
+
# # def set_daylight(self):
|
|
220
|
+
# # """set_daylight (experimental only)
|
|
221
|
+
# # """
|
|
222
|
+
# # self.__oLighting.info({'lighting' : 'daylight'})
|
|
223
|
+
|
|
224
|
+
# # @keyword
|
|
225
|
+
# # def set_nightlight(self):
|
|
226
|
+
# # """set_nightlight (experimental only)
|
|
227
|
+
# # """
|
|
228
|
+
# # self.__oLighting.info({'lighting' : 'nightlight'})
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
# --------------------------------------------------------------------------------------------------------------
|
|
232
|
+
# -- prometheus metric type 'Counter'
|
|
233
|
+
# --------------------------------------------------------------------------------------------------------------
|
|
234
|
+
#TM***
|
|
235
|
+
|
|
236
|
+
@keyword
|
|
237
|
+
def add_counter(self, name=None, description=None, labels=None):
|
|
238
|
+
"""This keyword adds a new counter. The values of existing counters can be changed with ``inc_counter``.
|
|
239
|
+
|
|
240
|
+
**Arguments:**
|
|
241
|
+
|
|
242
|
+
* ``name``
|
|
243
|
+
|
|
244
|
+
The name of the new counter
|
|
245
|
+
|
|
246
|
+
/ *Condition*: required / *Type*: str /
|
|
247
|
+
|
|
248
|
+
* ``description``
|
|
249
|
+
|
|
250
|
+
The description of the new counter
|
|
251
|
+
|
|
252
|
+
/ *Condition*: required / *Type*: str /
|
|
253
|
+
|
|
254
|
+
* ``labels``
|
|
255
|
+
|
|
256
|
+
A semicolon separated list of label names assigned to the new counter
|
|
257
|
+
|
|
258
|
+
/ *Condition*: optional / *Type*: str / *Default*: None /
|
|
259
|
+
|
|
260
|
+
**Returns:**
|
|
261
|
+
|
|
262
|
+
* ``success``
|
|
263
|
+
|
|
264
|
+
/ *Type*: bool /
|
|
265
|
+
|
|
266
|
+
Indicates if the computation of the keyword was successful or not
|
|
267
|
+
|
|
268
|
+
* ``result``
|
|
269
|
+
|
|
270
|
+
/ *Type*: str /
|
|
271
|
+
|
|
272
|
+
The result of the computation of the keyword
|
|
273
|
+
"""
|
|
274
|
+
success = False
|
|
275
|
+
result = "UNKNOWN"
|
|
276
|
+
if name is None:
|
|
277
|
+
result = "Parameter 'name' not defined"
|
|
278
|
+
return success, result
|
|
279
|
+
if description is None:
|
|
280
|
+
result = "Parameter 'description' not defined"
|
|
281
|
+
return success, result
|
|
282
|
+
if name in self.__dictCounter:
|
|
283
|
+
result = f"A counter with name '{name}' is already defined"
|
|
284
|
+
return success, result
|
|
285
|
+
oCounter = None
|
|
286
|
+
if labels is None:
|
|
287
|
+
oCounter = Counter(name, description)
|
|
288
|
+
else:
|
|
289
|
+
labellist = labels.split(';')
|
|
290
|
+
listLabelNames = []
|
|
291
|
+
for label in labellist:
|
|
292
|
+
label = label.strip()
|
|
293
|
+
listLabelNames.append(label)
|
|
294
|
+
oCounter = Counter(name, description, listLabelNames)
|
|
295
|
+
self.__dictCounter[name] = oCounter
|
|
296
|
+
success = True
|
|
297
|
+
listResults = []
|
|
298
|
+
listResults.append(f"Counter '{name}' added")
|
|
299
|
+
if labels is not None:
|
|
300
|
+
listResults.append(f"with labels: '{labels}'")
|
|
301
|
+
result = " ".join(listResults)
|
|
302
|
+
return success, result
|
|
303
|
+
# eof def add_counter(...):
|
|
304
|
+
|
|
305
|
+
@keyword
|
|
306
|
+
def inc_counter(self, name=None, value=None, labels=None):
|
|
307
|
+
"""This keyword increments a counter. The counter has to be added with '``add_counter``' before.
|
|
308
|
+
|
|
309
|
+
**Arguments:**
|
|
310
|
+
|
|
311
|
+
* ``name``
|
|
312
|
+
|
|
313
|
+
The name of the counter
|
|
314
|
+
|
|
315
|
+
/ *Condition*: required / *Type*: str /
|
|
316
|
+
|
|
317
|
+
* ``value``
|
|
318
|
+
|
|
319
|
+
The value of increment. If not given, the value of the counter is incremented by value 1.
|
|
320
|
+
|
|
321
|
+
/ *Condition*: optional / *Type*: int / *Default*: None /
|
|
322
|
+
|
|
323
|
+
* ``labels``
|
|
324
|
+
|
|
325
|
+
A semicolon separated list of labels assigned to the counter. The order of labels must fit to the order of label names like defined in ``add_counter``.
|
|
326
|
+
|
|
327
|
+
/ *Condition*: optional / *Type*: str / *Default*: None /
|
|
328
|
+
|
|
329
|
+
**Returns:**
|
|
330
|
+
|
|
331
|
+
* ``success``
|
|
332
|
+
|
|
333
|
+
/ *Type*: bool /
|
|
334
|
+
|
|
335
|
+
Indicates if the computation of the keyword was successful or not
|
|
336
|
+
|
|
337
|
+
* ``result``
|
|
338
|
+
|
|
339
|
+
/ *Type*: str /
|
|
340
|
+
|
|
341
|
+
The result of the computation of the keyword
|
|
342
|
+
"""
|
|
343
|
+
success = False
|
|
344
|
+
result = "UNKNOWN"
|
|
345
|
+
if name is None:
|
|
346
|
+
result = "Parameter 'name' not defined"
|
|
347
|
+
return success, result
|
|
348
|
+
if name not in self.__dictCounter:
|
|
349
|
+
result = f"Counter '{name}' not defined"
|
|
350
|
+
return success, result
|
|
351
|
+
if value is not None:
|
|
352
|
+
try:
|
|
353
|
+
value = int(value)
|
|
354
|
+
except Exception as ex:
|
|
355
|
+
success = False
|
|
356
|
+
result = str(ex)
|
|
357
|
+
return success, result
|
|
358
|
+
oCounter = self.__dictCounter[name]
|
|
359
|
+
if labels is None:
|
|
360
|
+
if value is None:
|
|
361
|
+
oCounter.inc()
|
|
362
|
+
else:
|
|
363
|
+
oCounter.inc(value)
|
|
364
|
+
else:
|
|
365
|
+
labellist = labels.split(';')
|
|
366
|
+
listLabelValues = []
|
|
367
|
+
for label in labellist:
|
|
368
|
+
label = label.strip()
|
|
369
|
+
listLabelValues.append(label)
|
|
370
|
+
if value is None:
|
|
371
|
+
oCounter.labels(*listLabelValues).inc()
|
|
372
|
+
else:
|
|
373
|
+
oCounter.labels(*listLabelValues).inc(value)
|
|
374
|
+
success = True
|
|
375
|
+
listResults = []
|
|
376
|
+
listResults.append(f"Counter '{name}' incremented")
|
|
377
|
+
if value is not None:
|
|
378
|
+
listResults.append(f"by value '{value}'")
|
|
379
|
+
if labels is not None:
|
|
380
|
+
listResults.append(f"with labels: '{labels}'")
|
|
381
|
+
result = " ".join(listResults)
|
|
382
|
+
return success, result
|
|
383
|
+
# eof def inc_counter(...):
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
# --------------------------------------------------------------------------------------------------------------
|
|
387
|
+
# -- prometheus metric type 'Gauge'
|
|
388
|
+
# --------------------------------------------------------------------------------------------------------------
|
|
389
|
+
#TM***
|
|
390
|
+
|
|
391
|
+
@keyword
|
|
392
|
+
def add_gauge(self, name=None, description=None, labels=None):
|
|
393
|
+
"""This keyword adds a new gauge. The values of existing gauges can be changed with ``set_gauge``, ``inc_gauge`` and ``dec_gauge``.
|
|
394
|
+
|
|
395
|
+
**Arguments:**
|
|
396
|
+
|
|
397
|
+
* ``name``
|
|
398
|
+
|
|
399
|
+
The name of the new gauge
|
|
400
|
+
|
|
401
|
+
/ *Condition*: required / *Type*: str /
|
|
402
|
+
|
|
403
|
+
* ``description``
|
|
404
|
+
|
|
405
|
+
The description of the new gauge
|
|
406
|
+
|
|
407
|
+
/ *Condition*: required / *Type*: str /
|
|
408
|
+
|
|
409
|
+
* ``labels``
|
|
410
|
+
|
|
411
|
+
A semicolon separated list of label names assigned to the new gauge
|
|
412
|
+
|
|
413
|
+
/ *Condition*: optional / *Type*: str / *Default*: None /
|
|
414
|
+
|
|
415
|
+
**Returns:**
|
|
416
|
+
|
|
417
|
+
* ``success``
|
|
418
|
+
|
|
419
|
+
/ *Type*: bool /
|
|
420
|
+
|
|
421
|
+
Indicates if the computation of the keyword was successful or not
|
|
422
|
+
|
|
423
|
+
* ``result``
|
|
424
|
+
|
|
425
|
+
/ *Type*: str /
|
|
426
|
+
|
|
427
|
+
The result of the computation of the keyword
|
|
428
|
+
"""
|
|
429
|
+
success = False
|
|
430
|
+
result = "UNKNOWN"
|
|
431
|
+
if name is None:
|
|
432
|
+
result = "Parameter 'name' not defined"
|
|
433
|
+
return success, result
|
|
434
|
+
if description is None:
|
|
435
|
+
result = "Parameter 'description' not defined"
|
|
436
|
+
return success, result
|
|
437
|
+
if name in self.__dictGauges:
|
|
438
|
+
result = f"A gauge with name '{name}' is already defined"
|
|
439
|
+
return success, result
|
|
440
|
+
oGauge = None
|
|
441
|
+
if labels is None:
|
|
442
|
+
oGauge = Gauge(name, description)
|
|
443
|
+
else:
|
|
444
|
+
labellist = labels.split(';')
|
|
445
|
+
listLabelNames = []
|
|
446
|
+
for label in labellist:
|
|
447
|
+
label = label.strip()
|
|
448
|
+
listLabelNames.append(label)
|
|
449
|
+
oGauge = Gauge(name, description, listLabelNames)
|
|
450
|
+
self.__dictGauges[name] = oGauge
|
|
451
|
+
success = True
|
|
452
|
+
listResults = []
|
|
453
|
+
listResults.append(f"Gauge '{name}' added")
|
|
454
|
+
if labels is not None:
|
|
455
|
+
listResults.append(f"with labels: '{labels}'")
|
|
456
|
+
result = " ".join(listResults)
|
|
457
|
+
return success, result
|
|
458
|
+
# eof def add_gauge(...):
|
|
459
|
+
|
|
460
|
+
@keyword
|
|
461
|
+
def set_gauge(self, name=None, value=None, labels=None):
|
|
462
|
+
"""This keyword sets the value for a gauge. The gauge has to be added with '``add_gauge``' before.
|
|
463
|
+
|
|
464
|
+
**Arguments:**
|
|
465
|
+
|
|
466
|
+
* ``name``
|
|
467
|
+
|
|
468
|
+
The name of the gauge
|
|
469
|
+
|
|
470
|
+
/ *Condition*: required / *Type*: str /
|
|
471
|
+
|
|
472
|
+
* ``value``
|
|
473
|
+
|
|
474
|
+
The new value of the gauge.
|
|
475
|
+
|
|
476
|
+
/ *Condition*: optional / *Type*: int / *Default*: None /
|
|
477
|
+
|
|
478
|
+
* ``labels``
|
|
479
|
+
|
|
480
|
+
A semicolon separated list of labels assigned to the gauge. The order of labels must fit to the order of label names like defined in ``add_gauge``.
|
|
481
|
+
|
|
482
|
+
/ *Condition*: optional / *Type*: str / *Default*: None /
|
|
483
|
+
|
|
484
|
+
**Returns:**
|
|
485
|
+
|
|
486
|
+
* ``success``
|
|
487
|
+
|
|
488
|
+
/ *Type*: bool /
|
|
489
|
+
|
|
490
|
+
Indicates if the computation of the keyword was successful or not
|
|
491
|
+
|
|
492
|
+
* ``result``
|
|
493
|
+
|
|
494
|
+
/ *Type*: str /
|
|
495
|
+
|
|
496
|
+
The result of the computation of the keyword
|
|
497
|
+
"""
|
|
498
|
+
success = False
|
|
499
|
+
result = "UNKNOWN"
|
|
500
|
+
if name is None:
|
|
501
|
+
result = "Parameter 'name' not defined"
|
|
502
|
+
return success, result
|
|
503
|
+
if name not in self.__dictGauges:
|
|
504
|
+
result = f"Gauge '{name}' not defined"
|
|
505
|
+
return success, result
|
|
506
|
+
if value is None:
|
|
507
|
+
result = "Parameter 'value' not defined"
|
|
508
|
+
return success, result
|
|
509
|
+
else:
|
|
510
|
+
try:
|
|
511
|
+
value = int(value)
|
|
512
|
+
except Exception as ex:
|
|
513
|
+
success = False
|
|
514
|
+
result = str(ex)
|
|
515
|
+
return success, result
|
|
516
|
+
oGauge = self.__dictGauges[name]
|
|
517
|
+
if labels is None:
|
|
518
|
+
oGauge.set(value)
|
|
519
|
+
else:
|
|
520
|
+
labellist = labels.split(';')
|
|
521
|
+
listLabelValues = []
|
|
522
|
+
for label in labellist:
|
|
523
|
+
label = label.strip()
|
|
524
|
+
listLabelValues.append(label)
|
|
525
|
+
oGauge.labels(*listLabelValues).set(value)
|
|
526
|
+
success = True
|
|
527
|
+
listResults = []
|
|
528
|
+
listResults.append(f"Gauge '{name}' set to value '{value}'")
|
|
529
|
+
if labels is not None:
|
|
530
|
+
listResults.append(f"with labels: '{labels}'")
|
|
531
|
+
result = " ".join(listResults)
|
|
532
|
+
return success, result
|
|
533
|
+
# eof def set_gauge(...):
|
|
534
|
+
|
|
535
|
+
@keyword
|
|
536
|
+
def inc_gauge(self, name=None, value=None, labels=None):
|
|
537
|
+
"""This keyword increments a gauge. The gauge has to be added with '``add_gauge``' before.
|
|
538
|
+
|
|
539
|
+
**Arguments:**
|
|
540
|
+
|
|
541
|
+
* ``name``
|
|
542
|
+
|
|
543
|
+
The name of the gauge
|
|
544
|
+
|
|
545
|
+
/ *Condition*: required / *Type*: str /
|
|
546
|
+
|
|
547
|
+
* ``value``
|
|
548
|
+
|
|
549
|
+
The value of increment. If not given, the value of the gauge is incremented by value 1.
|
|
550
|
+
|
|
551
|
+
/ *Condition*: optional / *Type*: int / *Default*: None /
|
|
552
|
+
|
|
553
|
+
* ``labels``
|
|
554
|
+
|
|
555
|
+
A semicolon separated list of labels assigned to the gauge. The order of labels must fit to the order of label names like defined in ``add_gauge``.
|
|
556
|
+
|
|
557
|
+
/ *Condition*: optional / *Type*: str / *Default*: None /
|
|
558
|
+
|
|
559
|
+
**Returns:**
|
|
560
|
+
|
|
561
|
+
* ``success``
|
|
562
|
+
|
|
563
|
+
/ *Type*: bool /
|
|
564
|
+
|
|
565
|
+
Indicates if the computation of the keyword was successful or not
|
|
566
|
+
|
|
567
|
+
* ``result``
|
|
568
|
+
|
|
569
|
+
/ *Type*: str /
|
|
570
|
+
|
|
571
|
+
The result of the computation of the keyword
|
|
572
|
+
"""
|
|
573
|
+
success = False
|
|
574
|
+
result = "UNKNOWN"
|
|
575
|
+
if name is None:
|
|
576
|
+
result = "Parameter 'name' not defined"
|
|
577
|
+
return success, result
|
|
578
|
+
if name not in self.__dictGauges:
|
|
579
|
+
result = f"Gauge '{name}' not defined"
|
|
580
|
+
return success, result
|
|
581
|
+
if value is not None:
|
|
582
|
+
try:
|
|
583
|
+
value = int(value)
|
|
584
|
+
except Exception as ex:
|
|
585
|
+
success = False
|
|
586
|
+
result = str(ex)
|
|
587
|
+
return success, result
|
|
588
|
+
oGauge = self.__dictGauges[name]
|
|
589
|
+
if labels is None:
|
|
590
|
+
if value is None:
|
|
591
|
+
oGauge.inc()
|
|
592
|
+
else:
|
|
593
|
+
oGauge.inc(value)
|
|
594
|
+
else:
|
|
595
|
+
labellist = labels.split(';')
|
|
596
|
+
listLabelValues = []
|
|
597
|
+
for label in labellist:
|
|
598
|
+
label = label.strip()
|
|
599
|
+
listLabelValues.append(label)
|
|
600
|
+
if value is None:
|
|
601
|
+
oGauge.labels(*listLabelValues).inc()
|
|
602
|
+
else:
|
|
603
|
+
oGauge.labels(*listLabelValues).inc(value)
|
|
604
|
+
success = True
|
|
605
|
+
listResults = []
|
|
606
|
+
listResults.append(f"Gauge '{name}' incremented")
|
|
607
|
+
if value is not None:
|
|
608
|
+
listResults.append(f"by value '{value}'")
|
|
609
|
+
if labels is not None:
|
|
610
|
+
listResults.append(f"with labels: '{labels}'")
|
|
611
|
+
result = " ".join(listResults)
|
|
612
|
+
return success, result
|
|
613
|
+
# eof def inc_gauge(...):
|
|
614
|
+
|
|
615
|
+
@keyword
|
|
616
|
+
def dec_gauge(self, name=None, value=None, labels=None):
|
|
617
|
+
"""This keyword decrements a gauge. The gauge has to be added with '``add_gauge``' before.
|
|
618
|
+
|
|
619
|
+
**Arguments:**
|
|
620
|
+
|
|
621
|
+
* ``name``
|
|
622
|
+
|
|
623
|
+
The name of the gauge
|
|
624
|
+
|
|
625
|
+
/ *Condition*: required / *Type*: str /
|
|
626
|
+
|
|
627
|
+
* ``value``
|
|
628
|
+
|
|
629
|
+
The value of decrement. If not given, the value of the gauge is decremented by value 1.
|
|
630
|
+
|
|
631
|
+
/ *Condition*: optional / *Type*: int / *Default*: None /
|
|
632
|
+
|
|
633
|
+
* ``labels``
|
|
634
|
+
|
|
635
|
+
A semicolon separated list of labels assigned to the gauge. The order of labels must fit to the order of label names like defined in ``add_gauge``.
|
|
636
|
+
|
|
637
|
+
/ *Condition*: optional / *Type*: str / *Default*: None /
|
|
638
|
+
|
|
639
|
+
**Returns:**
|
|
640
|
+
|
|
641
|
+
* ``success``
|
|
642
|
+
|
|
643
|
+
/ *Type*: bool /
|
|
644
|
+
|
|
645
|
+
Indicates if the computation of the keyword was successful or not
|
|
646
|
+
|
|
647
|
+
* ``result``
|
|
648
|
+
|
|
649
|
+
/ *Type*: str /
|
|
650
|
+
|
|
651
|
+
The result of the computation of the keyword
|
|
652
|
+
"""
|
|
653
|
+
success = False
|
|
654
|
+
result = "UNKNOWN"
|
|
655
|
+
if name is None:
|
|
656
|
+
result = "Parameter 'name' not defined"
|
|
657
|
+
return success, result
|
|
658
|
+
if name not in self.__dictGauges:
|
|
659
|
+
result = f"Gauge '{name}' not defined"
|
|
660
|
+
return success, result
|
|
661
|
+
if value is not None:
|
|
662
|
+
try:
|
|
663
|
+
value = int(value)
|
|
664
|
+
except Exception as ex:
|
|
665
|
+
success = False
|
|
666
|
+
result = str(ex)
|
|
667
|
+
return success, result
|
|
668
|
+
oGauge = self.__dictGauges[name]
|
|
669
|
+
if labels is None:
|
|
670
|
+
if value is None:
|
|
671
|
+
oGauge.dec()
|
|
672
|
+
else:
|
|
673
|
+
oGauge.dec(value)
|
|
674
|
+
else:
|
|
675
|
+
labellist = labels.split(';')
|
|
676
|
+
listLabelValues = []
|
|
677
|
+
for label in labellist:
|
|
678
|
+
label = label.strip()
|
|
679
|
+
listLabelValues.append(label)
|
|
680
|
+
if value is None:
|
|
681
|
+
oGauge.labels(*listLabelValues).dec()
|
|
682
|
+
else:
|
|
683
|
+
oGauge.labels(*listLabelValues).dec(value)
|
|
684
|
+
success = True
|
|
685
|
+
listResults = []
|
|
686
|
+
listResults.append(f"Gauge '{name}' decremented")
|
|
687
|
+
if value is not None:
|
|
688
|
+
listResults.append(f"by value '{value}'")
|
|
689
|
+
if labels is not None:
|
|
690
|
+
listResults.append(f"with labels: '{labels}'")
|
|
691
|
+
result = " ".join(listResults)
|
|
692
|
+
return success, result
|
|
693
|
+
# eof def dec_gauge(...):
|
|
694
|
+
|
|
695
|
+
|
|
696
|
+
# eof class prometheus_interface():
|
|
697
|
+
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
.. Copyright 2020-2024 Robert Bosch GmbH
|
|
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
|
+
Package Description
|
|
16
|
+
===================
|
|
17
|
+
|
|
18
|
+
The interface library **prometheus_interface** provides Robot Framework keywords to communicate with the monitoring system **Prometheus**.
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
Currently this library is under development. We work on it. But what is available up to now, is not ready for being used in productive systems
|
|
22
|
+
(but hopefully will be in near future).
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
Package Documentation
|
|
27
|
+
---------------------
|
|
28
|
+
|
|
29
|
+
A (growing) detailed documentation of the **prometheus_interface** can be found here:
|
|
30
|
+
|
|
31
|
+
`PrometheusInterface.pdf <https://github.com/test-fullautomation/robotframework-prometheus/blob/develop/PrometheusInterface/PrometheusInterface.pdf>`_
|
|
32
|
+
|
|
33
|
+
Feedback
|
|
34
|
+
--------
|
|
35
|
+
|
|
36
|
+
To give us a feedback, you can send an email to `Thomas Pollerspöck <mailto:Thomas.Pollerspoeck@de.bosch.com>`_
|
|
37
|
+
|
|
38
|
+
In case you want to report a bug or request any interesting feature, please don't hesitate to raise a ticket.
|
|
39
|
+
|
|
40
|
+
Maintainers
|
|
41
|
+
-----------
|
|
42
|
+
|
|
43
|
+
`Holger Queckenstedt <mailto:Holger.Queckenstedt@de.bosch.com>`_
|
|
44
|
+
|
|
45
|
+
`Thomas Pollerspöck <mailto:Thomas.Pollerspoeck@de.bosch.com>`_
|
|
46
|
+
|
|
47
|
+
Contributors
|
|
48
|
+
------------
|
|
49
|
+
|
|
50
|
+
`Holger Queckenstedt <mailto:Holger.Queckenstedt@de.bosch.com>`_
|
|
51
|
+
|
|
52
|
+
`Thomas Pollerspöck <mailto:Thomas.Pollerspoeck@de.bosch.com>`_
|
|
53
|
+
|
|
54
|
+
License
|
|
55
|
+
-------
|
|
56
|
+
|
|
57
|
+
Copyright 2020-2024 Robert Bosch GmbH
|
|
58
|
+
|
|
59
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
60
|
+
you may not use this file except in compliance with the License.
|
|
61
|
+
You may obtain a copy of the License at
|
|
62
|
+
|
|
63
|
+
|License: Apache v2|
|
|
64
|
+
|
|
65
|
+
Unless required by applicable law or agreed to in writing, software
|
|
66
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
67
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
68
|
+
See the License for the specific language governing permissions and
|
|
69
|
+
limitations under the License.
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
.. |License: Apache v2| image:: https://img.shields.io/pypi/l/robotframework.svg
|
|
73
|
+
:target: http://www.apache.org/licenses/LICENSE-2.0.html
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: robotframework-prometheus
|
|
3
|
+
Version: 0.6.1
|
|
4
|
+
Summary: Additional Robot Framework keywords
|
|
5
|
+
Home-page: https://github.com/test-fullautomation/robotframework-prometheus
|
|
6
|
+
Author: Holger Queckenstedt
|
|
7
|
+
Author-email: Holger.Queckenstedt@de.bosch.com
|
|
8
|
+
License: UNKNOWN
|
|
9
|
+
Platform: UNKNOWN
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Topic :: Software Development
|
|
16
|
+
Requires-Python: >=3.0
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
|
|
19
|
+
Package Description
|
|
20
|
+
===================
|
|
21
|
+
|
|
22
|
+
The interface library **prometheus\_interface** provides Robot Framework
|
|
23
|
+
keywords to communicate with the monitoring system **Prometheus**.
|
|
24
|
+
|
|
25
|
+
Currently this library is under development. We work on it. But what is
|
|
26
|
+
available up to now, is not ready for being used in productive systems
|
|
27
|
+
(but hopefully will be in near future).
|
|
28
|
+
|
|
29
|
+
Package Documentation
|
|
30
|
+
---------------------
|
|
31
|
+
|
|
32
|
+
A (growing) detailed documentation of the **prometheus\_interface** can
|
|
33
|
+
be found here:
|
|
34
|
+
|
|
35
|
+
[PrometheusInterface.pdf](https://github.com/test-fullautomation/robotframework-prometheus/blob/develop/PrometheusInterface/PrometheusInterface.pdf)
|
|
36
|
+
|
|
37
|
+
Feedback
|
|
38
|
+
--------
|
|
39
|
+
|
|
40
|
+
To give us a feedback, you can send an email to [Thomas
|
|
41
|
+
Pollerspöck](mailto:Thomas.Pollerspoeck@de.bosch.com)
|
|
42
|
+
|
|
43
|
+
In case you want to report a bug or request any interesting feature,
|
|
44
|
+
please don\'t hesitate to raise a ticket.
|
|
45
|
+
|
|
46
|
+
Maintainers
|
|
47
|
+
-----------
|
|
48
|
+
|
|
49
|
+
[Holger Queckenstedt](mailto:Holger.Queckenstedt@de.bosch.com)
|
|
50
|
+
|
|
51
|
+
[Thomas Pollerspöck](mailto:Thomas.Pollerspoeck@de.bosch.com)
|
|
52
|
+
|
|
53
|
+
Contributors
|
|
54
|
+
------------
|
|
55
|
+
|
|
56
|
+
[Holger Queckenstedt](mailto:Holger.Queckenstedt@de.bosch.com)
|
|
57
|
+
|
|
58
|
+
[Thomas Pollerspöck](mailto:Thomas.Pollerspoeck@de.bosch.com)
|
|
59
|
+
|
|
60
|
+
License
|
|
61
|
+
-------
|
|
62
|
+
|
|
63
|
+
Copyright 2020-2024 Robert Bosch GmbH
|
|
64
|
+
|
|
65
|
+
Licensed under the Apache License, Version 2.0 (the \"License\"); you
|
|
66
|
+
may not use this file except in compliance with the License. You may
|
|
67
|
+
obtain a copy of the License at
|
|
68
|
+
|
|
69
|
+
> [](http://www.apache.org/licenses/LICENSE-2.0.html)
|
|
71
|
+
|
|
72
|
+
Unless required by applicable law or agreed to in writing, software
|
|
73
|
+
distributed under the License is distributed on an \"AS IS\" BASIS,
|
|
74
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
75
|
+
See the License for the specific language governing permissions and
|
|
76
|
+
limitations under the License.
|
|
77
|
+
|
|
78
|
+
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
README.rst
|
|
2
|
+
setup.py
|
|
3
|
+
PrometheusInterface/PrometheusInterface.pdf
|
|
4
|
+
PrometheusInterface/__init__.py
|
|
5
|
+
PrometheusInterface/prometheus_interface.py
|
|
6
|
+
robotframework_prometheus.egg-info/PKG-INFO
|
|
7
|
+
robotframework_prometheus.egg-info/SOURCES.txt
|
|
8
|
+
robotframework_prometheus.egg-info/dependency_links.txt
|
|
9
|
+
robotframework_prometheus.egg-info/requires.txt
|
|
10
|
+
robotframework_prometheus.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
PrometheusInterface
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
# **************************************************************************************************************
|
|
2
|
+
#
|
|
3
|
+
# Copyright 2020-2024 Robert Bosch GmbH
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
#
|
|
17
|
+
# **************************************************************************************************************
|
|
18
|
+
#
|
|
19
|
+
# setup.py
|
|
20
|
+
#
|
|
21
|
+
# XC-HWP/ESW3-Queckenstedt
|
|
22
|
+
#
|
|
23
|
+
# Extends the standard setuptools installation by adding the documentation in PDF format
|
|
24
|
+
# (requires installation mode) and tidying up some folders.
|
|
25
|
+
#
|
|
26
|
+
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
27
|
+
#
|
|
28
|
+
# This script deletes folders (as defined in config.CRepositoryConfig, depending on the position of this script):
|
|
29
|
+
# - previous builds within this repository
|
|
30
|
+
# - previous installations within
|
|
31
|
+
# * <Python installation>\Lib\site-packages (Windows)
|
|
32
|
+
# * <Python installation>/../lib/python3.9/site-packages (Linux)
|
|
33
|
+
#
|
|
34
|
+
# before the build and the installation start again!
|
|
35
|
+
#
|
|
36
|
+
# !!! USE WITH CAUTION !!!
|
|
37
|
+
#
|
|
38
|
+
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
39
|
+
#
|
|
40
|
+
# --------------------------------------------------------------------------------------------------------------
|
|
41
|
+
#
|
|
42
|
+
# * Hints:
|
|
43
|
+
#
|
|
44
|
+
# The usual
|
|
45
|
+
# packages = setuptools.find_packages(),
|
|
46
|
+
# is replaced by
|
|
47
|
+
# packages = [str(oRepositoryConfig.Get('PACKAGENAME')), ],
|
|
48
|
+
# to avoid that also config.CRepositoryConfig() and additions.CExtendedSetup() are part of the distribution.
|
|
49
|
+
# CRepositoryConfig and CExtendedSetup() are only repository internal helper.
|
|
50
|
+
#
|
|
51
|
+
# * Known issues:
|
|
52
|
+
#
|
|
53
|
+
# - setuptools do not properly update an existing package installation under <Python installation>\Lib\site-packages\<package name>!
|
|
54
|
+
# > Files modified manually within installation folder, are still modified after repeated execution of setuptools.
|
|
55
|
+
# > Files added manually within installation folder, are still present there after repeated execution of setuptools.
|
|
56
|
+
# > Only files deleted manually within installation folder, are are restored there after repeated execution of setuptools.
|
|
57
|
+
# - No such issues with <Python installation>\Lib\site-packages\<package name>-<versions>.egg-info.
|
|
58
|
+
# - Solution: explicit deletion of all previous output (all documentation-, build- and installation-folder, except the egg-info folder)
|
|
59
|
+
# (see 'delete_previous_build()' and 'delete_previous_installation()')
|
|
60
|
+
#
|
|
61
|
+
# --------------------------------------------------------------------------------------------------------------
|
|
62
|
+
#
|
|
63
|
+
# 24.06.2022
|
|
64
|
+
#
|
|
65
|
+
# --------------------------------------------------------------------------------------------------------------
|
|
66
|
+
|
|
67
|
+
import os, sys, platform, shlex, subprocess
|
|
68
|
+
import setuptools
|
|
69
|
+
from setuptools.command.install import install
|
|
70
|
+
|
|
71
|
+
# prefer the repository local version of all additional libraries (instead of the installed version under site-packages)
|
|
72
|
+
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "./additions")))
|
|
73
|
+
|
|
74
|
+
from config.CRepositoryConfig import CRepositoryConfig # providing repository and environment specific information
|
|
75
|
+
from additions.CExtendedSetup import CExtendedSetup # providing functions to support the extended setup process
|
|
76
|
+
|
|
77
|
+
import colorama as col
|
|
78
|
+
|
|
79
|
+
col.init(autoreset=True)
|
|
80
|
+
|
|
81
|
+
COLBR = col.Style.BRIGHT + col.Fore.RED
|
|
82
|
+
COLBY = col.Style.BRIGHT + col.Fore.YELLOW
|
|
83
|
+
COLBG = col.Style.BRIGHT + col.Fore.GREEN
|
|
84
|
+
|
|
85
|
+
SUCCESS = 0
|
|
86
|
+
ERROR = 1
|
|
87
|
+
|
|
88
|
+
# --------------------------------------------------------------------------------------------------------------
|
|
89
|
+
|
|
90
|
+
def printerror(sMsg):
|
|
91
|
+
sys.stderr.write(COLBR + f"Error: {sMsg}!\n")
|
|
92
|
+
|
|
93
|
+
def printexception(sMsg):
|
|
94
|
+
sys.stderr.write(COLBR + f"Exception: {sMsg}!\n")
|
|
95
|
+
|
|
96
|
+
# --------------------------------------------------------------------------------------------------------------
|
|
97
|
+
|
|
98
|
+
class ExtendedInstallCommand(install):
|
|
99
|
+
"""Extended setup for installation mode."""
|
|
100
|
+
|
|
101
|
+
def run(self):
|
|
102
|
+
|
|
103
|
+
listCmdArgs = sys.argv
|
|
104
|
+
if ( ('install' in listCmdArgs) or ('build' in listCmdArgs) or ('sdist' in listCmdArgs) or ('bdist_wheel' in listCmdArgs) ):
|
|
105
|
+
install.run(self)
|
|
106
|
+
return SUCCESS
|
|
107
|
+
|
|
108
|
+
# eof class ExtendedInstallCommand(install):
|
|
109
|
+
|
|
110
|
+
# --------------------------------------------------------------------------------------------------------------
|
|
111
|
+
|
|
112
|
+
# -- Even in case of other command line parameters than 'install' or 'build' are used we need the following objects.
|
|
113
|
+
# (Without repository configuration commands like '--author-email' would not be possible)
|
|
114
|
+
|
|
115
|
+
# -- setting up the repository configuration
|
|
116
|
+
oRepositoryConfig = None
|
|
117
|
+
try:
|
|
118
|
+
oRepositoryConfig = CRepositoryConfig(os.path.abspath(sys.argv[0]))
|
|
119
|
+
except Exception as ex:
|
|
120
|
+
print()
|
|
121
|
+
printexception(str(ex))
|
|
122
|
+
print()
|
|
123
|
+
sys.exit(ERROR)
|
|
124
|
+
|
|
125
|
+
# -- setting up the extended setup
|
|
126
|
+
oExtendedSetup = None
|
|
127
|
+
try:
|
|
128
|
+
oExtendedSetup = CExtendedSetup(oRepositoryConfig)
|
|
129
|
+
except Exception as ex:
|
|
130
|
+
print()
|
|
131
|
+
printexception(str(ex))
|
|
132
|
+
print()
|
|
133
|
+
sys.exit(ERROR)
|
|
134
|
+
|
|
135
|
+
# --------------------------------------------------------------------------------------------------------------
|
|
136
|
+
|
|
137
|
+
long_description = "long description" # variable is required even in case of other command line parameters than 'install' or 'build' are used
|
|
138
|
+
|
|
139
|
+
listCmdArgs = sys.argv
|
|
140
|
+
if ( ('install' in listCmdArgs) or ('build' in listCmdArgs) or ('sdist' in listCmdArgs) or ('bdist_wheel' in listCmdArgs) ):
|
|
141
|
+
print()
|
|
142
|
+
print(COLBY + "Entering extended installation")
|
|
143
|
+
print()
|
|
144
|
+
|
|
145
|
+
print(COLBY + "Extended setup step 1/5: Calling the documentation builder")
|
|
146
|
+
print()
|
|
147
|
+
|
|
148
|
+
nReturn = oExtendedSetup.genpackagedoc()
|
|
149
|
+
if nReturn != SUCCESS:
|
|
150
|
+
sys.exit(nReturn)
|
|
151
|
+
|
|
152
|
+
print(COLBY + "Extended setup step 2/5: Converting the repository README")
|
|
153
|
+
print()
|
|
154
|
+
|
|
155
|
+
nReturn = oExtendedSetup.convert_repo_readme()
|
|
156
|
+
if nReturn != SUCCESS:
|
|
157
|
+
sys.exit(nReturn)
|
|
158
|
+
|
|
159
|
+
print(COLBY + "Extended setup step 3/5: Deleting previous setup outputs (build, dist, <package name>.egg-info within repository)")
|
|
160
|
+
print()
|
|
161
|
+
|
|
162
|
+
nReturn = oExtendedSetup.delete_previous_build()
|
|
163
|
+
if nReturn != SUCCESS:
|
|
164
|
+
sys.exit(nReturn)
|
|
165
|
+
|
|
166
|
+
if ( ('bdist_wheel' in listCmdArgs) or ('build' in listCmdArgs) ):
|
|
167
|
+
print()
|
|
168
|
+
print(COLBY + "Skipping extended setup step 4/5: Deleting previous package installation folder within site-packages")
|
|
169
|
+
print()
|
|
170
|
+
else:
|
|
171
|
+
print()
|
|
172
|
+
print(COLBY + "Extended setup step 4/5: Deleting previous package installation folder within site-packages") # (<package name> and <package name>_doc under <Python installation>\Lib\site-packages
|
|
173
|
+
print()
|
|
174
|
+
nReturn = oExtendedSetup.delete_previous_installation()
|
|
175
|
+
if nReturn != SUCCESS:
|
|
176
|
+
sys.exit(nReturn)
|
|
177
|
+
|
|
178
|
+
README_MD = str(oRepositoryConfig.Get('README_MD'))
|
|
179
|
+
with open(README_MD, "r", encoding="utf-8") as fh:
|
|
180
|
+
long_description = fh.read()
|
|
181
|
+
fh.close()
|
|
182
|
+
|
|
183
|
+
# --------------------------------------------------------------------------------------------------------------
|
|
184
|
+
|
|
185
|
+
# -- the 'setup' itself
|
|
186
|
+
|
|
187
|
+
print(COLBY + "Extended setup step 5/5: install.run(self)")
|
|
188
|
+
print()
|
|
189
|
+
|
|
190
|
+
setuptools.setup(
|
|
191
|
+
name = str(oRepositoryConfig.Get('REPOSITORYNAME')),
|
|
192
|
+
version = str(oRepositoryConfig.Get('PACKAGEVERSION')),
|
|
193
|
+
author = str(oRepositoryConfig.Get('AUTHOR')),
|
|
194
|
+
author_email = str(oRepositoryConfig.Get('AUTHOREMAIL')),
|
|
195
|
+
description = str(oRepositoryConfig.Get('DESCRIPTION')),
|
|
196
|
+
long_description = long_description,
|
|
197
|
+
long_description_content_type = str(oRepositoryConfig.Get('LONGDESCRIPTIONCONTENTTYPE')),
|
|
198
|
+
url = str(oRepositoryConfig.Get('URL')),
|
|
199
|
+
packages = [str(oRepositoryConfig.Get('PACKAGENAME')),],
|
|
200
|
+
package_dir = {str(oRepositoryConfig.Get('REPOSITORYNAME')) : str(oRepositoryConfig.Get('PACKAGENAME'))},
|
|
201
|
+
classifiers = [
|
|
202
|
+
str(oRepositoryConfig.Get('PROGRAMMINGLANGUAGE')),
|
|
203
|
+
str(oRepositoryConfig.Get('LICENCE')),
|
|
204
|
+
str(oRepositoryConfig.Get('OPERATINGSYSTEM')),
|
|
205
|
+
str(oRepositoryConfig.Get('DEVELOPMENTSTATUS')),
|
|
206
|
+
str(oRepositoryConfig.Get('INTENDEDAUDIENCE')),
|
|
207
|
+
str(oRepositoryConfig.Get('TOPIC')),
|
|
208
|
+
],
|
|
209
|
+
python_requires = str(oRepositoryConfig.Get('PYTHONREQUIRES')),
|
|
210
|
+
cmdclass={
|
|
211
|
+
'install': ExtendedInstallCommand,
|
|
212
|
+
},
|
|
213
|
+
install_requires = oRepositoryConfig.Get('INSTALLREQUIRES'),
|
|
214
|
+
package_data={f"{oRepositoryConfig.Get('PACKAGENAME')}" : oRepositoryConfig.Get('PACKAGEDATA')},
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
# --------------------------------------------------------------------------------------------------------------
|
|
218
|
+
|
|
219
|
+
print()
|
|
220
|
+
print(COLBG + "Extended installation done")
|
|
221
|
+
print()
|
|
222
|
+
|
|
223
|
+
# --------------------------------------------------------------------------------------------------------------
|
|
224
|
+
|