port-ocean 0.5.9__tar.gz → 0.5.11__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 (128) hide show
  1. {port_ocean-0.5.9 → port_ocean-0.5.11}/PKG-INFO +1 -1
  2. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/clients/port/authentication.py +3 -1
  3. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/clients/port/mixins/entities.py +2 -52
  4. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/clients/port/retry_transport.py +0 -5
  5. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/config/settings.py +9 -2
  6. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/handlers/entities_state_applier/port/applier.py +13 -75
  7. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/integrations/mixins/sync_raw.py +4 -3
  8. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/helpers/retry.py +49 -4
  9. {port_ocean-0.5.9 → port_ocean-0.5.11}/pyproject.toml +1 -1
  10. port_ocean-0.5.9/port_ocean/core/handlers/entities_state_applier/port/validate_entity_relations.py +0 -40
  11. {port_ocean-0.5.9 → port_ocean-0.5.11}/LICENSE.md +0 -0
  12. {port_ocean-0.5.9 → port_ocean-0.5.11}/README.md +0 -0
  13. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/__init__.py +0 -0
  14. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/bootstrap.py +0 -0
  15. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/__init__.py +0 -0
  16. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/cli.py +0 -0
  17. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/commands/__init__.py +0 -0
  18. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/commands/defaults/__init___.py +0 -0
  19. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/commands/defaults/clean.py +0 -0
  20. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/commands/defaults/dock.py +0 -0
  21. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/commands/defaults/group.py +0 -0
  22. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/commands/list_integrations.py +0 -0
  23. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/commands/main.py +0 -0
  24. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/commands/new.py +0 -0
  25. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/commands/pull.py +0 -0
  26. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/commands/sail.py +0 -0
  27. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/commands/version.py +0 -0
  28. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/cookiecutter/__init__.py +0 -0
  29. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/cookiecutter/cookiecutter.json +0 -0
  30. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/cookiecutter/extensions.py +0 -0
  31. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/cookiecutter/hooks/post_gen_project.py +0 -0
  32. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.dockerignore +0 -0
  33. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.gitignore +0 -0
  34. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/resources/.gitignore +0 -0
  35. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/spec.yaml +0 -0
  36. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/CHANGELOG.md +0 -0
  37. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/Dockerfile +0 -0
  38. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/Makefile +0 -0
  39. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/README.md +0 -0
  40. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/changelog/.gitignore +0 -0
  41. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/config.yaml +0 -0
  42. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/debug.py +0 -0
  43. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/main.py +0 -0
  44. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/poetry.toml +0 -0
  45. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/pyproject.toml +0 -0
  46. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/sonar-project.properties +0 -0
  47. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/tests/__init__.py +0 -0
  48. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/utils.py +0 -0
  49. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/clients/__init__.py +0 -0
  50. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/clients/port/__init__.py +0 -0
  51. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/clients/port/client.py +0 -0
  52. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/clients/port/mixins/__init__.py +0 -0
  53. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/clients/port/mixins/blueprints.py +0 -0
  54. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/clients/port/mixins/integrations.py +0 -0
  55. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/clients/port/mixins/migrations.py +0 -0
  56. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/clients/port/types.py +0 -0
  57. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/clients/port/utils.py +0 -0
  58. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/config/__init__.py +0 -0
  59. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/config/base.py +0 -0
  60. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/config/dynamic.py +0 -0
  61. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/consumers/__init__.py +0 -0
  62. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/consumers/kafka_consumer.py +0 -0
  63. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/context/__init__.py +0 -0
  64. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/context/event.py +0 -0
  65. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/context/ocean.py +0 -0
  66. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/context/resource.py +0 -0
  67. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/__init__.py +0 -0
  68. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/defaults/__init__.py +0 -0
  69. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/defaults/clean.py +0 -0
  70. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/defaults/common.py +0 -0
  71. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/defaults/initialize.py +0 -0
  72. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/event_listener/__init__.py +0 -0
  73. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/event_listener/base.py +0 -0
  74. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/event_listener/factory.py +0 -0
  75. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/event_listener/http.py +0 -0
  76. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/event_listener/kafka.py +0 -0
  77. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/event_listener/once.py +0 -0
  78. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/event_listener/polling.py +0 -0
  79. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/handlers/__init__.py +0 -0
  80. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/handlers/base.py +0 -0
  81. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/handlers/entities_state_applier/__init__.py +0 -0
  82. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/handlers/entities_state_applier/base.py +0 -0
  83. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/handlers/entities_state_applier/port/__init__.py +0 -0
  84. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/handlers/entities_state_applier/port/get_related_entities.py +0 -0
  85. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/handlers/entities_state_applier/port/order_by_entities_dependencies.py +0 -0
  86. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/handlers/entity_processor/__init__.py +0 -0
  87. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/handlers/entity_processor/base.py +0 -0
  88. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/handlers/entity_processor/jq_entity_processor.py +0 -0
  89. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/handlers/port_app_config/__init__.py +0 -0
  90. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/handlers/port_app_config/api.py +0 -0
  91. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/handlers/port_app_config/base.py +0 -0
  92. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/handlers/port_app_config/models.py +0 -0
  93. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/integrations/__init__.py +0 -0
  94. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/integrations/base.py +0 -0
  95. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/integrations/mixins/__init__.py +0 -0
  96. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/integrations/mixins/events.py +0 -0
  97. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/integrations/mixins/handler.py +0 -0
  98. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/integrations/mixins/sync.py +0 -0
  99. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/integrations/mixins/utils.py +0 -0
  100. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/models.py +0 -0
  101. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/ocean_types.py +0 -0
  102. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/utils.py +0 -0
  103. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/exceptions/__init__.py +0 -0
  104. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/exceptions/api.py +0 -0
  105. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/exceptions/base.py +0 -0
  106. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/exceptions/clients.py +0 -0
  107. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/exceptions/context.py +0 -0
  108. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/exceptions/core.py +0 -0
  109. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/exceptions/port_defaults.py +0 -0
  110. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/exceptions/utils.py +0 -0
  111. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/helpers/__init__.py +0 -0
  112. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/helpers/async_client.py +0 -0
  113. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/log/__init__.py +0 -0
  114. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/log/handlers.py +0 -0
  115. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/log/logger_setup.py +0 -0
  116. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/log/sensetive.py +0 -0
  117. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/middlewares.py +0 -0
  118. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/ocean.py +0 -0
  119. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/py.typed +0 -0
  120. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/run.py +0 -0
  121. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/sonar-project.properties +0 -0
  122. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/utils/__init__.py +0 -0
  123. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/utils/async_http.py +0 -0
  124. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/utils/cache.py +0 -0
  125. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/utils/misc.py +0 -0
  126. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/utils/repeat.py +0 -0
  127. {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/utils/signal.py +0 -0
  128. {port_ocean-0.5.9 → port_ocean-0.5.11}/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.9
3
+ Version: 0.5.11
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
@@ -49,7 +49,9 @@ class PortAuthentication:
49
49
 
50
50
  credentials = {"clientId": client_id, "clientSecret": client_secret}
51
51
  response = await self.client.post(
52
- f"{self.api_url}/auth/access_token", json=credentials
52
+ f"{self.api_url}/auth/access_token",
53
+ json=credentials,
54
+ extensions={"retryable": True},
53
55
  )
54
56
  handle_status_code(response)
55
57
  return TokenResponse(**response.json())
@@ -133,21 +133,6 @@ class EntityClientMixin:
133
133
  return_exceptions=True,
134
134
  )
