port-ocean 0.13.1.dev1__py3-none-any.whl → 0.14.4__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.

@@ -55,14 +55,14 @@ class RetryTransport(httpx.AsyncBaseTransport, httpx.BaseTransport):
55
55
  HTTPStatus.GATEWAY_TIMEOUT,
56
56
  ]
57
57
  )
58
- MAX_BACKOFF_WAIT = 60
58
+ MAX_BACKOFF_WAIT_IN_SECONDS = 60
59
59
 
60
60
  def __init__(
61
61
  self,
62
62
  wrapped_transport: Union[httpx.BaseTransport, httpx.AsyncBaseTransport],
63
63
  max_attempts: int = 10,
64
- max_backoff_wait: float = MAX_BACKOFF_WAIT,
65
- backoff_factor: float = 0.1,
64
+ max_backoff_wait: float = MAX_BACKOFF_WAIT_IN_SECONDS,
65
+ base_delay: float = 0.1,
66
66
  jitter_ratio: float = 0.1,
67
67
  respect_retry_after_header: bool = True,
68
68
  retryable_methods: Iterable[str] | None = None,
@@ -81,7 +81,7 @@ class RetryTransport(httpx.AsyncBaseTransport, httpx.BaseTransport):
81
81
  max_backoff_wait (float, optional):
82
82
  The maximum amount of time (in seconds) to wait before retrying a request.
83
83
  Defaults to 60.
84
- backoff_factor (float, optional):
84
+ base_delay (float, optional):
85
85
  The factor by which the waiting time will be multiplied in each retry attempt.
86
86
  Defaults to 0.1.
87
87
  jitter_ratio (float, optional):
@@ -105,7 +105,7 @@ class RetryTransport(httpx.AsyncBaseTransport, httpx.BaseTransport):
105
105
  )
106
106
 
107
107
  self._max_attempts = max_attempts
108
- self._backoff_factor = backoff_factor
108
+ self._base_delay = base_delay
109
109
  self._respect_retry_after_header = respect_retry_after_header
