port-ocean 0.24.16__py3-none-any.whl → 0.24.18__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.
port_ocean/cache/disk.py CHANGED
@@ -20,7 +20,7 @@ class DiskCacheProvider(CacheProvider):
20
20
 
21
21
  def __init__(self, cache_dir: str | None = None) -> None:
22
22
  if cache_dir is None:
23
- cache_dir = ".ocean_cache"
23
+ cache_dir = "/tmp/ocean/.ocean_cache"
24
24
  self._cache_dir = Path(cache_dir)
25
25
  self._cache_dir.mkdir(parents=True, exist_ok=True)
26
26
 
@@ -1,3 +1,4 @@
1
+ from collections import defaultdict
1
2
  from loguru import logger
2
3
 
3
4
  from port_ocean.clients.port.types import UserAgentType
@@ -125,20 +126,27 @@ class HttpEntitiesStateApplier(BaseEntitiesStateApplier):
125
126
  ) -> list[Entity]:
126
127
  logger.info(f"Upserting {len(entities)} entities")
127
128
  modified_entities: list[Entity] = []
128
- upserted_entities: list[tuple[bool, Entity]] = []
129
129
 
130
- upserted_entities = await self.context.port_client.upsert_entities_in_batches(
131
- entities,
132
- event.port_app_config.get_port_request_options(),
133
- user_agent_type,
134
- should_raise=False,
135
- )
130
+ blueprint_groups: dict[str, list[Entity]] = defaultdict(list)
131
+ for entity in entities:
132
+ blueprint_groups[entity.blueprint].append(entity)
133
+
134
+ for blueprint_entities in blueprint_groups.values():
135
+ upserted_entities = (
136
+ await self.context.port_client.upsert_entities_in_batches(
137
+ blueprint_entities,
138
+ event.port_app_config.get_port_request_options(),
139
+ user_agent_type,
140
+ should_raise=False,
141
+ )
142
+ )
143
+
144
+ for is_upserted, entity in upserted_entities:
145
+ if is_upserted:
146
+ modified_entities.append(entity)
147
+ else:
148
+ event.entity_topological_sorter.register_entity(entity)
136
149
 
137
- for is_upserted, entity in upserted_entities:
138
- if is_upserted:
139
- modified_entities.append(entity)
140
- else:
141
- event.entity_topological_sorter.register_entity(entity)
142
150
  return modified_entities
143
151
 
