port-ocean 0.27.2__py3-none-any.whl → 0.27.5__py3-none-any.whl

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.
@@ -16,6 +16,7 @@ from port_ocean.core.event_listener.base import (
16
16
  EventListenerEvents,
17
17
  EventListenerSettings,
18
18
  )
19
+ from pydantic import validator
19
20
 
20
21
 
21
22
  class KafkaEventListenerSettings(EventListenerSettings):
@@ -46,6 +47,19 @@ class KafkaEventListenerSettings(EventListenerSettings):
46
47
  kafka_security_enabled: bool = True
47
48
  consumer_poll_timeout: int = 1
48
49
 
50
+ @validator("brokers")
51
+ @classmethod
52
+ def parse_brokers(cls, v: str) -> str:
53
+ # If it's a JSON array string, parse and join
54
+ if v.strip().startswith("[") and v.strip().endswith("]"):
55
+ try:
56
+ parsed = json.loads(v)
57
+ if isinstance(parsed, list):
58
+ return ",".join(parsed)
59
+ except json.JSONDecodeError:
60
+ pass
61
+ return v
62
+
49
63
  def get_changelog_destination_details(self) -> dict[str, Any]:
50
64
  """
51
65
  Returns the changelog destination configuration for the Kafka event listener.
@@ -242,6 +242,7 @@ class JQEntityProcessor(BaseEntityProcessor):
242
242
  data: dict[str, Any],
243
243
  raw_entity_mappings: dict[str, Any],
244
244
  items_to_parse: str | None,
245
+ items_to_parse_name: str,
245
246
  selector_query: str,
246
247
  parse_all: bool = False,
247
248
  ) -> tuple[list[MappedEntity], list[Exception]]:
@@ -255,7 +256,7 @@ class JQEntityProcessor(BaseEntityProcessor):
255
256
  f" Skipping..."
256
257
  )
257
258
  return [], []
258
- raw_data = [{"item": item, **data} for item in items]
259
+ raw_data = [{items_to_parse_name: item, **data} for item in items]
259
260
 
260
261
  entities, errors = await gather_and_split_errors_from_results(
261
262
  [
@@ -304,6 +305,7 @@ class JQEntityProcessor(BaseEntityProcessor):
304
305
  self._calculate_entity,
305
306
  raw_entity_mappings,
306
307
  mapping.port.items_to_parse,
308
+ mapping.port.items_to_parse_name,
307
309
  mapping.selector.query,
308
310
  parse_all,
309
311
  )
@@ -39,6 +39,7 @@ class MappingsConfig(BaseModel):
39
39
  class PortResourceConfig(BaseModel):
40
40
  entity: MappingsConfig
41
41
  items_to_parse: str | None = Field(alias="itemsToParse")
42
+ items_to_parse_name: str | None = Field(alias="itemsToParseName", default="item")
42
43
 
43
44
 
44
45
  class Selector(BaseModel):
@@ -0,0 +1,70 @@
1
+ from port_ocean.core.event_listener.kafka import KafkaEventListenerSettings
2
+ import pytest
3
+ from pydantic import ValidationError
4
+
5
+
6
+ def test_default_kafka_settings() -> None:
7
+ """Test default values are properly set"""
8
+ config = KafkaEventListenerSettings(type="KAFKA")
9
+ assert config.type == "KAFKA"
10
+ assert config.security_protocol == "SASL_SSL"
11
+ assert config.authentication_mechanism == "SCRAM-SHA-512"
12
+ assert config.kafka_security_enabled is True
13
+ assert config.consumer_poll_timeout == 1
14
+ assert "b-1-public.publicclusterprod" in config.brokers
15
+
16
+
17
+ def test_brokers_json_array_parsing() -> None:
18
+ """Test that JSON array strings get converted to comma-separated"""
19
+ json_brokers = '["broker1:9092", "broker2:9092", "broker3:9092"]'
20
+ config = KafkaEventListenerSettings(type="KAFKA", brokers=json_brokers)
21
+ assert config.brokers == "broker1:9092,broker2:9092,broker3:9092"
22
+
23
+
24
+ def test_brokers_regular_string_unchanged() -> None:
25
+ """Test that regular comma-separated strings pass through unchanged"""
26
+ regular_brokers = "broker1:9092,broker2:9092"
27
+ config = KafkaEventListenerSettings(type="KAFKA", brokers=regular_brokers)
28
+ assert config.brokers == regular_brokers
29
+
30
+
31
+ def test_brokers_malformed_json_unchanged() -> None:
32
+ """Test that malformed JSON strings don't break validation"""
33
+ bad_json = "[broker1:9092, broker2:9092"
34
+ config = KafkaEventListenerSettings(type="KAFKA", brokers=bad_json)
35
+ assert config.brokers == bad_json
36
+
37
+
38
+ def test_custom_values() -> None:
39
+ """Test overriding default values"""
40
+ config = KafkaEventListenerSettings(
41
+ type="KAFKA",
42
+ brokers="custom:9092",
43
+ security_protocol="PLAINTEXT",
44
+ authentication_mechanism="PLAIN",
45
+ kafka_security_enabled=False,
46
+ consumer_poll_timeout=5,
47
+ )
48
+ assert config.brokers == "custom:9092"
49
+ assert config.security_protocol == "PLAINTEXT"
50
+ assert config.authentication_mechanism == "PLAIN"
51
+ assert config.kafka_security_enabled is False
52
+ assert config.consumer_poll_timeout == 5
53
+
54
+
55
+ def test_type_literal_validation() -> None:
56
+ """Test that type field only accepts KAFKA"""
57
+ with pytest.raises(ValidationError):
58
+ KafkaEventListenerSettings(type="RABBITMQ") # type: ignore[arg-type]
59
+
60
+
61
+ def test_empty_brokers_array() -> None:
62
+ """Test empty JSON array becomes empty string"""
63
+ config = KafkaEventListenerSettings(type="KAFKA", brokers="[]")
64
+ assert config.brokers == ""
65
+
66
+
67
+ def test_single_broker_array() -> None:
68
+ """Test single broker in JSON array"""
69
+ config = KafkaEventListenerSettings(type="KAFKA", brokers='["single:9092"]')
70
+ assert config.brokers == "single:9092"
@@ -60,7 +60,7 @@ class TestJQEntityProcessor:
60
60
  raw_entity_mappings = {"foo": ".foo"}
