dt-extensions-sdk 1.3.0__tar.gz → 1.3.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.
Files changed (84) hide show
  1. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/PKG-INFO +4 -3
  2. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/dynatrace_extension/__about__.py +1 -1
  3. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/dynatrace_extension/sdk/callback.py +8 -3
  4. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/dynatrace_extension/sdk/communication.py +23 -0
  5. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/dynatrace_extension/sdk/extension.py +6 -2
  6. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/tests/sdk/test_status.py +66 -3
  7. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/.github/workflows/gh-pages-docs.yml +0 -0
  8. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/.github/workflows/publish.yml +0 -0
  9. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/.gitignore +0 -0
  10. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/LICENSE.txt +0 -0
  11. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/README.md +0 -0
  12. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/docs/_static/dt-sdk-header.png +0 -0
  13. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/docs/_static/dt-sdk-logo.png +0 -0
  14. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/docs/_static/favicon.ico +0 -0
  15. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/docs/_static/img/migrate-01-new-extension.png +0 -0
  16. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/docs/_static/img/migrate-02-type.png +0 -0
  17. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/docs/_static/img/migrate-03-import.png +0 -0
  18. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/docs/_static/img/migrate-04-import-remote.png +0 -0
  19. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/docs/_static/img/migrate-05-activation.png +0 -0
  20. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/docs/_static/img/migrate-06-activation-config.png +0 -0
  21. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/docs/api/events/event_severity.rst +0 -0
  22. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/docs/api/events/event_type.rst +0 -0
  23. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/docs/api/events/index.rst +0 -0
  24. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/docs/api/extension.rst +0 -0
  25. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/docs/api/metrics/index.rst +0 -0
  26. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/docs/api/metrics/metric.rst +0 -0
  27. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/docs/api/metrics/metric_type.rst +0 -0
  28. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/docs/cli/assemble.rst +0 -0
  29. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/docs/cli/build.rst +0 -0
  30. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/docs/cli/create.rst +0 -0
  31. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/docs/cli/gencerts.rst +0 -0
  32. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/docs/cli/help.rst +0 -0
  33. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/docs/cli/run.rst +0 -0
  34. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/docs/cli/sign.rst +0 -0
  35. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/docs/cli/upload.rst +0 -0
  36. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/docs/cli/wheel.rst +0 -0
  37. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/docs/conf.py +0 -0
  38. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/docs/guides/building.rst +0 -0
  39. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/docs/guides/extension_structure.rst +0 -0
  40. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/docs/guides/installation.rst +0 -0
  41. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/docs/guides/migration.rst +0 -0
  42. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/docs/index.rst +0 -0
  43. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/docs/requirements.txt +0 -0
  44. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/dynatrace_extension/__init__.py +0 -0
  45. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/dynatrace_extension/cli/__init__.py +0 -0
  46. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/dynatrace_extension/cli/create/__init__.py +0 -0
  47. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/dynatrace_extension/cli/create/create.py +0 -0
  48. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/dynatrace_extension/cli/create/extension_template/.gitignore.template +0 -0
  49. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/dynatrace_extension/cli/create/extension_template/README.md.template +0 -0
  50. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/dynatrace_extension/cli/create/extension_template/activation.json.template +0 -0
  51. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/dynatrace_extension/cli/create/extension_template/extension/activationSchema.json.template +0 -0
  52. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/dynatrace_extension/cli/create/extension_template/extension/extension.yaml.template +0 -0
  53. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/dynatrace_extension/cli/create/extension_template/extension_name/__init__.py.template +0 -0
  54. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/dynatrace_extension/cli/create/extension_template/extension_name/__main__.py.template +0 -0
  55. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/dynatrace_extension/cli/create/extension_template/secrets.json.template +0 -0
  56. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/dynatrace_extension/cli/create/extension_template/setup.py.template +0 -0
  57. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/dynatrace_extension/cli/main.py +0 -0
  58. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/dynatrace_extension/cli/schema.py +0 -0
  59. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/dynatrace_extension/sdk/__init__.py +0 -0
  60. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/dynatrace_extension/sdk/activation.py +0 -0
  61. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/dynatrace_extension/sdk/event.py +0 -0
  62. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/dynatrace_extension/sdk/helper.py +0 -0
  63. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/dynatrace_extension/sdk/metric.py +0 -0
  64. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/dynatrace_extension/sdk/runtime.py +0 -0
  65. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/dynatrace_extension/sdk/snapshot.py +0 -0
  66. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/dynatrace_extension/sdk/vendor/__init__.py +0 -0
  67. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/dynatrace_extension/sdk/vendor/mureq/LICENSE +0 -0
  68. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/dynatrace_extension/sdk/vendor/mureq/__init__.py +0 -0
  69. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/dynatrace_extension/sdk/vendor/mureq/mureq.py +0 -0
  70. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/pyproject.toml +0 -0
  71. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/tests/__init__.py +0 -0
  72. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/tests/cli/__init__.py +0 -0
  73. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/tests/cli/test_dt_sdk.py +0 -0
  74. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/tests/cli/test_templates.py +0 -0
  75. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/tests/cli/test_types.py +0 -0
  76. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/tests/data/snapshot.json +0 -0
  77. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/tests/sdk/__init__.py +0 -0
  78. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/tests/sdk/test_activation.py +0 -0
  79. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/tests/sdk/test_callback.py +0 -0
  80. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/tests/sdk/test_communication.py +0 -0
  81. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/tests/sdk/test_extension.py +0 -0
  82. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/tests/sdk/test_metric.py +0 -0
  83. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/tests/sdk/test_runtime_properties.py +0 -0
  84. {dt_extensions_sdk-1.3.0 → dt_extensions_sdk-1.3.1}/tests/sdk/test_snapshot.py +0 -0
