port-ocean 0.5.17__tar.gz → 0.5.19__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 (130) hide show
  1. {port_ocean-0.5.17 → port_ocean-0.5.19}/PKG-INFO +1 -1
  2. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/config/settings.py +1 -0
  3. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/core/handlers/entity_processor/jq_entity_processor.py +11 -14
  4. port_ocean-0.5.19/port_ocean/core/handlers/port_app_config/base.py +82 -0
  5. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/core/integrations/mixins/sync_raw.py +5 -1
  6. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/core/utils.py +27 -31
  7. port_ocean-0.5.19/port_ocean/utils/queue_utils.py +81 -0
  8. {port_ocean-0.5.17 → port_ocean-0.5.19}/pyproject.toml +2 -2
  9. port_ocean-0.5.17/port_ocean/core/handlers/port_app_config/base.py +0 -44
  10. {port_ocean-0.5.17 → port_ocean-0.5.19}/LICENSE.md +0 -0
  11. {port_ocean-0.5.17 → port_ocean-0.5.19}/README.md +0 -0
  12. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/__init__.py +0 -0
  13. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/bootstrap.py +0 -0
  14. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/cli/__init__.py +0 -0
  15. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/cli/cli.py +0 -0
  16. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/cli/commands/__init__.py +0 -0
  17. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/cli/commands/defaults/__init___.py +0 -0
  18. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/cli/commands/defaults/clean.py +0 -0
  19. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/cli/commands/defaults/dock.py +0 -0
  20. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/cli/commands/defaults/group.py +0 -0
  21. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/cli/commands/list_integrations.py +0 -0
  22. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/cli/commands/main.py +0 -0
  23. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/cli/commands/new.py +0 -0
  24. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/cli/commands/pull.py +0 -0
  25. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/cli/commands/sail.py +0 -0
  26. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/cli/commands/version.py +0 -0
  27. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/cli/cookiecutter/__init__.py +0 -0
  28. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/cli/cookiecutter/cookiecutter.json +0 -0
  29. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/cli/cookiecutter/extensions.py +0 -0
  30. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/cli/cookiecutter/hooks/post_gen_project.py +0 -0
  31. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.dockerignore +0 -0
  32. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.gitignore +0 -0
  33. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/resources/.gitignore +0 -0
  34. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/spec.yaml +0 -0
  35. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/CHANGELOG.md +0 -0
  36. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/Dockerfile +0 -0
  37. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/Makefile +0 -0
  38. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/README.md +0 -0
  39. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/changelog/.gitignore +0 -0
  40. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/config.yaml +0 -0
  41. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/debug.py +0 -0
  42. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/main.py +0 -0
  43. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/poetry.toml +0 -0
  44. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/pyproject.toml +0 -0
  45. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/sonar-project.properties +0 -0
  46. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/tests/__init__.py +0 -0
  47. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/cli/utils.py +0 -0
  48. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/clients/__init__.py +0 -0
  49. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/clients/port/__init__.py +0 -0
  50. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/clients/port/authentication.py +0 -0
  51. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/clients/port/client.py +0 -0
  52. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/clients/port/mixins/__init__.py +0 -0
  53. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/clients/port/mixins/blueprints.py +0 -0
  54. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/clients/port/mixins/entities.py +0 -0
  55. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/clients/port/mixins/integrations.py +0 -0
  56. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/clients/port/mixins/migrations.py +0 -0
  57. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/clients/port/retry_transport.py +0 -0
  58. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/clients/port/types.py +0 -0
  59. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/clients/port/utils.py +0 -0
  60. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/config/__init__.py +0 -0
  61. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/config/base.py +0 -0
  62. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/config/dynamic.py +0 -0
  63. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/consumers/__init__.py +0 -0
  64. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/consumers/kafka_consumer.py +0 -0
  65. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/context/__init__.py +0 -0
  66. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/context/event.py +0 -0
  67. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/context/ocean.py +0 -0
  68. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/context/resource.py +0 -0
  69. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/core/__init__.py +0 -0
  70. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/core/defaults/__init__.py +0 -0
  71. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/core/defaults/clean.py +0 -0
  72. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/core/defaults/common.py +0 -0
  73. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/core/defaults/initialize.py +0 -0
  74. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/core/event_listener/__init__.py +0 -0
  75. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/core/event_listener/base.py +0 -0
  76. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/core/event_listener/factory.py +0 -0
  77. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/core/event_listener/http.py +0 -0
  78. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/core/event_listener/kafka.py +0 -0
  79. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/core/event_listener/once.py +0 -0
  80. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/core/event_listener/polling.py +0 -0
  81. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/core/handlers/__init__.py +0 -0
  82. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/core/handlers/base.py +0 -0
  83. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/core/handlers/entities_state_applier/__init__.py +0 -0
  84. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/core/handlers/entities_state_applier/base.py +0 -0
  85. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/core/handlers/entities_state_applier/port/__init__.py +0 -0
  86. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/core/handlers/entities_state_applier/port/applier.py +0 -0
  87. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/core/handlers/entities_state_applier/port/get_related_entities.py +0 -0
  88. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/core/handlers/entities_state_applier/port/order_by_entities_dependencies.py +0 -0
  89. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/core/handlers/entity_processor/__init__.py +0 -0
  90. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/core/handlers/entity_processor/base.py +0 -0
  91. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/core/handlers/port_app_config/__init__.py +0 -0
  92. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/core/handlers/port_app_config/api.py +0 -0
  93. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/core/handlers/port_app_config/models.py +0 -0
  94. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/core/integrations/__init__.py +0 -0
  95. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/core/integrations/base.py +0 -0
  96. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/core/integrations/mixins/__init__.py +0 -0
  97. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/core/integrations/mixins/events.py +0 -0
  98. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/core/integrations/mixins/handler.py +0 -0
  99. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/core/integrations/mixins/sync.py +0 -0
  100. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/core/integrations/mixins/utils.py +0 -0
  101. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/core/models.py +0 -0
  102. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/core/ocean_types.py +0 -0
  103. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/exceptions/__init__.py +0 -0
  104. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/exceptions/api.py +0 -0
  105. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/exceptions/base.py +0 -0
  106. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/exceptions/clients.py +0 -0
  107. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/exceptions/context.py +0 -0
  108. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/exceptions/core.py +0 -0
  109. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/exceptions/port_defaults.py +0 -0
  110. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/exceptions/utils.py +0 -0
  111. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/helpers/__init__.py +0 -0
  112. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/helpers/async_client.py +0 -0
  113. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/helpers/retry.py +0 -0
  114. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/log/__init__.py +0 -0
  115. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/log/handlers.py +0 -0
  116. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/log/logger_setup.py +0 -0
  117. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/log/sensetive.py +0 -0
  118. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/middlewares.py +0 -0
  119. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/ocean.py +0 -0
  120. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/py.typed +0 -0
  121. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/run.py +0 -0
  122. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/sonar-project.properties +0 -0
  123. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/utils/__init__.py +0 -0
  124. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/utils/async_http.py +0 -0
  125. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/utils/async_iterators.py +0 -0
  126. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/utils/cache.py +0 -0
  127. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/utils/misc.py +0 -0
  128. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/utils/repeat.py +0 -0
  129. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/utils/signal.py +0 -0
  130. {port_ocean-0.5.17 → port_ocean-0.5.19}/port_ocean/version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: port-ocean
