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.
- {port_ocean-0.5.9 → port_ocean-0.5.11}/PKG-INFO +1 -1
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/clients/port/authentication.py +3 -1
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/clients/port/mixins/entities.py +2 -52
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/clients/port/retry_transport.py +0 -5
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/config/settings.py +9 -2
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/handlers/entities_state_applier/port/applier.py +13 -75
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/integrations/mixins/sync_raw.py +4 -3
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/helpers/retry.py +49 -4
- {port_ocean-0.5.9 → port_ocean-0.5.11}/pyproject.toml +1 -1
- port_ocean-0.5.9/port_ocean/core/handlers/entities_state_applier/port/validate_entity_relations.py +0 -40
- {port_ocean-0.5.9 → port_ocean-0.5.11}/LICENSE.md +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/README.md +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/__init__.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/bootstrap.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/__init__.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/cli.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/commands/__init__.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/commands/defaults/__init___.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/commands/defaults/clean.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/commands/defaults/dock.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/commands/defaults/group.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/commands/list_integrations.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/commands/main.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/commands/new.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/commands/pull.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/commands/sail.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/commands/version.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/cookiecutter/__init__.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/cookiecutter/cookiecutter.json +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/cookiecutter/extensions.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/cookiecutter/hooks/post_gen_project.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.dockerignore +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.gitignore +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/resources/.gitignore +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/spec.yaml +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/CHANGELOG.md +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/Dockerfile +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/Makefile +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/README.md +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/changelog/.gitignore +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/config.yaml +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/debug.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/main.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/poetry.toml +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/pyproject.toml +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/sonar-project.properties +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/tests/__init__.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/utils.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/clients/__init__.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/clients/port/__init__.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/clients/port/client.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/clients/port/mixins/__init__.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/clients/port/mixins/blueprints.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/clients/port/mixins/integrations.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/clients/port/mixins/migrations.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/clients/port/types.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/clients/port/utils.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/config/__init__.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/config/base.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/config/dynamic.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/consumers/__init__.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/consumers/kafka_consumer.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/context/__init__.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/context/event.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/context/ocean.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/context/resource.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/__init__.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/defaults/__init__.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/defaults/clean.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/defaults/common.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/defaults/initialize.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/event_listener/__init__.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/event_listener/base.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/event_listener/factory.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/event_listener/http.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/event_listener/kafka.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/event_listener/once.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/event_listener/polling.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/handlers/__init__.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/handlers/base.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/handlers/entities_state_applier/__init__.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/handlers/entities_state_applier/base.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/handlers/entities_state_applier/port/__init__.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/handlers/entities_state_applier/port/get_related_entities.py +0 -0
- {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
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/handlers/entity_processor/__init__.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/handlers/entity_processor/base.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/handlers/entity_processor/jq_entity_processor.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/handlers/port_app_config/__init__.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/handlers/port_app_config/api.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/handlers/port_app_config/base.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/handlers/port_app_config/models.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/integrations/__init__.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/integrations/base.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/integrations/mixins/__init__.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/integrations/mixins/events.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/integrations/mixins/handler.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/integrations/mixins/sync.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/integrations/mixins/utils.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/models.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/ocean_types.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/utils.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/exceptions/__init__.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/exceptions/api.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/exceptions/base.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/exceptions/clients.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/exceptions/context.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/exceptions/core.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/exceptions/port_defaults.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/exceptions/utils.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/helpers/__init__.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/helpers/async_client.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/log/__init__.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/log/handlers.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/log/logger_setup.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/log/sensetive.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/middlewares.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/ocean.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/py.typed +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/run.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/sonar-project.properties +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/utils/__init__.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/utils/async_http.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/utils/cache.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/utils/misc.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/utils/repeat.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/utils/signal.py +0 -0
- {port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/version.py +0 -0
|
@@ -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",
|
|
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(
|
|
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(
|
|
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,
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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)
|
|
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.
|
|
74
|
+
await self.upsert(kept_entities, user_agent_type)
|
|
127
75
|
|
|
128
|
-
|
|
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"
|
|
91
|
+
f"Determining entities to delete ({len(diff.deleted)}/{len(kept_entities)})"
|
|
150
92
|
)
|
|
151
|
-
await self._validate_entity_diff(diff)
|
|
152
93
|
|
|
153
|
-
|
|
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
|
|
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
|
|
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.
|
|
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.
|
|
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
|
port_ocean-0.5.9/port_ocean/core/handlers/entities_state_applier/port/validate_entity_relations.py
DELETED
|
@@ -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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/cli/cookiecutter/hooks/post_gen_project.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/handlers/entities_state_applier/__init__.py
RENAMED
|
File without changes
|
{port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/handlers/entities_state_applier/base.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{port_ocean-0.5.9 → port_ocean-0.5.11}/port_ocean/core/handlers/entity_processor/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|