port-ocean 0.30.7__py3-none-any.whl → 0.31.0__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.
@@ -1,321 +1,9 @@
1
1
  import pytest
2
2
 
3
3
  from port_ocean.core.integrations.mixins.utils import (
4
- _build_mapping_jq_expression,
5
4
  extract_jq_deletion_path_revised,
6
- recursive_dict_merge,
7
5
  )
8
6
 
9
-
10
- class TestBuildMappingJqExpression:
11
- """Tests for _build_mapping_jq_expression function."""
12
-
13
- def test_build_mapping_jq_expression_non_path_type(self) -> None:
14
- """Test jq expression building for non-path type."""
15
- items_to_parse_name = "items"
16
- base_jq = ".file.content"
17
- delete_target = ".file.content.raw"
18
-
19
- result = _build_mapping_jq_expression(
20
- items_to_parse_name, base_jq, delete_target, is_path_type=False
21
- )
22
-
23
- expected = "map(($all | del(.file.content.raw)) + {items: . })"
24
- assert result == expected
25
-
26
- def test_build_mapping_jq_expression_path_type(self) -> None:
27
- """Test jq expression building for path type."""
28
- items_to_parse_name = "items"
29
- base_jq = ".file.content"
30
- delete_target = ".file.content.raw"
31
-
32
- result = _build_mapping_jq_expression(
33
- items_to_parse_name, base_jq, delete_target, is_path_type=True
34
- )
35
-
36
- expected = "map({items: . } | .file.content = (($all | del(.file.content.raw)) // {}))"
37
- assert result == expected
38
-
39
- def test_build_mapping_jq_expression_with_different_delete_target(self) -> None:
40
- """Test jq expression building with different delete targets."""
41
- items_to_parse_name = "parsed_data"
42
- base_jq = ".data"
43
- delete_target = ".data.temp"
44
-
45
- # Non-path type
46
- result_non_path = _build_mapping_jq_expression(
47
- items_to_parse_name, base_jq, delete_target, is_path_type=False
48
- )
49
- expected_non_path = "map(($all | del(.data.temp)) + {parsed_data: . })"
50
- assert result_non_path == expected_non_path
51
-
52
- # Path type
53
- result_path = _build_mapping_jq_expression(
54
- items_to_parse_name, base_jq, delete_target, is_path_type=True
55
- )
56
- expected_path = "map({parsed_data: . } | .data = (($all | del(.data.temp)) // {}))"
57
- assert result_path == expected_path
58
-
59
- def test_build_mapping_jq_expression_with_simple_delete_target(self) -> None:
60
- """Test jq expression building with simple delete target."""
61
- items_to_parse_name = "items"
62
- base_jq = "."
63
- delete_target = "."
64
-
65
- # Non-path type
66
- result_non_path = _build_mapping_jq_expression(
67
- items_to_parse_name, base_jq, delete_target, is_path_type=False
68
- )
69
- expected_non_path = "map(($all | del(.)) + {items: . })"
70
- assert result_non_path == expected_non_path
71
-
72
- # Path type
73
- result_path = _build_mapping_jq_expression(
74
- items_to_parse_name, base_jq, delete_target, is_path_type=True
75
- )
76
- expected_path = "map({items: . } | . = (($all | del(.)) // {}))"
77
- assert result_path == expected_path
78
-
79
-
80
- class TestRecursiveDictMerge:
81
- """Tests for recursive_dict_merge function."""
82
-
83
- def test_simple_merge_new_keys(self) -> None:
84
- """Test merging dictionaries with new keys."""
85
- d1 = {"a": 1, "b": 2}
86
- d2 = {"c": 3, "d": 4}
87
-
88
- result = recursive_dict_merge(d1, d2)
89
-
90
- assert result == {"a": 1, "b": 2, "c": 3, "d": 4}
91
- # Ensure original dicts are not modified
92
- assert d1 == {"a": 1, "b": 2}
93
- assert d2 == {"c": 3, "d": 4}
94
-
95
- def test_simple_overwrite(self) -> None:
96
- """Test overwriting values with non-dict values."""
97
- d1 = {"a": 1, "b": 2}
98
- d2 = {"b": 3, "c": 4}
99
-
100
- result = recursive_dict_merge(d1, d2)
101
-
102
- assert result == {"a": 1, "b": 3, "c": 4}
103
-
104
- def test_deep_merge(self) -> None:
105
- """Test recursive merging of nested dictionaries."""
106
- d1 = {"a": 1, "nested": {"x": 10, "y": 20}}
107
- d2 = {"b": 2, "nested": {"y": 30, "z": 40}}
108
-
109
- result = recursive_dict_merge(d1, d2)
110
-
111
- assert result == {"a": 1, "b": 2, "nested": {"x": 10, "y": 30, "z": 40}}
112
-
113
- def test_empty_dict_overwrite(self) -> None:
114
- """Test that empty dict in d2 overwrites non-empty dict in d1."""
115
- d1 = {"a": 1, "nested": {"x": 10, "y": 20}}
116
- d2 = {"nested": {}}
117
-
118
- result = recursive_dict_merge(d1, d2)
119
-
120
- assert result == {"a": 1, "nested": {}}
121
-
122
- def test_empty_dict_overwrite_multiple_levels(self) -> None:
123
- """Test empty dict overwrite at multiple nesting levels."""
124
- d1 = {
125
- "level1": {
126
- "level2": {
127
- "level3": {"value": 100}
128
- }
129
- }
130
- }
131
- d2 = {
132
- "level1": {
133
- "level2": {}
134
- }
135
- }
136
-
137
- result = recursive_dict_merge(d1, d2)
138
-
139
- assert result == {"level1": {"level2": {}}}
140
-
141
- def test_mixed_types(self) -> None:
142
- """Test merging with mixed value types."""
143
- d1 = {
144
- "string": "hello",
145
- "number": 42,
146
- "list": [1, 2, 3],
147
- "nested": {"a": 1}
148
- }
149
- d2 = {
150
- "string": "world",
151
- "number": 100,
152
- "list": [4, 5, 6],
153
- "nested": {"b": 2}
154
- }
155
-
156
- result = recursive_dict_merge(d1, d2)
157
-
158
- assert result == {
159
- "string": "world",
160
- "number": 100,
161
- "list": [4, 5, 6],
162
- "nested": {"a": 1, "b": 2}
163
- }
164
-
165
- def test_deep_nested_merge(self) -> None:
166
- """Test merging deeply nested structures."""
167
- d1 = {
168
- "a": {
169
- "b": {
170
- "c": {
171
- "d": 1,
172
- "e": 2
173
- }
174
- }
175
- }
176
- }
177
- d2 = {
178
- "a": {
179
- "b": {
180
- "c": {
181
- "e": 3,
182
- "f": 4
183
- }
184
- }
185
- }
186
- }
187
-
188
- result = recursive_dict_merge(d1, d2)
189
-
190
- assert result == {
191
- "a": {
192
- "b": {
193
- "c": {
194
- "d": 1,
195
- "e": 3,
196
- "f": 4
197
- }
198
- }
199
- }
200
- }
201
-
202
- def test_empty_dictionaries(self) -> None:
203
- """Test merging with empty dictionaries."""
204
- d1 = {}
205
- d2 = {"a": 1}
206
-
207
- result = recursive_dict_merge(d1, d2)
208
-
209
- assert result == {"a": 1}
210
-
211
- def test_both_empty_dictionaries(self) -> None:
212
- """Test merging two empty dictionaries."""
213
- d1 = {}
214
- d2 = {}
215
-
216
- result = recursive_dict_merge(d1, d2)
217
-
218
- assert result == {}
219
-
220
- def test_immutability_d1(self) -> None:
221
- """Test that d1 is not modified by the merge operation."""
222
- d1 = {"a": 1, "nested": {"x": 10}}
223
- d2 = {"b": 2, "nested": {"y": 20}}
224
-
225
- original_d1 = {"a": 1, "nested": {"x": 10}}
226
- result = recursive_dict_merge(d1, d2)
227
-
228
- # Verify d1 is unchanged
229
- assert d1 == original_d1
230
- # Verify result is correct
231
- assert result == {"a": 1, "b": 2, "nested": {"x": 10, "y": 20}}
232
-
233
- def test_immutability_d2(self) -> None:
234
- """Test that d2 is not modified by the merge operation."""
235
- d1 = {"a": 1}
236
- d2 = {"b": 2, "nested": {"x": 10}}
237
-
238
- original_d2 = {"b": 2, "nested": {"x": 10}}
239
- result = recursive_dict_merge(d1, d2)
240
-
241
- # Verify d2 is unchanged
242
- assert d2 == original_d2
243
- # Verify result is correct
244
- assert result == {"a": 1, "b": 2, "nested": {"x": 10}}
245
-
246
- def test_non_dict_value_overwrites_dict(self) -> None:
247
- """Test that non-dict value in d2 overwrites dict value in d1."""
248
- d1 = {"key": {"nested": "value"}}
249
- d2 = {"key": "simple_string"}
250
-
251
- result = recursive_dict_merge(d1, d2)
252
-
253
- assert result == {"key": "simple_string"}
254
-
255
- def test_dict_overwrites_non_dict_value(self) -> None:
256
- """Test that dict value in d2 overwrites non-dict value in d1."""
257
- d1 = {"key": "simple_string"}
258
- d2 = {"key": {"nested": "value"}}
259
-
260
- result = recursive_dict_merge(d1, d2)
261
-
262
- assert result == {"key": {"nested": "value"}}
263
-
264
- def test_complex_real_world_scenario(self) -> None:
265
- """Test a complex real-world merge scenario."""
266
- d1 = {
267
- "metadata": {
268
- "version": "1.0",
269
- "author": "Alice",
270
- "tags": ["python", "testing"]
271
- },
272
- "data": {
273
- "users": {
274
- "count": 100,
275
- "active": 80
276
- }
277
- },
278
- "config": {
279
- "debug": False
280
- }
281
- }
282
- d2 = {
283
- "metadata": {
284
- "version": "2.0",
285
- "tags": ["python", "testing", "advanced"]
286
- },
287
- "data": {
288
- "users": {
289
- "active": 90
290
- },
291
- "posts": {
292
- "count": 200
293
- }
294
- },
295
- "config": {}
296
- }
297
-
298
- result = recursive_dict_merge(d1, d2)
299
-
300
- assert result == {
301
- "metadata": {
302
- "version": "2.0",
303
- "author": "Alice",
304
- "tags": ["python", "testing", "advanced"]
305
- },
306
- "data": {
307
- "users": {
308
- "count": 100,
309
- "active": 90
310
- },
311
- "posts": {
312
- "count": 200
313
- }
314
- },
315
- "config": {}
316
- }
317
-
318
-
319
7
  class TestExtractJqDeletionPathRevised:
