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

@@ -51,4 +51,6 @@ def clean(path: str, force: bool, wait: bool) -> None:
51
51
  default_app,
52
52
  )
53
53
 
54
- clean_defaults(app.integration.AppConfigHandlerClass.CONFIG_CLASS, force, wait)
54
+ clean_defaults(
55
+ app.integration.AppConfigHandlerClass.CONFIG_CLASS, app.config, force, wait
56
+ )
@@ -78,6 +78,7 @@ class IntegrationConfiguration(BaseOceanSettings, extra=Extra.allow):
78
78
  default_factory=lambda: IntegrationSettings(type="", identifier="")
79
79
  )
80
80
  runtime: Runtime = Runtime.OnPrem
81
+ resources_path: str = Field(default=".port/resources")
81
82
 
82
83
  @root_validator()
83
84
  def validate_integration_config(cls, values: dict[str, Any]) -> dict[str, Any]:
@@ -4,6 +4,7 @@ from typing import Type
4
4
  import httpx
5
5
  from loguru import logger
6
6
 
7
+ from port_ocean.config.settings import IntegrationConfiguration
7
8
  from port_ocean.context.ocean import ocean
8
9
  from port_ocean.core.defaults.common import (
9
10
  get_port_integration_defaults,
@@ -14,12 +15,13 @@ from port_ocean.core.handlers.port_app_config.models import PortAppConfig
14
15
 
15
16
  def clean_defaults(
16
17
  config_class: Type[PortAppConfig],
18
+ integration_config: IntegrationConfiguration,
17
19
  force: bool,
18
20
  wait: bool,
19
21
  ) -> None:
20
22
  try:
21
23
  asyncio.new_event_loop().run_until_complete(
22
- _clean_defaults(config_class, force, wait)
24
+ _clean_defaults(config_class, integration_config, force, wait)
23
25
  )
24
26
 
25
27
  except Exception as e:
@@ -27,13 +29,18 @@ def clean_defaults(
27
29
 
28
30
 
29
31
  async def _clean_defaults(
30
- config_class: Type[PortAppConfig], force: bool, wait: bool
32
+ config_class: Type[PortAppConfig],
33
+ integration_config: IntegrationConfiguration,
34
+ force: bool,
35
+ wait: bool,
31
36
  ) -> None:
32
37
  port_client = ocean.port_client
33
38
  is_exists = await is_integration_exists(port_client)
34
39
  if not is_exists:
35
40
  return None
36
- defaults = get_port_integration_defaults(config_class)
41
+ defaults = get_port_integration_defaults(
42
+ config_class, integration_config.resources_path
43
+ )
37
44
  if not defaults:
38
45
  return None
39
46
 
@@ -3,6 +3,7 @@ from pathlib import Path
3
3
  from typing import Type, Any, TypedDict, Optional
4
4
 
5
5
  import httpx
6
+ from loguru import logger
6
7
  import yaml
7
8
  from pydantic import BaseModel, Field
8
9
  from starlette import status
@@ -77,18 +78,33 @@ def deconstruct_blueprints_to_creation_steps(
77
78
  )
78
79
 
79
80
 
81
+ def is_valid_dir(path: Path) -> bool:
82
+ return path.is_dir()
83
+
84
+
80
85
  def get_port_integration_defaults(
81
- port_app_config_class: Type[PortAppConfig], base_path: Path = Path(".")
86
+ port_app_config_class: Type[PortAppConfig],
87
+ custom_defaults_dir: Optional[str] = None,
88
+ base_path: Path = Path("."),
82
89
  ) -> Defaults | None:
83
- defaults_dir = base_path / ".port/resources"
84
- if not defaults_dir.exists():
85
- return None
86
-
87
- if not defaults_dir.is_dir():
88
- raise UnsupportedDefaultFileType(
89
- f"Defaults directory is not a directory: {defaults_dir}"
90
+ fallback_dir = base_path / ".port/resources"
91
+
92
+ if custom_defaults_dir and is_valid_dir(base_path / custom_defaults_dir):
93
+ defaults_dir = base_path / custom_defaults_dir
94
+ elif is_valid_dir(fallback_dir):
95
+ logger.info(
96
+ f"Could not find custom defaults directory {custom_defaults_dir}, falling back to {fallback_dir}",
97
+ fallback_dir=fallback_dir,
98
+ custom_defaults_dir=custom_defaults_dir,
99
+ )
100
+ defaults_dir = fallback_dir
101
+ else:
102
+ logger.warning(
103
+ f"Could not find defaults directory {fallback_dir}, skipping defaults"
90
104
  )
105
+ return None
91
106
 
107
+ logger.info(f"Loading defaults from {defaults_dir}", defaults_dir=defaults_dir)
92
108
  default_jsons = {}
93
109
  allowed_file_names = [
94
110
  field_model.alias for _, field_model in Defaults.__fields__.items()
@@ -198,7 +198,9 @@ async def _initialize_defaults(
198
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)
201
+ defaults = get_port_integration_defaults(
202
+ config_class, integration_config.resources_path
203
+ )
202
204
  if not defaults:
203
205
  logger.warning("No defaults found. Skipping initialization...")
204
206
  return None
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.1
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
@@ -4,7 +4,7 @@ port_ocean/cli/__init__.py,sha256=ZjTGS305llhbjC2BH2KkVj34gCASBGwqc5HZEO_0T_Q,32
4
4
  port_ocean/cli/cli.py,sha256=RvWTELEn5YFw9aM0vaNqm5YqZZrL50ILaBs27ptiGl0,57
5
5
  port_ocean/cli/commands/__init__.py,sha256=Y9Q6jeYw_ZAZ-mdfE_5DZTdS2KHhieQZoUTggk_AkwM,369
6
6
  port_ocean/cli/commands/defaults/__init___.py,sha256=5OKgakO79bTbplFv1_yWCrw1x_JJqSdRXAHHqKSuEpQ,88
7
- port_ocean/cli/commands/defaults/clean.py,sha256=b3MVxAc9pASGxG3O6AjbDJiFngw82UqclVuCZObVPGM,1544
7
+ port_ocean/cli/commands/defaults/clean.py,sha256=258rOSC1xGT-NTBIkv-V8HTY57ZipnOD-gV5yEenut0,1570
8
8
  port_ocean/cli/commands/defaults/dock.py,sha256=pFtHrU_LTvb5Ddrzj09Wxy-jg1Ym10wBYD-0tpDRugE,1104
9
9
  port_ocean/cli/commands/defaults/group.py,sha256=hii_4CYoQ7jSMePbnP4AmruO_RKWCUcoV7dXXBlZafc,115
10
10
  port_ocean/cli/commands/list_integrations.py,sha256=DVVioFruGUE-_v6UUHlcemWNN6RlWwCrf1X4HmAXsf8,1134
@@ -52,7 +52,7 @@ port_ocean/clients/port/utils.py,sha256=5B6rHgiVrtiL4YWh7Eq7_ncIeDwrDsB7jIvRik5x
52
52
  port_ocean/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
53
53
  port_ocean/config/base.py,sha256=x1gFbzujrxn7EJudRT81C6eN9WsYAb3vOHwcpcpX8Tc,6370
54
54
  port_ocean/config/dynamic.py,sha256=qOFkRoJsn_BW7581omi_AoMxoHqasf_foxDQ_G11_SI,2030
55
- port_ocean/config/settings.py,sha256=77MtPz-ZpOWjuuOcorAy4MSNuYhRE2a9DDBKx3sRrV8,4274
55
+ port_ocean/config/settings.py,sha256=65LATPdQ4YBdUTgQHMtZvzzPVrOxWUqAP7eerwFGZvg,4333
56
56
  port_ocean/consumers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
57
57
  port_ocean/consumers/kafka_consumer.py,sha256=N8KocjBi9aR0BOPG8hgKovg-ns_ggpEjrSxqSqF_BSo,4710
58
58
  port_ocean/context/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -61,9 +61,9 @@ port_ocean/context/ocean.py,sha256=2EreWOj-N2H7QUjEt5wGiv5KHP4pTZc70tn_wHcpF4w,4
61
61
  port_ocean/context/resource.py,sha256=yDj63URzQelj8zJPh4BAzTtPhpKr9Gw9DRn7I_0mJ1s,1692
62
62
  port_ocean/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
63
63
  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
64
+ port_ocean/core/defaults/clean.py,sha256=TOVe5b5FAjFspAkQuKA70k2BClCEFbrQ3xgiAoKXKYE,2427
65
+ port_ocean/core/defaults/common.py,sha256=zJsj7jvlqIMLGXhdASUlbKS8GIAf-FDKKB0O7jB6nx0,4166
66
+ port_ocean/core/defaults/initialize.py,sha256=M1EXgfbnrvP5e3f9or8Bi0-4zXECznfRfy7sJn2Gc14,8471
67
67
  port_ocean/core/event_listener/__init__.py,sha256=mzJ33wRq0kh60fpVdOHVmvMTUQIvz3vxmifyBgwDn0E,889
68
68
  port_ocean/core/event_listener/base.py,sha256=1Nmpg00OfT2AD2L8eFm4VQEcdG2TClpSWJMhWhAjkEE,2356
69
69
  port_ocean/core/event_listener/factory.py,sha256=AYYfSHPAF7P5H-uQECXT0JVJjKDHrYkWJJBSL4mGkg8,3697
@@ -115,13 +115,14 @@ port_ocean/log/handlers.py,sha256=ncVjgqrZRh6BhyRrA6DQG86Wsbxph1yWYuEC0cWfe-Q,36
115
115
  port_ocean/log/logger_setup.py,sha256=CoEDowe5OwNOL_5clU6Z4faktfh0VWaOTS0VLmyhHjw,2404
116
116
  port_ocean/log/sensetive.py,sha256=lVKiZH6b7TkrZAMmhEJRhcl67HNM94e56x12DwFgCQk,2920
117
117
  port_ocean/middlewares.py,sha256=9wYCdyzRZGK1vjEJ28FY_DkfwDNENmXp504UKPf5NaQ,2727
118
- port_ocean/ocean.py,sha256=oUNY9XT30oZ6e6asD6yM2dbd01-uD6RvtJXkmobUn7U,5282
118
+ port_ocean/ocean.py,sha256=NVdvooP0AiGyVs38VE8xXj6bzeT3XLoIPnh5FAS5ouM,5290
119
119
  port_ocean/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
120
120
  port_ocean/run.py,sha256=rTxBlrQd4yyrtgErCFJCHCEHs7d1OXrRiJehUYmIbN0,2212
121
121
  port_ocean/sonar-project.properties,sha256=X_wLzDOkEVmpGLRMb2fg9Rb0DxWwUFSvESId8qpvrPI,73
122
122
  port_ocean/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
123
123
  port_ocean/tests/clients/port/mixins/test_entities.py,sha256=A9myrnkLhKSQrnOLv1Zz2wiOVSxW65Q9RIUIRbn_V7w,1586
124
124
  port_ocean/tests/conftest.py,sha256=JXASSS0IY0nnR6bxBflhzxS25kf4iNaABmThyZ0mZt8,101
125
+ port_ocean/tests/core/defaults/test_common.py,sha256=sR7RqB3ZYV6Xn6NIg-c8k5K6JcGsYZ2SCe_PYX5vLYM,5560
125
126
  port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py,sha256=Yv03P-LDcJCKZ21exiTFrcT1eu0zn6Z954dilxrb52Y,10842
126
127
  port_ocean/tests/helpers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
127
128
  port_ocean/tests/helpers/fixtures.py,sha256=IQEplbHhRgjrAsZlnXrgSYA5YQEn25I9HgO3_Fjibxg,1481
@@ -132,18 +133,19 @@ port_ocean/tests/helpers/smoke_test.py,sha256=_9aJJFRfuGJEg2D2YQJVJRmpreS6gEPHHQ
132
133
  port_ocean/tests/log/test_handlers.py,sha256=bTOGnuj8fMIEXepwYblRvcg0FKqApCdyCBtAQZ2BlXM,2115
133
134
  port_ocean/tests/test_smoke.py,sha256=uix2uIg_yOm8BHDgHw2hTFPy1fiIyxBGW3ENU_KoFlo,2557
134
135
  port_ocean/tests/utils/test_async_iterators.py,sha256=3PLk1emEXekb8LcC5GgVh3OicaX15i5WyaJT_eFnu_4,1336
136
+ port_ocean/tests/utils/test_cache.py,sha256=GzoS8xGCBDbBcPwSDbdimsMMkRvJATrBC7UmFhdW3fw,4906
135
137
  port_ocean/utils/__init__.py,sha256=KMGnCPXZJbNwtgxtyMycapkDz8tpSyw23MSYT3iVeHs,91
136
138
  port_ocean/utils/async_http.py,sha256=arnH458TExn2Dju_Sy6pHas_vF5RMWnOp-jBz5WAAcE,1226
137
139
  port_ocean/utils/async_iterators.py,sha256=CPXskYWkhkZtAG-ducEwM8537t3z5usPEqXR9vcivzw,3715
138
- port_ocean/utils/cache.py,sha256=3KItZDE2yVrbVDr-hoM8lNna8s2dlpxhP4ICdLjH4LQ,2231
140
+ port_ocean/utils/cache.py,sha256=RgfN4SjjHrEkbqUChyboeD1mrXomolUUjsJtvbkmr3U,3353
139
141
  port_ocean/utils/misc.py,sha256=0q2cJ5psqxn_5u_56pT7vOVQ3shDM02iC1lzyWQ_zl0,2098
140
142
  port_ocean/utils/queue_utils.py,sha256=KWWl8YVnG-glcfIHhM6nefY-2sou_C6DVP1VynQwzB4,2762
141
143
  port_ocean/utils/repeat.py,sha256=0EFWM9d8lLXAhZmAyczY20LAnijw6UbIECf5lpGbOas,3231
142
144
  port_ocean/utils/signal.py,sha256=K-6kKFQTltcmKDhtyZAcn0IMa3sUpOHGOAUdWKgx0_E,1369
143
145
  port_ocean/utils/time.py,sha256=pufAOH5ZQI7gXvOvJoQXZXZJV-Dqktoj9Qp9eiRwmJ4,1939
144
146
  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,,
147
+ port_ocean-0.14.1.dist-info/LICENSE.md,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
148
+ port_ocean-0.14.1.dist-info/METADATA,sha256=wOX1EZAWACc4Y91LXEhR497CEE8Vtk8UPsHZDStMaME,6673
149
+ port_ocean-0.14.1.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
150
+ port_ocean-0.14.1.dist-info/entry_points.txt,sha256=F_DNUmGZU2Kme-8NsWM5LLE8piGMafYZygRYhOVtcjA,54
151
+ port_ocean-0.14.1.dist-info/RECORD,,