144
152
  async def delete(
@@ -228,3 +228,61 @@ async def test_using_create_entity_helper(
228
228
 
229
229
  mock_upsert.assert_called_once()
230
230
  assert len(result) == 1
231
+
232
+
233
+ @pytest.mark.asyncio
234
+ async def test_upsert_groups_entities_by_blueprint(
235
+ mock_ocean: Ocean,
236
+ mock_context: PortOceanContext,
237
+ mock_port_app_config: PortAppConfig,
238
+ ) -> None:
239
+ """Test that upsert groups entities by blueprint and calls upsert_entities_in_batches separately for each group."""
240
+ applier = HttpEntitiesStateApplier(mock_context)
241
+
242
+ # Create entities with different blueprints
243
+ service_entity_1 = Entity(identifier="service_1", blueprint="service")
244
+ service_entity_2 = Entity(identifier="service_2", blueprint="service")
245
+ deployment_entity = Entity(identifier="deployment_1", blueprint="deployment")
246
+ user_entity = Entity(identifier="user_1", blueprint="user")
247
+
248
+ entities = [service_entity_1, deployment_entity, service_entity_2, user_entity]
249
+
250
+ async with event_context(EventType.RESYNC, trigger_type="machine") as event:
251
+ event.port_app_config = mock_port_app_config
252
+
253
+ mock_ocean.config.upsert_entities_batch_max_length = 100
254
+ mock_ocean.config.upsert_entities_batch_max_size_in_bytes = 1000
255
+
256
+ # Mock the upsert_entities_in_batches method to track calls
257
+ mock_upsert = AsyncMock()
258
+ mock_upsert.side_effect = [
259
+ [
260
+ (True, service_entity_1),
261
+ (True, service_entity_2),
262
+ ], # First call for "service" blueprint
263
+ [(True, deployment_entity)], # Second call for "deployment" blueprint
264
+ [(True, user_entity)], # Third call for "user" blueprint
265
+ ]
266
+ setattr(mock_ocean.port_client, "upsert_entities_in_batches", mock_upsert)
267
+
268
+ result = await applier.upsert(entities, UserAgentType.exporter)
269
+
270
+ assert mock_upsert.call_count == 3
271
+
272
+ assert len(result) == 4
273
+
274
+ calls = mock_upsert.call_args_list
275
+
276
+ called_entities_groups = [call[0][0] for call in calls]
277
+ blueprint_counts = {}
278
+ for entities_group in called_entities_groups:
279
+ blueprint = entities_group[0].blueprint
280
+ for entity in entities_group:
281
+ assert entity.blueprint == blueprint
282
+ blueprint_counts[blueprint] = len(entities_group)
283
+
284
+ # Verify the expected blueprint counts
285
+ assert blueprint_counts["service"] == 2
286
+ assert blueprint_counts["deployment"] == 1
287
+ assert blueprint_counts["user"] == 1
288
+ assert len(blueprint_counts) == 3
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: port-ocean
3
- Version: 0.24.16
3
+ Version: 0.24.18
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
@@ -12,7 +12,7 @@ port_ocean/__init__.py,sha256=uMpjg5d_cXgnyCxA_LmICR8zqBmC6Fe9Ivu9hcvJ7EY,313
12
12
  port_ocean/bootstrap.py,sha256=CN1M5pVecZ7z_Vfu86Dk2HjFMiuiwt6E_SSOLFCYRMk,1321
13
13
  port_ocean/cache/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
14
  port_ocean/cache/base.py,sha256=XfsIfbE5y22pqr18sJMCCT4kS6h6BztHNpiH2aoubGM,661
15
- port_ocean/cache/disk.py,sha256=f1FHP74qWwVxMs4UdOzyoTWW0mPVTwfka8rITLi3ISg,1903
15
+ port_ocean/cache/disk.py,sha256=4yCJJEVWNSWT4DhtpvZe-FOD6gszvp_3zhCtfQDMXlI,1914
16
16
  port_ocean/cache/errors.py,sha256=KZ7c3L9k1e0Btw-BBERAxjONKkmQoH7EllTvFEiqQEA,145
17
17
  port_ocean/cache/memory.py,sha256=w4Jhvpa56j1vQ1XQ-XFe8KQPVkVzLsF8RmgwZm4XUCA,1246
18
18
  port_ocean/cli/__init__.py,sha256=ZjTGS305llhbjC2BH2KkVj34gCASBGwqc5HZEO_0T_Q,328
@@ -95,7 +95,7 @@ port_ocean/core/handlers/base.py,sha256=cTarblazu8yh8xz2FpB-dzDKuXxtoi143XJgPbV_
95
95
  port_ocean/core/handlers/entities_state_applier/__init__.py,sha256=kgLZDCeCEzi4r-0nzW9k78haOZNf6PX7mJOUr34A4c8,173
96
96
  port_ocean/core/handlers/entities_state_applier/base.py,sha256=5wHL0icfFAYRPqk8iV_wN49GdJ3aRUtO8tumSxBi4Wo,2268
97
97
  port_ocean/core/handlers/entities_state_applier/port/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
98
- port_ocean/core/handlers/entities_state_applier/port/applier.py,sha256=QzN8OWgp-i4bRwslnLo5qjS7rt93Stceq9C4FD11Vy4,6372
98
+ port_ocean/core/handlers/entities_state_applier/port/applier.py,sha256=NsLW35H1dhP5FFD7kHZxA2ndSBcD_-btan7qNWfvWrs,6683
99
99
  port_ocean/core/handlers/entities_state_applier/port/get_related_entities.py,sha256=1zncwCbE-Gej0xaWKlzZgoXxOBe9bgs_YxlZ8QW3NdI,1751
100
100
  port_ocean/core/handlers/entities_state_applier/port/order_by_entities_dependencies.py,sha256=lyv6xKzhYfd6TioUgR3AVRSJqj7JpAaj1LxxU2xAqeo,1720
101
101
  port_ocean/core/handlers/entity_processor/__init__.py,sha256=FvFCunFg44wNQoqlybem9MthOs7p1Wawac87uSXz9U8,156
@@ -163,7 +163,7 @@ port_ocean/tests/clients/port/mixins/test_organization_mixin.py,sha256=zzKYz3h8d
163
163
  port_ocean/tests/conftest.py,sha256=JXASSS0IY0nnR6bxBflhzxS25kf4iNaABmThyZ0mZt8,101
164
164
  port_ocean/tests/core/conftest.py,sha256=7K_M1--wQ08VmiQRB0vo1nst2X00cwsuBS5UfERsnG8,7589
165
165
  port_ocean/tests/core/defaults/test_common.py,sha256=sR7RqB3ZYV6Xn6NIg-c8k5K6JcGsYZ2SCe_PYX5vLYM,5560
166
- port_ocean/tests/core/handlers/entities_state_applier/test_applier.py,sha256=eJYXc7AwrV0XRS6HpixwzghjB3pspT5Gxr9twvJE7fk,8290
166
+ port_ocean/tests/core/handlers/entities_state_applier/test_applier.py,sha256=_CZyViY9_gnxjY6ogWcDdmEDuejvpALogf9ESjVAwFY,10675
167
167
  port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py,sha256=8WpMn559Mf0TFWmloRpZrVgr6yWwyA0C4n2lVHCtyq4,13596
168
168
  port_ocean/tests/core/handlers/mixins/test_live_events.py,sha256=iAwVpr3n3PIkXQLw7hxd-iB_SR_vyfletVXJLOmyz28,12480
169
169
  port_ocean/tests/core/handlers/mixins/test_sync_raw.py,sha256=-05ec3gRsmnMgmqzkIRjpm_yMdRZc3O3Br3RLFW2Kjw,44297
@@ -200,8 +200,8 @@ port_ocean/utils/repeat.py,sha256=U2OeCkHPWXmRTVoPV-VcJRlQhcYqPWI5NfmPlb1JIbc,32
200
200
  port_ocean/utils/signal.py,sha256=mMVq-1Ab5YpNiqN4PkiyTGlV_G0wkUDMMjTZp5z3pb0,1514
201
201
  port_ocean/utils/time.py,sha256=pufAOH5ZQI7gXvOvJoQXZXZJV-Dqktoj9Qp9eiRwmJ4,1939
202
202
  port_ocean/version.py,sha256=UsuJdvdQlazzKGD3Hd5-U7N69STh8Dq9ggJzQFnu9fU,177
203
- port_ocean-0.24.16.dist-info/LICENSE.md,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
204
- port_ocean-0.24.16.dist-info/METADATA,sha256=KM33tc1Hz4OpYMIto3ea5Q6Ouz1RTQn_-U37-JB2Xto,6856
205
- port_ocean-0.24.16.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
206
- port_ocean-0.24.16.dist-info/entry_points.txt,sha256=F_DNUmGZU2Kme-8NsWM5LLE8piGMafYZygRYhOVtcjA,54
207
- port_ocean-0.24.16.dist-info/RECORD,,
203
+ port_ocean-0.24.18.dist-info/LICENSE.md,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
204
+ port_ocean-0.24.18.dist-info/METADATA,sha256=_7Ml24Uq2yXvMqqCWmn8NpcME2Cr1Mle6BMb1GgzguA,6856
205
+ port_ocean-0.24.18.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
206
+ port_ocean-0.24.18.dist-info/entry_points.txt,sha256=F_DNUmGZU2Kme-8NsWM5LLE8piGMafYZygRYhOVtcjA,54
207
+ port_ocean-0.24.18.dist-info/RECORD,,