ul-uspd-middleware-sdk 1.0.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 (36) hide show
  1. ul_uspd_middleware_sdk-1.0.1/PKG-INFO +26 -0
  2. ul_uspd_middleware_sdk-1.0.1/README.md +0 -0
  3. ul_uspd_middleware_sdk-1.0.1/pyproject.toml +54 -0
  4. ul_uspd_middleware_sdk-1.0.1/setup.cfg +4 -0
  5. ul_uspd_middleware_sdk-1.0.1/ul_uspd_middleware_sdk.egg-info/PKG-INFO +26 -0
  6. ul_uspd_middleware_sdk-1.0.1/ul_uspd_middleware_sdk.egg-info/SOURCES.txt +34 -0
  7. ul_uspd_middleware_sdk-1.0.1/ul_uspd_middleware_sdk.egg-info/dependency_links.txt +1 -0
  8. ul_uspd_middleware_sdk-1.0.1/ul_uspd_middleware_sdk.egg-info/requires.txt +10 -0
  9. ul_uspd_middleware_sdk-1.0.1/ul_uspd_middleware_sdk.egg-info/top_level.txt +1 -0
  10. ul_uspd_middleware_sdk-1.0.1/uspd_middleware_sdk/README.md +3 -0
  11. ul_uspd_middleware_sdk-1.0.1/uspd_middleware_sdk/__init__.py +0 -0
  12. ul_uspd_middleware_sdk-1.0.1/uspd_middleware_sdk/__tests__/__init__.py +0 -0
  13. ul_uspd_middleware_sdk-1.0.1/uspd_middleware_sdk/__tests__/test_mac.py +15 -0
  14. ul_uspd_middleware_sdk-1.0.1/uspd_middleware_sdk/__tests__/test_uspd_middleware_sdk.py +39 -0
  15. ul_uspd_middleware_sdk-1.0.1/uspd_middleware_sdk/brokers/__init__.py +0 -0
  16. ul_uspd_middleware_sdk-1.0.1/uspd_middleware_sdk/brokers/shared_amqp_broker.py +10 -0
  17. ul_uspd_middleware_sdk-1.0.1/uspd_middleware_sdk/constants/__init__.py +0 -0
  18. ul_uspd_middleware_sdk-1.0.1/uspd_middleware_sdk/constants/enums.py +8 -0
  19. ul_uspd_middleware_sdk-1.0.1/uspd_middleware_sdk/constants/env.py +11 -0
  20. ul_uspd_middleware_sdk-1.0.1/uspd_middleware_sdk/constants/names.py +1 -0
  21. ul_uspd_middleware_sdk-1.0.1/uspd_middleware_sdk/dag.yml +24 -0
  22. ul_uspd_middleware_sdk-1.0.1/uspd_middleware_sdk/errors.py +15 -0
  23. ul_uspd_middleware_sdk-1.0.1/uspd_middleware_sdk/lib.py +7 -0
  24. ul_uspd_middleware_sdk-1.0.1/uspd_middleware_sdk/messages/__init__.py +0 -0
  25. ul_uspd_middleware_sdk-1.0.1/uspd_middleware_sdk/messages/manual_polling_status_message.py +15 -0
  26. ul_uspd_middleware_sdk-1.0.1/uspd_middleware_sdk/py.typed +0 -0
  27. ul_uspd_middleware_sdk-1.0.1/uspd_middleware_sdk/runtime_conf.py +10 -0
  28. ul_uspd_middleware_sdk-1.0.1/uspd_middleware_sdk/types/__init__.py +0 -0
  29. ul_uspd_middleware_sdk-1.0.1/uspd_middleware_sdk/types/manual_polling.py +16 -0
  30. ul_uspd_middleware_sdk-1.0.1/uspd_middleware_sdk/uspd_middleware_api_sdk.py +24 -0
  31. ul_uspd_middleware_sdk-1.0.1/uspd_middleware_sdk/uspd_middleware_api_sdk_config.py +6 -0
  32. ul_uspd_middleware_sdk-1.0.1/uspd_middleware_sdk/uspd_middleware_sdk.py +42 -0
  33. ul_uspd_middleware_sdk-1.0.1/uspd_middleware_sdk/uspd_middleware_sdk_config.py +5 -0
  34. ul_uspd_middleware_sdk-1.0.1/uspd_middleware_sdk/utils/__init__.py +0 -0
  35. ul_uspd_middleware_sdk-1.0.1/uspd_middleware_sdk/utils/internal_api_error_handler.py +32 -0
  36. ul_uspd_middleware_sdk-1.0.1/uspd_middleware_sdk/utils/mac.py +2 -0