@@ -1,11 +1,12 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: dt-extensions-sdk
3
- Version: 1.3.0
3
+ Version: 1.3.1
4
4
  Project-URL: Documentation, https://github.com/dynatrace-extensions/dt-extensions-python-sdk#readme
5
5
  Project-URL: Issues, https://github.com/dynatrace-extensions/dt-extensions-python-sdk/issues
6
6
  Project-URL: Source, https://github.com/dynatrace-extensions/dt-extensions-python-sdk
7
7
  Author-email: dlopes7 <davidribeirolopes@gmail.com>
8
- License: MIT
8
+ License-Expression: MIT
9
+ License-File: LICENSE.txt
9
10
  Classifier: Development Status :: 4 - Beta
10
11
  Classifier: Programming Language :: Python
11
12
  Classifier: Programming Language :: Python :: 3.10
@@ -3,4 +3,4 @@
3
3
  # SPDX-License-Identifier: MIT
4
4
 
5
5
 
6
- __version__ = "1.3.0"
6
+ __version__ = "1.3.1"
@@ -9,7 +9,7 @@ from timeit import default_timer as timer
9
9
  from typing import Callable, Dict, Optional, Tuple
10
10
 
11
11
  from .activation import ActivationType
12
- from .communication import Status, StatusValue
12
+ from .communication import MultiStatus, Status, StatusValue
13
13
 
14
14
 
15
15
  class WrappedCallback:
@@ -60,8 +60,13 @@ class WrappedCallback:
60
60
  start_time = timer()
61
61
  failed = False
62
62
  try:
63
- self.callback(*self.callback_args, **self.callback_kwargs)
64
- self.status = Status(StatusValue.OK)
63
+ ret = self.callback(*self.callback_args, **self.callback_kwargs)
64
+ if isinstance(ret, Status):
65
+ self.status = ret
66
+ elif isinstance(ret, MultiStatus):
67
+ self.status = ret.build()
68
+ else:
69
+ self.status = Status(StatusValue.OK)
65
70
  except Exception as e:
66
71
  failed = True
67
72
  self.logger.exception(f"Error running callback {self}: {e!r}")
@@ -59,6 +59,29 @@ class Status:
59
59
  return self.status not in (StatusValue.OK, StatusValue.EMPTY)
60
60
 
61
61
 
62
+ class MultiStatus:
63
+
64
+ def __init__(self):
65
+ self.statuses = []
66
+
67
+ def add_status(self, status: StatusValue, message):
68
+ self.statuses.append(Status(status, message))
69
+
70
+ def build(self) -> Status:
71
+ ret = Status(StatusValue.OK)
72
+ if len(self.statuses) == 0:
73
+ return ret
74
+
75
+ messages = []
76
+ for stored_status in self.statuses:
77
+ print(stored_status) # noqa: T201
78
+ if stored_status.is_error():
79
+ ret.status = stored_status.status
80
+ messages.append(stored_status.message)
81
+ ret.message = "\n".join(messages)
82
+ return ret
83
+
84
+
62
85
  class CommunicationClient(ABC):
