port-ocean 0.9.8__tar.gz → 0.9.12__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.9.8 → port_ocean-0.9.12}/PKG-INFO +1 -1
  2. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/cli/cookiecutter/hooks/post_gen_project.py +3 -2
  3. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/pyproject.toml +2 -1
  4. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/clients/port/mixins/entities.py +21 -4
  5. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/config/base.py +14 -12
  6. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/config/settings.py +31 -7
  7. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/core/handlers/entities_state_applier/base.py +4 -1
  8. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/core/handlers/entities_state_applier/port/applier.py +13 -10
  9. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/core/integrations/mixins/sync.py +4 -2
  10. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/core/integrations/mixins/sync_raw.py +8 -5
  11. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/ocean.py +5 -10
  12. {port_ocean-0.9.8 → port_ocean-0.9.12}/pyproject.toml +1 -1
  13. {port_ocean-0.9.8 → port_ocean-0.9.12}/LICENSE.md +0 -0
  14. {port_ocean-0.9.8 → port_ocean-0.9.12}/README.md +0 -0
  15. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/__init__.py +0 -0
  16. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/bootstrap.py +0 -0
  17. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/cli/__init__.py +0 -0
  18. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/cli/cli.py +0 -0
  19. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/cli/commands/__init__.py +0 -0
  20. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/cli/commands/defaults/__init___.py +0 -0
  21. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/cli/commands/defaults/clean.py +0 -0
  22. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/cli/commands/defaults/dock.py +0 -0
  23. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/cli/commands/defaults/group.py +0 -0
  24. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/cli/commands/list_integrations.py +0 -0
  25. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/cli/commands/main.py +0 -0
  26. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/cli/commands/new.py +0 -0
  27. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/cli/commands/pull.py +0 -0
  28. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/cli/commands/sail.py +0 -0
  29. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/cli/commands/version.py +0 -0
  30. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/cli/cookiecutter/__init__.py +0 -0
  31. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/cli/cookiecutter/cookiecutter.json +0 -0
  32. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/cli/cookiecutter/extensions.py +0 -0
  33. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.dockerignore +0 -0
  34. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.gitignore +0 -0
  35. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/resources/.gitignore +0 -0
  36. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/spec.yaml +0 -0
  37. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/CHANGELOG.md +0 -0
  38. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/Dockerfile +0 -0
  39. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/Makefile +0 -0
  40. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/README.md +0 -0
  41. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/changelog/.gitignore +0 -0
  42. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/debug.py +0 -0
  43. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/main.py +0 -0
  44. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/poetry.toml +0 -0
  45. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/sonar-project.properties +0 -0
  46. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/tests/__init__.py +0 -0
  47. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/cli/utils.py +0 -0
  48. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/clients/__init__.py +0 -0
  49. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/clients/port/__init__.py +0 -0
  50. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/clients/port/authentication.py +0 -0
  51. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/clients/port/client.py +0 -0
  52. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/clients/port/mixins/__init__.py +0 -0
  53. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/clients/port/mixins/blueprints.py +0 -0
  54. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/clients/port/mixins/integrations.py +0 -0
  55. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/clients/port/mixins/migrations.py +0 -0
  56. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/clients/port/retry_transport.py +0 -0
  57. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/clients/port/types.py +0 -0
  58. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/clients/port/utils.py +0 -0
  59. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/config/__init__.py +0 -0
  60. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/config/dynamic.py +0 -0
  61. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/consumers/__init__.py +0 -0
  62. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/consumers/kafka_consumer.py +0 -0
  63. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/context/__init__.py +0 -0
  64. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/context/event.py +0 -0
  65. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/context/ocean.py +0 -0
  66. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/context/resource.py +0 -0
  67. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/core/__init__.py +0 -0
  68. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/core/defaults/__init__.py +0 -0
  69. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/core/defaults/clean.py +0 -0
  70. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/core/defaults/common.py +0 -0
  71. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/core/defaults/initialize.py +0 -0
  72. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/core/event_listener/__init__.py +0 -0
  73. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/core/event_listener/base.py +0 -0
  74. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/core/event_listener/factory.py +0 -0
  75. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/core/event_listener/http.py +0 -0
  76. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/core/event_listener/kafka.py +0 -0
  77. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/core/event_listener/once.py +0 -0
  78. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/core/event_listener/polling.py +0 -0
  79. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/core/handlers/__init__.py +0 -0
  80. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/core/handlers/base.py +0 -0
  81. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/core/handlers/entities_state_applier/__init__.py +0 -0
  82. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/core/handlers/entities_state_applier/port/__init__.py +0 -0
  83. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/core/handlers/entities_state_applier/port/get_related_entities.py +0 -0
  84. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/core/handlers/entities_state_applier/port/order_by_entities_dependencies.py +0 -0
  85. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/core/handlers/entity_processor/__init__.py +0 -0
  86. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/core/handlers/entity_processor/base.py +0 -0
  87. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/core/handlers/entity_processor/jq_entity_processor.py +0 -0
  88. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/core/handlers/port_app_config/__init__.py +0 -0
  89. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/core/handlers/port_app_config/api.py +0 -0
  90. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/core/handlers/port_app_config/base.py +0 -0
  91. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/core/handlers/port_app_config/models.py +0 -0
  92. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/core/integrations/__init__.py +0 -0
  93. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/core/integrations/base.py +0 -0
  94. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/core/integrations/mixins/__init__.py +0 -0
  95. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/core/integrations/mixins/events.py +0 -0
  96. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/core/integrations/mixins/handler.py +0 -0
  97. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/core/integrations/mixins/utils.py +0 -0
  98. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/core/models.py +0 -0
  99. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/core/ocean_types.py +0 -0
  100. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/core/utils.py +0 -0
  101. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/exceptions/__init__.py +0 -0
  102. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/exceptions/api.py +0 -0
  103. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/exceptions/base.py +0 -0
  104. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/exceptions/clients.py +0 -0
  105. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/exceptions/context.py +0 -0
  106. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/exceptions/core.py +0 -0
  107. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/exceptions/port_defaults.py +0 -0
  108. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/exceptions/utils.py +0 -0
  109. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/helpers/__init__.py +0 -0
  110. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/helpers/async_client.py +0 -0
  111. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/helpers/retry.py +0 -0
  112. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/log/__init__.py +0 -0
  113. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/log/handlers.py +0 -0
  114. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/log/logger_setup.py +0 -0
  115. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/log/sensetive.py +0 -0
  116. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/middlewares.py +0 -0
  117. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/py.typed +0 -0
  118. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/run.py +0 -0
  119. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/sonar-project.properties +0 -0
  120. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/utils/__init__.py +0 -0
  121. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/utils/async_http.py +0 -0
  122. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/utils/async_iterators.py +0 -0
  123. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/utils/cache.py +0 -0
  124. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/utils/misc.py +0 -0
  125. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/utils/queue_utils.py +0 -0
  126. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/utils/repeat.py +0 -0
  127. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/utils/signal.py +0 -0
  128. {port_ocean-0.9.8 → port_ocean-0.9.12}/port_ocean/version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: port-ocean
