From 4e6ee6d3fa00f9d5d61c555d8a2e58ffec8b45b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pere=20Pic=C3=B3?= Date: Mon, 28 Sep 2026 10:24:04 +0200 Subject: [PATCH] refactor: make Transport and AsyncTransport private collaborators --- CHANGELOG.md | 14 +++++++------- .../{async_transport.py => _async_transport.py} | 6 +++--- UnleashClient/{transport.py => _transport.py} | 2 +- UnleashClient/async_metrics_reporter.py | 6 +++--- UnleashClient/clients/async_unleash_client.py | 4 ++-- UnleashClient/clients/unleash_client.py | 4 ++-- UnleashClient/connectors/_async_connector.py | 6 +++--- UnleashClient/connectors/polling_connector.py | 6 +++--- UnleashClient/headers.py | 2 +- UnleashClient/metrics_reporter.py | 6 +++--- .../unit_tests/connectors/test_async_connector.py | 4 ++-- .../connectors/test_polling_connector.py | 6 +++--- tests/unit_tests/test_async_metrics_reporter.py | 6 +++--- tests/unit_tests/test_async_transport.py | 10 +++++----- tests/unit_tests/test_metrics_reporter.py | 4 ++-- tests/unit_tests/test_transport.py | 8 ++++---- 16 files changed, 47 insertions(+), 47 deletions(-) rename UnleashClient/{async_transport.py => _async_transport.py} (98%) rename UnleashClient/{transport.py => _transport.py} (99%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5dd8a07b..ad8971e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,24 +9,24 @@ * (Minor): New `UnleashClient.errors` module with a hierarchy of SDK errors. `UnleashClientError` is the base of every error in the hierarchy, so catching it catches all of them without catching `Exception`. Each module gets one error grouping that module's errors, such as `InstanceRegistryError`, and specific errors derive from those, such as `MultipleInstancesNotAllowedError`. A client rejected under `InstanceAllowType.BLOCK` now raises `MultipleInstancesNotAllowedError` instead of a plain `Exception`, with the same message. It still derives from `Exception`, so existing `except Exception` handlers keep catching it. Other errors raised by the SDK are not part of the hierarchy yet. * (Bugfix): The in-progress asynchronous metrics reporter keeps impact metrics whose send timed out or was cancelled, and sends them with the next flush. A timed-out send now counts as a failed send, like any status other than 202. Cancelling the reporter mid-send, as `stop()` does, used to lose the impact metrics of that send; they now go out with the final flush. Feature metrics from a failed send are still dropped, as before. `UnleashClient` is unaffected. * (Minor): The in-progress asynchronous client gains an internal `_AsyncScheduler`, in the private `UnleashClient._async_scheduler` module, which runs recurring jobs as tasks on the event loop with the same interval, first-run delay and one-sided jitter as the synchronous `_Scheduler`. The module is not part of the public API and may change or disappear without notice. The asynchronous metrics reporter schedules its sends through it. Nothing changes for code using `UnleashClient`. -* (Minor): The in-progress async transport can no longer be used once it has been closed. Closing it used to only drop its connection pool, so a later request quietly opened a fresh session that nobody would ever close. Closing now takes the transport out of service, and feature fetches, registration and metrics submissions each raise `AlreadyClosedError` (importable from `UnleashClient.transport`). Closing a transport that is already closed still does nothing. `UnleashClient` is unaffected. +* (Minor): The in-progress async transport can no longer be used once it has been closed. Closing it used to only drop its connection pool, so a later request quietly opened a fresh session that nobody would ever close. Closing now takes the transport out of service, and feature fetches, registration and metrics submissions each raise `AlreadyClosedError` (importable from the private `UnleashClient._transport` module). Closing a transport that is already closed still does nothing. `UnleashClient` is unaffected. * (Minor): The Sphinx documentation site is no longer built or published. It was served from a GitHub Pages custom domain that stopped resolving, so nothing published there had been reachable for some time. Reference documentation for this SDK is at https://docs.getunleash.io/reference/sdks/python, and `README.md` covers installation, usage, configuration options, custom strategies, custom caches, event callbacks and the WSGI and Celery notes. Contributor setup and the release checklist are in `DEVELOPMENT.md`. The `Documentation` URL in the package metadata now points at the docs site rather than a page that returned 404. * (Minor): `AsyncUnleashClient` ignores `custom_options`. The constructor still accepts it and it still reaches the shared configuration, but the async request path never passes it to the HTTP library, so the async client's surface does not depend on aiohttp's own keyword arguments. `UnleashClient` is unaffected and keeps passing `custom_options` to `requests`. * (Minor): Duplicate-instance detection now happens through one internal `_InstanceRegistry`, in the private `UnleashClient._instance_registry` module, instead of an `InstanceCounter` and a private method on the client. The identifier a client is keyed by, the message, the error logged under `InstanceAllowType.WARN` and the counting are exactly what they were, and a client rejected under `BLOCK` is still not counted. `INSTANCES` keeps its name, both its import paths and all of its methods, and remains the supported way to reach the registry. The module is not part of the public API and may change or disappear without notice. `multiple_instance_mode` is unchanged. `UnleashClient.utils.InstanceCounter` is gone, so this affects code importing that class directly. Nothing changes for code using `UnleashClient`. * (Minor): The in-progress asynchronous client now performs the same duplicate-instance check and accepts `multiple_instance_mode`. Both flavors register into one process-wide registry, so a synchronous and an asynchronous client sharing an app name and instance id are reported as duplicates of each other. This is accurate, since both register with the server and both report metrics. Nothing changes for code using `UnleashClient`. -* (Minor): The in-progress asynchronous client now builds an `AsyncMetricsReporter` over its `AsyncTransport`, and exposes `impact_metrics` like the synchronous client does. Nothing starts it yet, as `initialize_client()` still raises `NotImplementedError`, so no metrics are sent, and nothing changes for code using `UnleashClient`. The request body, the impact-metrics collection and the restore-after-a-failed-send are shared with the synchronous reporter; only the request itself and the recurring schedule are separate. +* (Minor): The in-progress asynchronous client now builds an `AsyncMetricsReporter` over an internal `_AsyncTransport`, in the private `UnleashClient._async_transport` module, which is not part of the public API and may change or disappear without notice, and exposes `impact_metrics` like the synchronous client does. Nothing starts it yet, as `initialize_client()` still raises `NotImplementedError`, so no metrics are sent, and nothing changes for code using `UnleashClient`. The request body, the impact-metrics collection and the restore-after-a-failed-send are shared with the synchronous reporter; only the request itself and the recurring schedule are separate. * (Minor): The asynchronous reporter schedules its sends through the asynchronous client's `_AsyncScheduler` rather than the APScheduler-backed scheduler, because the send has to be awaited and APScheduler runs jobs on worker threads that cannot await. Like the synchronous reporter, it reads `unleash_metrics_interval` and `unleash_metrics_jitter` once, when reporting starts, and the interval and the one-sided jitter are identical. `UnleashClient` and its scheduler are unaffected, and the `scheduler` and `scheduler_executor` constructor arguments still work exactly as before. -* (Minor): The asynchronous client does not carry over `metrics_headers` or `metric_job`. `metrics_headers` has been informational since the `Transport` change below (set `unleash_custom_headers` instead), and the metrics job handle is internal. Both are unchanged on `UnleashClient`. +* (Minor): The asynchronous client does not carry over `metrics_headers` or `metric_job`. `metrics_headers` has been informational since the `_Transport` change below (set `unleash_custom_headers` instead), and the metrics job handle is internal. Both are unchanged on `UnleashClient`. * (Minor): Metrics reporting now happens through one internal `MetricsReporter` object instead of being spread across the module-level `aggregate_and_send_metrics`, the job registration in `initialize_client()` and a second, slightly different call in `destroy()`. The request body is now assembled by `build_metrics_payload` in `UnleashClient.payloads`, alongside the registration payload. The interval, the jitter, the fields sent and the impact-metrics restore-on-failure are exactly what they were, apart from the two entries below. `UnleashClient.periodic_tasks` and its `aggregate_and_send_metrics` are gone, so this affects code importing from `UnleashClient.periodic_tasks` directly. `metric_job`, `metrics_headers` and `impact_metrics` are unchanged on `UnleashClient`. Nothing changes for code using `UnleashClient`. -* (Minor): The metrics request body is now read from the configuration on every send. As a result, reassigning `unleash_app_name`, `unleash_instance_id`, `unleash_sdk_flavor` or `unleash_sdk_flavor_version` after `initialize_client()` now takes effect on the next metrics send, where those used to be captured when the job was registered and changes to them afterwards were silently ignored. This mirrors the read-through `Transport` already does for urls and headers. `unleash_metrics_interval` and `unleash_metrics_jitter` are still read once, when the job is registered, as before. +* (Minor): The metrics request body is now read from the configuration on every send. As a result, reassigning `unleash_app_name`, `unleash_instance_id`, `unleash_sdk_flavor` or `unleash_sdk_flavor_version` after `initialize_client()` now takes effect on the next metrics send, where those used to be captured when the job was registered and changes to them afterwards were silently ignored. This mirrors the read-through `_Transport` already does for urls and headers. `unleash_metrics_interval` and `unleash_metrics_jitter` are still read once, when the job is registered, as before. * (Bugfix): The metrics flush on `destroy()` now sends `sdkFlavor` and `sdkFlavorVersion` like every other metrics send. The final send of a client's life used to omit them. Only affects clients configured with `sdk_flavor`. * (Minor): `ImpactMetrics` gains `collect()` and `restore()`, so draining impact metrics for a send and handing them back after a failed one go through the object that owns them rather than reaching into the engine directly. * (Minor): Flag evaluation now happens through one internal `_Evaluator` object instead of being implemented on the client. `is_enabled()`, `get_variant()` and `feature_definitions()` keep their signatures, their return shapes and the impression events they emit. Nothing changes for code using `UnleashClient`. The in-progress asynchronous client is wired with the same object but does not expose it yet: its `is_enabled()`, `get_variant()` and `feature_definitions()` raise `NotImplementedError` alongside the rest of its surface until it can initialize. * (Minor): Custom strategies are now registered on the engine by `initialize_client()` rather than by the constructor. The `ValueError` raised for a strategy that has no `apply` method, or whose `apply` does not take exactly two parameters, therefore surfaces from `initialize_client()` instead of from `UnleashClient(...)`. Code that passes valid strategies and calls `initialize_client()` before evaluating anything is unaffected; a bootstrapped client that evaluates a custom-strategy flag before initializing now gets `False` for that strategy. * (Minor): New optional `async` extra: `pip install UnleashClient[async]` installs `aiohttp` for the in-progress asynchronous client. The default install is unchanged and pulls in no new packages. The asynchronous client itself is still unfinished and unexported. -* (Minor): Outbound HTTP now happens through one internal `Transport` object instead of the three module-level functions in `UnleashClient.api`. The requests on the wire (urls, methods, headers, bodies, status handling, the retry adapter on feature fetches, and the fatal-URL exceptions that registration re-raises) are exactly what they were. `UnleashClient.api` and its `get_feature_toggles`, `send_metrics`, `register_client` and `build_normalized_url` are gone, as is `UnleashClient.utils.log_resp_info`; `PollingConnector` now takes a `transport` instead of `url`, `app_name`, `instance_id`, `headers`, `custom_options`, `request_timeout`, `request_retries` and `project`, and `aggregate_and_send_metrics` takes one in first position instead of `url`, `headers`, `custom_options` and `request_timeout`. This only affects code importing from `UnleashClient.api`, `UnleashClient.connectors` or `UnleashClient.periodic_tasks` directly. Nothing changes for code using `UnleashClient`. -* (Minor): `Transport` asks the internal `HeaderFactory` for the header set each request needs, rather than being handed a dict built once at startup. As a result, reassigning `unleash_url`, `unleash_custom_headers`, `unleash_custom_options`, `unleash_request_timeout`, `unleash_request_retries`, `unleash_project_name`, `unleash_app_name` or `unleash_instance_id` after `initialize_client()` now takes effect on the next poll and the next metrics send. Those used to be captured when the connector and the metrics job were created, and changes to them afterwards were silently ignored. Registration always read them at call time and is unaffected. The headers on the wire are otherwise unchanged. -* (Minor): The `metrics_headers` attribute has been removed from `UnleashClient`. It used to hold the header dict handed to the metrics job at `initialize_client()`, so reassigning it changed what the metrics request sent; the `Transport` now builds that header set per request. Set `unleash_custom_headers` instead, as it is read on every send. +* (Minor): Outbound HTTP now happens through one internal `_Transport` object, in the private `UnleashClient._transport` module, instead of the three module-level functions in `UnleashClient.api`. The module is not part of the public API and may change or disappear without notice. The requests on the wire (urls, methods, headers, bodies, status handling, the retry adapter on feature fetches, and the fatal-URL exceptions that registration re-raises) are exactly what they were. `UnleashClient.api` and its `get_feature_toggles`, `send_metrics`, `register_client` and `build_normalized_url` are gone, as is `UnleashClient.utils.log_resp_info`; `PollingConnector` now takes a `transport` instead of `url`, `app_name`, `instance_id`, `headers`, `custom_options`, `request_timeout`, `request_retries` and `project`, and `aggregate_and_send_metrics` takes one in first position instead of `url`, `headers`, `custom_options` and `request_timeout`. This only affects code importing from `UnleashClient.api`, `UnleashClient.connectors` or `UnleashClient.periodic_tasks` directly. Nothing changes for code using `UnleashClient`. +* (Minor): `_Transport` asks the internal `HeaderFactory` for the header set each request needs, rather than being handed a dict built once at startup. As a result, reassigning `unleash_url`, `unleash_custom_headers`, `unleash_custom_options`, `unleash_request_timeout`, `unleash_request_retries`, `unleash_project_name`, `unleash_app_name` or `unleash_instance_id` after `initialize_client()` now takes effect on the next poll and the next metrics send. Those used to be captured when the connector and the metrics job were created, and changes to them afterwards were silently ignored. Registration always read them at call time and is unaffected. The headers on the wire are otherwise unchanged. +* (Minor): The `metrics_headers` attribute has been removed from `UnleashClient`. It used to hold the header dict handed to the metrics job at `initialize_client()`, so reassigning it changed what the metrics request sent; the `_Transport` now builds that header set per request. Set `unleash_custom_headers` instead, as it is read on every send. * (Minor): The registration request body is now assembled by `build_register_payload` in the new `UnleashClient.payloads` module rather than inline in `register_client`. The fields sent are unchanged, `started` is still stamped at the moment of the request, and nothing changes for code using `UnleashClient`. * (Minor): Job scheduling now happens through one internal `_Scheduler` object, in the private `UnleashClient._scheduler` module, instead of being re-implemented by the client and each connector. The module is not part of the public API and may change or disappear without notice. The jobs, intervals, jitter and executors are exactly what they were. `PollingConnector` and `OfflineConnector` now take that `_Scheduler` rather than an APScheduler instance, and no longer take `scheduler_executor`, so code importing from `UnleashClient.connectors` directly must build one. The `scheduler` and `scheduler_executor` constructor arguments, and the `unleash_scheduler` and `unleash_executor_name` attributes, are unchanged. * (Minor): Passing a `scheduler` that is already running no longer raises `SchedulerAlreadyRunningError`. Starting an already-started scheduler is now a no-op. diff --git a/UnleashClient/async_transport.py b/UnleashClient/_async_transport.py similarity index 98% rename from UnleashClient/async_transport.py rename to UnleashClient/_async_transport.py index d7b6623b..7d040c7f 100644 --- a/UnleashClient/async_transport.py +++ b/UnleashClient/_async_transport.py @@ -5,10 +5,10 @@ import threading from typing import Any, Dict, Optional +from UnleashClient._transport import AlreadyClosedError, FetchResult, _normalized_url from UnleashClient.config import UnleashConfig from UnleashClient.constants import FEATURES_URL, METRICS_URL, REGISTER_URL from UnleashClient.headers import HeaderFactory -from UnleashClient.transport import AlreadyClosedError, FetchResult, _normalized_url from UnleashClient.utils import LOGGER try: @@ -33,8 +33,8 @@ async def _log_resp_info(resp: "aiohttp.ClientResponse") -> None: LOGGER.debug("HTTP content: %s", await resp.text()) -class AsyncTransport: - """The asyncio twin of :class:`UnleashClient.transport.Transport`.""" +class _AsyncTransport: + """The asyncio twin of :class:`UnleashClient._transport._Transport`.""" def __init__(self, config: UnleashConfig, headers: HeaderFactory) -> None: """ diff --git a/UnleashClient/transport.py b/UnleashClient/_transport.py similarity index 99% rename from UnleashClient/transport.py rename to UnleashClient/_transport.py index bf9ee943..bdeb7551 100644 --- a/UnleashClient/transport.py +++ b/UnleashClient/_transport.py @@ -50,7 +50,7 @@ def _log_resp_info(resp: Response) -> None: LOGGER.debug("HTTP content: %s", resp.text) -class Transport: +class _Transport: """ Sends the SDK's requests to the Unleash server: feature fetches, client registration and metrics submission. diff --git a/UnleashClient/async_metrics_reporter.py b/UnleashClient/async_metrics_reporter.py index af01bae9..82984a3c 100644 --- a/UnleashClient/async_metrics_reporter.py +++ b/UnleashClient/async_metrics_reporter.py @@ -5,7 +5,7 @@ from yggdrasil_engine.engine import UnleashEngine from UnleashClient._async_scheduler import _AsyncJob, _AsyncScheduler -from UnleashClient.async_transport import AsyncTransport +from UnleashClient._async_transport import _AsyncTransport from UnleashClient.config import UnleashConfig from UnleashClient.impact_metrics import ImpactMetrics from UnleashClient.payloads import build_metrics_payload @@ -38,13 +38,13 @@ class AsyncMetricsReporter: def __init__( self, config: UnleashConfig, - transport: AsyncTransport, + transport: _AsyncTransport, scheduler: _AsyncScheduler, engine: UnleashEngine, impact_metrics: ImpactMetrics, ) -> None: self._config: UnleashConfig = config - self._transport: AsyncTransport = transport + self._transport: _AsyncTransport = transport self._scheduler: _AsyncScheduler = scheduler self._engine: UnleashEngine = engine self._impact_metrics: ImpactMetrics = impact_metrics diff --git a/UnleashClient/clients/async_unleash_client.py b/UnleashClient/clients/async_unleash_client.py index 9c31be97..0397a027 100644 --- a/UnleashClient/clients/async_unleash_client.py +++ b/UnleashClient/clients/async_unleash_client.py @@ -8,10 +8,10 @@ from yggdrasil_engine.engine import UnleashEngine from UnleashClient._async_scheduler import _AsyncScheduler +from UnleashClient._async_transport import _AsyncTransport from UnleashClient._evaluator import _Evaluator from UnleashClient._instance_registry import _get_instance_registry from UnleashClient.async_metrics_reporter import AsyncMetricsReporter -from UnleashClient.async_transport import AsyncTransport from UnleashClient.cache import BaseCache, FileCache from UnleashClient.config import ExperimentalMode, UnleashConfig from UnleashClient.constants import REQUEST_RETRIES, REQUEST_TIMEOUT @@ -113,7 +113,7 @@ def __init__( # noqa: PLR0913, PLR0917 config=self._config, events=self._event_dispatcher, ) - self._transport: AsyncTransport = AsyncTransport(self._config, self._headers) + self._transport: _AsyncTransport = _AsyncTransport(self._config, self._headers) self._scheduler: _AsyncScheduler = _AsyncScheduler() self._metrics: AsyncMetricsReporter = AsyncMetricsReporter( config=self._config, diff --git a/UnleashClient/clients/unleash_client.py b/UnleashClient/clients/unleash_client.py index db3c650b..720fdf44 100644 --- a/UnleashClient/clients/unleash_client.py +++ b/UnleashClient/clients/unleash_client.py @@ -12,6 +12,7 @@ from UnleashClient._evaluator import _Evaluator from UnleashClient._instance_registry import _get_instance_registry from UnleashClient._scheduler import _ScheduledJob, _Scheduler +from UnleashClient._transport import _Transport from UnleashClient.cache import BaseCache, FileCache from UnleashClient.config import ( ExperimentalMode, @@ -43,7 +44,6 @@ from UnleashClient.metrics_reporter import MetricsReporter from UnleashClient.payloads import build_register_payload from UnleashClient.store import FeatureStore -from UnleashClient.transport import Transport from UnleashClient.utils import ( LOGGER, InstanceAllowType, @@ -218,7 +218,7 @@ def __init__( # noqa: PLR0913, PLR0917 events=self.__events, ) - self._transport = Transport(self._config, self._headers) + self._transport = _Transport(self._config, self._headers) self._scheduler = _Scheduler(scheduler, scheduler_executor) diff --git a/UnleashClient/connectors/_async_connector.py b/UnleashClient/connectors/_async_connector.py index 399e1827..8d8bf66b 100644 --- a/UnleashClient/connectors/_async_connector.py +++ b/UnleashClient/connectors/_async_connector.py @@ -2,7 +2,7 @@ from typing import Optional from UnleashClient._async_scheduler import _AsyncScheduler -from UnleashClient.async_transport import AsyncTransport +from UnleashClient._async_transport import _AsyncTransport from UnleashClient.store import FeatureStore @@ -43,7 +43,7 @@ class _AsyncPollingConnector(_AsyncBaseConnector): def __init__( self, store: FeatureStore, - transport: AsyncTransport, + transport: _AsyncTransport, refresh_interval: float = 15, refresh_jitter: Optional[float] = None, ) -> None: @@ -55,7 +55,7 @@ def __init__( None for no jitter. """ super().__init__(store) - self._transport: AsyncTransport = transport + self._transport: _AsyncTransport = transport self._refresh_interval = refresh_interval self._refresh_jitter = refresh_jitter self._scheduler: _AsyncScheduler = _AsyncScheduler() diff --git a/UnleashClient/connectors/polling_connector.py b/UnleashClient/connectors/polling_connector.py index cd0e5b03..48145981 100644 --- a/UnleashClient/connectors/polling_connector.py +++ b/UnleashClient/connectors/polling_connector.py @@ -1,8 +1,8 @@ from typing import Optional from UnleashClient._scheduler import _ScheduledJob, _Scheduler +from UnleashClient._transport import _Transport from UnleashClient.store import FeatureStore -from UnleashClient.transport import Transport from .base_connector import BaseConnector @@ -14,7 +14,7 @@ def __init__( self, store: FeatureStore, scheduler: _Scheduler, - transport: Transport, + transport: _Transport, refresh_interval: int = 15, refresh_jitter: Optional[int] = None, ): @@ -26,7 +26,7 @@ def __init__( """ super().__init__(store) self.scheduler: _Scheduler = scheduler - self.transport: Transport = transport + self.transport: _Transport = transport self.refresh_interval = refresh_interval self.refresh_jitter = refresh_jitter self.job: _ScheduledJob = None diff --git a/UnleashClient/headers.py b/UnleashClient/headers.py index 9584111f..5c9378fe 100644 --- a/UnleashClient/headers.py +++ b/UnleashClient/headers.py @@ -13,7 +13,7 @@ class HeaderFactory: Every method returns a fresh dict and reads the config on each call, so reassigning or mutating ``config.custom_headers`` (which ``UnleashClient.unleash_custom_headers`` allows) is picked up by the next - call. :class:`~UnleashClient.transport.Transport` holds the factory and asks + call. :class:`~UnleashClient._transport._Transport` holds the factory and asks it once per request, so a change reaches the wire on the next poll or send. The client still calls ``streaming()`` once, at initialization, and hands the dict to the connector; that one keeps the headers it was given. diff --git a/UnleashClient/metrics_reporter.py b/UnleashClient/metrics_reporter.py index 1a94a366..a8150553 100644 --- a/UnleashClient/metrics_reporter.py +++ b/UnleashClient/metrics_reporter.py @@ -3,10 +3,10 @@ from yggdrasil_engine.engine import UnleashEngine from UnleashClient._scheduler import _ScheduledJob, _Scheduler +from UnleashClient._transport import _Transport from UnleashClient.config import UnleashConfig from UnleashClient.impact_metrics import ImpactMetrics from UnleashClient.payloads import build_metrics_payload -from UnleashClient.transport import Transport from UnleashClient.utils import LOGGER @@ -19,13 +19,13 @@ class MetricsReporter: def __init__( self, config: UnleashConfig, - transport: Transport, + transport: _Transport, scheduler: _Scheduler, engine: UnleashEngine, impact_metrics: ImpactMetrics, ) -> None: self._config: UnleashConfig = config - self._transport: Transport = transport + self._transport: _Transport = transport self._scheduler: _Scheduler = scheduler self._engine: UnleashEngine = engine self._impact_metrics: ImpactMetrics = impact_metrics diff --git a/tests/unit_tests/connectors/test_async_connector.py b/tests/unit_tests/connectors/test_async_connector.py index 5f39dbc3..f250f0f2 100644 --- a/tests/unit_tests/connectors/test_async_connector.py +++ b/tests/unit_tests/connectors/test_async_connector.py @@ -10,7 +10,7 @@ from tests.utilities.fake_unleash_server import FakeUnleash from tests.utilities.mocks.mock_features import MOCK_FEATURE_RESPONSE from tests.utilities.testing_constants import APP_NAME, ETAG_VALUE -from UnleashClient.async_transport import AsyncTransport +from UnleashClient._async_transport import _AsyncTransport from UnleashClient.config import UnleashConfig from UnleashClient.connectors._async_connector import _AsyncPollingConnector from UnleashClient.constants import ETAG, FEATURES_URL @@ -43,7 +43,7 @@ def _build_connector( store: FeatureStore, refresh_interval: float = INTERVAL ) -> _AsyncPollingConnector: config = UnleashConfig(server.base_url, APP_NAME, request_retries=0) - transport = AsyncTransport(config, HeaderFactory(config)) + transport = _AsyncTransport(config, HeaderFactory(config)) connector = _AsyncPollingConnector( store=store, transport=transport, refresh_interval=refresh_interval ) diff --git a/tests/unit_tests/connectors/test_polling_connector.py b/tests/unit_tests/connectors/test_polling_connector.py index 2e31c58c..c6b4c5e0 100644 --- a/tests/unit_tests/connectors/test_polling_connector.py +++ b/tests/unit_tests/connectors/test_polling_connector.py @@ -19,18 +19,18 @@ URL, ) from UnleashClient._scheduler import _Scheduler +from UnleashClient._transport import _Transport from UnleashClient.config import UnleashConfig from UnleashClient.connectors import PollingConnector from UnleashClient.constants import ETAG, FEATURES_URL from UnleashClient.events import EventDispatcher, UnleashEventType from UnleashClient.headers import HeaderFactory from UnleashClient.store import FeatureStore -from UnleashClient.transport import Transport FULL_FEATURE_URL = URL + FEATURES_URL -def build_transport(**kwargs) -> Transport: +def build_transport(**kwargs) -> _Transport: defaults = { "instance_id": INSTANCE_ID, "custom_headers": CUSTOM_HEADERS, @@ -40,7 +40,7 @@ def build_transport(**kwargs) -> Transport: } defaults.update(kwargs) config = UnleashConfig(URL, APP_NAME, **defaults) - return Transport(config, HeaderFactory(config)) + return _Transport(config, HeaderFactory(config)) @responses.activate diff --git a/tests/unit_tests/test_async_metrics_reporter.py b/tests/unit_tests/test_async_metrics_reporter.py index a35b96b9..0b1686a5 100644 --- a/tests/unit_tests/test_async_metrics_reporter.py +++ b/tests/unit_tests/test_async_metrics_reporter.py @@ -14,8 +14,8 @@ _AsyncJobFn, _AsyncScheduler, ) +from UnleashClient._async_transport import _AsyncTransport from UnleashClient.async_metrics_reporter import AsyncMetricsReporter -from UnleashClient.async_transport import AsyncTransport from UnleashClient.config import UnleashConfig from UnleashClient.constants import CLIENT_SPEC_VERSION, METRICS_URL from UnleashClient.headers import HeaderFactory @@ -114,7 +114,7 @@ def _build_reporter(impact_metrics=None, **kwargs) -> AsyncMetricsReporter: engine = UnleashEngine() reporter = AsyncMetricsReporter( config=config, - transport=AsyncTransport(config, HeaderFactory(config)), + transport=_AsyncTransport(config, HeaderFactory(config)), scheduler=RecordingScheduler(), engine=engine, impact_metrics=( @@ -252,7 +252,7 @@ async def test_the_config_is_read_on_every_flush(server, reporter): async def test_the_flush_goes_through_the_async_transport(reporter): # The flush runs on the client's loop, so a blocking transport would hold it up for # the length of every POST. - assert isinstance(reporter._transport, AsyncTransport) + assert isinstance(reporter._transport, _AsyncTransport) assert asyncio.iscoroutinefunction(reporter._transport.send_metrics) assert asyncio.iscoroutinefunction(reporter.flush) diff --git a/tests/unit_tests/test_async_transport.py b/tests/unit_tests/test_async_transport.py index 4d98289a..95a0fc5e 100644 --- a/tests/unit_tests/test_async_transport.py +++ b/tests/unit_tests/test_async_transport.py @@ -22,7 +22,8 @@ REQUEST_RETRIES, REQUEST_TIMEOUT, ) -from UnleashClient.async_transport import AsyncTransport +from UnleashClient._async_transport import _AsyncTransport +from UnleashClient._transport import AlreadyClosedError from UnleashClient.config import UnleashConfig from UnleashClient.constants import ( CLIENT_SPEC_VERSION, @@ -31,7 +32,6 @@ REGISTER_URL, ) from UnleashClient.headers import HeaderFactory -from UnleashClient.transport import AlreadyClosedError API_PREFIX = "/api" FEATURES_PATH = API_PREFIX + FEATURES_URL @@ -58,7 +58,7 @@ async def build_transport(server: FakeUnleash): """ built = [] - def _build_transport(**kwargs) -> AsyncTransport: + def _build_transport(**kwargs) -> _AsyncTransport: defaults = { "instance_id": INSTANCE_ID, "custom_headers": CUSTOM_HEADERS, @@ -67,7 +67,7 @@ def _build_transport(**kwargs) -> AsyncTransport: } defaults.update(kwargs) config = UnleashConfig(server.base_url, APP_NAME, **defaults) - transport = AsyncTransport(config, HeaderFactory(config)) + transport = _AsyncTransport(config, HeaderFactory(config)) built.append(transport) return transport @@ -79,7 +79,7 @@ def _build_transport(**kwargs) -> AsyncTransport: @pytest_asyncio.fixture -async def transport(build_transport: Callable[..., AsyncTransport]) -> AsyncTransport: +async def transport(build_transport: Callable[..., _AsyncTransport]) -> _AsyncTransport: """The transport the tests that need no config override share.""" return build_transport() diff --git a/tests/unit_tests/test_metrics_reporter.py b/tests/unit_tests/test_metrics_reporter.py index 0ddacc9b..aa273225 100644 --- a/tests/unit_tests/test_metrics_reporter.py +++ b/tests/unit_tests/test_metrics_reporter.py @@ -5,12 +5,12 @@ from yggdrasil_engine.engine import UnleashEngine from UnleashClient._scheduler import _Scheduler +from UnleashClient._transport import _Transport from UnleashClient.config import UnleashConfig from UnleashClient.constants import CLIENT_SPEC_VERSION, METRICS_URL from UnleashClient.headers import HeaderFactory from UnleashClient.impact_metrics import ImpactMetrics from UnleashClient.metrics_reporter import MetricsReporter -from UnleashClient.transport import Transport URL = "http://localhost:4242/api" APP_NAME = "pytest" @@ -66,7 +66,7 @@ def build_reporter(scheduler=None, impact_metrics=None, **kwargs) -> MetricsRepo engine = UnleashEngine() return MetricsReporter( config=config, - transport=Transport(config, HeaderFactory(config)), + transport=_Transport(config, HeaderFactory(config)), scheduler=scheduler if scheduler is not None else _Scheduler(), engine=engine, impact_metrics=( diff --git a/tests/unit_tests/test_transport.py b/tests/unit_tests/test_transport.py index d0775a29..664a3144 100644 --- a/tests/unit_tests/test_transport.py +++ b/tests/unit_tests/test_transport.py @@ -23,6 +23,7 @@ REQUEST_TIMEOUT, URL, ) +from UnleashClient._transport import _Transport from UnleashClient.config import UnleashConfig from UnleashClient.constants import ( CLIENT_SPEC_VERSION, @@ -31,7 +32,6 @@ REGISTER_URL, ) from UnleashClient.headers import HeaderFactory -from UnleashClient.transport import Transport FULL_FEATURE_URL = URL + FEATURES_URL FULL_REGISTER_URL = URL + REGISTER_URL @@ -42,7 +42,7 @@ def build_transport(): """Factory. Keyword arguments override the defaults on the config.""" - def _build_transport(**kwargs) -> Transport: + def _build_transport(**kwargs) -> _Transport: defaults = { "instance_id": INSTANCE_ID, "custom_headers": CUSTOM_HEADERS, @@ -52,13 +52,13 @@ def _build_transport(**kwargs) -> Transport: } defaults.update(kwargs) config = UnleashConfig(URL, APP_NAME, **defaults) - return Transport(config, HeaderFactory(config)) + return _Transport(config, HeaderFactory(config)) return _build_transport @pytest.fixture -def transport(build_transport) -> Transport: +def transport(build_transport) -> _Transport: return build_transport()