110
110
  self._retryable_methods = (
111
111
  frozenset(retryable_methods)
@@ -132,13 +132,18 @@ class RetryTransport(httpx.AsyncBaseTransport, httpx.BaseTransport):
132
132
  httpx.Response: The response received.
133
133
 
134
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
135
+ try:
136
+ transport: httpx.BaseTransport = self._wrapped_transport # type: ignore
137
+ if request.method in self._retryable_methods:
138
+ send_method = partial(transport.handle_request)
139
+ response = self._retry_operation(request, send_method)
140
+ else:
141
+ response = transport.handle_request(request)
142
+ return response
143
+ except Exception as e:
144
+ if not self._is_retryable_method(request) and self._logger is not None:
145
+ self._logger.exception(f"{repr(e)} - {request.url}", exc_info=e)
146
+ raise e
142
147
 
143
148
  async def handle_async_request(self, request: httpx.Request) -> httpx.Response:
144
149
  """Sends an HTTP request, possibly with retries.
@@ -150,13 +155,19 @@ class RetryTransport(httpx.AsyncBaseTransport, httpx.BaseTransport):
150
155
  The response.
151
156
 
152
157
  """
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
158
+ try:
159
+ transport: httpx.AsyncBaseTransport = self._wrapped_transport # type: ignore
160
+ if self._is_retryable_method(request):
161
+ send_method = partial(transport.handle_async_request)
162
+ response = await self._retry_operation_async(request, send_method)
163
+ else:
164
+ response = await transport.handle_async_request(request)
165
+ return response
166
+ except Exception as e:
167
+ # Retyable methods are logged via _log_error
168
+ if not self._is_retryable_method(request) and self._logger is not None:
169
+ self._logger.exception(f"{repr(e)} - {request.url}", exc_info=e)
170
+ raise e
160
171
 
161
172
  async def aclose(self) -> None:
162
173
  """
@@ -255,7 +266,7 @@ class RetryTransport(httpx.AsyncBaseTransport, httpx.BaseTransport):
255
266
  except ValueError:
256
267
  pass
257
268
 
258
- backoff = self._backoff_factor * (2 ** (attempts_made - 1))
269
+ backoff = self._base_delay * (2 ** (attempts_made - 1))
259
270
  jitter = (backoff * self._jitter_ratio) * random.choice([1, -1])
260
271
  total_backoff = backoff + jitter
261
272
  return min(total_backoff, self._max_backoff_wait)
port_ocean/ocean.py CHANGED
@@ -114,7 +114,7 @@ class Ocean:
114
114
  )
115
115
  await repeated_function()
116
116
 
117
- def initialize_app(self):
117
+ def initialize_app(self) -> None:
118
118
  self.fast_api_app.include_router(self.integration_router, prefix="/integration")
119
119
 
120
120
  @asynccontextmanager
@@ -0,0 +1,166 @@
1
+ import pytest
2
+ import json
3
+ from unittest.mock import patch
4
+ from pathlib import Path
5
+ from port_ocean.core.handlers.port_app_config.models import PortAppConfig
6
+ from port_ocean.core.defaults.common import (
7
+ get_port_integration_defaults,
8
+ Defaults,
9
+ )
10
+
11
+
12
+ @pytest.fixture
13
+ def setup_mock_directories(tmp_path: Path) -> tuple[Path, Path, Path]:
14
+ # Create .port/resources with sample files
15
+ default_dir = tmp_path / ".port/resources"
16
+ default_dir.mkdir(parents=True, exist_ok=True)
17
+
18
+ # Create mock JSON and YAML files with expected content
19
+ (default_dir / "blueprints.json").write_text(
20
+ json.dumps(
21
+ [
22
+ {
23
+ "identifier": "mock-identifier",
24
+ "title": "mock-title",
25
+ "icon": "mock-icon",
26
+ "schema": {
27
+ "type": "object",
28
+ "properties": {"key": {"type": "string"}},
29
+ },
30
+ }
31
+ ]
32
+ )
33
+ )
34
+ (default_dir / "port-app-config.json").write_text(
35
+ json.dumps(
36
+ {
37
+ "resources": [
38
+ {
39
+ "kind": "mock-kind",
40
+ "selector": {"query": "true"},
41
+ "port": {
42
+ "entity": {
43
+ "mappings": {
44
+ "identifier": ".id",
45
+ "title": ".title",
46
+ "blueprint": '"mock-identifier"',
47
+ }
48
+ }
49
+ },
50
+ }
51
+ ]
52
+ }
53
+ )
54
+ )
55
+
56
+ # Create .port/custom_resources with different sample files
57
+ custom_resources_dir = tmp_path / ".port/custom_resources"
58
+ custom_resources_dir.mkdir(parents=True, exist_ok=True)
59
+
60
+ # Create mock JSON and YAML files with expected content
61
+ (custom_resources_dir / "blueprints.json").write_text(
62
+ json.dumps(
63
+ [
64
+ {
65
+ "identifier": "mock-custom-identifier",
66
+ "title": "mock-custom-title",
67
+ "icon": "mock-custom-icon",
68
+ "schema": {
69
+ "type": "object",
70
+ "properties": {"key": {"type": "string"}},
71
+ },
72
+ }
73
+ ]
74
+ )
75
+ )
76
+ (custom_resources_dir / "port-app-config.json").write_text(
77
+ json.dumps(
78
+ {
79
+ "resources": [
80
+ {
81
+ "kind": "mock-custom-kind",
82
+ "selector": {"query": "true"},
83
+ "port": {
84
+ "entity": {
85
+ "mappings": {
86
+ "identifier": ".id",
87
+ "title": ".title",
88
+ "blueprint": '"mock-custom-identifier"',
89
+ }
90
+ }
91
+ },
92
+ }
93
+ ]
94
+ }
95
+ )
96
+ )
97
+
98
+ # Define the non-existing directory path
99
+ non_existing_dir = tmp_path / ".port/do_not_exist"
100
+
101
+ return default_dir, custom_resources_dir, non_existing_dir
102
+
103
+
104
+ def test_custom_defaults_dir_used_if_valid(
105
+ setup_mock_directories: tuple[Path, Path, Path]
106
+ ) -> None:
107
+ # Arrange
108
+ _, custom_resources_dir, _ = setup_mock_directories
109
+
110
+ with (
111
+ patch("port_ocean.core.defaults.common.is_valid_dir") as mock_is_valid_dir,
112
+ patch(
113
+ "pathlib.Path.iterdir",
114
+ return_value=custom_resources_dir.iterdir(),
115
+ ),
116
+ ):
117
+ mock_is_valid_dir.side_effect = lambda path: path == custom_resources_dir
118
+
119
+ # Act
120
+ defaults = get_port_integration_defaults(
121
+ port_app_config_class=PortAppConfig,
122
+ custom_defaults_dir=".port/custom_resources",
123
+ base_path=custom_resources_dir.parent.parent,
124
+ )
125
+
126
+ # Assert
127
+ assert isinstance(defaults, Defaults)
128
+ assert defaults.blueprints[0].get("identifier") == "mock-custom-identifier"
129
+ assert defaults.port_app_config is not None
130
+ assert defaults.port_app_config.resources[0].kind == "mock-custom-kind"
131
+
132
+
133
+ def test_fallback_to_default_dir_if_custom_dir_invalid(
134
+ setup_mock_directories: tuple[Path, Path, Path]
135
+ ) -> None:
136
+ resources_dir, _, non_existing_dir = setup_mock_directories
137
+
138
+ # Arrange
139
+ with (
140
+ patch("port_ocean.core.defaults.common.is_valid_dir") as mock_is_valid_dir,
141
+ patch("pathlib.Path.iterdir", return_value=resources_dir.iterdir()),
142
+ ):
143
+
144
+ mock_is_valid_dir.side_effect = lambda path: path == resources_dir
145
+
146
+ # Act
147
+ custom_defaults_dir = str(non_existing_dir.relative_to(resources_dir.parent))
148
+ defaults = get_port_integration_defaults(
149
+ port_app_config_class=PortAppConfig,
150
+ custom_defaults_dir=custom_defaults_dir,
151
+ base_path=resources_dir.parent.parent,
152
+ )
153
+
154
+ # Assert
155
+ assert isinstance(defaults, Defaults)
156
+ assert defaults.blueprints[0].get("identifier") == "mock-identifier"
157
+ assert defaults.port_app_config is not None
158
+ assert defaults.port_app_config.resources[0].kind == "mock-kind"
159
+
160
+
161
+ def test_default_resources_path_does_not_exist() -> None:
162
+ # Act
163
+ defaults = get_port_integration_defaults(port_app_config_class=PortAppConfig)
164
+
165
+ # Assert
166
+ assert defaults is None
@@ -0,0 +1,189 @@
1
+ from typing import Any
2
+ import asyncio
3
+ from port_ocean.utils import cache # Import the module where 'event' is used
4
+ import pytest
5
+ from dataclasses import dataclass, field
6
+ from typing import AsyncGenerator, AsyncIterator, List, TypeVar
7
+
8
+
9
+ @dataclass
10
+ class EventContext:
11
+ attributes: dict[str, Any] = field(default_factory=dict)
12
+
13
+
14
+ @pytest.fixture
15
+ def event() -> EventContext:
16
+ return EventContext()
17
+
18
+
19
+ T = TypeVar("T")
20
+
21
+
22
+ async def collect_iterator_results(iterator: AsyncIterator[List[T]]) -> List[T]:
23
+ results = []
24
+ async for item in iterator:
25
+ results.extend(item)
26
+ return results
27
+
28
+
29
+ @pytest.mark.asyncio
30
+ async def test_cache_iterator_result(event: EventContext, monkeypatch: Any) -> None:
31
+ monkeypatch.setattr(cache, "event", event)
32
+
33
+ call_count = 0
34
+
35
+ @cache.cache_iterator_result()
36
+ async def sample_iterator(x: int) -> AsyncGenerator[List[int], None]:
37
+ nonlocal call_count
38
+ call_count += 1
39
+ for i in range(x):
40
+ await asyncio.sleep(0.1)
41
+ yield [i]
42
+
43
+ result1 = await collect_iterator_results(sample_iterator(3))
44
+ assert result1 == [0, 1, 2]
45
+ assert call_count == 1
46
+
47
+ result2 = await collect_iterator_results(sample_iterator(3))
48
+ assert result2 == [0, 1, 2]
49
+ assert call_count == 1
50
+
51
+ result3 = await collect_iterator_results(sample_iterator(4))
52
+ assert result3 == [0, 1, 2, 3]
53
+ assert call_count == 2
54
+
55
+
56
+ @pytest.mark.asyncio
57
+ async def test_cache_iterator_result_with_kwargs(
58
+ event: EventContext, monkeypatch: Any
59
+ ) -> None:
60
+ monkeypatch.setattr(cache, "event", event)
61
+
62
+ call_count = 0
63
+
64
+ @cache.cache_iterator_result()
65
+ async def sample_iterator(x: int, y: int = 1) -> AsyncGenerator[List[int], None]:
66
+ nonlocal call_count
67
+ call_count += 1
68
+ for i in range(x * y):
69
+ await asyncio.sleep(0.1)
70
+ yield [i]
71
+
72
+ result1 = await collect_iterator_results(sample_iterator(2, y=2))
73
+ assert result1 == [0, 1, 2, 3]
74
+ assert call_count == 1
75
+
76
+ result2 = await collect_iterator_results(sample_iterator(2, y=2))
77
+ assert result2 == [0, 1, 2, 3]
78
+ assert call_count == 1
79
+
80
+ result3 = await collect_iterator_results(sample_iterator(2, y=3))
81
+ assert result3 == [0, 1, 2, 3, 4, 5]
82
+ assert call_count == 2
83
+
84
+
85
+ @pytest.mark.asyncio
86
+ async def test_cache_iterator_result_no_cache(
87
+ event: EventContext, monkeypatch: Any
88
+ ) -> None:
89
+ monkeypatch.setattr(cache, "event", event)
90
+
91
+ call_count = 0
92
+
93
+ @cache.cache_iterator_result()
94
+ async def sample_iterator(x: int) -> AsyncGenerator[List[int], None]:
95
+ nonlocal call_count
96
+ call_count += 1
97
+ for i in range(x):
98
+ await asyncio.sleep(0.1)
99
+ yield [i]
100
+
101
+ result1 = await collect_iterator_results(sample_iterator(3))
102
+ assert result1 == [0, 1, 2]
103
+ assert call_count == 1
104
+
105
+ event.attributes.clear()
106
+
107
+ result2 = await collect_iterator_results(sample_iterator(3))
108
+ assert result2 == [0, 1, 2]
109
+ assert call_count == 2
110
+
111
+
112
+ @pytest.mark.asyncio
113
+ async def test_cache_coroutine_result(event: EventContext, monkeypatch: Any) -> None:
114
+ monkeypatch.setattr(cache, "event", event)
115
+
116
+ call_count = 0
117
+
118
+ @cache.cache_coroutine_result()
119
+ async def sample_coroutine(x: int) -> int:
120
+ nonlocal call_count
121
+ call_count += 1
122
+ await asyncio.sleep(0.1)
123
+ return x * 2
124
+
125
+ result1 = await sample_coroutine(2)
126
+ assert result1 == 4
127
+ assert call_count == 1
128
+
129
+ result2 = await sample_coroutine(2)
130
+ assert result2 == 4
131
+ assert call_count == 1
132
+
133
+ result3 = await sample_coroutine(3)
134
+ assert result3 == 6
135
+ assert call_count == 2
136
+
137
+
138
+ @pytest.mark.asyncio
139
+ async def test_cache_coroutine_result_with_kwargs(
140
+ event: EventContext, monkeypatch: Any
141
+ ) -> None:
142
+ monkeypatch.setattr(cache, "event", event)
143
+
144
+ call_count = 0
145
+
146
+ @cache.cache_coroutine_result()
147
+ async def sample_coroutine(x: int, y: int = 1) -> int:
148
+ nonlocal call_count
149
+ call_count += 1
150
+ await asyncio.sleep(0.1)
151
+ return x * y
152
+
153
+ result1 = await sample_coroutine(2, y=3)
154
+ assert result1 == 6
155
+ assert call_count == 1
156
+
157
+ result2 = await sample_coroutine(2, y=3)
158
+ assert result2 == 6
159
+ assert call_count == 1
160
+
161
+ result3 = await sample_coroutine(2, y=4)
162
+ assert result3 == 8
163
+ assert call_count == 2
164
+
165
+
166
+ @pytest.mark.asyncio
167
+ async def test_cache_coroutine_result_no_cache(
168
+ event: EventContext, monkeypatch: Any
169
+ ) -> None:
170
+ monkeypatch.setattr(cache, "event", event)
171
+
172
+ call_count = 0
173
+
174
+ @cache.cache_coroutine_result()
175
+ async def sample_coroutine(x: int) -> int:
176
+ nonlocal call_count
177
+ call_count += 1
178
+ await asyncio.sleep(0.1)
179
+ return x * 2
180
+
181
+ result1 = await sample_coroutine(2)
182
+ assert result1 == 4
183
+ assert call_count == 1
184
+
185
+ event.attributes.clear()
186
+
187
+ result2 = await sample_coroutine(2)
188
+ assert result2 == 4
189
+ assert call_count == 2
port_ocean/utils/cache.py CHANGED
@@ -1,9 +1,10 @@
1
1
  import functools
2
2
  import hashlib
3
- from typing import Callable, AsyncIterator, Any
3
+ from typing import Callable, AsyncIterator, Awaitable, Any
4
4
  from port_ocean.context.event import event
5
5
 
6
6
  AsyncIteratorCallable = Callable[..., AsyncIterator[list[Any]]]
7
+ AsyncCallable = Callable[..., Awaitable[Any]]
7
8
 
8
9
 
9
10
  def hash_func(function_name: str, *args: Any, **kwargs: Any) -> str:
@@ -59,3 +60,38 @@ def cache_iterator_result() -> Callable[[AsyncIteratorCallable], AsyncIteratorCa
59
60
  return wrapper
60
61
 
61
62
  return decorator
63
+
64
+
65
+ def cache_coroutine_result() -> Callable[[AsyncCallable], AsyncCallable]:
66
+ """Coroutine version of `cache_iterator_result` from port_ocean.utils.cache
67
+
68
+ Decorator that caches the result of a coroutine function.
69
+ It checks if the result is already in the cache, and if not,
70
+ fetches the result, caches it, and returns the cached value.
71
+
72
+ The cache is stored in the scope of the running event and is
73
+ removed when the event is finished.
74
+
75
+ Usage:
76
+ ```python
77
+ @cache_coroutine_result()
78
+ async def my_coroutine_function():
79
+ # Your code here
80
+ ```
81
+ """
82
+
83
+ def decorator(func: AsyncCallable) -> AsyncCallable:
84
+ @functools.wraps(func)
85
+ async def wrapper(*args: Any, **kwargs: Any) -> Any:
86
+ cache_key = hash_func(func.__name__, *args, **kwargs)
87
+
88
+ if cache := event.attributes.get(cache_key):
89
+ return cache
90
+
91
+ result = await func(*args, **kwargs)
92
+ event.attributes[cache_key] = result
93
+ return result
94
+
95
+ return wrapper
96
+
97
+ return decorator
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: port-ocean
3
- Version: 0.13.1.dev1
3
+ Version: 0.14.4
4
4
  Summary: Port Ocean is a CLI tool for managing your Port projects.
5
5
  Home-page: https://app.getport.io
6
6
  Keywords: ocean,port-ocean,port
@@ -1,10 +1,18 @@
1
+ integrations/_infra/Dockerfile.Deb,sha256=iEyen_5YTa0syesJWS7NKuE-Oo4rM34Wwgjq9JzEjdA,1519
2
+ integrations/_infra/Dockerfile.alpine,sha256=iauglyEzz5uEPBxsN-9SLFr6qca3Tf4b0DPXKFFeKq4,3482
3
+ integrations/_infra/Dockerfile.base.builder,sha256=LwKLfJvQfKksMqacAT_aDQxFMC2Ty5fFKIa0Eu4QcCc,619
4
+ integrations/_infra/Dockerfile.base.runner,sha256=dsjTWgLQFm4x5gcm-IPhwkDv-M6VRKwdf-qct457h2c,357
5
+ integrations/_infra/Dockerfile.dockerignore,sha256=CM1Fxt3I2AvSvObuUZRmy5BNLSGC7ylnbpWzFgD4cso,1163
6
+ integrations/_infra/Makefile,sha256=vnuFuDau8AYiNgif3gfx0I17X1HqiPxcIS6uUqE9q1Y,2186
7
+ integrations/_infra/grpcio.sh,sha256=m924poYznoRZ6Tt7Ct8Cs5AV_cmmOx598yIZ3z4DvZE,616
8
+ integrations/_infra/init.sh,sha256=nN8lTrOhB286UfFvD6sJ9YJ-9asT9zVSddQB-RAb7Z4,99
1
9
  port_ocean/__init__.py,sha256=J3Mqp7d-CkEe9eMigGG8gSEiVKICY2bf7csNEwVOXk0,294
2
10
  port_ocean/bootstrap.py,sha256=CN1M5pVecZ7z_Vfu86Dk2HjFMiuiwt6E_SSOLFCYRMk,1321
3
11
  port_ocean/cli/__init__.py,sha256=ZjTGS305llhbjC2BH2KkVj34gCASBGwqc5HZEO_0T_Q,328
4
12
  port_ocean/cli/cli.py,sha256=RvWTELEn5YFw9aM0vaNqm5YqZZrL50ILaBs27ptiGl0,57
5
13
  port_ocean/cli/commands/__init__.py,sha256=Y9Q6jeYw_ZAZ-mdfE_5DZTdS2KHhieQZoUTggk_AkwM,369
6
14
  port_ocean/cli/commands/defaults/__init___.py,sha256=5OKgakO79bTbplFv1_yWCrw1x_JJqSdRXAHHqKSuEpQ,88
7
- port_ocean/cli/commands/defaults/clean.py,sha256=b3MVxAc9pASGxG3O6AjbDJiFngw82UqclVuCZObVPGM,1544
15
+ port_ocean/cli/commands/defaults/clean.py,sha256=258rOSC1xGT-NTBIkv-V8HTY57ZipnOD-gV5yEenut0,1570
8
16
  port_ocean/cli/commands/defaults/dock.py,sha256=pFtHrU_LTvb5Ddrzj09Wxy-jg1Ym10wBYD-0tpDRugE,1104
9
17
  port_ocean/cli/commands/defaults/group.py,sha256=hii_4CYoQ7jSMePbnP4AmruO_RKWCUcoV7dXXBlZafc,115
10
18
  port_ocean/cli/commands/list_integrations.py,sha256=DVVioFruGUE-_v6UUHlcemWNN6RlWwCrf1X4HmAXsf8,1134
@@ -16,8 +24,7 @@ port_ocean/cli/commands/version.py,sha256=hEuIEIcm6Zkamz41Z9nxeSM_4g3oNlAgWwQyDG
16
24
  port_ocean/cli/cookiecutter/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
25
  port_ocean/cli/cookiecutter/cookiecutter.json,sha256=N5UrAP2e5JbgEDz_WTQFIZlzSveME6x32sHeA7idjh0,481
18
26
  port_ocean/cli/cookiecutter/extensions.py,sha256=eQNjZvy2enDkJpvMbBGil77Xk9-38f862wfnmCjdoBc,446
19
- port_ocean/cli/cookiecutter/hooks/post_gen_project.py,sha256=xZbDPSmfP-ZXNlPaqQDsYLuNfdhFpLX9fIshiAd94Qg,535
20
- port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.dockerignore,sha256=9Mz_WI7XBpKzlJ7ILb4vlcuzYkh98Ql3bP_5GHN1sRY,1034
27
+ port_ocean/cli/cookiecutter/hooks/post_gen_project.py,sha256=tFqtsjSbu7HMN32WIiFO37S1a_dfHezvdPwmM6MmNJk,1182
21
28
  port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.env.example,sha256=LnNPRe3RnzjWPL4tNLYEQiMvFEZHSy3ceqwQEapcpwE,92
22
29
  port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.gitignore,sha256=32p1lDW_g5hyBz486GWfDeR9m7ikFlASVri5a8vmNoo,2698
23
30
  port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/resources/.gitignore,sha256=kCpRPdl3S_jqYYZaOrc0-xa6-l3KqVjNRXc6jCkd_-Q,12
@@ -26,7 +33,6 @@ port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/resources/po
26
33
  port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/spec.yaml,sha256=ie8bI_QOZnJJVG-N1e4KlMebdYts4LUNO_kKw8nGdhA,531
27
34
  port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/CHANGELOG.md,sha256=XVSgyxfXJZoZmtwaGbQ8XmCapIthe4E7flfuJub-m_s,338
28
35
  port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/CONTRIBUTING.md,sha256=ZQwD3K35q0wugHZmb1z5wnynmn0uuzwGFSpjm7GieZU,259
29
- port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/Dockerfile,sha256=LsH3vZqqEJkzeQG44cE7JkvPAuh_WPSqYam4YoMvG3M,328
30
36
  port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/README.md,sha256=5VZmgDRW9gO4d8UuzkujslOIDfIDBiAGL2Hd74HK770,468
31
37
  port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/changelog/.gitignore,sha256=JAo-DTfS6GthQGP1NH6wLU-ZymwlTea4KHH_jZVTKn0,14
32
38
  port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/debug.py,sha256=_TRsA2s6GV2E3CTI8CHcsH-ZuH4_Eh5-juDXWaET0ho,65
@@ -48,11 +54,11 @@ port_ocean/clients/port/mixins/integrations.py,sha256=t8OSa7Iopnpp8IOEcp3a7WgwOc
48
54
  port_ocean/clients/port/mixins/migrations.py,sha256=A6896oJF6WbFL2WroyTkMzr12yhVyWqGoq9dtLNSKBY,1457
49
55
  port_ocean/clients/port/retry_transport.py,sha256=PtIZOAZ6V-ncpVysRUsPOgt8Sf01QLnTKB5YeKBxkJk,1861
50
56
  port_ocean/clients/port/types.py,sha256=nvlgiAq4WH5_F7wQbz_GAWl-faob84LVgIjZ2Ww5mTk,451
51
- port_ocean/clients/port/utils.py,sha256=5B6rHgiVrtiL4YWh7Eq7_ncIeDwrDsB7jIvRik5xH8c,2373
57
+ port_ocean/clients/port/utils.py,sha256=SjhgmJXAqH2JqXfGy8GoGwzUYiJvUhWDrJyxQcenxZc,2512
52
58
  port_ocean/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
53
59
  port_ocean/config/base.py,sha256=x1gFbzujrxn7EJudRT81C6eN9WsYAb3vOHwcpcpX8Tc,6370
54
60
  port_ocean/config/dynamic.py,sha256=qOFkRoJsn_BW7581omi_AoMxoHqasf_foxDQ_G11_SI,2030
55
- port_ocean/config/settings.py,sha256=77MtPz-ZpOWjuuOcorAy4MSNuYhRE2a9DDBKx3sRrV8,4274
61
+ port_ocean/config/settings.py,sha256=65LATPdQ4YBdUTgQHMtZvzzPVrOxWUqAP7eerwFGZvg,4333
56
62
  port_ocean/consumers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
57
63
  port_ocean/consumers/kafka_consumer.py,sha256=N8KocjBi9aR0BOPG8hgKovg-ns_ggpEjrSxqSqF_BSo,4710
58
64
  port_ocean/context/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -61,9 +67,9 @@ port_ocean/context/ocean.py,sha256=2EreWOj-N2H7QUjEt5wGiv5KHP4pTZc70tn_wHcpF4w,4
61
67
  port_ocean/context/resource.py,sha256=yDj63URzQelj8zJPh4BAzTtPhpKr9Gw9DRn7I_0mJ1s,1692
62
68
  port_ocean/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
63
69
  port_ocean/core/defaults/__init__.py,sha256=8qCZg8n06WAdMu9s_FiRtDYLGPGHbOuS60vapeUoAks,142
64
- port_ocean/core/defaults/clean.py,sha256=S3UAfca-oU89WJKIB4OgGjGjPr0vxBQ2aRZsLTZhQ04,2185
65
- port_ocean/core/defaults/common.py,sha256=uVUg6VEn4RqtXQwLwMNGfkmT5zYRN_h5USfKw3poVyo,3561
66
- port_ocean/core/defaults/initialize.py,sha256=qg4JLIWjp0c5-9w09X99muHRYX4k1cGZ_77vYo-tnpU,8422
70
+ port_ocean/core/defaults/clean.py,sha256=TOVe5b5FAjFspAkQuKA70k2BClCEFbrQ3xgiAoKXKYE,2427
71
+ port_ocean/core/defaults/common.py,sha256=zJsj7jvlqIMLGXhdASUlbKS8GIAf-FDKKB0O7jB6nx0,4166
72
+ port_ocean/core/defaults/initialize.py,sha256=M1EXgfbnrvP5e3f9or8Bi0-4zXECznfRfy7sJn2Gc14,8471
67
73
  port_ocean/core/event_listener/__init__.py,sha256=mzJ33wRq0kh60fpVdOHVmvMTUQIvz3vxmifyBgwDn0E,889
68
74
  port_ocean/core/event_listener/base.py,sha256=1Nmpg00OfT2AD2L8eFm4VQEcdG2TClpSWJMhWhAjkEE,2356
69
75
  port_ocean/core/event_listener/factory.py,sha256=AYYfSHPAF7P5H-uQECXT0JVJjKDHrYkWJJBSL4mGkg8,3697
@@ -109,19 +115,20 @@ port_ocean/exceptions/port_defaults.py,sha256=45Bno5JEB-GXztvKsy8mw7TrydQmw13-4J
109
115
  port_ocean/exceptions/utils.py,sha256=gjOqpi-HpY1l4WlMFsGA9yzhxDhajhoGGdDDyGbLnqI,197
110
116
  port_ocean/helpers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
111
117
  port_ocean/helpers/async_client.py,sha256=SRlP6o7_FCSY3UHnRlZdezppePVxxOzZ0z861vE3K40,1783
112
- port_ocean/helpers/retry.py,sha256=IQ0RfQ2T5o6uoZh2WW2nrFH5TT6K_k3y2Im0HDp5j9Y,15059
118
+ port_ocean/helpers/retry.py,sha256=WO4yDFUd9NexZ0kESqxeTxBxNabU7_utKzgTj2-kMaM,15632
113
119
  port_ocean/log/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
114
120
  port_ocean/log/handlers.py,sha256=ncVjgqrZRh6BhyRrA6DQG86Wsbxph1yWYuEC0cWfe-Q,3631
115
121
  port_ocean/log/logger_setup.py,sha256=CoEDowe5OwNOL_5clU6Z4faktfh0VWaOTS0VLmyhHjw,2404
116
122
  port_ocean/log/sensetive.py,sha256=lVKiZH6b7TkrZAMmhEJRhcl67HNM94e56x12DwFgCQk,2920
117
123
  port_ocean/middlewares.py,sha256=9wYCdyzRZGK1vjEJ28FY_DkfwDNENmXp504UKPf5NaQ,2727
118
- port_ocean/ocean.py,sha256=oUNY9XT30oZ6e6asD6yM2dbd01-uD6RvtJXkmobUn7U,5282
124
+ port_ocean/ocean.py,sha256=NVdvooP0AiGyVs38VE8xXj6bzeT3XLoIPnh5FAS5ouM,5290
119
125
  port_ocean/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
120
126
  port_ocean/run.py,sha256=rTxBlrQd4yyrtgErCFJCHCEHs7d1OXrRiJehUYmIbN0,2212
121
127
  port_ocean/sonar-project.properties,sha256=X_wLzDOkEVmpGLRMb2fg9Rb0DxWwUFSvESId8qpvrPI,73
122
128
  port_ocean/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
123
129
  port_ocean/tests/clients/port/mixins/test_entities.py,sha256=A9myrnkLhKSQrnOLv1Zz2wiOVSxW65Q9RIUIRbn_V7w,1586
124
130
  port_ocean/tests/conftest.py,sha256=JXASSS0IY0nnR6bxBflhzxS25kf4iNaABmThyZ0mZt8,101
131
+ port_ocean/tests/core/defaults/test_common.py,sha256=sR7RqB3ZYV6Xn6NIg-c8k5K6JcGsYZ2SCe_PYX5vLYM,5560
125
132
  port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py,sha256=Yv03P-LDcJCKZ21exiTFrcT1eu0zn6Z954dilxrb52Y,10842
126
133
  port_ocean/tests/helpers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
127
134
  port_ocean/tests/helpers/fixtures.py,sha256=IQEplbHhRgjrAsZlnXrgSYA5YQEn25I9HgO3_Fjibxg,1481
@@ -132,18 +139,19 @@ port_ocean/tests/helpers/smoke_test.py,sha256=_9aJJFRfuGJEg2D2YQJVJRmpreS6gEPHHQ
132
139
  port_ocean/tests/log/test_handlers.py,sha256=bTOGnuj8fMIEXepwYblRvcg0FKqApCdyCBtAQZ2BlXM,2115
133
140
  port_ocean/tests/test_smoke.py,sha256=uix2uIg_yOm8BHDgHw2hTFPy1fiIyxBGW3ENU_KoFlo,2557
134
141
  port_ocean/tests/utils/test_async_iterators.py,sha256=3PLk1emEXekb8LcC5GgVh3OicaX15i5WyaJT_eFnu_4,1336
142
+ port_ocean/tests/utils/test_cache.py,sha256=GzoS8xGCBDbBcPwSDbdimsMMkRvJATrBC7UmFhdW3fw,4906
135
143
  port_ocean/utils/__init__.py,sha256=KMGnCPXZJbNwtgxtyMycapkDz8tpSyw23MSYT3iVeHs,91
136
144
  port_ocean/utils/async_http.py,sha256=arnH458TExn2Dju_Sy6pHas_vF5RMWnOp-jBz5WAAcE,1226
137
145
  port_ocean/utils/async_iterators.py,sha256=CPXskYWkhkZtAG-ducEwM8537t3z5usPEqXR9vcivzw,3715
138
- port_ocean/utils/cache.py,sha256=3KItZDE2yVrbVDr-hoM8lNna8s2dlpxhP4ICdLjH4LQ,2231
146
+ port_ocean/utils/cache.py,sha256=RgfN4SjjHrEkbqUChyboeD1mrXomolUUjsJtvbkmr3U,3353
139
147
  port_ocean/utils/misc.py,sha256=0q2cJ5psqxn_5u_56pT7vOVQ3shDM02iC1lzyWQ_zl0,2098
140
148
  port_ocean/utils/queue_utils.py,sha256=KWWl8YVnG-glcfIHhM6nefY-2sou_C6DVP1VynQwzB4,2762
141
149
  port_ocean/utils/repeat.py,sha256=0EFWM9d8lLXAhZmAyczY20LAnijw6UbIECf5lpGbOas,3231
142
150
  port_ocean/utils/signal.py,sha256=K-6kKFQTltcmKDhtyZAcn0IMa3sUpOHGOAUdWKgx0_E,1369
143
151
  port_ocean/utils/time.py,sha256=pufAOH5ZQI7gXvOvJoQXZXZJV-Dqktoj9Qp9eiRwmJ4,1939
144
152
  port_ocean/version.py,sha256=UsuJdvdQlazzKGD3Hd5-U7N69STh8Dq9ggJzQFnu9fU,177
145
- port_ocean-0.13.1.dev1.dist-info/LICENSE.md,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
146
- port_ocean-0.13.1.dev1.dist-info/METADATA,sha256=y1F3De2qTYoHTZufqBoGQA2n-Y-dtmk8dJj4SMNtS0g,6678
147
- port_ocean-0.13.1.dev1.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
148
- port_ocean-0.13.1.dev1.dist-info/entry_points.txt,sha256=F_DNUmGZU2Kme-8NsWM5LLE8piGMafYZygRYhOVtcjA,54
149
- port_ocean-0.13.1.dev1.dist-info/RECORD,,
153
+ port_ocean-0.14.4.dist-info/LICENSE.md,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
154
+ port_ocean-0.14.4.dist-info/METADATA,sha256=I8hKNbKejXTSk8cm5WKrjCZb1ElaKrNtuvETQoRVh9k,6673
155
+ port_ocean-0.14.4.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
156
+ port_ocean-0.14.4.dist-info/entry_points.txt,sha256=F_DNUmGZU2Kme-8NsWM5LLE8piGMafYZygRYhOVtcjA,54
157
+ port_ocean-0.14.4.dist-info/RECORD,,