63
86
  """
64
87
  Abstract class for extension communication
@@ -32,6 +32,7 @@ TIME_DIFF_INTERVAL = timedelta(seconds=60)
32
32
 
33
33
  CALLBACKS_THREAD_POOL_SIZE = 100
34
34
  INTERNAL_THREAD_POOL_SIZE = 20
35
+ HEARTBEAT_THREAD_POOL_SIZE = 10
35
36
 
36
37
  RFC_3339_FORMAT = "%Y-%m-%dT%H:%M:%SZ"
37
38
  DATASOURCE_TYPE = "python"
@@ -220,6 +221,7 @@ class Extension:
220
221
  # Executors for the callbacks and internal methods
221
222
  self._callbacks_executor = ThreadPoolExecutor(max_workers=CALLBACKS_THREAD_POOL_SIZE)
222
223
  self._internal_executor = ThreadPoolExecutor(max_workers=INTERNAL_THREAD_POOL_SIZE)
224
+ self._heartbeat_executor = ThreadPoolExecutor(max_workers=HEARTBEAT_THREAD_POOL_SIZE)
223
225
 
224
226
  # Extension metrics
225
227
  self._metrics_lock = RLock()
@@ -827,7 +829,7 @@ class Extension:
827
829
  self._scheduler.enterabs(next_timestamp, 1, self._timediff_iteration)
828
830
 
829
831
  def _heartbeat_iteration(self):
830
- self._internal_executor.submit(self._heartbeat)
832
+ self._heartbeat_executor.submit(self._heartbeat)
831
833
  next_timestamp = self._get_and_set_next_internal_callback_timestamp("heartbeat", HEARTBEAT_INTERVAL)
832
834
  self._scheduler.enterabs(next_timestamp, 2, self._heartbeat_iteration)
833
835
 
@@ -976,7 +978,9 @@ class Extension:
976
978
  if callback.status.is_error():
977
979
  overall_status.status = callback.status.status
978
980
  messages.append(f"{callback}: {callback.status.message}")
979
-
981
+ continue
982
+ if callback.status.message is not None and callback.status.message != "":
983
+ messages.append(f"{callback}: {callback.status.message}")
980
984
  overall_status.message = "\n".join(messages)
981
985
  return overall_status
982
986
 
@@ -4,7 +4,7 @@ from datetime import timedelta
4
4
  from unittest.mock import MagicMock
5
5
 
6
6
  from dynatrace_extension import Extension
7
- from dynatrace_extension.sdk.communication import DebugClient
7
+ from dynatrace_extension.sdk.communication import DebugClient, MultiStatus
8
8
  from dynatrace_extension.sdk.extension import Status, StatusValue
9
9
 
10
10
 
@@ -52,7 +52,7 @@ class TestStatus(unittest.TestCase):
52
52
  self.assertEqual(status.status, StatusValue.GENERIC_ERROR)
53
53
  self.assertIn("something went wrong", status.message)
54
54
 
55
- def test_mutiple_bad_status(self):
55
+ def test_multiple_bad_status(self):
56
56
  ext = Extension()
57
57
  ext.logger = MagicMock()
58
58
  ext._running_in_sim = True
@@ -70,7 +70,7 @@ class TestStatus(unittest.TestCase):
70
70
  ext.schedule(bad_method_1, timedelta(seconds=1))
71
71
  ext.schedule(bad_method_2, timedelta(seconds=1))
72
72
  ext._scheduler.run(blocking=False)
73
- time.sleep(0.01)
73
+ time.sleep(1)
74
74
 
75
75
  status = ext._build_current_status()
76
76
  self.assertEqual(status.status, StatusValue.GENERIC_ERROR)
@@ -93,3 +93,66 @@ class TestStatus(unittest.TestCase):
93
93
 
94
94
  self.assertTrue(extension._scheduled_callbacks[1].status.is_error())
95
95
  self.assertIn("longer than the interval", extension._scheduled_callbacks[1].status.message)
96
+
97
+ def test_direct_status_return(self):
98
+ ext = Extension()
99
+ ext.logger = MagicMock()
100
+ ext._running_in_sim = True
101
+ ext._client = DebugClient("", "", MagicMock())
102
+ ext._is_fastcheck = False
103
+
104
+ def callback():
105
+ return Status(StatusValue.OK, "foo1")
106
+
107
+ ext.schedule(callback, timedelta(seconds=1))
108
+ ext._scheduler.run(blocking=False)
109
+ time.sleep(0.01)
110
+
111
+ status = ext._build_current_status()
112
+ self.assertEqual(status.status, StatusValue.OK)
113
+ self.assertIn("foo1", status.message)
114
+
115
+ def test_direct_statuses_return(self):
116
+
117
+ def callback():
118
+ return Status(StatusValue.OK, "foo1")
119
+
120
+ def custom_query():
121
+ return Status(StatusValue.EMPTY, "foo2")
122
+
123
+ ext = Extension()
124
+ ext.logger = MagicMock()
125
+ ext._running_in_sim = True
126
+ ext._client = DebugClient("", "", MagicMock())
127
+ ext._is_fastcheck = False
128
+
129
+ ext.schedule(callback, timedelta(seconds=1))
130
+ ext.schedule(custom_query, timedelta(seconds=1))
131
+ ext._scheduler.run(blocking=False)
132
+ time.sleep(0.01)
133
+
134
+ status = ext._build_current_status()
135
+ self.assertEqual(status.status, StatusValue.OK)
136
+ self.assertIn("foo1", status.message)
137
+ self.assertIn("foo2", status.message)
138
+
139
+ def test_multistatus(self):
140
+ ext = Extension()
141
+ ext.logger = MagicMock()
142
+ ext._running_in_sim = True
143
+ ext._client = DebugClient("", "", MagicMock())
144
+ ext._is_fastcheck = False
145
+
146
+ def callback():
147
+ ret = MultiStatus()
148
+ ret.add_status(StatusValue.OK, "foo1")
149
+ ret.add_status(StatusValue.UNKNOWN_ERROR, "foo2")
150
+ return ret
151
+
152
+ ext.schedule(callback, timedelta(seconds=1))
153
+ ext._scheduler.run(blocking=False)
154
+ time.sleep(1)
155
+
156
+ status = ext._build_current_status()
157
+ self.assertEqual(status.status, StatusValue.UNKNOWN_ERROR)
158
+ self.assertIn("foo1", status.message)