135
135
 
136
- async def validate_entity_exist(self, identifier: str, blueprint: str) -> None:
137
- logger.info(f"Validating entity {identifier} of blueprint {blueprint} exists")
138
-
139
- response = await self.client.get(
140
- f"{self.auth.api_url}/blueprints/{blueprint}/entities/{identifier}",
141
- headers=await self.auth.headers(),
142
- )
143
- if response.is_error:
144
- logger.error(
145
- f"Error validating "
146
- f"entity: {identifier} of "
147
- f"blueprint: {blueprint}"
148
- )
149
- handle_status_code(response)
150
-
151
136
  async def search_entities(self, user_agent_type: UserAgentType) -> list[Entity]:
152
137
  query = {
153
138
  "combinator": "and",
@@ -174,43 +159,8 @@ class EntityClientMixin:
174
159
  "exclude_calculated_properties": "true",
175
160
  "include": ["blueprint", "identifier"],
176
161
  },
162
+ extensions={"retryable": True},
163
+ timeout=30,
177
164
  )
178
165
  handle_status_code(response)
179
166
  return [Entity.parse_obj(result) for result in response.json()["entities"]]
180
-
181
- async def search_dependent_entities(self, entity: Entity) -> list[Entity]:
182
- body = {
183
- "combinator": "and",
184
- "rules": [
185
- {
186
- "operator": "relatedTo",
187
- "blueprint": entity.blueprint,
188
- "value": entity.identifier,
189
- "direction": "downstream",
190
- }
191
- ],
192
- }
193
-
194
- logger.info(f"Searching dependent entity with body {body}")
195
- response = await self.client.post(
196
- f"{self.auth.api_url}/entities/search",
197
- headers=await self.auth.headers(),
198
- json=body,
199
- )
200
- handle_status_code(response)
201
-
202
- return [Entity.parse_obj(result) for result in response.json()["entities"]]
203
-
204
- async def validate_entity_payload(
205
- self, entity: Entity, merge: bool, create_missing_related_entities: bool
206
- ) -> None:
207
- logger.info(f"Validating entity {entity.identifier}")
208
- await self.upsert_entity(
209
- entity,
210
- {
211
- "merge": merge,
212
- "create_missing_related_entities": create_missing_related_entities,
213
- "delete_dependent_entities": False,
214
- "validation_only": True,
215
- },
216
- )
@@ -15,11 +15,6 @@ class TokenRetryTransport(RetryTransport):
15
15
  super().__init__(**kwargs)
