port-ocean 0.14.0__tar.gz → 0.14.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

Files changed (150) hide show
  1. {port_ocean-0.14.0 → port_ocean-0.14.1}/PKG-INFO +1 -1
  2. port_ocean-0.14.1/port_ocean/tests/utils/test_cache.py +189 -0
  3. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/utils/cache.py +37 -1
  4. {port_ocean-0.14.0 → port_ocean-0.14.1}/pyproject.toml +1 -1
  5. {port_ocean-0.14.0 → port_ocean-0.14.1}/LICENSE.md +0 -0
  6. {port_ocean-0.14.0 → port_ocean-0.14.1}/README.md +0 -0
  7. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/__init__.py +0 -0
  8. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/bootstrap.py +0 -0
  9. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/cli/__init__.py +0 -0
  10. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/cli/cli.py +0 -0
  11. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/cli/commands/__init__.py +0 -0
  12. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/cli/commands/defaults/__init___.py +0 -0
  13. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/cli/commands/defaults/clean.py +0 -0
  14. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/cli/commands/defaults/dock.py +0 -0
  15. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/cli/commands/defaults/group.py +0 -0
  16. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/cli/commands/list_integrations.py +0 -0
  17. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/cli/commands/main.py +0 -0
  18. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/cli/commands/new.py +0 -0
  19. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/cli/commands/pull.py +0 -0
  20. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/cli/commands/sail.py +0 -0
  21. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/cli/commands/version.py +0 -0
  22. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/cli/cookiecutter/__init__.py +0 -0
  23. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/cli/cookiecutter/cookiecutter.json +0 -0
  24. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/cli/cookiecutter/extensions.py +0 -0
  25. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/cli/cookiecutter/hooks/post_gen_project.py +0 -0
  26. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.dockerignore +0 -0
  27. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.env.example +0 -0
  28. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.gitignore +0 -0
  29. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/resources/.gitignore +0 -0
  30. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/resources/blueprints.json +0 -0
  31. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/resources/port-app-config.yml +0 -0
  32. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/spec.yaml +0 -0
  33. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/CHANGELOG.md +0 -0
  34. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/CONTRIBUTING.md +0 -0
  35. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/Dockerfile +0 -0
  36. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/README.md +0 -0
  37. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/changelog/.gitignore +0 -0
  38. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/debug.py +0 -0
  39. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/main.py +0 -0
  40. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/poetry.toml +0 -0
  41. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/pyproject.toml +0 -0
  42. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/sonar-project.properties +0 -0
  43. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/tests/__init__.py +0 -0
  44. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/tests/test_sample.py +0 -0
  45. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/cli/utils.py +0 -0
  46. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/clients/__init__.py +0 -0
  47. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/clients/port/__init__.py +0 -0
  48. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/clients/port/authentication.py +0 -0
  49. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/clients/port/client.py +0 -0
  50. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/clients/port/mixins/__init__.py +0 -0
  51. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/clients/port/mixins/blueprints.py +0 -0
  52. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/clients/port/mixins/entities.py +0 -0
  53. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/clients/port/mixins/integrations.py +0 -0
  54. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/clients/port/mixins/migrations.py +0 -0
  55. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/clients/port/retry_transport.py +0 -0
  56. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/clients/port/types.py +0 -0
  57. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/clients/port/utils.py +0 -0
  58. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/config/__init__.py +0 -0
  59. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/config/base.py +0 -0
  60. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/config/dynamic.py +0 -0
  61. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/config/settings.py +0 -0
  62. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/consumers/__init__.py +0 -0
  63. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/consumers/kafka_consumer.py +0 -0
  64. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/context/__init__.py +0 -0
  65. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/context/event.py +0 -0
  66. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/context/ocean.py +0 -0
  67. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/context/resource.py +0 -0
  68. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/core/__init__.py +0 -0
  69. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/core/defaults/__init__.py +0 -0
  70. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/core/defaults/clean.py +0 -0
  71. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/core/defaults/common.py +0 -0
  72. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/core/defaults/initialize.py +0 -0
  73. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/core/event_listener/__init__.py +0 -0
  74. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/core/event_listener/base.py +0 -0
  75. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/core/event_listener/factory.py +0 -0
  76. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/core/event_listener/http.py +0 -0
  77. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/core/event_listener/kafka.py +0 -0
  78. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/core/event_listener/once.py +0 -0
  79. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/core/event_listener/polling.py +0 -0
  80. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/core/handlers/__init__.py +0 -0
  81. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/core/handlers/base.py +0 -0
  82. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/core/handlers/entities_state_applier/__init__.py +0 -0
  83. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/core/handlers/entities_state_applier/base.py +0 -0
  84. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/core/handlers/entities_state_applier/port/__init__.py +0 -0
  85. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/core/handlers/entities_state_applier/port/applier.py +0 -0
  86. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/core/handlers/entities_state_applier/port/get_related_entities.py +0 -0
  87. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/core/handlers/entities_state_applier/port/order_by_entities_dependencies.py +0 -0
  88. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/core/handlers/entity_processor/__init__.py +0 -0
  89. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/core/handlers/entity_processor/base.py +0 -0
  90. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/core/handlers/entity_processor/jq_entity_processor.py +0 -0
  91. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/core/handlers/port_app_config/__init__.py +0 -0
  92. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/core/handlers/port_app_config/api.py +0 -0
  93. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/core/handlers/port_app_config/base.py +0 -0
  94. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/core/handlers/port_app_config/models.py +0 -0
  95. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/core/handlers/resync_state_updater/__init__.py +0 -0
  96. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/core/handlers/resync_state_updater/updater.py +0 -0
  97. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/core/integrations/__init__.py +0 -0
  98. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/core/integrations/base.py +0 -0
  99. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/core/integrations/mixins/__init__.py +0 -0
  100. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/core/integrations/mixins/events.py +0 -0
  101. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/core/integrations/mixins/handler.py +0 -0
  102. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/core/integrations/mixins/sync.py +0 -0
  103. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/core/integrations/mixins/sync_raw.py +0 -0
  104. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/core/integrations/mixins/utils.py +0 -0
  105. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/core/models.py +0 -0
  106. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/core/ocean_types.py +0 -0
  107. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/core/utils.py +0 -0
  108. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/exceptions/__init__.py +0 -0
  109. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/exceptions/api.py +0 -0
  110. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/exceptions/base.py +0 -0
  111. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/exceptions/clients.py +0 -0
  112. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/exceptions/context.py +0 -0
  113. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/exceptions/core.py +0 -0
  114. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/exceptions/port_defaults.py +0 -0
  115. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/exceptions/utils.py +0 -0
  116. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/helpers/__init__.py +0 -0
  117. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/helpers/async_client.py +0 -0
  118. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/helpers/retry.py +0 -0
  119. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/log/__init__.py +0 -0
  120. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/log/handlers.py +0 -0
  121. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/log/logger_setup.py +0 -0
  122. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/log/sensetive.py +0 -0
  123. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/middlewares.py +0 -0
  124. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/ocean.py +0 -0
  125. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/py.typed +0 -0
  126. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/run.py +0 -0
  127. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/sonar-project.properties +0 -0
  128. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/tests/__init__.py +0 -0
  129. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/tests/clients/port/mixins/test_entities.py +0 -0
  130. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/tests/conftest.py +0 -0
  131. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/tests/core/defaults/test_common.py +0 -0
  132. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py +0 -0
  133. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/tests/helpers/__init__.py +0 -0
  134. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/tests/helpers/fixtures.py +0 -0
  135. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/tests/helpers/integration.py +0 -0
  136. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/tests/helpers/ocean_app.py +0 -0
  137. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/tests/helpers/port_client.py +0 -0
  138. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/tests/helpers/smoke_test.py +0 -0
  139. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/tests/log/test_handlers.py +0 -0
  140. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/tests/test_smoke.py +0 -0
  141. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/tests/utils/test_async_iterators.py +0 -0
  142. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/utils/__init__.py +0 -0
  143. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/utils/async_http.py +0 -0
  144. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/utils/async_iterators.py +0 -0
  145. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/utils/misc.py +0 -0
  146. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/utils/queue_utils.py +0 -0
  147. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/utils/repeat.py +0 -0
  148. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/utils/signal.py +0 -0
  149. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/utils/time.py +0 -0
  150. {port_ocean-0.14.0 → port_ocean-0.14.1}/port_ocean/version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: port-ocean
3
- Version: 0.14.0
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
@@ -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
@@ -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
  [tool.poetry]
2
2
  name = "port-ocean"
3
- version = "0.14.0"
3
+ version = "0.14.1"
4
4
  description = "Port Ocean is a CLI tool for managing your Port projects."
5
5
  readme = "README.md"
6
6
  homepage = "https://app.getport.io"
File without changes
File without changes