320
8
  """Tests for extract_jq_deletion_path_revised function."""
321
9
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: port-ocean
3
- Version: 0.30.7
3
+ Version: 0.31.0
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
@@ -1,13 +1,14 @@
1
- integrations/_infra/Dockerfile.Deb,sha256=ZqAg-p3GbLaneWS0sIcUDHp1FLwLoxHLvsKT5H8sCLc,2562
1
+ integrations/_infra/Dockerfile.Deb,sha256=sS-NHNFhHILEJYTeE_EB-ucSdv7uXvjnxrt4CPO0F1M,2571
2
2
  integrations/_infra/Dockerfile.alpine,sha256=7E4Sb-8supsCcseerHwTkuzjHZoYcaHIyxiBZ-wewo0,3482
3
3
  integrations/_infra/Dockerfile.base.builder,sha256=ESe1PKC6itp_AuXawbLI75k1Kruny6NTANaTinxOgVs,743
4
4
  integrations/_infra/Dockerfile.base.runner,sha256=uAcs2IsxrAAUHGXt_qULA5INr-HFguf5a5fCKiqEzbY,384
5
5
  integrations/_infra/Dockerfile.dockerignore,sha256=CM1Fxt3I2AvSvObuUZRmy5BNLSGC7ylnbpWzFgD4cso,1163