16
16
  self.port_client = port_client
17
17
 
18
- def _is_retryable_method(self, request: httpx.Request) -> bool:
19
- return super()._is_retryable_method(request) or request.url.path.endswith(
20
- "/auth/access_token"
21
- )
22
-
23
18
  async def _handle_unauthorized(self, response: httpx.Response) -> None:
24
19
  token = await self.port_client.auth.token
25
20
  response.headers["Authorization"] = f"Bearer {token}"
@@ -1,6 +1,7 @@
1
1
  from typing import Any, Literal
2
2
 
3
3
  from pydantic import Extra, AnyHttpUrl, parse_obj_as, validator
4
+ from pydantic.env_settings import InitSettingsSource, EnvSettingsSource, BaseSettings
4
5
  from pydantic.fields import Field
5
6
  from pydantic.main import BaseModel
6
7
 
@@ -10,7 +11,7 @@ from port_ocean.core.event_listener import EventListenerSettingsType
10
11
  LogLevelType = Literal["ERROR", "WARNING", "INFO", "DEBUG", "CRITICAL"]
11
12
 
12
13
 
13
- class ApplicationSettings(BaseOceanModel):
14
+ class ApplicationSettings(BaseSettings):
14
15
  log_level: LogLevelType = "INFO"
15
16
  enable_http_logging: bool = True
16
17
  port: int = 8000
@@ -21,7 +22,13 @@ class ApplicationSettings(BaseOceanModel):
21
22
  env_file_encoding = "utf-8"
22
23
 
23
24
  @classmethod
24
- def customise_sources(cls, init_settings, env_settings, *_, **__): # type: ignore
25
+ def customise_sources( # type: ignore
26
+ cls,
27
+ init_settings: InitSettingsSource,
28
+ env_settings: EnvSettingsSource,
29
+ *_,
30
+ **__,
31
+ ):
25
32
  return env_settings, init_settings
26
33
 
27
34
 
@@ -1,6 +1,3 @@
1
- import asyncio
2
- from itertools import chain
3
-
4
1
  from loguru import logger
5
2
 
6
3
  from port_ocean.clients.port.types import UserAgentType
@@ -14,14 +11,9 @@ from port_ocean.core.handlers.entities_state_applier.port.get_related_entities i
14
11
  from port_ocean.core.handlers.entities_state_applier.port.order_by_entities_dependencies import (
15
12
  order_by_entities_dependencies,
16
13
  )
17
- from port_ocean.core.handlers.entities_state_applier.port.validate_entity_relations import (
18
- validate_entity_relations,
19
- )
20
- from port_ocean.core.handlers.entity_processor.base import EntityPortDiff
21
14
  from port_ocean.core.models import Entity