3
- Version: 0.5.17
3
+ Version: 0.5.19
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
@@ -36,6 +36,7 @@ class PortSettings(BaseOceanModel, extra=Extra.allow):
36
36
  client_id: str = Field(..., sensitive=True)
37
37
  client_secret: str = Field(..., sensitive=True)
38
38
  base_url: AnyHttpUrl = parse_obj_as(AnyHttpUrl, "https://api.getport.io")
39
+ port_app_config_cache_ttl: int = 60
39
40
 
40
41
 
41
42
  class IntegrationSettings(BaseOceanModel, extra=Extra.allow):
@@ -14,6 +14,7 @@ from port_ocean.core.ocean_types import (
14
14
  EntitySelectorDiff,
15
15
  )
16
16
  from port_ocean.exceptions.core import EntityProcessorException
17
+ from port_ocean.utils.queue_utils import process_in_queue
17
18
 
18
19
 
19
20
  class JQEntityProcessor(BaseEntityProcessor):
@@ -128,23 +129,19 @@ class JQEntityProcessor(BaseEntityProcessor):
128
129
  raw_entity_mappings: dict[str, Any] = mapping.port.entity.mappings.dict(
129
130
  exclude_unset=True
130
131
  )
131
- calculate_entities_tasks = [
132
- asyncio.create_task(
133
- self._calculate_entity(
134
- data,
135
- raw_entity_mappings,
136
- mapping.port.items_to_parse,
137
- mapping.selector.query,
138
- parse_all,
139
- )
140
- )
141
- for data in raw_results
142
- ]
143
- calculate_entities_results = await asyncio.gather(*calculate_entities_tasks)
132
+
133
+ calculated_entities_results = await process_in_queue(
134
+ raw_results,
135
+ self._calculate_entity,
136
+ raw_entity_mappings,
137
+ mapping.port.items_to_parse,
138
+ mapping.selector.query,
139
+ parse_all,
140
+ )
144
141
 