3
- Version: 0.9.8
3
+ Version: 0.9.12
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
@@ -2,11 +2,12 @@ import os
2
2
 
3
3
 
4
4
  def handle_private_integration_flags():
5
+ print("{{ cookiecutter.is_private_integration }}")
5
6
  if "{{ cookiecutter.is_private_integration }}" == "True":
7
+ os.remove("sonar-project.properties")
8
+ if "{{ cookiecutter.is_private_integration }}" == "False":
6
9
  os.remove("Dockerfile")
7
10
  os.remove(".dockerignore")
8
- if "{{ cookiecutter.is_private_integration }}" == "False":
9
- os.remove("sonar-project.properties")
10
11
 
11
12
 
12
13
  if __name__ == "__main__":
@@ -19,7 +19,8 @@ towncrier = "^23.6.0"
19
19
  [tool.towncrier]
20
20
  directory = "changelog"
21
21
  filename = "CHANGELOG.md"
22
- package = "port_ocean"
22
+ title_format = "## {version} ({project_date})"
23
+ underlines = [""]
23
24
 
24
25
  [[tool.towncrier.type]]
25
26
  directory = "breaking"
@@ -29,7 +29,7 @@ class EntityClientMixin:
29
29
  request_options: RequestOptions,
30
30
  user_agent_type: UserAgentType | None = None,