22
15
  from port_ocean.core.ocean_types import EntityDiff
23
- from port_ocean.core.utils import is_same_entity, get_unique, get_port_diff
24
- from port_ocean.exceptions.core import RelationValidationException
16
+ from port_ocean.core.utils import is_same_entity, get_port_diff
25
17
 
26
18
 
27
19
  class HttpEntitiesStateApplier(BaseEntitiesStateApplier):
@@ -32,63 +24,17 @@ class HttpEntitiesStateApplier(BaseEntitiesStateApplier):
32
24
  through HTTP requests.
33
25
  """
34
26
 
35
- async def _validate_delete_dependent_entities(self, entities: list[Entity]) -> None:
36
- logger.info("Validated deleted entities")
37
- if not event.port_app_config.delete_dependent_entities:
38
- dependent_entities = await asyncio.gather(
39
- *(
40
- self.context.port_client.search_dependent_entities(entity)
41
- for entity in entities
42
- )
43
- )
44
- new_dependent_entities = get_unique(
45
- [
46
- entity
47
- for entity in chain.from_iterable(dependent_entities)
48
- if not any(is_same_entity(item, entity) for item in entities)
49
- ]
50
- )
51
-
52
- if new_dependent_entities:
53
- raise RelationValidationException(
54
- f"Must enable delete_dependent_entities flag or delete all dependent entities: "
55
- f" {[(dep.blueprint, dep.identifier) for dep in new_dependent_entities]}"
56
- )
57
-
58
- async def _validate_entity_diff(self, diff: EntityPortDiff) -> None:
59
- config = event.port_app_config
60
- await self._validate_delete_dependent_entities(diff.deleted)
61
- modified_or_created_entities = diff.modified + diff.created
62
-
63
- if modified_or_created_entities and not config.create_missing_related_entities:
64
- logger.info("Validating modified or created entities")
65
-
66
- await asyncio.gather(
67
- *(
68
- self.context.port_client.validate_entity_payload(
69
- entity,
70
- config.enable_merge_entity,
71
- create_missing_related_entities=config.create_missing_related_entities,
72
- )
73
- for entity in modified_or_created_entities
74
- )
75
- )
76
-
77
- if not event.port_app_config.delete_dependent_entities:
78
- logger.info("Validating no relation blocks the operation")
79
- await validate_entity_relations(diff, self.context.port_client)
80
-
81
- async def _delete_diff(
27
+ async def _safe_delete(
82
28
  self,
83
29
  entities_to_delete: list[Entity],
84
- created_entities: list[Entity],
30
+ entities_to_protect: list[Entity],
85
31
  user_agent_type: UserAgentType,
86
32
  ) -> None:
87
33
  if not entities_to_delete:
88
34
  return
89
35
 
90
36
  related_entities = await get_related_entities(
91
- created_entities, self.context.port_client
37
+ entities_to_protect, self.context.port_client
92
38
  )
93
39
 
94
40
  allowed_entities_to_delete = []
@@ -98,7 +44,8 @@ class HttpEntitiesStateApplier(BaseEntitiesStateApplier):
98
44
  is_same_entity(entity, entity_to_delete) for entity in related_entities
99
45
  )
100
46
  is_part_of_created = any(
101
- is_same_entity(entity, entity_to_delete) for entity in created_entities
47
+ is_same_entity(entity, entity_to_delete)
48
+ for entity in entities_to_protect
102
49
  )
103
50
  if is_part_of_related:
104
51
  if event.port_app_config.create_missing_related_entities:
@@ -119,21 +66,14 @@ class HttpEntitiesStateApplier(BaseEntitiesStateApplier):
119
66
  user_agent_type: UserAgentType,
120
67
  ) -> None:
121
68
  diff = get_port_diff(entities["before"], entities["after"])
69
+ kept_entities = diff.created + diff.modified
122
70
 
123
71
  logger.info(
124
72
  f"Updating entity diff (created: {len(diff.created)}, deleted: {len(diff.deleted)}, modified: {len(diff.modified)})"
125
73
  )
126
- await self._validate_entity_diff(diff)
74
+ await self.upsert(kept_entities, user_agent_type)
127
75
 
128
- logger.info("Upserting new entities")
129
- await self.upsert(diff.created, user_agent_type)
130
- logger.info("Upserting modified entities")
131
- await self.upsert(diff.modified, user_agent_type)
132
-
133
- logger.info("Deleting diff entities")
134
- await self._delete_diff(
135
- diff.deleted, diff.created + diff.modified, user_agent_type
136
- )
76
+ await self._safe_delete(diff.deleted, kept_entities, user_agent_type)
137
77
 
138
78
  async def delete_diff(
139
79
  self,
@@ -145,15 +85,13 @@ class HttpEntitiesStateApplier(BaseEntitiesStateApplier):
145
85
  if not diff.deleted:
146
86
  return
147
87
 
88
+ kept_entities = diff.created + diff.modified
89
+
148
90
  logger.info(
149
- f"Updating entity diff (created: {len(diff.created)}, deleted: {len(diff.deleted)}, modified: {len(diff.modified)})"
91
+ f"Determining entities to delete ({len(diff.deleted)}/{len(kept_entities)})"
150
92
  )
151
- await self._validate_entity_diff(diff)
152
93
 
153
- logger.info("Deleting diff entities")
154
- await self._delete_diff(
155
- diff.deleted, diff.created + diff.modified, user_agent_type
156
- )
94
+ await self._safe_delete(diff.deleted, kept_entities, user_agent_type)
157
95
 
158
96
  async def upsert(
159
97
  self, entities: list[Entity], user_agent_type: UserAgentType
@@ -333,8 +333,6 @@ class SyncRawMixin(HandlerMixin, EventsMixin):
333
333
  ):
334
334
  app_config = await self.port_app_config_handler.get_port_app_config()
335
335
 
336
- entities_at_port = await ocean.port_client.search_entities(user_agent_type)
337
-
338
336
  creation_results: list[tuple[list[Entity], list[Exception]]] = []
339
337
 
340
338
  try:
@@ -369,8 +367,11 @@ class SyncRawMixin(HandlerMixin, EventsMixin):
369
367
 
370
368
  logger.error(message, exc_info=error_group)
371
369
  else:
370
+ entities_at_port = await ocean.port_client.search_entities(
371
+ user_agent_type
372
+ )
372
373
  logger.info(
373
- f"Running resync diff calculation, number of entities at Port before resync: {len(entities_at_port)}, number of entities created during sync: {len(flat_created_entities)}"
374
+ f"Running resync diff calculation, number of entities found at Port: {len(entities_at_port)}, number of entities found during sync: {len(flat_created_entities)}"
374
375
  )
375
376
  await self.entities_state_applier.delete_diff(
376
377
  {"before": entities_at_port, "after": flat_created_entities},
@@ -179,12 +179,35 @@ class RetryTransport(httpx.AsyncBaseTransport, httpx.BaseTransport):
179
179
  transport.close()
180
180
 
181
181
  def _is_retryable_method(self, request: httpx.Request) -> bool:
182
- return request.method in self._retryable_methods
182
+ return request.method in self._retryable_methods or request.extensions.get(
183
+ "retryable", False
184
+ )
183
185
 
184
186
  def _should_retry(self, response: httpx.Response) -> bool:
185
187
  return response.status_code in self._retry_status_codes
186
188
 
187
- def _log_failure(
189
+ def _log_error(
190
+ self,
191
+ request: httpx.Request,
192
+ error: Exception | None,
193
+ ) -> None:
194
+ if not self._logger:
195
+ return
196
+
197
+ if isinstance(error, httpx.ConnectTimeout):
198
+ self._logger.error(
199
+ f"Request {request.method} {request.url} failed to connect: {str(error)}"
200
+ )
201
+ elif isinstance(error, httpx.TimeoutException):
202
+ self._logger.error(
203
+ f"Request {request.method} {request.url} failed with a timeout exception: {str(error)}"
204
+ )
205
+ elif isinstance(error, httpx.HTTPError):
206
+ self._logger.error(
207
+ f"Request {request.method} {request.url} failed with an HTTP error: {str(error)}"
208
+ )
209
+
210
+ def _log_before_retry(
188
211
  self,
189
212
  request: httpx.Request,
190
213
  sleep_time: float,
@@ -249,7 +272,7 @@ class RetryTransport(httpx.AsyncBaseTransport, httpx.BaseTransport):
249
272
  while True:
250
273
  if attempts_made > 0:
251
274
  sleep_time = self._calculate_sleep(attempts_made, {})
252
- self._log_failure(request, sleep_time, response, error)
275
+ self._log_before_retry(request, sleep_time, response, error)
253
276
  await asyncio.sleep(sleep_time)
254
277
 
255
278
  error = None
@@ -262,9 +285,20 @@ class RetryTransport(httpx.AsyncBaseTransport, httpx.BaseTransport):
262
285
  ):
263
286
  return response
264
287
  await response.aclose()
288
+ except httpx.ConnectTimeout as e:
289
+ error = e
290
+ if remaining_attempts < 1:
291
+ self._log_error(request, error)
292
+ raise
293
+ except httpx.TimeoutException as e:
294
+ error = e
295
+ if remaining_attempts < 1:
296
+ self._log_error(request, error)
297
+ raise
265
298
  except httpx.HTTPError as e:
266
299
  error = e
267
300
  if remaining_attempts < 1:
301
+ self._log_error(request, error)
268
302
  raise
269
303
  attempts_made += 1
270
304
  remaining_attempts -= 1
@@ -281,7 +315,7 @@ class RetryTransport(httpx.AsyncBaseTransport, httpx.BaseTransport):
281
315
  while True:
282
316
  if attempts_made > 0:
283
317
  sleep_time = self._calculate_sleep(attempts_made, {})
284
- self._log_failure(request, sleep_time, response, error)
318
+ self._log_before_retry(request, sleep_time, response, error)
285
319
  time.sleep(sleep_time)
286
320
 
287
321
  error = None
@@ -292,9 +326,20 @@ class RetryTransport(httpx.AsyncBaseTransport, httpx.BaseTransport):
292
326
  if remaining_attempts < 1 or not self._should_retry(response):
293
327
  return response
294
328
  response.close()
329
+ except httpx.ConnectTimeout as e:
330
+ error = e
331
+ if remaining_attempts < 1:
332
+ self._log_error(request, error)
333
+ raise
334
+ except httpx.TimeoutException as e:
335
+ error = e
336
+ if remaining_attempts < 1:
337
+ self._log_error(request, error)
338
+ raise
295
339
  except httpx.HTTPError as e:
296
340
  error = e
297
341
  if remaining_attempts < 1:
342
+ self._log_error(request, error)
298
343
  raise
299
344
  attempts_made += 1
300
345
  remaining_attempts -= 1
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "port-ocean"
3
- version = "0.5.9"
3
+ version = "0.5.11"
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"
@@ -1,40 +0,0 @@
1
- import asyncio
2
-
3
- from port_ocean.clients.port.client import PortClient
4
- from port_ocean.core.handlers.entities_state_applier.port.get_related_entities import (
5
- get_related_entities,
6
- )
7
- from port_ocean.core.handlers.entity_processor.base import EntityPortDiff
8
- from port_ocean.core.utils import is_same_entity
9
- from port_ocean.exceptions.core import RelationValidationException
10
-
11
-
12
- async def validate_entity_relations(
13
- diff: EntityPortDiff, port_client: PortClient
14
- ) -> None:
15
- modified_or_created_entities = diff.modified + diff.created
16
- related_entities = await get_related_entities(
17
- modified_or_created_entities, port_client
18
- )
19
-
20
- required_entities = []
21
-
22
- for entity in related_entities:
23
- if any(is_same_entity(item, entity) for item in diff.deleted):
24
- raise RelationValidationException(
25
- f"Cant delete entity {entity} of blueprint {entity.blueprint} "
26
- f"because it was specified as relation target of entity {entity} "
27
- f"of blueprint {entity.blueprint}"
28
- )
29
-
30
- if not any(
31
- is_same_entity(item, entity) for item in modified_or_created_entities
32
- ):
33
- required_entities.append(entity)
34
-
35
- await asyncio.gather(
36
- *(
37
- port_client.validate_entity_exist(item.identifier, item.blueprint)
38
- for item in required_entities
39
- )
40
- )
File without changes
File without changes