145
142
  passed_entities = []
146
143
  failed_entities = []
147
- for entities_results in calculate_entities_results:
144
+ for entities_results in calculated_entities_results:
148
145
  for entity, did_entity_pass_selector in entities_results:
149
146
  if entity.get("identifier") and entity.get("blueprint"):
150
147
  parsed_entity = Entity.parse_obj(entity)
@@ -0,0 +1,82 @@
1
+ from abc import abstractmethod
2
+ from typing import Type, Any
3
+
4
+ from loguru import logger
5
+ from pydantic import ValidationError
6
+
7
+ from port_ocean.context.event import event
8
+ from port_ocean.context.ocean import PortOceanContext
9
+ from port_ocean.core.handlers.base import BaseHandler
10
+ from port_ocean.core.handlers.port_app_config.models import PortAppConfig
11
+ from port_ocean.utils.misc import get_time
12
+
13
+
14
+ class PortAppConfigCache:
15
+ _port_app_config: PortAppConfig | None
16
+ _retrieval_time: float
17
+
18
+ def __init__(self, cache_ttl: int):
19
+ self._cache_ttl = cache_ttl
20
+
21
+ @property
22
+ def port_app_config(self) -> PortAppConfig:
23
+ if self._port_app_config is None:
24
+ raise ValueError("Port app config is not set")
25
+ return self._port_app_config
26
+
27
+ @port_app_config.setter
28
+ def port_app_config(self, value: PortAppConfig) -> None:
29
+ self._retrieval_time = get_time()
30
+ self._port_app_config = value
31
+
32
+ @property
33
+ def is_cache_invalid(self) -> bool:
34
+ return (
35
+ not self._port_app_config
36
+ or self._retrieval_time + self._cache_ttl < get_time()
37
+ )
38
+
39
+
40
+ class BasePortAppConfig(BaseHandler):
41
+ """Abstract base class for managing port application configurations.
42
+
43
+ This class defines methods for obtaining and processing port application configurations.
44
+
45
+ Attributes:
46
+ context (Any): The context to be used during port application configuration.
47
+ CONFIG_CLASS (Type[PortAppConfig]): The class used for defining port application configuration settings.
48
+ """
49
+
50
+ CONFIG_CLASS: Type[PortAppConfig] = PortAppConfig
51
+
52
+ def __init__(self, context: PortOceanContext):
53
+ super().__init__(context)
54
+ self._app_config_cache = PortAppConfigCache(
55
+ self.context.config.port.port_app_config_cache_ttl
56
+ )
57
+
58
+ @abstractmethod
59
+ async def _get_port_app_config(self) -> dict[str, Any]:
60
+ pass
61
+
62
+ async def get_port_app_config(self, use_cache: bool = True) -> PortAppConfig:
63
+ """
64
+ Retrieve and parse the port application configuration.
65
+
66
+ :param use_cache: Determines whether to use the cached port-app-config if it exists, or to fetch it regardless
67
+ :return: The parsed port application configuration.
68
+ """
69
+ if not use_cache or self._app_config_cache.is_cache_invalid:
70
+ raw_config = await self._get_port_app_config()
71
+ try:
72
+ self._app_config_cache.port_app_config = self.CONFIG_CLASS.parse_obj(
73
+ raw_config
74
+ )
75
+ except ValidationError:
76
+ logger.error(
77
+ "Invalid port app config found. Please check that the integration has been configured correctly."
78
+ )
79
+ raise
80
+
81
+ event.port_app_config = self._app_config_cache.port_app_config
82
+ return self._app_config_cache.port_app_config
@@ -362,7 +362,11 @@ class SyncRawMixin(HandlerMixin, EventsMixin):
362
362
  EventType.RESYNC,