61
61
  selector_query = '.foo == "bar"'
62
62
  result, errors = await mocked_processor._calculate_entity(
63
- data, raw_entity_mappings, None, selector_query
63
+ data, raw_entity_mappings, None, "item", selector_query
64
64
  )
65
65
  assert len(result) == 1
66
66
  assert result[0].entity == {"foo": "bar"}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: port-ocean
3
- Version: 0.27.2
3
+ Version: 0.27.5
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
@@ -26,7 +26,7 @@ Requires-Dist: aiostream (>=0.5.2,<0.7.0)
26
26
  Requires-Dist: click (>=8.1.3,<9.0.0) ; extra == "cli"
27
27
  Requires-Dist: confluent-kafka (>=2.10.1,<3.0.0)
28
28
  Requires-Dist: cookiecutter (>=2.1.1,<3.0.0) ; extra == "cli"
29
- Requires-Dist: fastapi (>=0.115.3,<0.116.0)
29
+ Requires-Dist: fastapi (>=0.116.0,<0.117.0)
30
30
  Requires-Dist: httpx (>=0.28.1,<0.29.0)
31
31
  Requires-Dist: jinja2 (>=3.1.6)
32
32
  Requires-Dist: jinja2-time (>=0.2.0,<0.3.0) ; extra == "cli"
@@ -87,7 +87,7 @@ port_ocean/core/event_listener/__init__.py,sha256=T3E52MKs79fNEW381p7zU9F2vOMvIi
87
87
  port_ocean/core/event_listener/base.py,sha256=GFBTHiYhCzps50phzopQFUlTGAluQkCRlyaRqOG4g1Y,2995