6
- integrations/_infra/Dockerfile.local,sha256=yLkNs8AB1QMsSXyb2OOo0F8cPXeNF9bb2pzAt2d9fZ8,1663
6
+ integrations/_infra/Dockerfile.local,sha256=k99T8tihUnr0XooazZIJOvaCn-dPhCb1Y3Urzmai2Xk,1672
7
7
  integrations/_infra/Makefile,sha256=YgLKvuF_Dw4IA7X98Nus6zIW_3cJ60M1QFGs3imj5c4,2430
8
8
  integrations/_infra/README.md,sha256=ZtJFSMCTU5zTeM8ddRuW1ZL1ga8z7Ic2F3mxmgOSjgo,1195
9
- integrations/_infra/entry_local.sh,sha256=Sn2TexTEpruH2ixIAGsk-fZV6Y7pT3jd2Pi9TxBeFuw,633
9
+ integrations/_infra/entry_local.sh,sha256=cCzEL8LQS5ZpxjdNEmmwAS1sTmdEzwWovxFQKx2B6QE,644
10
10
  integrations/_infra/grpcio.sh,sha256=m924poYznoRZ6Tt7Ct8Cs5AV_cmmOx598yIZ3z4DvZE,616
11
+ integrations/_infra/hosts,sha256=EYAFgljS0Oq0HXiGuAYSod7SltSxrCB6UK_TTcEqSTI,114
11
12
  integrations/_infra/init.sh,sha256=oVsYmJDseEZXuuzcuicgXkFbKHNyN8F6AIBHDwIMPb8,109