31
31
  should_raise: bool = True,
32
- ) -> None:
32
+ ) -> Entity:
33
33
  validation_only = request_options["validation_only"]
34
34
  async with self.semaphore:
35
35
  logger.debug(
@@ -57,6 +57,12 @@ class EntityClientMixin:
57
57
  f"blueprint: {entity.blueprint}"
58
58
  )
59
59
  handle_status_code(response, should_raise)
60
+ result = response.json()
61
+ result_entity = Entity.parse_obj(result)
62
+ # Set the results of the search relation and identifier to the entity
63
+ entity.identifier = result_entity.identifier or entity.identifier
64
+ entity.relations = result_entity.relations or entity.relations
65
+ return entity
60
66
 
61
67
  async def batch_upsert_entities(
62
68
  self,
@@ -64,8 +70,8 @@ class EntityClientMixin:
64
70
  request_options: RequestOptions,
65
71
  user_agent_type: UserAgentType | None = None,
66
72
  should_raise: bool = True,
67
- ) -> None:
68
- await asyncio.gather(
73
+ ) -> list[Entity]:
74
+ modified_entities_results = await asyncio.gather(
69
75
  *(
70
76
  self.upsert_entity(
71
77
  entity,
@@ -75,8 +81,19 @@ class EntityClientMixin:
75
81
  )
76
82
  for entity in entities
77
83
  ),
78
- return_exceptions=True,
84
+ return_exceptions=should_raise,
79
85
  )
86
+ entity_results = [
87
+ entity for entity in modified_entities_results if isinstance(entity, Entity)
88
+ ]
89
+ if not should_raise:
90
+ return entity_results
91
+
92
+ for entity_result in modified_entities_results:
93
+ if isinstance(entity_result, Exception):
94
+ raise entity_result
95
+
96
+ return entity_results
80
97
 