88
88
  port_ocean/core/event_listener/factory.py,sha256=M4Qi05pI840sjDIbdjUEgYe9Gp5ckoCkX-KgLBxUpZg,4096
89
89
  port_ocean/core/event_listener/http.py,sha256=_hkQmi9nNh8YG6hbfLrhkATsmGVO8y3qBWvrBHX5Nhk,2992
90
- port_ocean/core/event_listener/kafka.py,sha256=pVQfGtElIJN2P5lPBrMxyl05B8c2Q2wp5WvA6Pqjnyc,7501
90
+ port_ocean/core/event_listener/kafka.py,sha256=7bUq4EoVv5sIBxiJnfhi7zdAI7whKoSIaS64Ic9B4Ys,7963
91
91
  port_ocean/core/event_listener/once.py,sha256=6DhxQLSz5hjEGhmgLU7aA2ZVRQw3tuwh8sh7N63gRdU,5855
92
92
  port_ocean/core/event_listener/polling.py,sha256=iZt59z4Dyus_wVvNfIPbq-G1CozAW9kfPU7uRDLPJVE,3604
93
93
  port_ocean/core/event_listener/webhooks_only.py,sha256=PTWnmbLtbJb3ySfotMpTWMYgDVy9zOSYIIGqNbWK0UU,1214
@@ -101,11 +101,11 @@ port_ocean/core/handlers/entities_state_applier/port/get_related_entities.py,sha
101
101
  port_ocean/core/handlers/entities_state_applier/port/order_by_entities_dependencies.py,sha256=lyv6xKzhYfd6TioUgR3AVRSJqj7JpAaj1LxxU2xAqeo,1720
102
102
  port_ocean/core/handlers/entity_processor/__init__.py,sha256=FvFCunFg44wNQoqlybem9MthOs7p1Wawac87uSXz9U8,156
103
103
  port_ocean/core/handlers/entity_processor/base.py,sha256=PsnpNRqjHth9xwOvDRe7gKu8cjnVV0XGmTIHGvOelX0,1867
104
- port_ocean/core/handlers/entity_processor/jq_entity_processor.py,sha256=t_Z6etgxG6IQLNRLxG06SEj5IyAVRujuf0ox0DXd4A8,12873
104
+ port_ocean/core/handlers/entity_processor/jq_entity_processor.py,sha256=qvPMbIH1XRvaZ-TvW7lw9k4W27ZPCHcXGSdqnZ0wblw,12970
105
105
  port_ocean/core/handlers/port_app_config/__init__.py,sha256=8AAT5OthiVM7KCcM34iEgEeXtn2pRMrT4Dze5r1Ixbk,134
106
106
  port_ocean/core/handlers/port_app_config/api.py,sha256=r_Th66NEw38IpRdnXZcRvI8ACfvxW_A6V62WLwjWXlQ,1044
107
107
  port_ocean/core/handlers/port_app_config/base.py,sha256=Sup4-X_a7JGa27rMy_OgqGIjFHMlKBpKevicaK3AeHU,2919
108
- port_ocean/core/handlers/port_app_config/models.py,sha256=pO7oI7GIYZ9c2ZxLu8EQ97U2IPqzsbJf3gRQxlizEjE,2933
108
+ port_ocean/core/handlers/port_app_config/models.py,sha256=M9NJRRacvpZQYCFgHGlRwrdgumbIIJ82WpCyvtOUf5w,3019
109
109
  port_ocean/core/handlers/queue/__init__.py,sha256=yzgicE_jAR1wtljFKxgyG6j-HbLcG_Zze5qw1kkALUI,171
110
110
  port_ocean/core/handlers/queue/abstract_queue.py,sha256=SaivrYbqg8qsX6wtQlJZyxgcbdMD5B9NZG3byN9AvrI,782