363
363
  trigger_type=trigger_type,
364
364
  ):
365
- app_config = await self.port_app_config_handler.get_port_app_config()
365
+ # If a resync is triggered due to a mappings change, we want to make sure that we have the updated version
366
+ # rather than the old cache
367
+ app_config = await self.port_app_config_handler.get_port_app_config(
368
+ use_cache=False
369
+ )
366
370
 
367
371
  creation_results: list[tuple[list[Entity], list[Exception]]] = []
368
372
 
@@ -28,38 +28,34 @@ def is_same_entity(first_entity: Entity, second_entity: Entity) -> bool:
28
28
  )
29
29
 
30
30
 
31
- def get_unique(array: list[Entity]) -> list[Entity]:
32
- result: list[Entity] = []
33
- for item in array:
34
- if all(not is_same_entity(item, seen_item) for seen_item in result):
35
- result.append(item)
36
- return result
37
-
38
-
39
31
  def get_port_diff(
40
32
  before: Iterable[Entity],
41
33
  after: Iterable[Entity],
42
34
  ) -> EntityPortDiff:
43
- return EntityPortDiff(
44
- deleted=get_unique(
45
- [
46
- item
47
- for item in before
48
- if not any(is_same_entity(item, item_after) for item_after in after)
49
- ],
50
- ),
51
- created=get_unique(
52
- [
53
- item
54
- for item in after
55
- if not any(is_same_entity(item, item_before) for item_before in before)
56
- ],
57
- ),
58
- modified=get_unique(
59
- [
60
- item
61
- for item in after
62
- if any(is_same_entity(item, item_before) for item_before in before)
63
- ],
64
- ),
65
- )
35
+ before_dict = {}
36
+ after_dict = {}
37
+ created = []
38
+ modified = []
39
+ deleted = []
40
+
41
+ # Create dictionaries for before and after lists
42
+ for entity in before:
43
+ key = (entity.identifier, entity.blueprint)
44
+ before_dict[key] = entity
45
+
46
+ for entity in after:
47
+ key = (entity.identifier, entity.blueprint)
48
+ after_dict[key] = entity
49
+
50
+ # Find created, modified, and deleted objects
51
+ for key, obj in after_dict.items():
52
+ if key not in before_dict:
53
+ created.append(obj)
54
+ else:
55
+ modified.append(obj)
56
+
57
+ for key, obj in before_dict.items():
58
+ if key not in after_dict:
59
+ deleted.append(obj)
60
+
61
+ return EntityPortDiff(created=created, modified=modified, deleted=deleted)
@@ -0,0 +1,81 @@
1
+ import asyncio
2
+ from asyncio import Queue, Task
3
+ from typing import Any, TypeVar, Callable, Coroutine
4
+
5
+ from loguru import logger
6
+
7
+ T = TypeVar("T")
8
+
9
+
10
+ async def _start_processor_worker(
11
+ queue: Queue[Any | None],
12
+ func: Callable[..., Coroutine[Any, Any, T]],
13
+ results: list[T],
14
+ ) -> None:
15
+ while True:
16
+ raw_params = await queue.get()
17
+ try:
18
+ if raw_params is None:
19
+ return
20
+ logger.debug(f"Processing {raw_params[0]}")
21
+ results.append(await func(*raw_params))
22
+ finally:
23
+ queue.task_done()
24
+
25
+
26
+ async def process_in_queue(
27
+ objects_to_process: list[Any],
28
+ func: Callable[..., Coroutine[Any, Any, T]],
29
+ *args: Any,
30
+ concurrency: int = 50,
31
+ ) -> list[T]:
32
+ """
33
+ This function executes multiple asynchronous tasks in a bounded way
34
+ (e.g. having 200 tasks to execute, while running only 20 concurrently),
35
+ to prevent overload and memory issues when dealing with large sets of data and tasks.
36
+ read more -> https://stackoverflow.com/questions/38831322/making-1-milion-requests-with-aiohttp-asyncio-literally
37
+
38
+ Usage:
39
+ ```python
40
+ async def incrementBy(num: int, increment_by: int) -> int:
41
+ await asyncio.sleep(3)
42
+ return num + increment_by
43
+
44
+ async def main():
45
+ raw_objects = [1, 2, 3, 4, 5]
46
+ processed_objects = await process_in_queue(
47
+ raw_objects,
48
+ incrementBy,
49
+ 5
50
+ )
51
+ ```
52
+
53
+ :param objects_to_process: A list of the raw objects to process
54
+ :param func: An async function that turns raw object into result object
55
+ :param args: Static arguments to pass to the func when called
56
+ :param concurrency: An integer specifying the concurrent workers count
57
+ :return: A list of result objects
58
+ """
59
+ queue: Queue[Any | None] = Queue(maxsize=concurrency * 2)
60
+ tasks: list[Task[Any]] = []
61
+ processing_results: list[T] = []
62
+
63
+ for i in range(concurrency):
64
+ tasks.append(
65
+ asyncio.create_task(
66
+ _start_processor_worker(queue, func, processing_results)
67
+ )
68
+ )
69
+
70
+ for i in range(len(objects_to_process)):
71
+ await queue.put((objects_to_process[i], *args))
72
+
73
+ for i in range(concurrency):
74
+ # We put None value into the queue, so the workers will know that we
75
+ # are done sending more input and they can terminate
76
+ await queue.put(None)
77
+
78
+ await queue.join()
79
+ await asyncio.gather(*tasks)
80
+
81
+ return processing_results
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "port-ocean"
3
- version = "0.5.17"
3
+ version = "0.5.19"
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"
@@ -68,7 +68,7 @@ black = ">=23.3,<25.0"
68
68
  mypy = "^1.3.0"
