utf-queue-client 1.18.0a1__tar.gz → 1.19.0__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 (89) hide show
  1. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/.idea/.gitignore +0 -2
  2. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/.idea/utf_queue_client_python.iml +1 -3
  3. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/Jenkinsfile +0 -1
  4. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/PKG-INFO +1 -1
  5. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/pyproject.toml +1 -1
  6. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/sonar-project.properties +1 -1
  7. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/test/conftest.py +22 -19
  8. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/test/test_amqp_connections.py +1 -1
  9. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/test/test_sqa_test_result_producer.py +0 -36
  10. utf_queue_client-1.19.0/test/test_xray_data_producer.py +65 -0
  11. utf_queue_client-1.19.0/tools/build_dist.bat +14 -0
  12. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/utf_queue_client/clients/http_producer.py +2 -2
  13. utf_queue_client-1.19.0/utf_queue_client/clients/xray_data_producer.py +95 -0
  14. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/utf_queue_client/models/schemas/utf_queue_models/models/python/generated_models.py +24 -0
  15. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/utf_queue_client/models/schemas/utf_queue_models/models/python/generated_models_pydantic_v1.py +79 -2
  16. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/utf_queue_client/models/schemas/utf_queue_models/models/python/generated_models_pydantic_v2.py +79 -2
  17. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/utf_queue_client/models/schemas/utf_queue_models/schema/queue_message.json +250 -1
  18. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/utf_queue_client/scripts/__init__.py +0 -2
  19. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/utf_queue_client.egg-info/PKG-INFO +1 -1
  20. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/utf_queue_client.egg-info/SOURCES.txt +2 -1
  21. utf_queue_client-1.18.0a1/tools/build_dist.bat +0 -12
  22. utf_queue_client-1.18.0a1/utf_queue_client/models/schemas/utf_queue_models/models/python/model_test.py +0 -23
  23. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/.gitignore +0 -0
  24. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/.gitmodules +0 -0
  25. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/.idea/modules.xml +0 -0
  26. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/.idea/vcs.xml +0 -0
  27. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/.pre-commit-config.yaml +0 -0
  28. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/README.md +0 -0
  29. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/examples/example_async_consumer.py +0 -0
  30. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/requirements.txt +0 -0
  31. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/setup.cfg +0 -0
  32. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/test/.gitattributes +0 -0
  33. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/test/Dockerfile.script_test +0 -0
  34. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/test/pytest.ini +0 -0
  35. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/test/script_test.groovy +0 -0
  36. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/test/stopwatch.py +0 -0
  37. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/test/test.hex +0 -0
  38. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/test/test_async_consumer.py +0 -0
  39. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/test/test_connection_retry.py +0 -0
  40. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/test/test_data_lake_data_producer.py +0 -0
  41. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/test/test_http_producer.py +0 -0
  42. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/test/test_models.py +0 -0
  43. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/test/test_opentelemetry_data_producer.py +0 -0
  44. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/test/test_publish_release_info.py +0 -0
  45. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/test/test_publish_test_results.py +0 -0
  46. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/test/test_rail_data_producer_tests.py +0 -0
  47. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/test/test_ubai_copy.py +0 -0
  48. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/test/test_ubai_search.py +0 -0
  49. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/test/test_ubai_update_retention.py +0 -0
  50. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/test/test_ubai_upload.py +0 -0
  51. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/test/test_utils.py +0 -0
  52. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/test-requirements-pydantic-v1.txt +0 -0
  53. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/test-requirements.txt +0 -0
  54. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/tools/setup_venv.bat +0 -0
  55. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/tools/silabs-net.pem +0 -0
  56. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/tools/silabs.pem +0 -0
  57. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/tools/update_schema.bat +0 -0
  58. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/tools/upload_to_nexus.bat +0 -0
  59. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/tools/upload_to_pypi.bat +0 -0
  60. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/tools/upload_to_testpypi.bat +0 -0
  61. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/tox.ini +0 -0
  62. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/utf_queue_client/__init__.py +0 -0
  63. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/utf_queue_client/clients/__init__.py +0 -0
  64. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/utf_queue_client/clients/async_consumer.py +0 -0
  65. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/utf_queue_client/clients/base_producer.py +0 -0
  66. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/utf_queue_client/clients/data_lake_data_producer.py +0 -0
  67. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/utf_queue_client/clients/opentelemetry_data_producer.py +0 -0
  68. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/utf_queue_client/clients/sqa_test_result_producer.py +0 -0
  69. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/utf_queue_client/clients/test_rail_data_producer.py +0 -0
  70. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/utf_queue_client/clients/ubai_artifact_upload_request_producer.py +0 -0
  71. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/utf_queue_client/exceptions/__init__.py +0 -0
  72. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/utf_queue_client/models/__init__.py +0 -0
  73. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/utf_queue_client/models/base_model.py +0 -0
  74. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/utf_queue_client/models/model_factory.py +0 -0
  75. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/utf_queue_client/models/schemas/__init__.py +0 -0
  76. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/utf_queue_client/models/schemas/utf_queue_models/models/python/__init__.py +0 -0
  77. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/utf_queue_client/scripts/publish_release_info_cli.py +0 -0
  78. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/utf_queue_client/scripts/publish_test_results_cli.py +0 -0
  79. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/utf_queue_client/scripts/ubai_copy_cli.py +0 -0
  80. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/utf_queue_client/scripts/ubai_search_cli.py +0 -0
  81. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/utf_queue_client/scripts/ubai_update_retention_cli.py +0 -0
  82. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/utf_queue_client/scripts/ubai_upload_cli.py +0 -0
  83. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/utf_queue_client/utils/__init__.py +0 -0
  84. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/utf_queue_client/utils/queue_metrics_exporter.py +0 -0
  85. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/utf_queue_client/utils/queue_span_exporter.py +0 -0
  86. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/utf_queue_client.egg-info/dependency_links.txt +0 -0
  87. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/utf_queue_client.egg-info/entry_points.txt +0 -0
  88. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/utf_queue_client.egg-info/requires.txt +0 -0
  89. {utf_queue_client-1.18.0a1 → utf_queue_client-1.19.0}/utf_queue_client.egg-info/top_level.txt +0 -0