111
111
  port_ocean/core/handlers/queue/group_queue.py,sha256=JvvJOwz9z_aI4CjPr7yQX-0rOgqLI5wMdxWk2x5x-34,4989
@@ -167,8 +167,9 @@ port_ocean/tests/config/test_config.py,sha256=Rk4N-ldVSOfn1p23NzdVdfqUpPrqG2cMut
167
167
  port_ocean/tests/conftest.py,sha256=JXASSS0IY0nnR6bxBflhzxS25kf4iNaABmThyZ0mZt8,101
168
168
  port_ocean/tests/core/conftest.py,sha256=5shShx81LRuQTBwS2sDIjNJO2LSD6cUNz46SgNYzjGY,7686
169
169
  port_ocean/tests/core/defaults/test_common.py,sha256=sR7RqB3ZYV6Xn6NIg-c8k5K6JcGsYZ2SCe_PYX5vLYM,5560
170
+ port_ocean/tests/core/event_listener/test_kafka.py,sha256=PH90qk2fvdrQOSZD2QrvkGy8w_WoYb_KHGnqJ6PLHAo,2681
170
171
  port_ocean/tests/core/handlers/entities_state_applier/test_applier.py,sha256=7XWgwUB9uVYRov4VbIz1A-7n2YLbHTTYT-4rKJxjB0A,10711
171
- port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py,sha256=AyzLclJFKz8YzSi2hiFYVdXRzCFmqQwTxnwNFTo9roU,14091
172
+ port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py,sha256=TjSj8ssIqH23VJlO5PGovbudCqDbuE2-54iNQsD9K-I,14099
172
173
  port_ocean/tests/core/handlers/mixins/test_live_events.py,sha256=6yUsYooBYchiZP_eYa8PN1IhiztJShBdPguoseyNMzY,12482
173
174
  port_ocean/tests/core/handlers/mixins/test_sync_raw.py,sha256=-Jd2rUG63fZM8LuyKtCp1tt4WEqO2m5woESjs1c91sU,44428
174
175
  port_ocean/tests/core/handlers/port_app_config/test_api.py,sha256=eJZ6SuFBLz71y4ca3DNqKag6d6HUjNJS0aqQPwiLMTI,1999
@@ -205,8 +206,8 @@ port_ocean/utils/repeat.py,sha256=U2OeCkHPWXmRTVoPV-VcJRlQhcYqPWI5NfmPlb1JIbc,32
205
206
  port_ocean/utils/signal.py,sha256=mMVq-1Ab5YpNiqN4PkiyTGlV_G0wkUDMMjTZp5z3pb0,1514
206
207
  port_ocean/utils/time.py,sha256=pufAOH5ZQI7gXvOvJoQXZXZJV-Dqktoj9Qp9eiRwmJ4,1939
207
208
  port_ocean/version.py,sha256=UsuJdvdQlazzKGD3Hd5-U7N69STh8Dq9ggJzQFnu9fU,177
208
- port_ocean-0.27.2.dist-info/LICENSE.md,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
209
- port_ocean-0.27.2.dist-info/METADATA,sha256=i1U80P8ZYN4o6kNPfWsYpcCnPlQsBSoh0llLjg4Dk7A,6887
210
- port_ocean-0.27.2.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
211
- port_ocean-0.27.2.dist-info/entry_points.txt,sha256=F_DNUmGZU2Kme-8NsWM5LLE8piGMafYZygRYhOVtcjA,54
212
- port_ocean-0.27.2.dist-info/RECORD,,
209
+ port_ocean-0.27.5.dist-info/LICENSE.md,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
210
+ port_ocean-0.27.5.dist-info/METADATA,sha256=YxYbuOrrT9MffCzL-2qz0CxfqVKSVokwwolQfOHxSsI,6887
211
+ port_ocean-0.27.5.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
212
+ port_ocean-0.27.5.dist-info/entry_points.txt,sha256=F_DNUmGZU2Kme-8NsWM5LLE8piGMafYZygRYhOVtcjA,54
213
+ port_ocean-0.27.5.dist-info/RECORD,,