69
69
  pylint = ">=2.17.4,<4.0.0"
70
70
  types-pyyaml = "^6.0.12.10"
71
- ruff = ">=0.0.278,<0.4.3"
71
+ ruff = ">=0.0.278,<0.4.4"
72
72
  types-toml = "^0.10.8.6"
73
73
  towncrier = "^23.6.0"
74
74
  yamllint = "^1.32.0"
@@ -1,44 +0,0 @@
1
- from abc import abstractmethod
2
- from typing import Type, Any
3
-
4
- from loguru import logger
5
- from pydantic import ValidationError
6
-
7
- from port_ocean.context.event import event
8
- from port_ocean.core.handlers.base import BaseHandler
9
- from port_ocean.core.handlers.port_app_config.models import PortAppConfig
10
-
11
-
12
- class BasePortAppConfig(BaseHandler):
13
- """Abstract base class for managing port application configurations.
14
-
15
- This class defines methods for obtaining and processing port application configurations.
16
-
17
- Attributes:
18
- context (Any): The context to be used during port application configuration.
19
- CONFIG_CLASS (Type[PortAppConfig]): The class used for defining port application configuration settings.
20
- """
21
-
22
- CONFIG_CLASS: Type[PortAppConfig] = PortAppConfig
23
-
24
- @abstractmethod
25
- async def _get_port_app_config(self) -> dict[str, Any]:
26
- pass
27
-
28
- async def get_port_app_config(self) -> PortAppConfig:
29
- """Retrieve and parse the port application configuration.
30
-
31
- Returns:
32
- PortAppConfig: The parsed port application configuration.
33
- """
34
- raw_config = await self._get_port_app_config()
35
- try:
36
- config = self.CONFIG_CLASS.parse_obj(raw_config)
37
- except ValidationError:
38
- logger.error(
39
- "Invalid port app config found. Please check that the integration has been configured correctly."
40
- )
41
- raise
42
-
43
- event.port_app_config = config
44
- return config
File without changes
File without changes