@@ -0,0 +1,26 @@
1
+ Metadata-Version: 2.4
2
+ Name: ul_uspd_middleware_sdk
3
+ Version: 1.0.1
4
+ Summary: USPD middleware sdk
5
+ Author: Unic-lab
6
+ License: MIT
7
+ Classifier: Intended Audience :: Developers
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Classifier: Programming Language :: Python
10
+ Classifier: Programming Language :: Python :: 3.14
11
+ Classifier: Operating System :: OS Independent
12
+ Requires-Python: >=3.14
13
+ Description-Content-Type: text/markdown
14
+ Requires-Dist: requests>=2.32.0
15
+ Requires-Dist: ul-api-utils>=10.0.14
16
+ Requires-Dist: ul-db-utils>=6.0.3
17
+ Requires-Dist: ul-py-tool>=3.0.3
18
+ Requires-Dist: ul-data-aggregator-sdk>=11.0.4
19
+ Requires-Dist: loguru>=0.7.2
20
+ Requires-Dist: tenacity>=9.0.0
21
+ Provides-Extra: dev
22
+ Requires-Dist: uv-script>=0.1.9; extra == "dev"
23
+
24
+ # USPD Middleware SDK
25
+
26
+ HTTP client and shared contracts for uspd-middleware integration.
File without changes
@@ -0,0 +1,54 @@
1
+ [build-system]
2
+ requires = ["setuptools>=80", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "ul_uspd_middleware_sdk"
7
+ version = "1.0.1"
8
+ description = "USPD middleware sdk"
9
+ readme = "uspd_middleware_sdk/README.md"
10
+ license = { text = "MIT" }
11
+ authors = [{ name = "Unic-lab" }]
12
+ requires-python = ">=3.14"
13
+ classifiers = [
14
+ "Intended Audience :: Developers",
15
+ "License :: OSI Approved :: MIT License",
16
+ "Programming Language :: Python",
17
+ "Programming Language :: Python :: 3.14",
18
+ "Operating System :: OS Independent",
19
+ ]
20
+ dependencies = [
21
+ "requests>=2.32.0",
22
+ "ul-api-utils>=10.0.14",
23
+ "ul-db-utils>=6.0.3",
24
+ "ul-py-tool>=3.0.3",
25
+ "ul-data-aggregator-sdk>=11.0.4",
26
+ "loguru>=0.7.2",
27
+ "tenacity>=9.0.0",
28
+ ]
29
+
30
+ [project.optional-dependencies]
31
+ dev = [
32
+ "uv-script>=0.1.9",
33
+ ]
34
+
35
+ [tool.setuptools.packages.find]
36
+ include = ["uspd_middleware_sdk*"]
37
+
38
+ [tool.setuptools.package-data]
39
+ "*" = ["*.yml"]
40
+ "uspd_middleware_sdk" = ["py.typed", "dag.yml"]
41
+
42
+ [[tool.uv.index]]
43
+ url = "https://pip-cache.dev-unic-lab.by/repository/pip-cache/simple"
44
+ default = true
45
+
46
+ [tool.uvs.scripts]
47
+ prepare = "python3 -m build"
48
+ lint = "ulpytool lint --ignore-setup-packages ul-unipipeline --exclude-import flask requests --py-files-ignore **/migrations/**/*.py --helmtemplatefiles-ignore .helm/**"
49
+ test = "ulpytool test"
50
+ setup = "uv sync --frozen --extra dev"
51
+ setup-dev = "uv sync --frozen --extra dev && ulpytool install"
52
+ version-major = "ulpytool major"
53
+ version-minor = "ulpytool minor"
54
+ version-patch = "ulpytool patch"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,26 @@
1
+ Metadata-Version: 2.4
2
+ Name: ul_uspd_middleware_sdk
3
+ Version: 1.0.1
4
+ Summary: USPD middleware sdk
5
+ Author: Unic-lab
6
+ License: MIT
7
+ Classifier: Intended Audience :: Developers
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Classifier: Programming Language :: Python
10
+ Classifier: Programming Language :: Python :: 3.14
11
+ Classifier: Operating System :: OS Independent
12
+ Requires-Python: >=3.14
13
+ Description-Content-Type: text/markdown
14
+ Requires-Dist: requests>=2.32.0
15
+ Requires-Dist: ul-api-utils>=10.0.14
16
+ Requires-Dist: ul-db-utils>=6.0.3
17
+ Requires-Dist: ul-py-tool>=3.0.3
18
+ Requires-Dist: ul-data-aggregator-sdk>=11.0.4
19
+ Requires-Dist: loguru>=0.7.2
20
+ Requires-Dist: tenacity>=9.0.0
21
+ Provides-Extra: dev
22
+ Requires-Dist: uv-script>=0.1.9; extra == "dev"
23
+
24
+ # USPD Middleware SDK
25
+
26
+ HTTP client and shared contracts for uspd-middleware integration.
@@ -0,0 +1,34 @@
1
+ README.md
2
+ pyproject.toml
3
+ ul_uspd_middleware_sdk.egg-info/PKG-INFO
4
+ ul_uspd_middleware_sdk.egg-info/SOURCES.txt
5
+ ul_uspd_middleware_sdk.egg-info/dependency_links.txt
6
+ ul_uspd_middleware_sdk.egg-info/requires.txt
7
+ ul_uspd_middleware_sdk.egg-info/top_level.txt
8
+ uspd_middleware_sdk/README.md
9
+ uspd_middleware_sdk/__init__.py
10
+ uspd_middleware_sdk/dag.yml
11
+ uspd_middleware_sdk/errors.py
12
+ uspd_middleware_sdk/lib.py
13
+ uspd_middleware_sdk/py.typed
14
+ uspd_middleware_sdk/runtime_conf.py
15
+ uspd_middleware_sdk/uspd_middleware_api_sdk.py
16
+ uspd_middleware_sdk/uspd_middleware_api_sdk_config.py
17
+ uspd_middleware_sdk/uspd_middleware_sdk.py
18
+ uspd_middleware_sdk/uspd_middleware_sdk_config.py
19
+ uspd_middleware_sdk/__tests__/__init__.py
20
+ uspd_middleware_sdk/__tests__/test_mac.py
21
+ uspd_middleware_sdk/__tests__/test_uspd_middleware_sdk.py
22
+ uspd_middleware_sdk/brokers/__init__.py
23
+ uspd_middleware_sdk/brokers/shared_amqp_broker.py
24
+ uspd_middleware_sdk/constants/__init__.py
25
+ uspd_middleware_sdk/constants/enums.py
26
+ uspd_middleware_sdk/constants/env.py
27
+ uspd_middleware_sdk/constants/names.py
28
+ uspd_middleware_sdk/messages/__init__.py
29
+ uspd_middleware_sdk/messages/manual_polling_status_message.py
30
+ uspd_middleware_sdk/types/__init__.py
31
+ uspd_middleware_sdk/types/manual_polling.py
32
+ uspd_middleware_sdk/utils/__init__.py
33
+ uspd_middleware_sdk/utils/internal_api_error_handler.py
34
+ uspd_middleware_sdk/utils/mac.py
@@ -0,0 +1,10 @@
1
+ requests>=2.32.0
2
+ ul-api-utils>=10.0.14
3
+ ul-db-utils>=6.0.3
4
+ ul-py-tool>=3.0.3
5
+ ul-data-aggregator-sdk>=11.0.4
6
+ loguru>=0.7.2
7
+ tenacity>=9.0.0
8
+
9
+ [dev]
10
+ uv-script>=0.1.9
@@ -0,0 +1,3 @@
1
+ # USPD Middleware SDK
2
+
3
+ HTTP client and shared contracts for uspd-middleware integration.
@@ -0,0 +1,15 @@
1
+ import unittest
2
+
3
+ from uspd_middleware_sdk.utils.mac import normalize_mac
4
+
5
+
6
+ class TestNormalizeMac(unittest.TestCase):
7
+ def test_normalizes_string_mac(self) -> None:
8
+ self.assertEqual(normalize_mac('aa:bb:cc'), 'AA:BB:CC')
9
+
10
+ def test_normalizes_int_mac(self) -> None:
11
+ self.assertEqual(normalize_mac(123456), '123456')
12
+
13
+
14
+ if __name__ == '__main__':
15
+ unittest.main()
@@ -0,0 +1,39 @@
1
+ import unittest
2
+ from datetime import datetime, timezone
3
+ from unittest.mock import MagicMock, patch
4
+ from uuid import uuid4
5
+
6
+ from uspd_middleware_sdk.constants.enums import ManualPollingStatusEnum
7
+ from uspd_middleware_sdk.messages.manual_polling_status_message import ManualPollingStatusV0Message
8
+ from uspd_middleware_sdk.uspd_middleware_sdk import UspdMiddlewareSdk
9
+ from uspd_middleware_sdk.uspd_middleware_sdk_config import UspdMiddlewareSdkConfig
10
+
11
+
12
+ class TestUspdMiddlewareSdk(unittest.TestCase):
13
+ def test_publish_skips_when_broker_uri_missing(self) -> None:
14
+ sdk = UspdMiddlewareSdk(UspdMiddlewareSdkConfig(shared_broker_url=''))
15
+ with patch.object(sdk, '_uni') as uni_mock:
16
+ sdk.publish_manual_polling_status(
17
+ ManualPollingStatusV0Message(
18
+ task_id=uuid4(),
19
+ status=ManualPollingStatusEnum.queued,
20
+ timestamp=datetime.now(tz=timezone.utc),
21
+ ),
22
+ )
23
+ uni_mock.send_to.assert_not_called()
24
+
25
+ def test_publish_sends_to_manual_polling_status_worker(self) -> None:
26
+ sdk = UspdMiddlewareSdk(UspdMiddlewareSdkConfig(shared_broker_url='amqp://admin:admin@localhost:5672'))
27
+ sdk._producer_initialized = True
28
+ sdk._uni = MagicMock()
29
+ message = ManualPollingStatusV0Message(
30
+ task_id=uuid4(),
31
+ status=ManualPollingStatusEnum.queued,
32
+ timestamp=datetime.now(tz=timezone.utc),
33
+ )
34
+ sdk.publish_manual_polling_status(message)
35
+ sdk._uni.send_to.assert_called_once_with('manual_polling_status', message)
36
+
37
+
38
+ if __name__ == '__main__':
39
+ unittest.main()
@@ -0,0 +1,10 @@
1
+ from ul_unipipeline.brokers.uni_amqp_py_broker import UniAmqpPyBroker
2
+
3
+ from uspd_middleware_sdk.runtime_conf import get_shared_broker_uri
4
+
5
+
6
+ class SharedAmqpBroker(UniAmqpPyBroker):
7
+
8
+ @classmethod
9
+ def get_connection_uri(cls) -> str:
10
+ return get_shared_broker_uri()
@@ -0,0 +1,8 @@
1
+ from enum import Enum
2
+
3
+
4
+ class ManualPollingStatusEnum(str, Enum):
5
+ queued = 'queued'
6
+ in_progress = 'in_progress'
7
+ success = 'success'
8
+ error = 'error'
@@ -0,0 +1,11 @@
1
+ import os
2
+
3
+ ENV_USPD_MIDDLEWARE__SHARED_AMQP_BROKER__URI = 'USPD_MIDDLEWARE__SHARED_AMQP_BROKER__URI'
4
+
5
+
6
+ def get_shared_broker_uri_from_env() -> str:
7
+ return os.environ.get(ENV_USPD_MIDDLEWARE__SHARED_AMQP_BROKER__URI, '')
8
+
9
+
10
+ def is_shared_amqp_broker_configured() -> bool:
11
+ return bool(get_shared_broker_uri_from_env())
@@ -0,0 +1 @@
1
+ MANUAL_POLLING_STATUS_WORKER_NAME = 'manual_polling_status'
@@ -0,0 +1,24 @@
1
+ ---
2
+
3
+ service:
4
+ name: "uspd_middleware"
5
+ echo_colors: true
6
+ echo_level: debug
7
+
8
+ external:
9
+ manual_polling_status: {}
10
+
11
+ brokers:
12
+ shared_amqp_broker:
13
+ import_template: "uspd_middleware_sdk.brokers.shared_amqp_broker:SharedAmqpBroker"
14
+
15
+ messages:
16
+ manual_polling_status:
17
+ import_template: "uspd_middleware_sdk.messages.manual_polling_status_message:ManualPollingStatusV0Message"
18
+
19
+ workers:
20
+ manual_polling_status:
21
+ broker: shared_amqp_broker
22
+ input_message: manual_polling_status
23
+ external: manual_polling_status
24
+ topic: "manual_polling_status"
@@ -0,0 +1,15 @@
1
+ class UspdMiddlewareAbstractError(Exception):
2
+ def __init__(self, message: str, error: Exception, status_code: int) -> None:
3
+ assert isinstance(message, str), f'message must be str. "{type(message).__name__}" was given'
4
+ assert isinstance(error, Exception), f'error must be Exception. "{type(error).__name__}" was given'
5
+ super().__init__(f'{message} :: {str(error)} :: {status_code})')
6
+ self.status_code = status_code
7
+ self.error = error
8
+
9
+
10
+ class UspdMiddlewareRequestError(UspdMiddlewareAbstractError):
11
+ pass
12
+
13
+
14
+ class UspdMiddlewareResponseError(UspdMiddlewareAbstractError):
15
+ pass
@@ -0,0 +1,7 @@
1
+ import os
2
+
3
+ from ul_unipipeline.modules.uni import Uni
4
+
5
+ CONFIG_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'dag.yml')
6
+
7
+ uni = Uni(CONFIG_FILE)
@@ -0,0 +1,15 @@
1
+ from datetime import datetime
2
+ from typing import Optional
3
+ from uuid import UUID
4
+
5
+ from ul_unipipeline.message.uni_message import UniMessage
6
+
7
+ from uspd_middleware_sdk.constants.enums import ManualPollingStatusEnum
8
+
9
+
10
+ class ManualPollingStatusV0Message(UniMessage):
11
+ task_id: UUID
12
+ status: ManualPollingStatusEnum
13
+ timestamp: datetime
14
+ error_message: Optional[str] = None
15
+ not_found_devices: list[str] = []
@@ -0,0 +1,10 @@
1
+ broker_uri = ''
2
+
3
+
4
+ def set_shared_broker_uri(uri: str) -> None:
5
+ global broker_uri
6
+ broker_uri = uri
7
+
8
+
9
+ def get_shared_broker_uri() -> str:
10
+ return broker_uri
@@ -0,0 +1,16 @@
1
+ from typing import List
2
+ from uuid import UUID
3
+
4
+ from pydantic import BaseModel, Field
5
+ from ul_api_utils.api_resource.api_response import JsonApiResponsePayload
6
+
7
+ from uspd_middleware_sdk.constants.enums import ManualPollingStatusEnum
8
+
9
+
10
+ class ApiManualPollingRequest(BaseModel):
11
+ macs: List[str] = Field(title='MACs', description='list of device MAC addresses to poll')
12
+
13
+
14
+ class ApiManualPollingResponse(JsonApiResponsePayload):
15
+ task_id: UUID = Field(title='Task ID', description='manual polling task identifier')
16
+ status: ManualPollingStatusEnum = Field(title='Status', description='initial task status')
@@ -0,0 +1,24 @@
1
+ from typing import List
2
+
3
+ from ul_api_utils.internal_api.internal_api import InternalApi
4
+
5
+ from uspd_middleware_sdk.types.manual_polling import ApiManualPollingResponse
6
+ from uspd_middleware_sdk.uspd_middleware_api_sdk_config import UspdMiddlewareApiSdkConfig
7
+ from uspd_middleware_sdk.utils.internal_api_error_handler import internal_api_error_handler
8
+
9
+
10
+ class UspdMiddlewareApiSdk:
11
+ def __init__(self, config: UspdMiddlewareApiSdkConfig) -> None:
12
+ self._config = config
13
+ self._api = InternalApi(
14
+ self._config.api_url,
15
+ default_auth_token=self._config.api_token,
16
+ )
17
+
18
+ @internal_api_error_handler
19
+ def post_manual_polling(self, macs: List[str]) -> ApiManualPollingResponse:
20
+ '''used in services: iot-account-application-backend'''
21
+ return self._api.request_post(
22
+ '/manual-polling',
23
+ json={'macs': macs},
24
+ ).typed(ApiManualPollingResponse).check().payload
@@ -0,0 +1,6 @@
1
+ from typing import NamedTuple
2
+
3
+
4
+ class UspdMiddlewareApiSdkConfig(NamedTuple):
5
+ api_url: str
6
+ api_token: str
@@ -0,0 +1,42 @@
1
+ import logging
2
+
3
+ from ul_unipipeline.modules.uni import Uni
4
+
5
+ from uspd_middleware_sdk.constants.names import MANUAL_POLLING_STATUS_WORKER_NAME
6
+ from uspd_middleware_sdk.lib import CONFIG_FILE
7
+ from uspd_middleware_sdk.messages.manual_polling_status_message import ManualPollingStatusV0Message
8
+ from uspd_middleware_sdk.runtime_conf import get_shared_broker_uri, set_shared_broker_uri
9
+ from uspd_middleware_sdk.uspd_middleware_sdk_config import UspdMiddlewareSdkConfig
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+
14
+ class UspdMiddlewareSdk:
15
+
16
+ def __init__(self, config: UspdMiddlewareSdkConfig) -> None:
17
+ self._config = config
18
+ self._uni = Uni(CONFIG_FILE)
19
+ set_shared_broker_uri(self._config.shared_broker_url)
20
+ self._producer_initialized = False
21
+
22
+ def init_producer_worker(self) -> None:
23
+ if not get_shared_broker_uri():
24
+ logger.info(
25
+ 'Shared AMQP broker URI is not configured; manual polling status publisher stub mode',
26
+ )
27
+ return
28
+ self._uni.init_producer_worker(MANUAL_POLLING_STATUS_WORKER_NAME)
29
+ self._uni.initialize()
30
+ self._producer_initialized = True
31
+
32
+ def publish_manual_polling_status(self, message: ManualPollingStatusV0Message) -> None:
33
+ if not get_shared_broker_uri():
34
+ logger.info(
35
+ 'Shared AMQP broker URI is not configured; skip manual polling status publish',
36
+ )
37
+ return
38
+ if not self._producer_initialized:
39
+ self.init_producer_worker()
40
+ if not self._producer_initialized:
41
+ return
42
+ self._uni.send_to(MANUAL_POLLING_STATUS_WORKER_NAME, message)
@@ -0,0 +1,5 @@
1
+ from typing import NamedTuple
2
+
3
+
4
+ class UspdMiddlewareSdkConfig(NamedTuple):
5
+ shared_broker_url: str
@@ -0,0 +1,32 @@
1
+ from functools import wraps
2
+ from typing import Any, Callable, Dict, List, TypeVar, cast
3
+
4
+ from ul_api_utils.errors import (
5
+ Client4XXInternalApiError,
6
+ NotFinishedRequestInternalApiError,
7
+ ResponseJsonInternalApiError,
8
+ Server5XXInternalApiError,
9
+ )
10
+
11
+ from uspd_middleware_sdk.errors import UspdMiddlewareRequestError, UspdMiddlewareResponseError
12
+
13
+ TKwargs = TypeVar('TKwargs', bound=Dict[str, Any])
14
+ STDResp = TypeVar('STDResp', bound=Dict[str, Any] | List[Dict[str, Any]])
15
+ TFn = TypeVar('TFn', bound=Callable) # type: ignore
16
+
17
+
18
+ def internal_api_error_handler(api_method_fn: TFn) -> TFn:
19
+ @wraps(api_method_fn)
20
+ def error_handler_wrapper(*args: Any, **kwargs: TKwargs) -> TFn:
21
+ try:
22
+ return api_method_fn(*args, **kwargs)
23
+ except Client4XXInternalApiError as e:
24
+ raise UspdMiddlewareRequestError(str(e), e, e.status_code)
25
+ except Server5XXInternalApiError as e:
26
+ raise UspdMiddlewareResponseError(str(e), e, e.status_code)
27
+ except ResponseJsonInternalApiError as e:
28
+ raise UspdMiddlewareResponseError(str(e), e, 500)
29
+ except NotFinishedRequestInternalApiError as e:
30
+ raise UspdMiddlewareResponseError("SERVICE TEMPORARY UNAVAIBLE", e, 503)
31
+
32
+ return cast(TFn, error_handler_wrapper)
@@ -0,0 +1,2 @@
1
+ def normalize_mac(mac: str | int) -> str:
2
+ return str(mac).strip().upper()