qase-python-commons 4.1.1__tar.gz → 4.1.2__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.
Potentially problematic release.
This version of qase-python-commons might be problematic. Click here for more details.
- {qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/PKG-INFO +2 -1
- {qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/pyproject.toml +2 -1
- {qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/models/result.py +2 -2
- {qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/models/step.py +3 -2
- {qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/reporters/report.py +2 -2
- qase_python_commons-4.1.2/src/qase/commons/utils.py +185 -0
- {qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase_python_commons.egg-info/PKG-INFO +2 -1
- {qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase_python_commons.egg-info/requires.txt +1 -0
- qase_python_commons-4.1.1/src/qase/commons/utils.py +0 -107
- {qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/README.md +0 -0
- {qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/setup.cfg +0 -0
- {qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/__init__.py +0 -0
- {qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/__init__.py +0 -0
- {qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/client/api_v1_client.py +0 -0
- {qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/client/api_v2_client.py +0 -0
- {qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/client/base_api_client.py +0 -0
- {qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/config.py +0 -0
- {qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/exceptions/reporter.py +0 -0
- {qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/loader.py +0 -0
- {qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/logger.py +0 -0
- {qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/models/__init__.py +0 -0
- {qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/models/attachment.py +0 -0
- {qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/models/basemodel.py +0 -0
- {qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/models/config/api.py +0 -0
- {qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/models/config/batch.py +0 -0
- {qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/models/config/connection.py +0 -0
- {qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/models/config/framework.py +0 -0
- {qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/models/config/plan.py +0 -0
- {qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/models/config/qaseconfig.py +0 -0
- {qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/models/config/report.py +0 -0
- {qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/models/config/run.py +0 -0
- {qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/models/config/testops.py +0 -0
- {qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/models/external_link.py +0 -0
- {qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/models/relation.py +0 -0
- {qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/models/run.py +0 -0
- {qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/models/runtime.py +0 -0
- {qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/profilers/__init__.py +0 -0
- {qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/profilers/db.py +0 -0
- {qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/profilers/network.py +0 -0
- {qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/profilers/sleep.py +0 -0
- {qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/reporters/__init__.py +0 -0
- {qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/reporters/core.py +0 -0
- {qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/reporters/testops.py +0 -0
- {qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/status_mapping/__init__.py +0 -0
- {qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/status_mapping/status_mapping.py +0 -0
- {qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/util/__init__.py +0 -0
- {qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/util/host_data.py +0 -0
- {qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/validators/base.py +0 -0
- {qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase_python_commons.egg-info/SOURCES.txt +0 -0
- {qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase_python_commons.egg-info/dependency_links.txt +0 -0
- {qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase_python_commons.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: qase-python-commons
|
|
3
|
-
Version: 4.1.
|
|
3
|
+
Version: 4.1.2
|
|
4
4
|
Summary: A library for Qase TestOps and Qase Report
|
|
5
5
|
Author-email: Qase Team <support@qase.io>
|
|
6
6
|
Project-URL: Homepage, https://github.com/qase-tms/qase-python/tree/main/qase-python-commons
|
|
@@ -31,6 +31,7 @@ Requires-Dist: mock; extra == "testing"
|
|
|
31
31
|
Requires-Dist: more_itertools; extra == "testing"
|
|
32
32
|
Requires-Dist: requests; extra == "testing"
|
|
33
33
|
Requires-Dist: urllib3; extra == "testing"
|
|
34
|
+
Requires-Dist: freezegun; extra == "testing"
|
|
34
35
|
|
|
35
36
|
# Qase Python Commons
|
|
36
37
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "qase-python-commons"
|
|
7
|
-
version = "4.1.
|
|
7
|
+
version = "4.1.2"
|
|
8
8
|
description = "A library for Qase TestOps and Qase Report"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
authors = [{name = "Qase Team", email = "support@qase.io"}]
|
|
@@ -42,6 +42,7 @@ testing = [
|
|
|
42
42
|
"more_itertools",
|
|
43
43
|
"requests",
|
|
44
44
|
"urllib3",
|
|
45
|
+
"freezegun",
|
|
45
46
|
]
|
|
46
47
|
|
|
47
48
|
[tool.tox]
|
|
@@ -25,7 +25,7 @@ class Execution(BaseModel):
|
|
|
25
25
|
stacktrace: Optional[str] = None,
|
|
26
26
|
thread: Optional[str] = QaseUtils.get_thread_name()
|
|
27
27
|
):
|
|
28
|
-
self.start_time =
|
|
28
|
+
self.start_time = QaseUtils.get_real_time()
|
|
29
29
|
self.status = status
|
|
30
30
|
self.end_time = end_time
|
|
31
31
|
self.duration = duration
|
|
@@ -48,7 +48,7 @@ class Execution(BaseModel):
|
|
|
48
48
|
return self.status
|
|
49
49
|
|
|
50
50
|
def complete(self):
|
|
51
|
-
self.end_time =
|
|
51
|
+
self.end_time = QaseUtils.get_real_time()
|
|
52
52
|
self.duration = (int)((self.end_time - self.start_time) * 1000)
|
|
53
53
|
|
|
54
54
|
|
|
@@ -5,6 +5,7 @@ from enum import Enum
|
|
|
5
5
|
from typing import Optional, Union, Dict, List, Type
|
|
6
6
|
from .attachment import Attachment
|
|
7
7
|
from .basemodel import BaseModel
|
|
8
|
+
from .. import QaseUtils
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
class StepType(Enum):
|
|
@@ -95,7 +96,7 @@ class StepSleepData(BaseModel):
|
|
|
95
96
|
|
|
96
97
|
class StepExecution(BaseModel):
|
|
97
98
|
def __init__(self, status: Optional[str] = 'untested', end_time: int = 0, duration: int = 0):
|
|
98
|
-
self.start_time =
|
|
99
|
+
self.start_time = QaseUtils.get_real_time()
|
|
99
100
|
self.status = status
|
|
100
101
|
self.end_time = end_time
|
|
101
102
|
self.duration = duration
|
|
@@ -108,7 +109,7 @@ class StepExecution(BaseModel):
|
|
|
108
109
|
raise ValueError('Step status must be one of: passed, failed, skipped, blocked, untested, invalid')
|
|
109
110
|
|
|
110
111
|
def complete(self):
|
|
111
|
-
self.end_time =
|
|
112
|
+
self.end_time = QaseUtils.get_real_time()
|
|
112
113
|
self.duration = int((self.end_time - self.start_time) * 1000)
|
|
113
114
|
|
|
114
115
|
def add_attachment(self, attachment: Attachment):
|
{qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/reporters/report.py
RENAMED
|
@@ -31,10 +31,10 @@ class QaseReport:
|
|
|
31
31
|
|
|
32
32
|
def start_run(self):
|
|
33
33
|
self._check_report_path()
|
|
34
|
-
self.start_time = str(
|
|
34
|
+
self.start_time = str(QaseUtils.get_real_time())
|
|
35
35
|
|
|
36
36
|
def complete_run(self):
|
|
37
|
-
self.end_time = str(
|
|
37
|
+
self.end_time = str(QaseUtils.get_real_time())
|
|
38
38
|
self._compile_report()
|
|
39
39
|
|
|
40
40
|
def complete_worker(self):
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import platform
|
|
3
|
+
import threading
|
|
4
|
+
import sys
|
|
5
|
+
from typing import Union, List
|
|
6
|
+
import pip
|
|
7
|
+
import string
|
|
8
|
+
import uuid
|
|
9
|
+
import time
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class QaseUtils:
|
|
13
|
+
|
|
14
|
+
@staticmethod
|
|
15
|
+
def get_real_time() -> float:
|
|
16
|
+
"""
|
|
17
|
+
Get real system time, bypassing time mocking libraries like freezegun.
|
|
18
|
+
|
|
19
|
+
This is necessary when reporting test results to external systems that validate
|
|
20
|
+
timestamps against current time, even when tests are using time mocking.
|
|
21
|
+
|
|
22
|
+
Returns:
|
|
23
|
+
float: Current Unix timestamp in seconds with microsecond precision
|
|
24
|
+
"""
|
|
25
|
+
# Try to get the original time function if it was wrapped by freezegun
|
|
26
|
+
# freezegun stores the original function in __wrapped__ attribute
|
|
27
|
+
if hasattr(time.time, '__wrapped__'):
|
|
28
|
+
return time.time.__wrapped__()
|
|
29
|
+
|
|
30
|
+
# Fallback: use direct system call via ctypes
|
|
31
|
+
# This works on Unix-like systems and Windows
|
|
32
|
+
try:
|
|
33
|
+
import ctypes
|
|
34
|
+
import ctypes.util
|
|
35
|
+
|
|
36
|
+
if sys.platform == 'win32':
|
|
37
|
+
# Windows: use GetSystemTimeAsFileTime
|
|
38
|
+
class FILETIME(ctypes.Structure):
|
|
39
|
+
_fields_ = [("dwLowDateTime", ctypes.c_uint32),
|
|
40
|
+
("dwHighDateTime", ctypes.c_uint32)]
|
|
41
|
+
|
|
42
|
+
kernel32 = ctypes.windll.kernel32
|
|
43
|
+
ft = FILETIME()
|
|
44
|
+
kernel32.GetSystemTimeAsFileTime(ctypes.byref(ft))
|
|
45
|
+
|
|
46
|
+
# Convert FILETIME to Unix timestamp
|
|
47
|
+
# FILETIME is 100-nanosecond intervals since January 1, 1601
|
|
48
|
+
timestamp = (ft.dwHighDateTime << 32) + ft.dwLowDateTime
|
|
49
|
+
# Convert to seconds and adjust epoch (1601 -> 1970)
|
|
50
|
+
return (timestamp / 10000000.0) - 11644473600.0
|
|
51
|
+
else:
|
|
52
|
+
# Unix-like systems: use gettimeofday for microsecond precision
|
|
53
|
+
# Try multiple approaches to find libc
|
|
54
|
+
libc = None
|
|
55
|
+
|
|
56
|
+
# Method 1: Use find_library (works on most systems)
|
|
57
|
+
libc_path = ctypes.util.find_library('c')
|
|
58
|
+
if libc_path:
|
|
59
|
+
try:
|
|
60
|
+
libc = ctypes.CDLL(libc_path)
|
|
61
|
+
except OSError:
|
|
62
|
+
pass
|
|
63
|
+
|
|
64
|
+
# Method 2: Try common library names directly (for Alpine Linux, musl libc, etc.)
|
|
65
|
+
if libc is None:
|
|
66
|
+
for lib_name in ['libc.so.6', 'libc.so', 'libc.dylib']:
|
|
67
|
+
try:
|
|
68
|
+
libc = ctypes.CDLL(lib_name)
|
|
69
|
+
break
|
|
70
|
+
except OSError:
|
|
71
|
+
continue
|
|
72
|
+
|
|
73
|
+
if libc is None:
|
|
74
|
+
raise OSError("Could not load C library")
|
|
75
|
+
|
|
76
|
+
class timeval(ctypes.Structure):
|
|
77
|
+
_fields_ = [("tv_sec", ctypes.c_long),
|
|
78
|
+
("tv_usec", ctypes.c_long)]
|
|
79
|
+
|
|
80
|
+
tv = timeval()
|
|
81
|
+
libc.gettimeofday(ctypes.byref(tv), None)
|
|
82
|
+
|
|
83
|
+
return float(tv.tv_sec) + (float(tv.tv_usec) / 1000000.0)
|
|
84
|
+
except Exception:
|
|
85
|
+
# Last resort: return the potentially mocked time
|
|
86
|
+
# This will still work in normal cases without freezegun
|
|
87
|
+
# If freezegun is active, the user might see timestamp validation errors
|
|
88
|
+
# but the core functionality will continue to work
|
|
89
|
+
return time.time()
|
|
90
|
+
|
|
91
|
+
@staticmethod
|
|
92
|
+
def build_tree(items):
|
|
93
|
+
nodes = {item.id: item for item in items}
|
|
94
|
+
|
|
95
|
+
roots = []
|
|
96
|
+
for item in items:
|
|
97
|
+
try:
|
|
98
|
+
parent_id = item.parent_id
|
|
99
|
+
except Exception as e:
|
|
100
|
+
print(f'Failed to get parent id: {e}')
|
|
101
|
+
|
|
102
|
+
if parent_id is None:
|
|
103
|
+
# If the item has no parent, it's a root node
|
|
104
|
+
roots.append(item)
|
|
105
|
+
else:
|
|
106
|
+
# If the item has a parent, add it to the parent's children list
|
|
107
|
+
try:
|
|
108
|
+
parent = nodes[parent_id]
|
|
109
|
+
parent.steps.append(item)
|
|
110
|
+
except Exception as e:
|
|
111
|
+
print(f'Failed to append child to parent: {e}')
|
|
112
|
+
|
|
113
|
+
return roots
|
|
114
|
+
|
|
115
|
+
@staticmethod
|
|
116
|
+
def get_thread_name() -> str:
|
|
117
|
+
return f"{os.getpid()}-{threading.current_thread().name}"
|
|
118
|
+
|
|
119
|
+
@staticmethod
|
|
120
|
+
def parse_bool(value) -> bool:
|
|
121
|
+
return value in ("y", "yes", "true", "True", "TRUE", "1", 1, True)
|
|
122
|
+
|
|
123
|
+
@staticmethod
|
|
124
|
+
def uuid() -> str:
|
|
125
|
+
return str(uuid.uuid4())
|
|
126
|
+
|
|
127
|
+
@staticmethod
|
|
128
|
+
def get_host_data() -> dict:
|
|
129
|
+
try:
|
|
130
|
+
return {
|
|
131
|
+
"system": platform.uname().system,
|
|
132
|
+
"node": platform.uname().node,
|
|
133
|
+
"release": platform.uname().release,
|
|
134
|
+
"version": platform.uname().version,
|
|
135
|
+
"machine": platform.uname().machine,
|
|
136
|
+
'python': '.'.join(map(str, sys.version_info)),
|
|
137
|
+
'pip': pip.__version__
|
|
138
|
+
}
|
|
139
|
+
except Exception as e:
|
|
140
|
+
return {}
|
|
141
|
+
|
|
142
|
+
@staticmethod
|
|
143
|
+
def get_filename(path) -> str:
|
|
144
|
+
return os.path.basename(path)
|
|
145
|
+
|
|
146
|
+
@staticmethod
|
|
147
|
+
def get_signature(testops_ids: Union[List[int], None], suites: List[str], params: dict) -> str:
|
|
148
|
+
signature_parts = []
|
|
149
|
+
|
|
150
|
+
if testops_ids:
|
|
151
|
+
signature_parts.append(
|
|
152
|
+
f"{'-'.join(map(str, testops_ids))}")
|
|
153
|
+
|
|
154
|
+
for suite in suites:
|
|
155
|
+
signature_parts.append(suite.lower().replace(" ", "_"))
|
|
156
|
+
|
|
157
|
+
for key, val in params.items():
|
|
158
|
+
signature_parts.append(f"{{{key}:{val}}}")
|
|
159
|
+
|
|
160
|
+
return "::".join(signature_parts)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
class StringFormatter(string.Formatter):
|
|
164
|
+
"""
|
|
165
|
+
is designed to enhance string formatting by allowing it to gracefully handle and skip any keys in the format string
|
|
166
|
+
that are not provided in the arguments, rather than raising exceptions for missing keys or indexes.
|
|
167
|
+
This makes it particularly useful for formatting strings in contexts where not all variables may be known
|
|
168
|
+
or provided ahead of time, enhancing robustness and reducing the need for extensive error handling in code
|
|
169
|
+
that generates dynamic text output.
|
|
170
|
+
"""
|
|
171
|
+
|
|
172
|
+
class SafeError(Exception):
|
|
173
|
+
pass
|
|
174
|
+
|
|
175
|
+
def get_value(self, key, args, kwargs):
|
|
176
|
+
try:
|
|
177
|
+
return super().get_value(key, args, kwargs)
|
|
178
|
+
except (IndexError, KeyError):
|
|
179
|
+
raise self.SafeError()
|
|
180
|
+
|
|
181
|
+
def get_field(self, field, args, kwargs):
|
|
182
|
+
try:
|
|
183
|
+
return super().get_field(field, args, kwargs)
|
|
184
|
+
except self.SafeError:
|
|
185
|
+
return "{" + field + "}", field
|
{qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase_python_commons.egg-info/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: qase-python-commons
|
|
3
|
-
Version: 4.1.
|
|
3
|
+
Version: 4.1.2
|
|
4
4
|
Summary: A library for Qase TestOps and Qase Report
|
|
5
5
|
Author-email: Qase Team <support@qase.io>
|
|
6
6
|
Project-URL: Homepage, https://github.com/qase-tms/qase-python/tree/main/qase-python-commons
|
|
@@ -31,6 +31,7 @@ Requires-Dist: mock; extra == "testing"
|
|
|
31
31
|
Requires-Dist: more_itertools; extra == "testing"
|
|
32
32
|
Requires-Dist: requests; extra == "testing"
|
|
33
33
|
Requires-Dist: urllib3; extra == "testing"
|
|
34
|
+
Requires-Dist: freezegun; extra == "testing"
|
|
34
35
|
|
|
35
36
|
# Qase Python Commons
|
|
36
37
|
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import platform
|
|
3
|
-
import threading
|
|
4
|
-
import sys
|
|
5
|
-
from typing import Union, List
|
|
6
|
-
import pip
|
|
7
|
-
import string
|
|
8
|
-
import uuid
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class QaseUtils:
|
|
12
|
-
|
|
13
|
-
@staticmethod
|
|
14
|
-
def build_tree(items):
|
|
15
|
-
nodes = {item.id: item for item in items}
|
|
16
|
-
|
|
17
|
-
roots = []
|
|
18
|
-
for item in items:
|
|
19
|
-
try:
|
|
20
|
-
parent_id = item.parent_id
|
|
21
|
-
except Exception as e:
|
|
22
|
-
print(f'Failed to get parent id: {e}')
|
|
23
|
-
|
|
24
|
-
if parent_id is None:
|
|
25
|
-
# If the item has no parent, it's a root node
|
|
26
|
-
roots.append(item)
|
|
27
|
-
else:
|
|
28
|
-
# If the item has a parent, add it to the parent's children list
|
|
29
|
-
try:
|
|
30
|
-
parent = nodes[parent_id]
|
|
31
|
-
parent.steps.append(item)
|
|
32
|
-
except Exception as e:
|
|
33
|
-
print(f'Failed to append child to parent: {e}')
|
|
34
|
-
|
|
35
|
-
return roots
|
|
36
|
-
|
|
37
|
-
@staticmethod
|
|
38
|
-
def get_thread_name() -> str:
|
|
39
|
-
return f"{os.getpid()}-{threading.current_thread().name}"
|
|
40
|
-
|
|
41
|
-
@staticmethod
|
|
42
|
-
def parse_bool(value) -> bool:
|
|
43
|
-
return value in ("y", "yes", "true", "True", "TRUE", "1", 1, True)
|
|
44
|
-
|
|
45
|
-
@staticmethod
|
|
46
|
-
def uuid() -> str:
|
|
47
|
-
return str(uuid.uuid4())
|
|
48
|
-
|
|
49
|
-
@staticmethod
|
|
50
|
-
def get_host_data() -> dict:
|
|
51
|
-
try:
|
|
52
|
-
return {
|
|
53
|
-
"system": platform.uname().system,
|
|
54
|
-
"node": platform.uname().node,
|
|
55
|
-
"release": platform.uname().release,
|
|
56
|
-
"version": platform.uname().version,
|
|
57
|
-
"machine": platform.uname().machine,
|
|
58
|
-
'python': '.'.join(map(str, sys.version_info)),
|
|
59
|
-
'pip': pip.__version__
|
|
60
|
-
}
|
|
61
|
-
except Exception as e:
|
|
62
|
-
return {}
|
|
63
|
-
|
|
64
|
-
@staticmethod
|
|
65
|
-
def get_filename(path) -> str:
|
|
66
|
-
return os.path.basename(path)
|
|
67
|
-
|
|
68
|
-
@staticmethod
|
|
69
|
-
def get_signature(testops_ids: Union[List[int], None], suites: List[str], params: dict) -> str:
|
|
70
|
-
signature_parts = []
|
|
71
|
-
|
|
72
|
-
if testops_ids:
|
|
73
|
-
signature_parts.append(
|
|
74
|
-
f"{'-'.join(map(str, testops_ids))}")
|
|
75
|
-
|
|
76
|
-
for suite in suites:
|
|
77
|
-
signature_parts.append(suite.lower().replace(" ", "_"))
|
|
78
|
-
|
|
79
|
-
for key, val in params.items():
|
|
80
|
-
signature_parts.append(f"{{{key}:{val}}}")
|
|
81
|
-
|
|
82
|
-
return "::".join(signature_parts)
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
class StringFormatter(string.Formatter):
|
|
86
|
-
"""
|
|
87
|
-
is designed to enhance string formatting by allowing it to gracefully handle and skip any keys in the format string
|
|
88
|
-
that are not provided in the arguments, rather than raising exceptions for missing keys or indexes.
|
|
89
|
-
This makes it particularly useful for formatting strings in contexts where not all variables may be known
|
|
90
|
-
or provided ahead of time, enhancing robustness and reducing the need for extensive error handling in code
|
|
91
|
-
that generates dynamic text output.
|
|
92
|
-
"""
|
|
93
|
-
|
|
94
|
-
class SafeError(Exception):
|
|
95
|
-
pass
|
|
96
|
-
|
|
97
|
-
def get_value(self, key, args, kwargs):
|
|
98
|
-
try:
|
|
99
|
-
return super().get_value(key, args, kwargs)
|
|
100
|
-
except (IndexError, KeyError):
|
|
101
|
-
raise self.SafeError()
|
|
102
|
-
|
|
103
|
-
def get_field(self, field, args, kwargs):
|
|
104
|
-
try:
|
|
105
|
-
return super().get_field(field, args, kwargs)
|
|
106
|
-
except self.SafeError:
|
|
107
|
-
return "{" + field + "}", field
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/client/api_v1_client.py
RENAMED
|
File without changes
|
{qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/client/api_v2_client.py
RENAMED
|
File without changes
|
{qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/client/base_api_client.py
RENAMED
|
File without changes
|
|
File without changes
|
{qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/exceptions/reporter.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/models/attachment.py
RENAMED
|
File without changes
|
{qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/models/basemodel.py
RENAMED
|
File without changes
|
{qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/models/config/api.py
RENAMED
|
File without changes
|
{qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/models/config/batch.py
RENAMED
|
File without changes
|
{qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/models/config/connection.py
RENAMED
|
File without changes
|
{qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/models/config/framework.py
RENAMED
|
File without changes
|
{qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/models/config/plan.py
RENAMED
|
File without changes
|
{qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/models/config/qaseconfig.py
RENAMED
|
File without changes
|
{qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/models/config/report.py
RENAMED
|
File without changes
|
{qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/models/config/run.py
RENAMED
|
File without changes
|
{qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/models/config/testops.py
RENAMED
|
File without changes
|
{qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/models/external_link.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/profilers/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/profilers/network.py
RENAMED
|
File without changes
|
|
File without changes
|
{qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/reporters/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/reporters/testops.py
RENAMED
|
File without changes
|
{qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase/commons/status_mapping/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{qase_python_commons-4.1.1 → qase_python_commons-4.1.2}/src/qase_python_commons.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|