81
98
  async def delete_entity(
82
99
  self,
@@ -1,11 +1,11 @@
1
1
  import os
2
2
  import re
3
- from pathlib import Path
4
3
  from types import GenericAlias
5
4
  from typing import Any
6
5
 
7
6
  import yaml
8
7
  from humps import decamelize
8
+ from pathlib import Path
9
9
  from pydantic import BaseSettings
10
10
  from pydantic.env_settings import EnvSettingsSource, InitSettingsSource
11
11
  from pydantic.main import ModelMetaclass, BaseModel
@@ -14,13 +14,17 @@ PROVIDER_WRAPPER_PATTERN = r"{{ from (.*) }}"
14
14
  PROVIDER_CONFIG_PATTERN = r"^[a-zA-Z0-9]+ .*$"
15
15
 
16
16
 
17
- def read_yaml_config_settings_source(
18
- settings: "BaseOceanSettings", base_path: str
19
- ) -> dict[str, Any]:
20
- yaml_file = getattr(settings.__config__, "yaml_file", "")
17
+ def read_yaml_config_settings_source(settings: "BaseOceanSettings") -> dict[str, Any]:
18
+ yaml_file = getattr(settings.Config, "yaml_file", "")
21
19
 
22
20
  assert yaml_file, "Settings.yaml_file not properly configured"
23
- path = Path(base_path, yaml_file)
21
+ path = Path(
22
+ getattr(
23
+ settings,
24
+ "_base_path",
25
+ ),
26
+ yaml_file,
27
+ )
24
28
 
25
29
  if not path.exists():
26
30
  return {}
@@ -119,15 +123,15 @@ def decamelize_config(
119
123
 
120
124
 
121
125
  def load_providers(
122
- settings: "BaseOceanSettings", existing_values: dict[str, Any], base_path: str
126
+ settings: "BaseOceanSettings", existing_values: dict[str, Any]
123
127
  ) -> dict[str, Any]:
124
- data = read_yaml_config_settings_source(settings, base_path)
128
+ data = read_yaml_config_settings_source(settings)
125
129
  snake_case_config = decamelize_config(settings, data)
126
130
  return parse_providers(settings, snake_case_config, existing_values)
127
131
 
128
132
 
129
133
  class BaseOceanSettings(BaseSettings):
130
- base_path: str
134
+ _base_path: str = "./"
131
135
 
132
136
  def get_sensitive_fields_data(self) -> set[str]:
133
137
  return _get_sensitive_information(self)
@@ -150,9 +154,7 @@ class BaseOceanSettings(BaseSettings):
150
154
  return (
151
155
  init_settings,
152
156
  env_settings,
153
- lambda s: load_providers(
154
- s, env_settings(s), init_settings.init_kwargs["base_path"]
155
- ),
157
+ lambda s: load_providers(s, {**env_settings(s), **init_settings(s)}),
156
158
  )
157
159
 
158
160
 
@@ -1,15 +1,16 @@
1
- from typing import Any, Literal
1
+ from typing import Any, Literal, Type
2
2
 
3
- from port_ocean.config.base import BaseOceanSettings, BaseOceanModel
4
- from port_ocean.core.event_listener import EventListenerSettingsType
5
- from port_ocean.core.models import Runtime
6
- from port_ocean.utils.misc import get_integration_name, get_spec_file
7
- from pydantic import Extra, AnyHttpUrl, parse_obj_as
3
+ from pydantic import Extra, AnyHttpUrl, parse_obj_as, parse_raw_as
8
4
  from pydantic.class_validators import root_validator, validator
9
5
  from pydantic.env_settings import InitSettingsSource, EnvSettingsSource, BaseSettings
10
6
  from pydantic.fields import Field
11
7
  from pydantic.main import BaseModel
12
8
 
9
+ from port_ocean.config.base import BaseOceanSettings, BaseOceanModel
10
+ from port_ocean.core.event_listener import EventListenerSettingsType
11
+ from port_ocean.core.models import Runtime
12
+ from port_ocean.utils.misc import get_integration_name, get_spec_file
13
+
13
14
  LogLevelType = Literal["ERROR", "WARNING", "INFO", "DEBUG", "CRITICAL"]
14
15
 
15
16
 
@@ -44,7 +45,7 @@ class PortSettings(BaseOceanModel, extra=Extra.allow):
44
45
  class IntegrationSettings(BaseOceanModel, extra=Extra.allow):
45
46
  identifier: str
46
47
  type: str
47
- config: dict[str, Any] | BaseModel = Field(default_factory=dict)
48
+ config: Any = Field(default_factory=dict)
48
49
 
49
50
  @root_validator(pre=True)
50
51
  def root_validator(cls, values: dict[str, Any]) -> dict[str, Any]:
@@ -62,6 +63,8 @@ class IntegrationSettings(BaseOceanModel, extra=Extra.allow):
62
63
 
63
64
 
64
65
  class IntegrationConfiguration(BaseOceanSettings, extra=Extra.allow):
66
+ _integration_config_model: BaseModel | None = None
67
+
65
68
  allow_environment_variables_jq_access: bool = True
66
69
  initialize_port_resources: bool = True
67
70
  scheduled_resync_interval: int | None = None
@@ -73,6 +76,27 @@ class IntegrationConfiguration(BaseOceanSettings, extra=Extra.allow):
73
76
  integration: IntegrationSettings = IntegrationSettings(type="", identifier="")
74
77
  runtime: Runtime = "OnPrem"
75
78
 
79
+ @root_validator()
80
+ def validate_integration_config(cls, values: dict[str, Any]) -> dict[str, Any]:
81
+ if not (config_model := values.get("_integration_config_model")):
82
+ return values
83
+
84
+ # Using the integration dynamic config model to parse the config
85
+ def parse_config(model: Type[BaseModel], config: Any) -> BaseModel:
86
+ # In some cases, the config is parsed as a string so we need to handle it
87
+ # Example: when the config is loaded from the environment variables and there is an object inside the config
88
+ if isinstance(config, str):
89
+ return parse_raw_as(model, config)
90
+ else:
91
+ return parse_obj_as(model, config)
92
+
93
+ integration_config = values["integration"]
94
+ integration_config.config = parse_config(
95
+ config_model, integration_config.config
96
+ )
97
+
98
+ return values
99
+
76
100
  @validator("runtime")
77
101
  def validate_runtime(cls, runtime: Literal["OnPrem", "Saas"]) -> Runtime:
78
102
  if runtime == "Saas":
@@ -47,12 +47,15 @@ class BaseEntitiesStateApplier(BaseHandler):
47
47
  @abstractmethod
48
48
  async def upsert(
49
49
  self, entities: list[Entity], user_agent_type: UserAgentType
50
- ) -> None:
50
+ ) -> list[Entity]:
51
51
  """Upsert (insert or update) the given entities into the state.
52
52
 
53
53
  Args:
54
54
  entities (list[Entity]): The entities to be upserted.
55
55
  user_agent_type (UserAgentType): The user agent responsible for the upsert.
56
+
57
+ Returns:
58
+ list[Entity]: The upserted entities.
56
59
  """
57
60
  pass
58
61
 
@@ -71,9 +71,9 @@ class HttpEntitiesStateApplier(BaseEntitiesStateApplier):
71
71
  logger.info(
72
72
  f"Updating entity diff (created: {len(diff.created)}, deleted: {len(diff.deleted)}, modified: {len(diff.modified)})"
73
73
  )
74
- await self.upsert(kept_entities, user_agent_type)
74
+ modified_entities = await self.upsert(kept_entities, user_agent_type)
75
75
 
76
- await self._safe_delete(diff.deleted, kept_entities, user_agent_type)
76
+ await self._safe_delete(diff.deleted, modified_entities, user_agent_type)
77
77
 
78
78
  async def delete_diff(
79
79
  self,
@@ -95,10 +95,11 @@ class HttpEntitiesStateApplier(BaseEntitiesStateApplier):
95
95
 
96
96
  async def upsert(
97
97
  self, entities: list[Entity], user_agent_type: UserAgentType
98
- ) -> None:
98
+ ) -> list[Entity]:
99
99
  logger.info(f"Upserting {len(entities)} entities")
100
+ modified_entities: list[Entity] = []
100
101
  if event.port_app_config.create_missing_related_entities:
101
- await self.context.port_client.batch_upsert_entities(
102
+ modified_entities = await self.context.port_client.batch_upsert_entities(
102
103
  entities,
103
104
  event.port_app_config.get_port_request_options(),
104
105
  user_agent_type,
@@ -108,14 +109,16 @@ class HttpEntitiesStateApplier(BaseEntitiesStateApplier):
108
109
  ordered_created_entities = reversed(
109
110
  order_by_entities_dependencies(entities)
110
111
  )
111
-
112
112
  for entity in ordered_created_entities:
113
- await self.context.port_client.upsert_entity(
114
- entity,
115
- event.port_app_config.get_port_request_options(),
116
- user_agent_type,
117
- should_raise=False,
113
+ modified_entities.append(
114
+ await self.context.port_client.upsert_entity(
115
+ entity,
116
+ event.port_app_config.get_port_request_options(),
117
+ user_agent_type,
118
+ should_raise=False,
119
+ )
118
120
  )
121
+ return modified_entities
119
122
 
120
123
  async def delete(
121
124
  self, entities: list[Entity], user_agent_type: UserAgentType
@@ -97,9 +97,11 @@ class SyncMixin(HandlerMixin):
97
97
  """
98
98
  entities_at_port = await ocean.port_client.search_entities(user_agent_type)
99
99
 
100
- await self.entities_state_applier.upsert(entities, user_agent_type)
100
+ modified_entities = await self.entities_state_applier.upsert(
101
+ entities, user_agent_type
102
+ )
101
103
  await self.entities_state_applier.delete_diff(
102
- {"before": entities_at_port, "after": entities}, user_agent_type
104
+ {"before": entities_at_port, "after": modified_entities}, user_agent_type
103
105
  )
104
106
 
105
107
  logger.info("Finished syncing change")
@@ -140,11 +140,13 @@ class SyncRawMixin(HandlerMixin, EventsMixin):
140
140
  objects_diff = await self._calculate_raw(
141
141
  [(resource, results)], parse_all, send_raw_data_examples_amount
142
142
  )
143
- await self.entities_state_applier.upsert(
143
+ modified_objects = await self.entities_state_applier.upsert(
144
144
  objects_diff[0].entity_selector_diff.passed, user_agent_type
145
145
  )
146
-
147
- return objects_diff[0]
146
+ return CalculationResult(
147
+ objects_diff[0].entity_selector_diff._replace(passed=modified_objects),
148
+ errors=objects_diff[0].errors,
149
+ )
148
150
 
149
151
  async def _unregister_resource_raw(
150
152
  self,
@@ -418,6 +420,7 @@ class SyncRawMixin(HandlerMixin, EventsMixin):
418
420
  )
419
421
  logger.info(f"Resync will use the following mappings: {app_config.dict()}")
420
422
  try:
423
+ did_fetched_current_state = True
421
424
  entities_at_port = await ocean.port_client.search_entities(
422
425
  user_agent_type
423
426
  )
@@ -429,7 +432,7 @@ class SyncRawMixin(HandlerMixin, EventsMixin):
429
432
  f"Response status code: {e.response.status_code if isinstance(e, httpx.HTTPStatusError) else None}\n"
430
433
  f"Response content: {e.response.text if isinstance(e, httpx.HTTPStatusError) else None}\n"
431
434
  )
432
- entities_at_port = []
435
+ did_fetched_current_state = False
433
436
 
434
437
  creation_results: list[tuple[list[Entity], list[Exception]]] = []
435
438
 
@@ -448,7 +451,7 @@ class SyncRawMixin(HandlerMixin, EventsMixin):
448
451
  except asyncio.CancelledError as e:
449
452
  logger.warning("Resync aborted successfully")
450
453
  else:
451
- if not entities_at_port:
454
+ if not did_fetched_current_state:
452
455
  logger.warning(
453
456
  "Due to an error before the resync, the previous state of entities at Port is unknown."
454
457
  " Skipping delete phase due to unknown initial state."
@@ -2,7 +2,7 @@ import asyncio
2
2
  import sys
3
3
  import threading
4
4
  from contextlib import asynccontextmanager
5
- from typing import Callable, Any, Dict, AsyncIterator
5
+ from typing import Callable, Any, Dict, AsyncIterator, Type
6
6
 
7
7
  from fastapi import FastAPI, APIRouter
8
8
  from loguru import logger
@@ -32,7 +32,7 @@ class Ocean:
32
32
  app: FastAPI | None = None,
33
33
  integration_class: Callable[[PortOceanContext], BaseIntegration] | None = None,
34
34
  integration_router: APIRouter | None = None,
35
- config_factory: Callable[..., BaseModel] | None = None,
35
+ config_factory: Type[BaseModel] | None = None,
36
36
  config_override: Dict[str, Any] | None = None,
37
37
  ):
38
38
  initialize_port_ocean_context(self)
@@ -40,16 +40,11 @@ class Ocean:
40
40
  self.fast_api_app.middleware("http")(request_handler)
41
41
 
42
42
  self.config = IntegrationConfiguration(
43
- base_path="./", **(config_override or {})
43
+ # type: ignore
44
+ _integration_config_model=config_factory,
45
+ **(config_override or {}),
44
46
  )
45
47
 
46
- if config_factory:
47
- raw_config = (
48
- self.config.integration.config
49
- if isinstance(self.config.integration.config, dict)
50
- else self.config.integration.config.dict()
51
- )
52
- self.config.integration.config = config_factory(**raw_config)
53
48
  # add the integration sensitive configuration to the sensitive patterns to mask out
54
49
  sensitive_log_filter.hide_sensitive_strings(
55
50
  *self.config.get_sensitive_fields_data()
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "port-ocean"
3
- version = "0.9.8"
3
+ version = "0.9.12"
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