@@ -11,5 +11,3 @@ dataSources/
11
11
  # Editor-based HTTP Client requests
12
12
  /httpRequests/
13
13
 
14
- # GitHub Copilot persisted chat sessions
15
- /copilot/chatSessions
@@ -2,11 +2,9 @@
2
2
  <module type="PYTHON_MODULE" version="4">
3
3
  <component name="NewModuleRootManager">
4
4
  <content url="file://$MODULE_DIR$">
5
- <excludeFolder url="file://$MODULE_DIR$/.idea/copilot/chatSessions" />
6
5
  <excludeFolder url="file://$MODULE_DIR$/venv" />
7
- <excludeFolder url="file://$MODULE_DIR$/venv2" />
8
6
  </content>
9
- <orderEntry type="jdk" jdkName="Python 3.13 (utf_queue_client_python)" jdkType="Python SDK" />
7
+ <orderEntry type="inheritedJdk" />
10
8
  <orderEntry type="sourceFolder" forTests="false" />
11
9
  </component>
12
10
  <component name="PyDocumentationSettings">
@@ -25,7 +25,6 @@ pipeline {
25
25
  TEST_RESULTS_DIR = 'test/test_results'
26
26
  OTEL_EXPORTER_OTLP_ENDPOINT = "https://otel-collector-http.silabs.net"
27
27
  OTEL_EXPORTER_OTLP_PROTOCOL = "http/protobuf"
28
- OTEL_EXPORTER_OTLP_CERTIFICATE = "/usr/share/ca-certificates/vault/vault-ca-prod.crt"
29
28
  UTF_QUEUE_VIRTUAL_HOST = "testing"
30
29
  OTEL_SERVICE_NAME = "utf-queue-client-tests"
31
30
  PYENV_VERSION = "3.9"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: utf-queue-client
3
- Version: 1.18.0a1
3
+ Version: 1.19.0
4
4
  Summary: No description provided
5
5
  Author-email: Joe Savage <joe.savage@silabs.com>
6
6
  Keywords: UTF
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "utf-queue-client"
7
- version = "1.18.0a1"
7
+ version = "1.19.0"
8
8
  description = "No description provided"
9
9
  authors = [
10
10
  { name = "Joe Savage", email = "joe.savage@silabs.com" }
@@ -2,7 +2,7 @@ sonar.projectKey=utf:queue-client-python
2
2
  sonar.projectName=utf-queue-client-python
3
3
  sonar.sources=utf_queue_client
4
4
  sonar.tests=./test
5
- sonar.exclusions=utf_queue_client/models/schemas/utf_queue_models/models/java/**
5
+ sonar.exclusions=utf_queue_client/models/schemas/utf_queue_models/models/**
6
6
  sonar.coverage.exclusions=test/**
7
7
  sonar.python.coverage.reportPaths=test/test_results/coverage.xml
8
8
  sonar.python.xunit.reportPath=test/test_results/junit*.xml
@@ -7,7 +7,6 @@ from urllib import parse
7
7
 
8
8
  import ndjson
9
9
  import pytest
10
- import requests
11
10
  from otel_extensions_pytest import TelemetryOptions, instrumented_fixture
12
11
  from stopwatch import Stopwatch
13
12
 
@@ -19,6 +18,9 @@ from utf_queue_client.models import (
19
18
  )
20
19
  from utf_queue_client.models.schemas.utf_queue_models.models.python.generated_models import (
21
20
  TestRailResult,
21
+ XrayImportTestExecution,
22
+ XrayInfo,
23
+ XrayTestExecUpdate,
22
24
  )
23
25
 
24
26
  pytest_plugins = ("otel_extensions",)
@@ -35,24 +37,6 @@ def pytest_addoption(parser, pluginmanager):
35
37
  if options.OTEL_EXPORTER_OTLP_ENDPOINT is None:
36
38
  options.OTEL_EXPORTER_OTLP_ENDPOINT = "https://otel-collector-http.silabs.net/"
37
39
  options.OTEL_EXPORTER_OTLP_PROTOCOL = "http/protobuf"
38
- cert_bundle = os.path.join(os.path.dirname(__file__), "silabs-net.pem")
39
- options.OTEL_EXPORTER_OTLP_CERTIFICATE = cert_bundle
40
- if not os.path.exists(cert_bundle):
41
- with open(cert_bundle, "wb") as bundle:
42
- r = requests.get(
43
- "https://vault.dev.silabs.net:443/v1/pki/ca/pem", verify=False
44
- )
45
- cert_file = os.path.join(os.path.dirname(__file__), "vault-ca-dev.crt")
46
- with open(cert_file, "wb") as f:
47
- f.write(r.content)
48
- bundle.write(r.content + b"\n")
49
- r = requests.get(
50
- "https://vault.silabs.net:443/v1/pki/ca/pem", verify=False
51
- )
52
- cert_file = os.path.join(os.path.dirname(__file__), "vault-ca.crt")
53
- with open(cert_file, "wb") as f:
54
- f.write(r.content)
55
- bundle.write(r.content)
56
40
 
57
41
 
58
42
  @pytest.fixture()
@@ -157,6 +141,25 @@ def test_rail_add_test_result():
157
141
  )
158
142
 
159
143
 
144
+ @pytest.fixture()
145
+ def xray_import_test_execution_data():
146
+ yield XrayImportTestExecution(
147
+ test_execution_key="DUMMY_EXEC",
148
+ add_tests_to_plan=True,
149
+ info=XrayInfo(project="DUMMY", test_plan_key="DUMMY_PLAN"),
150
+ tests=[
151
+ XrayTestExecUpdate(
152
+ comment="",
153
+ executed_by="test",
154
+ finish="2025-02-11T07:39:25+00:00",
155
+ start="2025-02-11T07:39:23+00:00",
156
+ status="PASS",
157
+ test_key="TC1234567890",
158
+ )
159
+ ],
160
+ )
161
+
162
+
160
163
  @pytest.fixture()
161
164
  def data_lake_tenant_key():
162
165
  return "dummy_key"
@@ -37,7 +37,7 @@ def test_producer(queue_server, username, password):
37
37
  params = pika.URLParameters(p.url)
38
38
  logger.info(f"stack timeout: {params.stack_timeout}")
39
39
  begin = time.time()
40
- for _ in range(0, 10):
40
+ for _ in range(0, 3):
41
41
  logger.info(f"{queue_server}: declaring queue...")
42
42
  start = time.time()
43
43
  p.queue_declare("default", durable=True)
@@ -1,6 +1,4 @@
1
1
  import os
2
- import uuid
3
- import datetime
4
2
 
5
3
  import pytest
6
4
 
@@ -48,37 +46,3 @@ def test_dummy_producer(sqa_app_build_result, sqa_test_result, sqa_test_session)
48
46
  producer.publish_test_session_start(sqa_test_session)
49
47
  producer.publish_test_session_stop(sqa_test_session)
50
48
  producer.publish_test_result(sqa_test_result)
51
-
52
-
53
- def test_result_producer_dev(
54
- sqa_app_build_result,
55
- sqa_test_result,
56
- sqa_test_session,
57
- ):
58
- os.environ["UTF_PRODUCER_APP_ID"] = "test_result_producer_dev"
59
- os.environ["UTF_QUEUE_USE_HTTP_PRODUCER"] = "true"
60
- os.environ["UTF_QUEUE_SERVER_URL"] = (
61
- "amqps://mwlabuser-jenkins:Lab10Rocks%3f%3f@utf-queue-central.dev.silabs.net:443/%2f"
62
- )
63
- producer = SqaTestResultProducerFactory.create_producer(use_http_producer=True)
64
- producer.queue_name = "sqa_test_results_dev"
65
- for _ in range(0, 1):
66
- sqa_test_session.PK_ID = str(uuid.uuid4())
67
- sqa_test_session.startTime = datetime.datetime.now(tz=datetime.UTC).isoformat()
68
- sqa_test_session.stopTime = None
69
- print("Session PKID = ", sqa_test_session.PK_ID)
70
- sqa_app_build_result.session_pk_id = sqa_test_session.PK_ID
71
-
72
- producer.publish_test_session_start(sqa_test_session)
73
- sqa_test_session.PASS_cnt = 100
74
- sqa_test_session.FAIL_cnt = 0
75
- sqa_test_session.SKIP_cnt = 0
76
- for i in range(0, 5):
77
- sqa_app_build_result.test_duration_sec = i
78
- sqa_app_build_result.app_description = "app description " + str(i + 1)
79
- producer.publish_app_build_result(sqa_app_build_result)
80
- sqa_test_session.stopTime = datetime.datetime.now(tz=datetime.UTC).isoformat()
81
- producer.publish_test_session_stop(sqa_test_session)
82
-
83
-
84
- # ede5e03b-e8d0-4604-8dd5-ed4c6c5a2686
@@ -0,0 +1,65 @@
1
+ from unittest.mock import MagicMock
2
+
3
+ import pytest
4
+
5
+ from utf_queue_client.clients.xray_data_producer import (
6
+ DummyXrayDataProducer,
7
+ LocalXrayDataProducer,
8
+ XrayDataProducer,
9
+ XrayDataProducerFactory,
10
+ )
11
+
12
+
13
+ def test_xray_data_producer_empty_url():
14
+ with pytest.raises(RuntimeError):
15
+ _ = XrayDataProducer()
16
+
17
+
18
+ def test_xray_data_producer_create_connect_error(mocker):
19
+ mock_class = mocker.patch(
20
+ "utf_queue_client.clients.xray_data_producer.LocalXrayDataProducer"
21
+ )
22
+ mock_instance = MagicMock()
23
+ mock_class.return_value = mock_instance
24
+ mock_class.side_effect = ConnectionError("failing for test")
25
+ with pytest.raises(ConnectionError):
26
+ _ = XrayDataProducerFactory.create_producer()
27
+
28
+
29
+ def test_dummy_producer(xray_import_test_execution_data):
30
+ producer = DummyXrayDataProducer()
31
+ producer.publish_test_execution(xray_import_test_execution_data)
32
+
33
+
34
+ def test_local_xray_producer(xray_import_test_execution_data, mocker):
35
+ mocker.patch(
36
+ "utf_queue_client.clients.base_producer.BlockingProducer.__init__",
37
+ return_value=None,
38
+ )
39
+ mocker.patch(
40
+ "utf_queue_client.clients.base_producer.BlockingProducer.queue_declare"
41
+ )
42
+ mock_producer_publish = mocker.patch(
43
+ "utf_queue_client.clients.base_producer.BlockingProducer.publish"
44
+ )
45
+ producer = LocalXrayDataProducer()
46
+ producer.producer_app_id = "DUMMY"
47
+ producer.publish_test_execution(xray_import_test_execution_data)
48
+ assert mock_producer_publish.called
49
+ kwargs = mock_producer_publish.call_args.kwargs
50
+ payload = kwargs.get("payload")
51
+ assert payload.get("recordSubType") == "IMPORT_TEST_EXECUTION"
52
+ assert payload.get("tenantKey") == "DUMMY"
53
+ payload_data = payload.get("payload")
54
+ assert payload_data.get("test_execution_key") == "DUMMY_EXEC"
55
+ assert payload_data.get("add_tests_to_plan") is True
56
+ assert payload_data.get("info").get("project") == "DUMMY"
57
+ assert payload_data.get("info").get("test_plan_key") == "DUMMY_PLAN"
58
+ assert len(payload_data.get("tests")) == 1
59
+ test = payload_data.get("tests")[0]
60
+ assert test.get("comment") == ""
61
+ assert test.get("executed_by") == "test"
62
+ assert test.get("finish") == "2025-02-11T07:39:25+00:00"
63
+ assert test.get("start") == "2025-02-11T07:39:23+00:00"
64
+ assert test.get("status") == "PASS"
65
+ assert test.get("test_key") == "TC1234567890"
@@ -0,0 +1,14 @@
1
+ setlocal
2
+ call %~dp0setup_venv.bat
3
+
4
+ pushd ..
5
+
6
+ rd /s /q build
7
+ rd /s /q dist
8
+ rd /s /q utf_queue_client.egg-info
9
+
10
+ pip install wheel
11
+ pip install -r test-requirements.txt --index-url https://artifactory.silabs.net/artifactory/api/pypi/infrasw-python-virtual/simple
12
+ python -m build
13
+
14
+ popd
@@ -187,7 +187,7 @@ class CompositeHTTPProducer(Loggable):
187
187
  for index, producer in enumerate(self.producers):
188
188
  if index:
189
189
  self.logger.warning(
190
- f"Failed to execute queue_declare for host {self.producers[index-1].hostname}, retrying with {producer.hostname}..."
190
+ f"Failed to execute queue_declare for host {self.producers[index - 1].hostname}, retrying with {producer.hostname}..."
191
191
  )
192
192
  try:
193
193
  return producer.queue_declare(queue, **kwargs)
@@ -200,7 +200,7 @@ class CompositeHTTPProducer(Loggable):
200
200
  for index, producer in enumerate(self.producers):
201
201
  if index:
202
202
  self.logger.warning(
203
- f"Failed to execute publish for host {self.producers[index-1].hostname}, retrying with {producer.hostname}..."
203
+ f"Failed to execute publish for host {self.producers[index - 1].hostname}, retrying with {producer.hostname}..."
204
204
  )
205
205
  try:
206
206
  return producer.publish(exchange, routing_key, payload, persistent)
@@ -0,0 +1,95 @@
1
+ import os
2
+ from abc import ABC, abstractmethod
3
+ from datetime import datetime
4
+ from socket import gethostname
5
+ from typing import Optional
6
+
7
+ from otel_extensions import instrumented
8
+
9
+ from ..models import QueueMessage, XrayImportTestExecution
10
+ from . import Loggable
11
+ from .base_producer import BlockingProducer as AMQPBlockingProducer
12
+ from .base_producer import ConnectionError
13
+ from .http_producer import CompositeHTTPProducer
14
+
15
+ __all__ = [
16
+ "XrayDataProducer",
17
+ "LocalXrayDataProducer",
18
+ "ConnectionError",
19
+ "XrayDataProducerFactory",
20
+ ]
21
+
22
+
23
+ class BaseXrayDataProducer(ABC):
24
+ @abstractmethod
25
+ def publish_test_execution(self, import_test_exec: dict):
26
+ """publish a test execution object"""
27
+
28
+
29
+ class XrayDataProducer(BaseXrayDataProducer):
30
+ RECORD_TYPE = "XRAY_EVENT"
31
+
32
+ def __init__(
33
+ self,
34
+ url=None,
35
+ producer_app_id: str = None,
36
+ producer_class: Optional[type] = None,
37
+ ):
38
+ if producer_class is None:
39
+ producer_class = AMQPBlockingProducer
40
+ self.queue_name = "default"
41
+ self.__producer_client = producer_class(url, producer_app_id)
42
+ self.__producer_client.queue_declare(queue=self.queue_name, durable=True)
43
+ self.producer_app_id = producer_app_id
44
+
45
+ @instrumented
46
+ def publish_test_execution(self, import_test_exec: XrayImportTestExecution):
47
+ queue_message = QueueMessage(
48
+ payload=import_test_exec,
49
+ recordType=self.RECORD_TYPE,
50
+ recordSubType="IMPORT_TEST_EXECUTION",
51
+ tenantKey=self.producer_app_id,
52
+ recordTimestamp=datetime.now().isoformat(),
53
+ )
54
+ self.__producer_client.publish(
55
+ exchange="",
56
+ routing_key=self.queue_name,
57
+ payload=queue_message.as_dict(),
58
+ persistent=True,
59
+ )
60
+
61
+
62
+ class DummyXrayDataProducer(BaseXrayDataProducer):
63
+ def publish_test_execution(self, import_test_exec: XrayImportTestExecution):
64
+ # noqa
65
+ pass
66
+
67
+
68
+ class LocalXrayDataProducer(XrayDataProducer):
69
+ def __init__(self):
70
+ super().__init__(
71
+ "amqp://guest:guest@localhost:5672/%2f",
72
+ os.environ.get(
73
+ "UTF_PRODUCER_APP_ID", f"LocalXrayDataProducer at {gethostname()}"
74
+ ),
75
+ )
76
+
77
+
78
+ class XrayDataProducerFactory(Loggable):
79
+ @classmethod
80
+ def create_producer(cls, raise_on_connection_error=False):
81
+ try:
82
+ queue_server_url = os.environ.get("UTF_QUEUE_SERVER_URL")
83
+ if queue_server_url is not None:
84
+ return XrayDataProducer(
85
+ url=queue_server_url,
86
+ producer_app_id=os.environ.get("UTF_PRODUCER_APP_ID"),
87
+ producer_class=CompositeHTTPProducer,
88
+ )
89
+ else:
90
+ return LocalXrayDataProducer()
91
+ except ConnectionError as e:
92
+ cls.logger.warning(f"Unable to connect to queue server: {repr(e)}")
93
+ if raise_on_connection_error:
94
+ raise
95
+ return DummyXrayDataProducer()
@@ -18,6 +18,14 @@ if IS_PYDANTIC_V1:
18
18
  from .generated_models_pydantic_v1 import ExceptionEvent
19
19
  from .generated_models_pydantic_v1 import TestRailResult
20
20
  from .generated_models_pydantic_v1 import TestResultCustomProps
21
+ from .generated_models_pydantic_v1 import XrayInfo
22
+ from .generated_models_pydantic_v1 import XrayStep
23
+ from .generated_models_pydantic_v1 import XrayParameter
24
+ from .generated_models_pydantic_v1 import XrayCustomField
25
+ from .generated_models_pydantic_v1 import XrayIteration
26
+ from .generated_models_pydantic_v1 import XrayTestInfo
27
+ from .generated_models_pydantic_v1 import XrayTestExecUpdate
28
+ from .generated_models_pydantic_v1 import XrayImportTestExecution
21
29
  else:
22
30
  from .generated_models_pydantic_v2 import QueueMessage
23
31
  from .generated_models_pydantic_v2 import QueueMessageV1
@@ -34,6 +42,14 @@ else:
34
42
  from .generated_models_pydantic_v2 import ExceptionEvent
35
43
  from .generated_models_pydantic_v2 import TestRailResult
36
44
  from .generated_models_pydantic_v2 import TestResultCustomProps
45
+ from .generated_models_pydantic_v2 import XrayInfo
46
+ from .generated_models_pydantic_v2 import XrayStep
47
+ from .generated_models_pydantic_v2 import XrayParameter
48
+ from .generated_models_pydantic_v2 import XrayCustomField
49
+ from .generated_models_pydantic_v2 import XrayIteration
50
+ from .generated_models_pydantic_v2 import XrayTestInfo
51
+ from .generated_models_pydantic_v2 import XrayTestExecUpdate
52
+ from .generated_models_pydantic_v2 import XrayImportTestExecution
37
53
 
38
54
  __all__ = [
39
55
  "QueueMessage",
@@ -51,4 +67,12 @@ __all__ = [
51
67
  "ExceptionEvent",
52
68
  "TestRailResult",
53
69
  "TestResultCustomProps",
70
+ "XrayInfo",
71
+ "XrayStep",
72
+ "XrayParameter",
73
+ "XrayCustomField",
74
+ "XrayIteration",
75
+ "XrayTestInfo",
76
+ "XrayTestExecUpdate",
77
+ "XrayImportTestExecution",
54
78
  ]
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: queue_message.json
3
- # timestamp: 2025-01-27T23:29:08+00:00
3
+ # timestamp: 2025-03-05T15:14:50+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -223,6 +223,76 @@ class TestResultCustomProps(BaseModel):
223
223
  extra = Extra.allow
224
224
 
225
225
 
226
+ class XrayInfo(BaseModel):
227
+ project: Optional[str] = None
228
+ summary: Optional[str] = None
229
+ description: Optional[str] = None
230
+ version: Optional[str] = None
231
+ revision: Optional[str] = None
232
+ user: Optional[str] = None
233
+ start_date: Optional[str] = None
234
+ finish_date: Optional[str] = None
235
+ test_plan_key: Optional[str] = None
236
+ test_environments: Optional[List[str]] = None
237
+
238
+
239
+ class XrayStep(BaseModel):
240
+ action: str
241
+ data: str
242
+ result: str
243
+
244
+
245
+ class XrayParameter(BaseModel):
246
+ name: str
247
+ value: str
248
+
249
+
250
+ class XrayCustomField(BaseModel):
251
+ name: str
252
+ id: Optional[int] = None
253
+ value: str
254
+
255
+
256
+ class XrayIteration(BaseModel):
257
+ name: Optional[str] = None
258
+ id: Optional[int] = None
259
+ parameters: List[XrayParameter]
260
+ status: Literal["ABORTED", "EXECUTING", "FAIL", "PASS", "TODO"]
261
+
262
+
263
+ class XrayTestInfo(BaseModel):
264
+ project_key: str
265
+ summary: Optional[str] = None
266
+ description: Optional[str] = None
267
+ test_type: Optional[str] = None
268
+ requirement_keys: Optional[List[str]] = None
269
+ labels: Optional[List[str]] = None
270
+ steps: Optional[List[XrayStep]] = None
271
+
272
+
273
+ class XrayTestExecUpdate(BaseModel):
274
+ test_key: str
275
+ status: Literal["ABORTED", "EXECUTING", "FAIL", "PASS", "TODO"]
276
+ test_info: Optional[XrayTestInfo] = None
277
+ test_version: Optional[str] = None
278
+ start: Optional[str] = None
279
+ finish: Optional[str] = None
280
+ comment: Optional[str] = None
281
+ executed_by: Optional[str] = None
282
+ assignee: Optional[str] = None
283
+ steps: Optional[List[XrayStep]] = None
284
+ iterations: Optional[List[XrayIteration]] = None
285
+ custom_fields: Optional[List[XrayCustomField]] = None
286
+
287
+
288
+ class XrayImportTestExecution(BaseModel):
289
+ test_execution_key: str
290
+ tests: List[XrayTestExecUpdate]
291
+ test_map_field_name: Optional[str] = None
292
+ info: Optional[XrayInfo] = None
293
+ add_tests_to_plan: Optional[bool] = None
294
+
295
+
226
296
  class QueueMessage(BaseModel):
227
297
  recordType: Literal[
228
298
  "ARTIFACT_UPLOAD_REQUEST",
@@ -232,9 +302,16 @@ class QueueMessage(BaseModel):
232
302
  "OPENTELEMETRY_DATA",
233
303
  "TEST_RAIL_EVENT",
234
304
  "UTF_TEST_EVENT",
305
+ "XRAY_EVENT",
235
306
  ] = Field(..., description="Type of record")
236
307
  recordSubType: Optional[
237
- Literal["BUILD_RESULT", "SESSION_START", "SESSION_STOP", "TEST_RESULT"]
308
+ Literal[
309
+ "BUILD_RESULT",
310
+ "IMPORT_TEST_EXECUTION",
311
+ "SESSION_START",
312
+ "SESSION_STOP",
313
+ "TEST_RESULT",
314
+ ]
238
315
  ] = Field(
239
316
  None,
240
317
  description="Subtype of record. Not all types have a subtype, but it is required when they have one.",
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: queue_message.json
3
- # timestamp: 2025-01-27T23:29:08+00:00
3
+ # timestamp: 2025-03-05T15:14:51+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -220,6 +220,76 @@ class TestResultCustomProps(BaseModel):
220
220
  model_config = ConfigDict(extra="allow")
221
221
 
222
222
 
223
+ class XrayInfo(BaseModel):
224
+ project: Optional[str] = None
225
+ summary: Optional[str] = None
226
+ description: Optional[str] = None
227
+ version: Optional[str] = None
228
+ revision: Optional[str] = None
229
+ user: Optional[str] = None
230
+ start_date: Optional[str] = None
231
+ finish_date: Optional[str] = None
232
+ test_plan_key: Optional[str] = None
233
+ test_environments: Optional[List[str]] = None
234
+
235
+
236
+ class XrayStep(BaseModel):
237
+ action: str
238
+ data: str
239
+ result: str
240
+
241
+
242
+ class XrayParameter(BaseModel):
243
+ name: str
244
+ value: str
245
+
246
+
247
+ class XrayCustomField(BaseModel):
248
+ name: str
249
+ id: Optional[int] = None
250
+ value: str
251
+
252
+
253
+ class XrayIteration(BaseModel):
254
+ name: Optional[str] = None
255
+ id: Optional[int] = None
256
+ parameters: List[XrayParameter]
257
+ status: Literal["ABORTED", "EXECUTING", "FAIL", "PASS", "TODO"]
258
+
259
+
260
+ class XrayTestInfo(BaseModel):
261
+ project_key: str
262
+ summary: Optional[str] = None
263
+ description: Optional[str] = None
264
+ test_type: Optional[str] = None
265
+ requirement_keys: Optional[List[str]] = None
266
+ labels: Optional[List[str]] = None
267
+ steps: Optional[List[XrayStep]] = None
268
+
269
+
270
+ class XrayTestExecUpdate(BaseModel):
271
+ test_key: str
272
+ status: Literal["ABORTED", "EXECUTING", "FAIL", "PASS", "TODO"]
273
+ test_info: Optional[XrayTestInfo] = None
274
+ test_version: Optional[str] = None
275
+ start: Optional[str] = None
276
+ finish: Optional[str] = None
277
+ comment: Optional[str] = None
278
+ executed_by: Optional[str] = None
279
+ assignee: Optional[str] = None
280
+ steps: Optional[List[XrayStep]] = None
281
+ iterations: Optional[List[XrayIteration]] = None
282
+ custom_fields: Optional[List[XrayCustomField]] = None
283
+
284
+
285
+ class XrayImportTestExecution(BaseModel):
286
+ test_execution_key: str
287
+ tests: List[XrayTestExecUpdate]
288
+ test_map_field_name: Optional[str] = None
289
+ info: Optional[XrayInfo] = None
290
+ add_tests_to_plan: Optional[bool] = None
291
+
292
+
223
293
  class QueueMessage(BaseModel):
224
294
 
225
295
  @field_validator("payload", mode="before")
@@ -236,9 +306,16 @@ class QueueMessage(BaseModel):
236
306
  "OPENTELEMETRY_DATA",
237
307
  "TEST_RAIL_EVENT",
238
308
  "UTF_TEST_EVENT",
309
+ "XRAY_EVENT",
239
310
  ] = Field(..., description="Type of record")
240
311
  recordSubType: Optional[
241
- Literal["BUILD_RESULT", "SESSION_START", "SESSION_STOP", "TEST_RESULT"]
312
+ Literal[
313
+ "BUILD_RESULT",
314
+ "IMPORT_TEST_EXECUTION",
315
+ "SESSION_START",
316
+ "SESSION_STOP",
317
+ "TEST_RESULT",
318
+ ]
242
319
  ] = Field(
243
320
  None,
244
321
  description="Subtype of record. Not all types have a subtype, but it is required when they have one.",
@@ -13,7 +13,8 @@
13
13
  "LOG_EVENT",
14
14
  "OPENTELEMETRY_DATA",
15
15
  "TEST_RAIL_EVENT",
16
- "UTF_TEST_EVENT"
16
+ "UTF_TEST_EVENT",
17
+ "XRAY_EVENT"
17
18
  ],
18
19
  "type": "string"
19
20
  },
@@ -21,6 +22,7 @@
21
22
  "description": "Subtype of record. Not all types have a subtype, but it is required when they have one.",
22
23
  "enum": [
23
24
  "BUILD_RESULT",
25
+ "IMPORT_TEST_EXECUTION",
24
26
  "SESSION_START",
25
27
  "SESSION_STOP",
26
28
  "TEST_RESULT"
@@ -661,6 +663,253 @@
661
663
  "additionalProperties": {
662
664
  "type": "string"
663
665
  }
666
+ },
667
+ "XrayInfo": {
668
+ "type": "object",
669
+ "properties": {
670
+ "project": {
671
+ "type": "string"
672
+ },
673
+ "summary": {
674
+ "type": "string"
675
+ },
676
+ "description": {
677
+ "type": "string"
678
+ },
679
+ "version": {
680
+ "type": "string"
681
+ },
682
+ "revision": {
683
+ "type": "string"
684
+ },
685
+ "user": {
686
+ "type": "string"
687
+ },
688
+ "start_date": {
689
+ "type": "string"
690
+ },
691
+ "finish_date": {
692
+ "type": "string"
693
+ },
694
+ "test_plan_key": {
695
+ "type": "string"
696
+ },
697
+ "test_environments": {
698
+ "type": "array",
699
+ "items": {
700
+ "type": "string"
701
+ }
702
+ }
703
+ }
704
+ },
705
+ "XrayStep": {
706
+ "type": "object",
707
+ "properties": {
708
+ "action": {
709
+ "type": "string"
710
+ },
711
+ "data": {
712
+ "type": "string"
713
+ },
714
+ "result": {
715
+ "type": "string"
716
+ }
717
+ },
718
+ "required": [
719
+ "action",
720
+ "data",
721
+ "result"
722
+ ]
723
+ },
724
+ "XrayParameter": {
725
+ "type": "object",
726
+ "properties": {
727
+ "name": {
728
+ "type": "string"
729
+ },
730
+ "value": {
731
+ "type": "string"
732
+ }
733
+ },
734
+ "required": [
735
+ "name",
736
+ "value"
737
+ ]
738
+ },
739
+ "XrayCustomField": {
740
+ "type": "object",
741
+ "properties": {
742
+ "name": {
743
+ "type": "string"
744
+ },
745
+ "id": {
746
+ "type": "integer"
747
+ },
748
+ "value": {
749
+ "type": "string"
750
+ }
751
+ },
752
+ "required": [
753
+ "name",
754
+ "value"
755
+ ]
756
+ },
757
+ "XrayIteration": {
758
+ "type": "object",
759
+ "properties": {
760
+ "name": {
761
+ "type": "string"
762
+ },
763
+ "id": {
764
+ "type": "integer"
765
+ },
766
+ "parameters": {
767
+ "type": "array",
768
+ "items": {
769
+ "$ref": "#/definitions/XrayParameter"
770
+ }
771
+ },
772
+ "status": {
773
+ "enum": [
774
+ "ABORTED",
775
+ "EXECUTING",
776
+ "FAIL",
777
+ "PASS",
778
+ "TODO"
779
+ ],
780
+ "type": "string"
781
+ }
782
+ },
783
+ "required": [
784
+ "parameters",
785
+ "status"
786
+ ]
787
+ },
788
+ "XrayTestInfo": {
789
+ "type": "object",
790
+ "properties": {
791
+ "project_key": {
792
+ "type": "string"
793
+ },
794
+ "summary": {
795
+ "type": "string"
796
+ },
797
+ "description": {
798
+ "type": "string"
799
+ },
800
+ "test_type": {
801
+ "type": "string"
802
+ },
803
+ "requirement_keys": {
804
+ "type": "array",
805
+ "items": {
806
+ "type": "string"
807
+ }
808
+ },
809
+ "labels": {
810
+ "type": "array",
811
+ "items": {
812
+ "type": "string"
813
+ }
814
+ },
815
+ "steps": {
816
+ "type": "array",
817
+ "items": {
818
+ "$ref": "#/definitions/XrayStep"
819
+ }
820
+ }
821
+ },
822
+ "required": [
823
+ "project_key"
824
+ ]
825
+ },
826
+ "XrayTestExecUpdate": {
827
+ "type": "object",
828
+ "properties": {
829
+ "test_key": {
830
+ "type": "string"
831
+ },
832
+ "status": {
833
+ "enum": [
834
+ "ABORTED",
835
+ "EXECUTING",
836
+ "FAIL",
837
+ "PASS",
838
+ "TODO"
839
+ ],
840
+ "type": "string"
841
+ },
842
+ "test_info": {
843
+ "$ref": "#/definitions/XrayTestInfo"
844
+ },
845
+ "test_version": {
846
+ "type": "string"
847
+ },
848
+ "start": {
849
+ "type": "string"
850
+ },
851
+ "finish": {
852
+ "type": "string"
853
+ },
854
+ "comment": {
855
+ "type": "string"
856
+ },
857
+ "executed_by": {
858
+ "type": "string"
859
+ },
860
+ "assignee": {
861
+ "type": "string"
862
+ },
863
+ "steps": {
864
+ "type": "array",
865
+ "items": {
866
+ "$ref": "#/definitions/XrayStep"
867
+ }
868
+ },
869
+ "iterations": {
870
+ "type": "array",
871
+ "items": {
872
+ "$ref": "#/definitions/XrayIteration"
873
+ }
874
+ },
875
+ "custom_fields": {
876
+ "type": "array",
877
+ "items": {
878
+ "$ref": "#/definitions/XrayCustomField"
879
+ }
880
+ }
881
+ },
882
+ "required": [
883
+ "status",
884
+ "test_key"
885
+ ]
886
+ },
887
+ "XrayImportTestExecution": {
888
+ "type": "object",
889
+ "properties": {
890
+ "test_execution_key": {
891
+ "type": "string"
892
+ },
893
+ "tests": {
894
+ "type": "array",
895
+ "items": {
896
+ "$ref": "#/definitions/XrayTestExecUpdate"
897
+ }
898
+ },
899
+ "test_map_field_name": {
900
+ "type": "string"
901
+ },
902
+ "info": {
903
+ "$ref": "#/definitions/XrayInfo"
904
+ },
905
+ "add_tests_to_plan": {
906
+ "type": "boolean"
907
+ }
908
+ },
909
+ "required": [
910
+ "test_execution_key",
911
+ "tests"
912
+ ]
664
913
  }
665
914
  }
666
915
  }
@@ -66,8 +66,6 @@ def setup_telemetry():
66
66
  OTLPSpanExporter._MAX_RETRY_TIMEOUT = 4
67
67
  global telemetry_initialized
68
68
  if not telemetry_initialized:
69
- if os.environ.get("OTEL_EXPORTER_OTLP_CERTIFICATE") is None:
70
- os.environ["OTEL_EXPORTER_OTLP_CERTIFICATE"] = get_or_make_ca_file()
71
69
  if (
72
70
  os.environ.get("DISABLE_SSL_VERIFICATION", DISABLE_SSL_VERIFICATION_DEFAULT)
73
71
  == "true"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: utf-queue-client
3
- Version: 1.18.0a1
3
+ Version: 1.19.0
4
4
  Summary: No description provided
5
5
  Author-email: Joe Savage <joe.savage@silabs.com>
6
6
  Keywords: UTF
@@ -37,6 +37,7 @@ test/test_ubai_search.py
37
37
  test/test_ubai_update_retention.py
38
38
  test/test_ubai_upload.py
39
39
  test/test_utils.py
40
+ test/test_xray_data_producer.py
40
41
  tools/build_dist.bat
41
42
  tools/setup_venv.bat
42
43
  tools/silabs-net.pem
@@ -61,6 +62,7 @@ utf_queue_client/clients/opentelemetry_data_producer.py
61
62
  utf_queue_client/clients/sqa_test_result_producer.py
62
63
  utf_queue_client/clients/test_rail_data_producer.py
63
64
  utf_queue_client/clients/ubai_artifact_upload_request_producer.py
65
+ utf_queue_client/clients/xray_data_producer.py
64
66
  utf_queue_client/exceptions/__init__.py
65
67
  utf_queue_client/models/__init__.py
66
68
  utf_queue_client/models/base_model.py
@@ -70,7 +72,6 @@ utf_queue_client/models/schemas/utf_queue_models/models/python/__init__.py
70
72
  utf_queue_client/models/schemas/utf_queue_models/models/python/generated_models.py
71
73
  utf_queue_client/models/schemas/utf_queue_models/models/python/generated_models_pydantic_v1.py
72
74
  utf_queue_client/models/schemas/utf_queue_models/models/python/generated_models_pydantic_v2.py
73
- utf_queue_client/models/schemas/utf_queue_models/models/python/model_test.py
74
75
  utf_queue_client/models/schemas/utf_queue_models/schema/queue_message.json
75
76
  utf_queue_client/scripts/__init__.py
76
77
  utf_queue_client/scripts/publish_release_info_cli.py
@@ -1,12 +0,0 @@
1
- setlocal
2
- call %~dp0setup_venv.bat
3
-
4
- pushd ..
5
-
6
- rd /s /q build
7
- rd /s /q dist
8
- rd /s /q utf_queue_client.egg-info
9
-
10
- python setup.py sdist bdist_wheel
11
-
12
- popd
@@ -1,23 +0,0 @@
1
- from pydantic import BaseModel, TypeAdapter
2
- import json
3
-
4
-
5
- class PayloadBase(BaseModel):
6
- class Config:
7
- extra = "allow"
8
-
9
-
10
- class PayloadResult(PayloadBase):
11
- value: str
12
- is_error: bool
13
-
14
-
15
- adapter = TypeAdapter(PayloadResult)
16
-
17
- print(PayloadResult.model_json_schema())
18
- print(
19
- json.dumps(
20
- adapter.json_schema(ref_template="#/components/schemas/{model}"),
21
- indent=2,
22
- )
23
- )