qase-python-commons 5.1.0__tar.gz → 5.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.
Files changed (52) hide show
  1. {qase_python_commons-5.1.0 → qase_python_commons-5.1.2}/PKG-INFO +1 -1
  2. {qase_python_commons-5.1.0 → qase_python_commons-5.1.2}/pyproject.toml +1 -1
  3. {qase_python_commons-5.1.0 → qase_python_commons-5.1.2}/src/qase/commons/client/api_v2_client.py +0 -7
  4. {qase_python_commons-5.1.0 → qase_python_commons-5.1.2}/src/qase/commons/models/result.py +8 -0
  5. {qase_python_commons-5.1.0 → qase_python_commons-5.1.2}/src/qase/commons/reporters/core.py +9 -3
  6. {qase_python_commons-5.1.0 → qase_python_commons-5.1.2}/src/qase/commons/reporters/testops_multi.py +12 -0
  7. qase_python_commons-5.1.2/src/qase/commons/util/token_masker.py +46 -0
  8. {qase_python_commons-5.1.0 → qase_python_commons-5.1.2}/src/qase_python_commons.egg-info/PKG-INFO +1 -1
  9. {qase_python_commons-5.1.0 → qase_python_commons-5.1.2}/src/qase_python_commons.egg-info/SOURCES.txt +1 -0
  10. {qase_python_commons-5.1.0 → qase_python_commons-5.1.2}/README.md +0 -0
  11. {qase_python_commons-5.1.0 → qase_python_commons-5.1.2}/setup.cfg +0 -0
  12. {qase_python_commons-5.1.0 → qase_python_commons-5.1.2}/src/qase/__init__.py +0 -0
  13. {qase_python_commons-5.1.0 → qase_python_commons-5.1.2}/src/qase/commons/__init__.py +0 -0
  14. {qase_python_commons-5.1.0 → qase_python_commons-5.1.2}/src/qase/commons/client/api_v1_client.py +0 -0
  15. {qase_python_commons-5.1.0 → qase_python_commons-5.1.2}/src/qase/commons/client/base_api_client.py +0 -0
  16. {qase_python_commons-5.1.0 → qase_python_commons-5.1.2}/src/qase/commons/config.py +0 -0
  17. {qase_python_commons-5.1.0 → qase_python_commons-5.1.2}/src/qase/commons/exceptions/reporter.py +0 -0
  18. {qase_python_commons-5.1.0 → qase_python_commons-5.1.2}/src/qase/commons/loader.py +0 -0
  19. {qase_python_commons-5.1.0 → qase_python_commons-5.1.2}/src/qase/commons/logger.py +0 -0
  20. {qase_python_commons-5.1.0 → qase_python_commons-5.1.2}/src/qase/commons/models/__init__.py +0 -0
  21. {qase_python_commons-5.1.0 → qase_python_commons-5.1.2}/src/qase/commons/models/attachment.py +0 -0
  22. {qase_python_commons-5.1.0 → qase_python_commons-5.1.2}/src/qase/commons/models/basemodel.py +0 -0
  23. {qase_python_commons-5.1.0 → qase_python_commons-5.1.2}/src/qase/commons/models/config/api.py +0 -0
  24. {qase_python_commons-5.1.0 → qase_python_commons-5.1.2}/src/qase/commons/models/config/batch.py +0 -0
  25. {qase_python_commons-5.1.0 → qase_python_commons-5.1.2}/src/qase/commons/models/config/connection.py +0 -0
  26. {qase_python_commons-5.1.0 → qase_python_commons-5.1.2}/src/qase/commons/models/config/framework.py +0 -0
  27. {qase_python_commons-5.1.0 → qase_python_commons-5.1.2}/src/qase/commons/models/config/plan.py +0 -0
  28. {qase_python_commons-5.1.0 → qase_python_commons-5.1.2}/src/qase/commons/models/config/qaseconfig.py +0 -0
  29. {qase_python_commons-5.1.0 → qase_python_commons-5.1.2}/src/qase/commons/models/config/report.py +0 -0
  30. {qase_python_commons-5.1.0 → qase_python_commons-5.1.2}/src/qase/commons/models/config/run.py +0 -0
  31. {qase_python_commons-5.1.0 → qase_python_commons-5.1.2}/src/qase/commons/models/config/testops.py +0 -0
  32. {qase_python_commons-5.1.0 → qase_python_commons-5.1.2}/src/qase/commons/models/external_link.py +0 -0
  33. {qase_python_commons-5.1.0 → qase_python_commons-5.1.2}/src/qase/commons/models/relation.py +0 -0
  34. {qase_python_commons-5.1.0 → qase_python_commons-5.1.2}/src/qase/commons/models/run.py +0 -0
  35. {qase_python_commons-5.1.0 → qase_python_commons-5.1.2}/src/qase/commons/models/runtime.py +0 -0
  36. {qase_python_commons-5.1.0 → qase_python_commons-5.1.2}/src/qase/commons/models/step.py +0 -0
  37. {qase_python_commons-5.1.0 → qase_python_commons-5.1.2}/src/qase/commons/profilers/__init__.py +0 -0
  38. {qase_python_commons-5.1.0 → qase_python_commons-5.1.2}/src/qase/commons/profilers/db.py +0 -0
  39. {qase_python_commons-5.1.0 → qase_python_commons-5.1.2}/src/qase/commons/profilers/network.py +0 -0
  40. {qase_python_commons-5.1.0 → qase_python_commons-5.1.2}/src/qase/commons/profilers/sleep.py +0 -0
  41. {qase_python_commons-5.1.0 → qase_python_commons-5.1.2}/src/qase/commons/reporters/__init__.py +0 -0
  42. {qase_python_commons-5.1.0 → qase_python_commons-5.1.2}/src/qase/commons/reporters/report.py +0 -0
  43. {qase_python_commons-5.1.0 → qase_python_commons-5.1.2}/src/qase/commons/reporters/testops.py +0 -0
  44. {qase_python_commons-5.1.0 → qase_python_commons-5.1.2}/src/qase/commons/status_mapping/__init__.py +0 -0
  45. {qase_python_commons-5.1.0 → qase_python_commons-5.1.2}/src/qase/commons/status_mapping/status_mapping.py +0 -0
  46. {qase_python_commons-5.1.0 → qase_python_commons-5.1.2}/src/qase/commons/util/__init__.py +0 -0
  47. {qase_python_commons-5.1.0 → qase_python_commons-5.1.2}/src/qase/commons/util/host_data.py +0 -0
  48. {qase_python_commons-5.1.0 → qase_python_commons-5.1.2}/src/qase/commons/utils.py +0 -0
  49. {qase_python_commons-5.1.0 → qase_python_commons-5.1.2}/src/qase/commons/validators/base.py +0 -0
  50. {qase_python_commons-5.1.0 → qase_python_commons-5.1.2}/src/qase_python_commons.egg-info/dependency_links.txt +0 -0
  51. {qase_python_commons-5.1.0 → qase_python_commons-5.1.2}/src/qase_python_commons.egg-info/requires.txt +0 -0
  52. {qase_python_commons-5.1.0 → qase_python_commons-5.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: 5.1.0
3
+ Version: 5.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
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "qase-python-commons"
7
- version = "5.1.0"
7
+ version = "5.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"}]
@@ -157,13 +157,6 @@ class ApiV2Client(ApiV1Client):
157
157
  if param == "":