12
13
  port_ocean/__init__.py,sha256=uMpjg5d_cXgnyCxA_LmICR8zqBmC6Fe9Ivu9hcvJ7EY,313
13
14
  port_ocean/bootstrap.py,sha256=CN1M5pVecZ7z_Vfu86Dk2HjFMiuiwt6E_SSOLFCYRMk,1321
@@ -71,7 +72,7 @@ port_ocean/clients/port/utils.py,sha256=osFyAjw7Y5Qf2uVSqC7_RTCQfijiL1zS74JJM0go
71
72
  port_ocean/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
72
73
  port_ocean/config/base.py,sha256=x1gFbzujrxn7EJudRT81C6eN9WsYAb3vOHwcpcpX8Tc,6370
73
74
  port_ocean/config/dynamic.py,sha256=Lrk4JRGtR-0YKQ9DDGexX5NGFE7EJ6VoHya19YYhssM,2687
74
- port_ocean/config/settings.py,sha256=8NSEUwO1lOmH-D865zEllHS4e7yR1gd6Hqalwkt7AJM,8839
75
+ port_ocean/config/settings.py,sha256=eWuIXoZSLvbv8De3qC2RDE0WqWj3vo5zoq2lFdRjax0,8802
75
76
  port_ocean/consumers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
76
77
  port_ocean/consumers/kafka_consumer.py,sha256=N8KocjBi9aR0BOPG8hgKovg-ns_ggpEjrSxqSqF_BSo,4710
77
78
  port_ocean/context/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -106,7 +107,7 @@ port_ocean/core/handlers/entities_state_applier/port/get_related_entities.py,sha
106
107
  port_ocean/core/handlers/entities_state_applier/port/order_by_entities_dependencies.py,sha256=lyv6xKzhYfd6TioUgR3AVRSJqj7JpAaj1LxxU2xAqeo,1720
107
108
  port_ocean/core/handlers/entity_processor/__init__.py,sha256=FvFCunFg44wNQoqlybem9MthOs7p1Wawac87uSXz9U8,156
108
109
  port_ocean/core/handlers/entity_processor/base.py,sha256=PsnpNRqjHth9xwOvDRe7gKu8cjnVV0XGmTIHGvOelX0,1867
