port-ocean 0.12.2.dev11__py3-none-any.whl → 0.12.2.dev12__py3-none-any.whl

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.

Potentially problematic release.


This version of port-ocean might be problematic. Click here for more details.

@@ -1,7 +1,7 @@
1
1
  import asyncio
2
2
  from typing import Type, Any
3
3
 
4
- import httpx
4
+ import aiohttp
5
5
  from loguru import logger
6
6
 
7
7
  from port_ocean.clients.port.client import PortClient
@@ -21,7 +21,7 @@ from port_ocean.exceptions.port_defaults import (
21
21
 
22
22
 
23
23
  def deconstruct_blueprints_to_creation_steps(
24
- raw_blueprints: list[dict[str, Any]],
24
+ raw_blueprints: list[dict[str, Any]],
25
25
  ) -> tuple[list[dict[str, Any]], ...]:
26
26
  """
27
27
  Deconstructing the blueprint into stages so the api wont fail to create a blueprint if there is a conflict
@@ -53,9 +53,9 @@ def deconstruct_blueprints_to_creation_steps(
53
53
 
54
54
 
55
55
  async def _initialize_required_integration_settings(
56
- port_client: PortClient,
57
- default_mapping: PortAppConfig,
58
- integration_config: IntegrationConfiguration,
56
+ port_client: PortClient,
57
+ default_mapping: PortAppConfig,
58
+ integration_config: IntegrationConfiguration,
59
59
  ) -> None:
60
60
  try:
61
61
  logger.info("Initializing integration at port")
@@ -80,8 +80,8 @@ async def _initialize_required_integration_settings(
80
80
  integration_config.event_listener.to_request(),
81
81
  port_app_config=default_mapping,
82
82
  )
83
- except httpx.HTTPStatusError as err:
84
- logger.error(f"Failed to apply default mapping: {err.response.text}.")
83
+ except aiohttp.ClientResponseError as err:
84
+ logger.error(f"Failed to apply default mapping: {err.message}.")
85
85
  raise err
86
86
 
87
87
  logger.info("Checking for diff in integration configuration")
@@ -89,9 +89,9 @@ async def _initialize_required_integration_settings(
89
89
  "changelog_destination"
90
90
  )
91
91
  if (
92
- integration.get("changelogDestination") != changelog_destination
93
- or integration.get("installationAppType") != integration_config.integration.type
94
- or integration.get("version") != port_client.integration_version
92
+ integration.get("changelogDestination") != changelog_destination
93
+ or integration.get("installationAppType") != integration_config.integration.type
94
+ or integration.get("version") != port_client.integration_version
95
95
  ):
96
96
  await port_client.patch_integration(
97
97
  integration_config.integration.type, changelog_destination
@@ -99,8 +99,8 @@ async def _initialize_required_integration_settings(
99
99
 
100
100
 
101
101
  async def _create_resources(
102
- port_client: PortClient,
103
- defaults: Defaults,
102
+ port_client: PortClient,
103
+ defaults: Defaults,
104
104
  ) -> None:
105
105
  creation_stage, *blueprint_patches = deconstruct_blueprints_to_creation_steps(
106
106
  defaults.blueprints
@@ -133,9 +133,9 @@ async def _create_resources(
133
133
 
134
134
  if blueprint_errors:
135
135
  for error in blueprint_errors:
136
- if isinstance(error, httpx.HTTPStatusError):
136
+ if isinstance(error, aiohttp.ClientResponseError):
137
137
  logger.warning(
138
- f"Failed to create resources: {error.response.text}. Rolling back changes..."
138
+ f"Failed to create resources: {error.message}. Rolling back changes..."
139
139
  )
140
140
 
141
141
  raise AbortDefaultCreationError(
@@ -155,8 +155,8 @@ async def _create_resources(
155
155
  )
156
156
  )
157
157
 
158
- except httpx.HTTPStatusError as err:
159
- logger.error(f"Failed to create resources: {err.response.text}. continuing...")
158
+ except aiohttp.ClientResponseError as err:
159
+ logger.error(f"Failed to create resources: {err.message}. continuing...")
160
160
  raise AbortDefaultCreationError(created_blueprints_identifiers, [err])
161
161
  try:
162
162
  created_actions, actions_errors = await gather_and_split_errors_from_results(
@@ -185,9 +185,9 @@ async def _create_resources(
185
185
  errors = actions_errors + scorecards_errors + pages_errors
186
186
  if errors:
187
187
  for error in errors:
188
- if isinstance(error, httpx.HTTPStatusError):
188
+ if isinstance(error, aiohttp.ClientResponseError):
189
189
  logger.warning(
190
- f"Failed to create resource: {error.response.text}. continuing..."
190
+ f"Failed to create resource: {error.message}. continuing..."
191
191
  )
192
192
 
193
193
  except Exception as err:
@@ -195,44 +195,45 @@ async def _create_resources(
195
195
 
196
196
 
197
197
  async def _initialize_defaults(
198
- config_class: Type[PortAppConfig], integration_config: IntegrationConfiguration
198
+ config_class: Type[PortAppConfig], integration_config: IntegrationConfiguration
199
199
  ) -> None:
200
200
  port_client = ocean.port_client
201
- defaults = get_port_integration_defaults(config_class)
202
- if not defaults:
203
- logger.warning("No defaults found. Skipping initialization...")
204
- return None
205
-
206
- if defaults.port_app_config:
207
- await _initialize_required_integration_settings(
208
- port_client, defaults.port_app_config, integration_config
209
- )
201
+ async with ocean.port_client.client:
202
+ defaults = get_port_integration_defaults(config_class)
203
+ if not defaults:
204
+ logger.warning("No defaults found. Skipping initialization...")
205
+ return None
206
+
207
+ if defaults.port_app_config:
208
+ await _initialize_required_integration_settings(
209
+ port_client, defaults.port_app_config, integration_config
210
+ )
210
211
 
211
- if not integration_config.initialize_port_resources:
212
- return
212
+ if not integration_config.initialize_port_resources:
213
+ return
213
214
 
214
- try:
215
- logger.info("Found default resources, starting creation process")
216
- await _create_resources(port_client, defaults)
217
- except AbortDefaultCreationError as e:
218
- logger.warning(
219
- f"Failed to create resources. Rolling back blueprints : {e.blueprints_to_rollback}"
220
- )
221
- await asyncio.gather(
222
- *(
223
- port_client.delete_blueprint(
224
- identifier,
225
- should_raise=False,
226
- user_agent_type=UserAgentType.exporter,
215
+ try:
216
+ logger.info("Found default resources, starting creation process")
217
+ await _create_resources(port_client, defaults)
218
+ except AbortDefaultCreationError as e:
219
+ logger.warning(
220
+ f"Failed to create resources. Rolling back blueprints : {e.blueprints_to_rollback}"
221
+ )
222
+ await asyncio.gather(
223
+ *(
224
+ port_client.delete_blueprint(
225
+ identifier,
226
+ should_raise=False,
227
+ user_agent_type=UserAgentType.exporter,
228
+ )
229
+ for identifier in e.blueprints_to_rollback
227
230
  )
228
- for identifier in e.blueprints_to_rollback
229
231
  )
230
- )
231
- raise ExceptionGroup(str(e), e.errors)
232
+ raise ExceptionGroup(str(e), e.errors)
232
233
 
233
234
 
234
235
  def initialize_defaults(
235
- config_class: Type[PortAppConfig], integration_config: IntegrationConfiguration
236
+ config_class: Type[PortAppConfig], integration_config: IntegrationConfiguration
236
237
  ) -> None:
237
238
  asyncio.new_event_loop().run_until_complete(
238
239
  _initialize_defaults(config_class, integration_config)
@@ -431,13 +431,13 @@ class SyncRawMixin(HandlerMixin, EventsMixin):
431
431
  # entities_at_port = await ocean.port_client.search_entities(
432
432
  # user_agent_type
433
433
  # )
434
- # except httpx.HTTPError as e:
434
+ # except aiohttp.ClientError as e:
435
435
  # logger.warning(
436
436
  # "Failed to fetch the current state of entities at Port. "
437
437
  # "Skipping delete phase due to unknown initial state. "
438
438
  # f"Error: {e}\n"
439
- # f"Response status code: {e.response.status_code if isinstance(e, httpx.HTTPStatusError) else None}\n"
440
- # f"Response content: {e.response.text if isinstance(e, httpx.HTTPStatusError) else None}\n"
439
+ # f"Response status code: {e.status if isinstance(e, aiohttp.ClientResponseError) else None}\n"
440
+ # f"Response content: {e.message if isinstance(e, aiohttp.ClientResponseError) else None}\n"
441
441
  # )
442
442
  # did_fetched_current_state = False
443
443
 
port_ocean/core/utils.py CHANGED
@@ -39,9 +39,10 @@ async def validate_integration_runtime(
39
39
  requested_runtime: Runtime,
40
40
  ) -> None:
41
41
  logger.debug("Validating integration runtime")
42
- current_integration = await port_client.get_current_integration(
43
- should_raise=False, should_log=False
44
- )
42
+ async with port_client.client:
43
+ current_integration = await port_client.get_current_integration(
44
+ should_raise=False, should_log=False
45
+ )
45
46
  current_runtime = current_integration.get("installationType", "OnPrem")
46
47
  if current_integration and current_runtime != requested_runtime.value:
47
48
  raise IntegrationRuntimeException(
@@ -1,51 +1,18 @@
1
1
  import asyncio
2
+ import functools
2
3
  import random
3
- import time
4
4
  from datetime import datetime
5
- from functools import partial
6
5
  from http import HTTPStatus
7
- from typing import Any, Callable, Coroutine, Iterable, Mapping, Union
6
+ from typing import Any, Callable, Coroutine, Iterable, Mapping
8
7
 
9
- import httpx
8
+ import aiohttp
9
+ from aiohttp import ClientResponse
10
10
  from dateutil.parser import isoparse
11
+ from loguru import logger
11
12
 
12
13
 
13
- # Adapted from https://github.com/encode/httpx/issues/108#issuecomment-1434439481
14
- class RetryTransport(httpx.AsyncBaseTransport, httpx.BaseTransport):
15
- """
16
- A custom HTTP transport that automatically retries requests using an exponential backoff strategy
17
- for specific HTTP status codes and request methods.
18
-
19
- Args:
20
- wrapped_transport (Union[httpx.BaseTransport, httpx.AsyncBaseTransport]): The underlying HTTP transport
21
- to wrap and use for making requests.
22
- max_attempts (int, optional): The maximum number of times to retry a request before giving up. Defaults to 10.
23
- max_backoff_wait (float, optional): The maximum time to wait between retries in seconds. Defaults to 60.
24
- backoff_factor (float, optional): The factor by which the wait time increases with each retry attempt.
25
- Defaults to 0.1.
26
- jitter_ratio (float, optional): The amount of jitter to add to the backoff time. Jitter is a random
27
- value added to the backoff time to avoid a "thundering herd" effect. The value should be between 0 and 0.5.
28
- Defaults to 0.1.
29
- respect_retry_after_header (bool, optional): Whether to respect the Retry-After header in HTTP responses
30
- when deciding how long to wait before retrying. Defaults to True.
31
- retryable_methods (Iterable[str], optional): The HTTP methods that can be retried. Defaults to
32
- ["HEAD", "GET", "PUT", "DELETE", "OPTIONS", "TRACE"].
33
- retry_status_codes (Iterable[int], optional): The HTTP status codes that can be retried. Defaults to
34
- [429, 502, 503, 504].
35
-
36
- Attributes:
37
- _wrapped_transport (Union[httpx.BaseTransport, httpx.AsyncBaseTransport]): The underlying HTTP transport
38
- being wrapped.
39
- _max_attempts (int): The maximum number of times to retry a request.
40
- _backoff_factor (float): The factor by which the wait time increases with each retry attempt.
41
- _respect_retry_after_header (bool): Whether to respect the Retry-After header in HTTP responses.
42
- _retryable_methods (frozenset): The HTTP methods that can be retried.
43
- _retry_status_codes (frozenset): The HTTP status codes that can be retried.
44
- _jitter_ratio (float): The amount of jitter to add to the backoff time.
45
- _max_backoff_wait (float): The maximum time to wait between retries in seconds.
46
-
47
- """
48
-
14
+ # Adapted from https://github.com/encode/httpx/issues/108#issuecomment-1434439481n
15
+ class RetryRequestClass(aiohttp.ClientRequest):
49
16
  RETRYABLE_METHODS = frozenset(["HEAD", "GET", "PUT", "DELETE", "OPTIONS", "TRACE"])
50
17
  RETRYABLE_STATUS_CODES = frozenset(
51
18
  [
@@ -58,23 +25,23 @@ class RetryTransport(httpx.AsyncBaseTransport, httpx.BaseTransport):
58
25
  MAX_BACKOFF_WAIT = 60
59
26
 
60
27
  def __init__(
61
- self,
62
- wrapped_transport: Union[httpx.BaseTransport, httpx.AsyncBaseTransport],
63
- max_attempts: int = 10,
64
- max_backoff_wait: float = MAX_BACKOFF_WAIT,
65
- backoff_factor: float = 0.1,
66
- jitter_ratio: float = 0.1,
67
- respect_retry_after_header: bool = True,
68
- retryable_methods: Iterable[str] | None = None,
69
- retry_status_codes: Iterable[int] | None = None,
70
- logger: Any | None = None,
28
+ self,
29
+ method,
30
+ url,
31
+ max_attempts: int = 10,
32
+ max_backoff_wait: float = MAX_BACKOFF_WAIT,
33
+ backoff_factor: float = 0.1,
34
+ jitter_ratio: float = 0.1,
35
+ respect_retry_after_header: bool = True,
36
+ retryable_methods: Iterable[str] | None = None,
37
+ retry_status_codes: Iterable[int] | None = None,
38
+ *args,
39
+ **kwargs
71
40
  ) -> None:
72
41
  """
73
42
  Initializes the instance of RetryTransport class with the given parameters.
74
43
 
75
44
  Args:
76
- wrapped_transport (Union[httpx.BaseTransport, httpx.AsyncBaseTransport]):
77
- The transport layer that will be wrapped and retried upon failure.
78
45
  max_attempts (int, optional):
79
46
  The maximum number of times the request can be retried in case of failure.
80
47
  Defaults to 10.
@@ -98,7 +65,6 @@ class RetryTransport(httpx.AsyncBaseTransport, httpx.BaseTransport):
98
65
  Defaults to [429, 502, 503, 504].
99
66
  logger (Any): The logger to use for logging retries.
100
67
  """
101
- self._wrapped_transport = wrapped_transport
102
68
  if jitter_ratio < 0 or jitter_ratio > 0.5:
103
69
  raise ValueError(
104
70
  f"Jitter ratio should be between 0 and 0.5, actual {jitter_ratio}"
@@ -119,117 +85,34 @@ class RetryTransport(httpx.AsyncBaseTransport, httpx.BaseTransport):
119
85
  )
120
86
  self._jitter_ratio = jitter_ratio
121
87
  self._max_backoff_wait = max_backoff_wait
122
- self._logger = logger
123
-
124
- def handle_request(self, request: httpx.Request) -> httpx.Response:
125
- """
126
- Sends an HTTP request, possibly with retries.
127
-
128
- Args:
129
- request (httpx.Request): The request to send.
130
-
131
- Returns:
132
- httpx.Response: The response received.
133
-
134
- """
135
- transport: httpx.BaseTransport = self._wrapped_transport # type: ignore
136
- if request.method in self._retryable_methods:
137
- send_method = partial(transport.handle_request)
138
- response = self._retry_operation(request, send_method)
139
- else:
140
- response = transport.handle_request(request)
141
- return response
142
-
143
- async def handle_async_request(self, request: httpx.Request) -> httpx.Response:
144
- """Sends an HTTP request, possibly with retries.
145
-
146
- Args:
147
- request: The request to perform.
148
-
149
- Returns:
150
- The response.
151
-
152
- """
153
- transport: httpx.AsyncBaseTransport = self._wrapped_transport # type: ignore
154
- if self._is_retryable_method(request):
155
- send_method = partial(transport.handle_async_request)
156
- response = await self._retry_operation_async(request, send_method)
157
- else:
158
- response = await transport.handle_async_request(request)
159
- return response
160
-
161
- async def aclose(self) -> None:
162
- """
163
- Closes the underlying HTTP transport, terminating all outstanding connections and rejecting any further
164
- requests.
165
-
166
- This should be called before the object is dereferenced, to ensure that connections are properly cleaned up.
167
- """
168
- transport: httpx.AsyncBaseTransport = self._wrapped_transport # type: ignore
169
- await transport.aclose()
170
88
 
171
- def close(self) -> None:
172
- """
173
- Closes the underlying HTTP transport, terminating all outstanding connections and rejecting any further
174
- requests.
89
+ super().__init__(method, url, *args, **kwargs)
175
90
 
176
- This should be called before the object is dereferenced, to ensure that connections are properly cleaned up.
177
- """
178
- transport: httpx.BaseTransport = self._wrapped_transport # type: ignore
179
- transport.close()
180
-
181
- def _is_retryable_method(self, request: httpx.Request) -> bool:
182
- return request.method in self._retryable_methods or request.extensions.get(
183
- "retryable", False
184
- )
185
-
186
- def _should_retry(self, response: httpx.Response) -> bool:
187
- return response.status_code in self._retry_status_codes
91
+ def _is_retryable(self) -> bool:
92
+ return self.method in self._retryable_methods
188
93
 
189
94
  def _log_error(
190
- self,
191
- request: httpx.Request,
192
- error: Exception | None,
95
+ self,
96
+ error: Exception | None,
193
97
  ) -> None:
194
- if not self._logger:
195
- return
196
-
197
- if isinstance(error, httpx.ConnectTimeout):
198
- self._logger.error(
199
- f"Request {request.method} {request.url} failed to connect: {str(error)}"
98
+ if isinstance(error, aiohttp.ServerConnectionError):
99
+ logger.error(
100
+ f"Request {self.method} {self.url} failed to connect: {str(error)}"
200
101
  )
201
- elif isinstance(error, httpx.TimeoutException):
202
- self._logger.error(
203
- f"Request {request.method} {request.url} failed with a timeout exception: {str(error)}"
102
+ elif isinstance(error, aiohttp.ConnectionTimeoutError):
103
+ logger.error(
104
+ f"Request {self.method} {self.url} failed with a timeout exception: {str(error)}"
204
105
  )
205
- elif isinstance(error, httpx.HTTPError):
206
- self._logger.error(
207
- f"Request {request.method} {request.url} failed with an HTTP error: {str(error)}"
106
+ elif isinstance(error, aiohttp.ClientError):
107
+ logger.error(
108
+ f"Request {self.method} {self.url} failed with an HTTP error: {str(error)}"
208
109
  )
209
110
 
210
- def _log_before_retry(
211
- self,
212
- request: httpx.Request,
213
- sleep_time: float,
214
- response: httpx.Response | None,
215
- error: Exception | None,
216
- ) -> None:
217
- if self._logger and response:
218
- self._logger.warning(
219
- f"Request {request.method} {request.url} failed with status code:"
220
- f" {response.status_code}, retrying in {sleep_time} seconds." # noqa: F821
221
- )
222
- elif self._logger and error:
223
- self._logger.warning(
224
- f"Request {request.method} {request.url} failed with exception:"
225
- f" {type(error).__name__} - {str(error) or 'No error message'}, retrying in {sleep_time} seconds."
226
- )
227
-
228
- async def _should_retry_async(self, response: httpx.Response) -> bool:
229
- return response.status_code in self._retry_status_codes
111
+ async def _should_retry_async(self, response: ClientResponse) -> bool:
112
+ return response.status in self._retry_status_codes
230
113
 
231
114
  def _calculate_sleep(
232
- self, attempts_made: int, headers: Union[httpx.Headers, Mapping[str, str]]
115
+ self, attempts_made: int, headers: Mapping[str, str]
233
116
  ) -> float:
234
117
  # Retry-After
235
118
  # The Retry-After response HTTP header indicates how long the user agent should wait before
@@ -260,91 +143,58 @@ class RetryTransport(httpx.AsyncBaseTransport, httpx.BaseTransport):
260
143
  total_backoff = backoff + jitter
261
144
  return min(total_backoff, self._max_backoff_wait)
262
145
 
146
+ def _log_before_retry(
147
+ self,
148
+ sleep_time: float,
149
+ response: ClientResponse | None,
150
+ error: Exception | None,
151
+ ) -> None:
152
+ if response:
153
+ logger.warning(
154
+ f"Request {self.method} {self.url} failed with status code:"
155
+ f" {response.status}, retrying in {sleep_time} seconds." # noqa: F821
156
+ )
157
+ elif error:
158
+ logger.warning(
159
+ f"Request {self.method} {self.url} failed with exception:"
160
+ f" {type(error).__name__} - {str(error) or 'No error message'}, retrying in {sleep_time} seconds."
161
+ )
162
+
263
163
  async def _retry_operation_async(
264
- self,
265
- request: httpx.Request,
266
- send_method: Callable[..., Coroutine[Any, Any, httpx.Response]],
267
- ) -> httpx.Response:
164
+ self, request: Callable[..., Coroutine[Any, Any, ClientResponse]]
165
+ ) -> ClientResponse:
268
166
  remaining_attempts = self._max_attempts
269
167
  attempts_made = 0
270
- response: httpx.Response | None = None
168
+ response: ClientResponse | None = None
271
169
  error: Exception | None = None
272
170
  while True:
273
171
  if attempts_made > 0:
274
- sleep_time = self._calculate_sleep(attempts_made, {})
275
- self._log_before_retry(request, sleep_time, response, error)
172
+ sleep_time = self._calculate_sleep(attempts_made, response.headers if response else {})
173
+ self._log_before_retry(sleep_time, response, error)
276
174
  await asyncio.sleep(sleep_time)
277
175
 
278
176
  error = None
279
177
  response = None
280
178
  try:
281
- response = await send_method(request)
282
- response.request = request
179
+ response = await request()
283
180
  if remaining_attempts < 1 or not (
284
- await self._should_retry_async(response)
181
+ await self._should_retry_async(response)
285
182
  ):
286
183
  return response
287
- await response.aclose()
288
- except httpx.ConnectTimeout as e:
184
+ except (aiohttp.ServerConnectionError, aiohttp.ConnectionTimeoutError, aiohttp.ClientError) as e:
289
185
  error = e
290
186
  if remaining_attempts < 1:
291
- self._log_error(request, error)
292
- raise
293
- except httpx.ReadTimeout as e:
294
- error = e
295
- if remaining_attempts < 1:
296
- self._log_error(request, error)
297
- raise
298
- except httpx.TimeoutException as e:
299
- error = e
300
- if remaining_attempts < 1:
301
- self._log_error(request, error)
302
- raise
303
- except httpx.HTTPError as e:
304
- error = e
305
- if remaining_attempts < 1:
306
- self._log_error(request, error)
187
+ self._log_error(error)
307
188
  raise
308
189
  attempts_made += 1
309
190
  remaining_attempts -= 1
310
191
 
311
- def _retry_operation(
312
- self,
313
- request: httpx.Request,
314
- send_method: Callable[..., httpx.Response],
315
- ) -> httpx.Response:
316
- remaining_attempts = self._max_attempts
317
- attempts_made = 0
318
- response: httpx.Response | None = None
319
- error: Exception | None = None
320
- while True:
321
- if attempts_made > 0:
322
- sleep_time = self._calculate_sleep(attempts_made, {})
323
- self._log_before_retry(request, sleep_time, response, error)
324
- time.sleep(sleep_time)
325
-
326
- error = None
327
- response = None
328
- try:
329
- response = send_method(request)
330
- response.request = request
331
- if remaining_attempts < 1 or not self._should_retry(response):
332
- return response
333
- response.close()
334
- except httpx.ConnectTimeout as e:
335
- error = e
336
- if remaining_attempts < 1:
337
- self._log_error(request, error)
338
- raise
339
- except httpx.TimeoutException as e:
340
- error = e
341
- if remaining_attempts < 1:
342
- self._log_error(request, error)
343
- raise
344
- except httpx.HTTPError as e:
345
- error = e
346
- if remaining_attempts < 1:
347
- self._log_error(request, error)
348
- raise
349
- attempts_made += 1
350
- remaining_attempts -= 1
192
+ async def send(self, conn: "Connection") -> "ClientResponse":
193
+ request = functools.partial(
194
+ super().send, conn
195
+ )
196
+ if self._is_retryable():
197
+ response = await self._retry_operation_async(request)
198
+ else:
199
+ response = await request()
200
+ return response
port_ocean/ocean.py CHANGED
@@ -1,6 +1,5 @@
1
1
  import asyncio
2
2
  import sys
3
- import threading
4
3
  from contextlib import asynccontextmanager
5
4
  from typing import Callable, Any, Dict, AsyncIterator, Type
6
5
 
@@ -30,12 +29,12 @@ from port_ocean.version import __integration_version__
30
29
 
31
30
  class Ocean:
32
31
  def __init__(
33
- self,
34
- app: FastAPI | None = None,
35
- integration_class: Callable[[PortOceanContext], BaseIntegration] | None = None,
36
- integration_router: APIRouter | None = None,
37
- config_factory: Type[BaseModel] | None = None,
38
- config_override: Dict[str, Any] | None = None,
32
+ self,
33
+ app: FastAPI | None = None,
34
+ integration_class: Callable[[PortOceanContext], BaseIntegration] | None = None,
35
+ integration_router: APIRouter | None = None,
36
+ config_factory: Type[BaseModel] | None = None,
37
+ config_override: Dict[str, Any] | None = None,
39
38
  ):
40
39
  initialize_port_ocean_context(self)
41
40
  self.fast_api_app = app or FastAPI()
@@ -73,7 +72,7 @@ class Ocean:
73
72
  return self.config.runtime == Runtime.Saas
74
73
 
75
74
  async def _setup_scheduled_resync(
76
- self,
75
+ self,
77
76
  ) -> None:
78
77
  async def execute_resync_all() -> None:
79
78
  # await self.resync_state_updater.update_before_resync()
@@ -103,11 +102,7 @@ class Ocean:
103
102
  # Not running the resync immediately because the event listener should run resync on startup
104
103
  wait_first=False,
105
104
  )(
106
- lambda: threading.Thread(
107
- target=lambda: asyncio.run_coroutine_threadsafe(
108
- execute_resync_all(), loop
109
- )
110
- ).start()
105
+ execute_resync_all
111
106
  )
112
107
  await repeated_function()
113
108
 
@@ -1,12 +1,11 @@
1
1
  from typing import Any
2
2
  from unittest.mock import MagicMock
3
3
 
4
+ import aiohttp
4
5
  import pytest
5
6
 
6
7
  from port_ocean.clients.port.mixins.entities import EntityClientMixin
7
8
  from port_ocean.core.models import Entity
8
- from httpx import ReadTimeout
9
-
10
9
 
11
10
  errored_entity_identifier: str = "a"
12
11
  expected_result_entities = [
@@ -20,7 +19,7 @@ all_entities = [
20
19
 
21
20
  async def mock_upsert_entity(entity: Entity, *args: Any, **kwargs: Any) -> Entity:
22
21
  if entity.identifier == errored_entity_identifier:
23
- raise ReadTimeout("")
22
+ raise aiohttp.ConnectionTimeoutError("")
24
23
  else:
25
24
  return entity
26
25
 
@@ -47,7 +46,7 @@ async def test_batch_upsert_entities_read_timeout_should_raise_false(
47
46
  async def test_batch_upsert_entities_read_timeout_should_raise_true(
48
47
  entity_client: EntityClientMixin,
49
48
  ) -> None:
50
- with pytest.raises(ReadTimeout):
49
+ with pytest.raises(aiohttp.ConnectionTimeoutError):
51
50
  await entity_client.batch_upsert_entities(
52
51
  entities=all_entities, request_options=MagicMock(), should_raise=True
53
52
  )