158
158
  result.params[key] = "empty"
159
159
 
160
- # Merge result.tags into fields["tags"] for API
161
- if result.tags:
162
- existing_str = result.fields.get("tags", "")
163
- existing = [t.strip() for t in existing_str.split(",") if t.strip()] if existing_str else []
164
- all_tags = list(dict.fromkeys(existing + result.tags))
165
- result.fields["tags"] = ",".join(all_tags)
166
-
167
160
  result_model_v2 = ResultCreate(
168
161
  title=result.get_title(),
169
162
  signature=result.signature,
@@ -98,6 +98,14 @@ class Result(BaseModel):
98
98
  def add_tags(self, tags: List[str]) -> None:
99
99
  for tag in tags:
100
100
  self.add_tag(tag)
101
+ self._sync_tags_to_fields()
102
+
103
+ def _sync_tags_to_fields(self) -> None:
104
+ if self.tags:
105
+ existing_str = self.fields.get("tags", "")
106
+ existing = [t.strip() for t in existing_str.split(",") if t.strip()] if existing_str else []
107
+ all_tags = list(dict.fromkeys(existing + self.tags))
108
+ self.fields["tags"] = ",".join(all_tags)
101
109
 
102
110
  def get_tags(self) -> List[str]:
103
111
  return self.tags
@@ -12,6 +12,7 @@ from ..models.config.qaseconfig import Mode
12
12
  from typing import Union, List, Dict
13
13
 
14
14
  from ..util import get_host_info
15
+ from ..util.token_masker import sanitize_config_for_log
15
16
  from ..status_mapping.status_mapping import StatusMapping
16
17
  from ..exceptions.reporter import ReporterException
17
18
 
@@ -68,7 +69,7 @@ class QaseCoreReporter:
68
69
 
69
70
  self.fallback = self._fallback_setup()
70
71
 
71
- self.logger.log_debug(f"Config: {self.config}")
72
+ self.logger.log_debug(f"Config: {sanitize_config_for_log(self.config)}")
72
73
 
73
74
  host_data = get_host_info(framework, reporter_name)
74
75
  self.logger.log_debug(f"Host data: {host_data}")
@@ -260,10 +261,15 @@ class QaseCoreReporter:
260
261
  for profiler in self.profilers:
261
262
  profiler.disable()
262
263
 
263
- def set_run_id(self, run_id: str) -> None:
264
+ def set_run_id(self, run_id) -> None:
264
265
  if self.reporter:
265
266
  try:
266
- self.reporter.set_run_id(run_id)
267
+ # Multi-project mode: run_id is a dict of project -> run_id.
268
+ # Dispatch to set_run_ids so each project gets seeded.
269
+ if isinstance(run_id, dict) and hasattr(self.reporter, 'set_run_ids'):
270
+ self.reporter.set_run_ids(run_id)
271
+ else:
272
+ self.reporter.set_run_id(run_id)
267
273
  except Exception as e:
268
274
  # Log error and run fallback
269
275
  self.logger.log('Failed to set run id', 'info')
@@ -166,6 +166,18 @@ class QaseTestOpsMulti:
166
166
  else:
167
167
  self.logger.log(f"Unknown project code: {project_code}", "warning")
168
168
 
169
+ def set_run_ids(self, run_ids: Dict[str, Union[str, int]]) -> None:
170
+ """Set run_ids for multiple projects at once.
171
+
172
+ Used by xdist workers to seed run ids produced by the controller.
173
+ Unknown project codes are skipped with a warning but do not raise.
174
+ """
175
+ for project_code, run_id in run_ids.items():
176
+ if project_code in self.project_configs:
177
+ self.project_runs[project_code] = int(run_id) if isinstance(run_id, str) else run_id
178
+ else:
179
+ self.logger.log(f"Unknown project code: {project_code}", "warning")
180
+
169
181
  def start_run(self) -> Dict[str, int]:
170
182
  """
171
183
  Create or verify test runs for all projects.
@@ -0,0 +1,46 @@
1
+ """Token masking utilities for safe config logging.
2
+
3
+ Mirrors the qase-javascript-commons `token-masker.ts` contract so leaked
4
+ debug logs cannot expose customer API tokens. The only secret we currently
5
+ need to mask sits at ``config.testops.api.token``.
6
+ """
7
+
8
+ import json
9
+ from typing import Any
10
+
11
+
12
+ def mask_token(token: str) -> str:
13
+ """Return a masked representation of an API token.
14
+
15
+ Tokens of 7 chars or fewer are fully replaced with asterisks.
16
+ Longer tokens keep the first 3 and last 4 characters: ``abc****wxyz``.
17
+ """
18
+ if not isinstance(token, str):
19
+ return token
20
+ if len(token) <= 7:
21
+ return "*" * len(token)
22
+ return f"{token[:3]}****{token[-4:]}"
23
+
24
+
25
+ def sanitize_config_for_log(config: Any) -> str:
26
+ """Return a JSON string of ``config`` with the API token masked.
27
+
28
+ Accepts any object with a JSON-serialisable ``__str__`` (e.g. ``BaseModel``)
29
+ or a dict. Falls back to ``str(config)`` if the serialised form cannot be
30
+ parsed as JSON, so callers never lose log output to a masking bug.
31
+ """
32
+ try:
33
+ raw = config if isinstance(config, str) else str(config)
34
+ parsed = json.loads(raw)
35
+ except (TypeError, ValueError):
36
+ return str(config)
37
+
38
+ token = (
39
+ parsed.get("testops", {}).get("api", {}).get("token")
40
+ if isinstance(parsed, dict)
41
+ else None
42
+ )
43
+ if token:
44
+ parsed["testops"]["api"]["token"] = mask_token(token)
45
+
46
+ return json.dumps(parsed, indent=4, sort_keys=True)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qase-python-commons
3
- Version: 5.1.0
3
+ Version: 5.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
@@ -41,6 +41,7 @@ src/qase/commons/status_mapping/__init__.py
41
41
  src/qase/commons/status_mapping/status_mapping.py
42
42
  src/qase/commons/util/__init__.py
43
43
  src/qase/commons/util/host_data.py
44
+ src/qase/commons/util/token_masker.py
44
45
  src/qase/commons/validators/base.py
45
46
  src/qase_python_commons.egg-info/PKG-INFO
46
47
  src/qase_python_commons.egg-info/SOURCES.txt