109
- port_ocean/core/handlers/entity_processor/jq_entity_processor.py,sha256=uGNo17A5esYIF7B9ihRWDs-TqIyuJvWt2XtLwgM405I,33281
110
+ port_ocean/core/handlers/entity_processor/jq_entity_processor.py,sha256=X39JOjRiF7lTmpN426KtRYjPM-tfL0MLrXkgEenkUZc,13697
110
111
  port_ocean/core/handlers/entity_processor/jq_input_evaluator.py,sha256=R88wf69RVtBl8t5m2IKGTmgt4JEQSbct_AmHI_tUOjg,5350
111
112
  port_ocean/core/handlers/port_app_config/__init__.py,sha256=8AAT5OthiVM7KCcM34iEgEeXtn2pRMrT4Dze5r1Ixbk,134
112
113
  port_ocean/core/handlers/port_app_config/api.py,sha256=r_Th66NEw38IpRdnXZcRvI8ACfvxW_A6V62WLwjWXlQ,1044
@@ -130,7 +131,7 @@ port_ocean/core/integrations/mixins/handler.py,sha256=mZ7-0UlG3LcrwJttFbMe-R4xcO
130
131
  port_ocean/core/integrations/mixins/live_events.py,sha256=zM24dhNc7uHx9XYZ6toVhDADPA90EnpOmZxgDegFZbA,4196
131
132
  port_ocean/core/integrations/mixins/sync.py,sha256=Vm_898pLKBwfVewtwouDWsXoxcOLicnAy6pzyqqk6U8,4053
132
133
  port_ocean/core/integrations/mixins/sync_raw.py,sha256=kcL7flnQ25E3KKyo6L3aL9wSzgBtoWYzgQjS4uRbDOs,42612
133
- port_ocean/core/integrations/mixins/utils.py,sha256=nvLxzbRqOpbVhpI0xbKczrTCtLcR0HysFxck9b1BBy0,17425
134
+ port_ocean/core/integrations/mixins/utils.py,sha256=EdjKtwdGQeUsktGyiMW4wcqq6KPYQlwR3TN5YBTQ96A,7559
134
135
  port_ocean/core/models.py,sha256=8ZNEmM3Nq0VSB3fYJVgEdJVjJmaGjMnng-bm-ZBbTNg,3695
135
136
  port_ocean/core/ocean_types.py,sha256=bkLlTd8XfJK6_JDl0eXUHfE_NygqgiInSMwJ4YJH01Q,1399
136
137
  port_ocean/core/utils/entity_topological_sorter.py,sha256=MDUjM6OuDy4Xj68o-7InNN0w1jqjxeDfeY8U02vySNI,3081
@@ -180,7 +181,7 @@ port_ocean/tests/core/defaults/test_initialize.py,sha256=wx-DyV6ooV4HtwWH6RUaUlp
180
181
  port_ocean/tests/core/event_listener/test_kafka.py,sha256=RN_JOCy4aRDUNvyQocO6WFvUMH2XeAZy-PIWHOYnD9M,2888
181
182
  port_ocean/tests/core/handlers/actions/test_execution_manager.py,sha256=5bOlcQ9qcXF_leoSFtw3FzTa7C1awUPo6TSss5e_76w,30753
182
183
  port_ocean/tests/core/handlers/entities_state_applier/test_applier.py,sha256=7XWgwUB9uVYRov4VbIz1A-7n2YLbHTTYT-4rKJxjB0A,10711
183
- port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py,sha256=gyyWbkQop50NsPaHGq1K1wlUD_SYYdnquQfOTqTbnGc,59403
184
+ port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py,sha256=ZiHwRIwBlL86m9rBaDnj_BlMFDAYmkvpV9hnRzWMryo,14990
184
185
  port_ocean/tests/core/handlers/entity_processor/test_jq_input_evaluator.py,sha256=xNlDK8d8YQOplgjZGSBq4rZYZx_atg2R5YyQnH0qfI4,42151
185
186
  port_ocean/tests/core/handlers/mixins/test_live_events.py,sha256=Sbv9IZAGQoZDhf27xDjMMVYxUSie9mHltDtxLSqckmM,12548
186
187
  port_ocean/tests/core/handlers/mixins/test_sync_raw.py,sha256=-Jd2rUG63fZM8LuyKtCp1tt4WEqO2m5woESjs1c91sU,44428
@@ -191,7 +192,7 @@ port_ocean/tests/core/handlers/queue/test_local_queue.py,sha256=9Ly0HzZXbs6Rbl_b
191
192
  port_ocean/tests/core/handlers/webhook/test_abstract_webhook_processor.py,sha256=zKwHhPAYEZoZ5Z2UETp1t--mbkS8uyvlXThB0obZTTc,3340
192
193
  port_ocean/tests/core/handlers/webhook/test_processor_manager.py,sha256=wKzKO79HByqtLcKoYUQ6PjZ-VZAUT1TwdZXyH9NchfY,52365
193
194
  port_ocean/tests/core/handlers/webhook/test_webhook_event.py,sha256=oR4dEHLO65mp6rkfNfszZcfFoRZlB8ZWee4XetmsuIk,3181
194
- port_ocean/tests/core/integrations/mixins/test_integration_utils.py,sha256=MDNCnx5V_XVmUgeJB68Mwpm57_fbpWksijKe7aTMU4k,17552
195
+ port_ocean/tests/core/integrations/mixins/test_integration_utils.py,sha256=3Rga7q3ZiEGuC-rHzxd0_oKqJlA3bVEbaagOLa1HaPk,8099
195
196
  port_ocean/tests/core/test_utils.py,sha256=Z3kdhb5V7Svhcyy3EansdTpgHL36TL6erNtU-OPwAcI,2647
196
197
  port_ocean/tests/core/utils/test_entity_topological_sorter.py,sha256=zuq5WSPy_88PemG3mOUIHTxWMR_js1R7tOzUYlgBd68,3447
197
198
  port_ocean/tests/core/utils/test_get_port_diff.py,sha256=YoQxAHZdX5nVpvrKV5Aox-jQ4w14AbfJVo-QK-ICAb8,4297
@@ -222,8 +223,8 @@ port_ocean/utils/repeat.py,sha256=U2OeCkHPWXmRTVoPV-VcJRlQhcYqPWI5NfmPlb1JIbc,32
222
223
  port_ocean/utils/signal.py,sha256=J1sI-e_32VHP_VUa5bskLMFoJjJOAk5isrnewKDikUI,2125
223
224
  port_ocean/utils/time.py,sha256=pufAOH5ZQI7gXvOvJoQXZXZJV-Dqktoj9Qp9eiRwmJ4,1939
224
225
  port_ocean/version.py,sha256=UsuJdvdQlazzKGD3Hd5-U7N69STh8Dq9ggJzQFnu9fU,177
225
- port_ocean-0.30.7.dist-info/LICENSE.md,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
226
- port_ocean-0.30.7.dist-info/METADATA,sha256=yhpz6MhQJbnfoqEshsGCT3nccx7bF9u9S19w1epTRiI,7095
227
- port_ocean-0.30.7.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
228
- port_ocean-0.30.7.dist-info/entry_points.txt,sha256=F_DNUmGZU2Kme-8NsWM5LLE8piGMafYZygRYhOVtcjA,54
229
- port_ocean-0.30.7.dist-info/RECORD,,
226
+ port_ocean-0.31.0.dist-info/LICENSE.md,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
227
+ port_ocean-0.31.0.dist-info/METADATA,sha256=hSdcBvk272olYEEOjGWHMaabTV8wspdOj_ZMiQFDA2g,7095
228
+ port_ocean-0.31.0.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
229
+ port_ocean-0.31.0.dist-info/entry_points.txt,sha256=F_DNUmGZU2Kme-8NsWM5LLE8piGMafYZygRYhOVtcjA,54
230
+ port_ocean-0.31.0.dist-info/RECORD,,