port-ocean 0.28.11__py3-none-any.whl → 0.28.14__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.

Potentially problematic release.


This version of port-ocean might be problematic. Click here for more details.

@@ -272,3 +272,243 @@ async def test_cache_failures_dont_affect_execution(
272
272
  # Verify that both read and write errors were raised
273
273
  assert isinstance(mock_cache_provider.get.side_effect, FailedToReadCacheError)
274
274
  assert isinstance(mock_cache_provider.set.side_effect, FailedToWriteCacheError)
275
+
276
+
277
+ @pytest.mark.asyncio
278
+ async def test_cache_iterator_result_on_instance_method(
279
+ mock_ocean: Any, monkeypatch: Any
280
+ ) -> None:
281
+ monkeypatch.setattr(cache, "ocean", mock_ocean)
282
+
283
+ class Sample:
284
+ def __init__(self) -> None:
285
+ self.calls = 0
286
+
287
+ @cache.cache_iterator_result()
288
+ async def inst_method(self, x: int) -> AsyncGenerator[List[int], None]:
289
+ self.calls += 1
290
+ for i in range(x):
291
+ await asyncio.sleep(0.01)
292
+ yield [i]
293
+
294
+ s = Sample()
295
+
296
+ # First call should MISS and increment calls
297
+ result1 = await collect_iterator_results(s.inst_method(3))
298
+ assert result1 == [0, 1, 2]
299
+ assert s.calls == 1
300
+
301
+ # Second call with same args should HIT cache
302
+ result2 = await collect_iterator_results(s.inst_method(3))
303
+ assert result2 == [0, 1, 2]
304
+ assert s.calls == 1 # no extra call
305
+
306
+ # Different args should MISS again
307
+ result3 = await collect_iterator_results(s.inst_method(4))
308
+ assert result3 == [0, 1, 2, 3]
309
+ assert s.calls == 2
310
+
311
+
312
+ @pytest.mark.asyncio
313
+ async def test_cache_iterator_result_on_class_method(
314
+ mock_ocean: Any, monkeypatch: Any
315
+ ) -> None:
316
+ monkeypatch.setattr(cache, "ocean", mock_ocean)
317
+
318
+ class Sample:
319
+ calls = 0
320
+
321
+ @classmethod
322
+ @cache.cache_iterator_result()
323
+ async def cls_method(cls, x: int) -> AsyncGenerator[List[int], None]:
324
+ cls.calls += 1
325
+ for i in range(x):
326
+ await asyncio.sleep(0.01)
327
+ yield [i]
328
+
329
+ # First call should MISS
330
+ result1 = await collect_iterator_results(Sample.cls_method(3))
331
+ assert result1 == [0, 1, 2]
332
+ assert Sample.calls == 1
333
+
334
+ # Second call with same args should HIT cache
335
+ result2 = await collect_iterator_results(Sample.cls_method(3))
336
+ assert result2 == [0, 1, 2]
337
+ assert Sample.calls == 1
338
+
339
+ # Different args should MISS
340
+ result3 = await collect_iterator_results(Sample.cls_method(2))
341
+ assert result3 == [0, 1]
342
+ assert Sample.calls == 2
343
+
344
+
345
+ @pytest.mark.asyncio
346
+ async def test_cache_iterator_result_on_static_method(
347
+ mock_ocean: Any, monkeypatch: Any
348
+ ) -> None:
349
+ monkeypatch.setattr(cache, "ocean", mock_ocean)
350
+
351
+ class Sample:
352
+ calls = 0
353
+
354
+ @staticmethod
355
+ @cache.cache_iterator_result()
356
+ async def static_method(x: int) -> AsyncGenerator[List[int], None]:
357
+ Sample.calls += 1
358
+ for i in range(x):
359
+ await asyncio.sleep(0.01)
360
+ yield [i]
361
+
362
+ # First call should MISS
363
+ result1 = await collect_iterator_results(Sample.static_method(3))
364
+ assert result1 == [0, 1, 2]
365
+ assert Sample.calls == 1
366
+
367
+ # Second call with same args should HIT
368
+ result2 = await collect_iterator_results(Sample.static_method(3))
369
+ assert result2 == [0, 1, 2]
370
+ assert Sample.calls == 1
371
+
372
+ # Different args should MISS
373
+ result3 = await collect_iterator_results(Sample.static_method(4))
374
+ assert result3 == [0, 1, 2, 3]
375
+ assert Sample.calls == 2
376
+
377
+
378
+ @pytest.mark.asyncio
379
+ async def test_regular_iterator_with_self_param_not_filtered(
380
+ mock_ocean: Any, monkeypatch: Any
381
+ ) -> None:
382
+ """Test that regular iterator functions with 'self' parameter are not filtered (by design)."""
383
+ monkeypatch.setattr(cache, "ocean", mock_ocean)
384
+
385
+ async def regular_function_with_self(
386
+ self: int, y: int
387
+ ) -> AsyncGenerator[List[int], None]:
388
+ for i in range(self + y):
389
+ await asyncio.sleep(0.01)
390
+ yield [i]
391
+
392
+ # Test that 'self' parameter IS filtered (by design, for consistency)
393
+ key1 = cache.hash_func(regular_function_with_self, 5, y=3)
394
+ key2 = cache.hash_func(regular_function_with_self, 4, y=3)
395
+
396
+ # Keys should not be the same because 'self' is not filtered (by design)
397
+ assert key1 != key2
398
+
399
+
400
+ @pytest.mark.asyncio
401
+ async def test_cache_coroutine_result_on_instance_method(
402
+ mock_ocean: Any, monkeypatch: Any
403
+ ) -> None:
404
+ monkeypatch.setattr(cache, "ocean", mock_ocean)
405
+
406
+ class Sample:
407
+ def __init__(self) -> None:
408
+ self.calls = 0
409
+
410
+ @cache.cache_coroutine_result()
411
+ async def inst_method(self, x: int) -> int:
412
+ self.calls += 1
413
+ await asyncio.sleep(0.01)
414
+ return x * 2
415
+
416
+ s = Sample()
417
+
418
+ # First call should MISS and increment calls
419
+ result1 = await s.inst_method(3)
420
+ assert result1 == 6
421
+ assert s.calls == 1
422
+
423
+ # Second call with same args should HIT cache
424
+ result2 = await s.inst_method(3)
425
+ assert result2 == 6
426
+ assert s.calls == 1 # still 1 call
427
+
428
+ # Different args should MISS again
429
+ result3 = await s.inst_method(4)
430
+ assert result3 == 8
431
+ assert s.calls == 2
432
+
433
+
434
+ @pytest.mark.asyncio
435
+ async def test_cache_coroutine_result_on_class_method(
436
+ mock_ocean: Any, monkeypatch: Any
437
+ ) -> None:
438
+ monkeypatch.setattr(cache, "ocean", mock_ocean)
439
+
440
+ class Sample:
441
+ calls = 0
442
+
443
+ @classmethod
444
+ @cache.cache_coroutine_result()
445
+ async def cls_method(cls, x: int) -> int:
446
+ cls.calls += 1
447
+ await asyncio.sleep(0.01)
448
+ return x + 5
449
+
450
+ # First call should MISS
451
+ result1 = await Sample.cls_method(3)
452
+ assert result1 == 8
453
+ assert Sample.calls == 1
454
+
455
+ # Second call with same args should HIT
456
+ result2 = await Sample.cls_method(3)
457
+ assert result2 == 8
458
+ assert Sample.calls == 1
459
+
460
+ # Different args should MISS
461
+ result3 = await Sample.cls_method(2)
462
+ assert result3 == 7
463
+ assert Sample.calls == 2
464
+
465
+
466
+ @pytest.mark.asyncio
467
+ async def test_cache_coroutine_result_on_static_method(
468
+ mock_ocean: Any, monkeypatch: Any
469
+ ) -> None:
470
+ monkeypatch.setattr(cache, "ocean", mock_ocean)
471
+
472
+ class Sample:
473
+ calls = 0
474
+
475
+ @staticmethod
476
+ @cache.cache_coroutine_result()
477
+ async def static_method(x: int) -> int:
478
+ Sample.calls += 1
479
+ await asyncio.sleep(0.01)
480
+ return x * x
481
+
482
+ # First call should MISS
483
+ result1 = await Sample.static_method(3)
484
+ assert result1 == 9
485
+ assert Sample.calls == 1
486
+
487
+ # Second call with same args should HIT
488
+ result2 = await Sample.static_method(3)
489
+ assert result2 == 9
490
+ assert Sample.calls == 1
491
+
492
+ # Different args should MISS
493
+ result3 = await Sample.static_method(4)
494
+ assert result3 == 16
495
+ assert Sample.calls == 2
496
+
497
+
498
+ @pytest.mark.asyncio
499
+ async def test_regular_coroutine_with_self_param_not_filtered(
500
+ mock_ocean: Any, monkeypatch: Any
501
+ ) -> None:
502
+ """Test that regular coroutines with 'self' parameter are not filtered (by design)."""
503
+ monkeypatch.setattr(cache, "ocean", mock_ocean)
504
+
505
+ @cache.cache_coroutine_result()
506
+ async def regular_function_with_self(self: int, y: int) -> int:
507
+ await asyncio.sleep(0.01)
508
+ return self + y
509
+
510
+ key1 = cache.hash_func(regular_function_with_self, 5, y=3)
511
+ key2 = cache.hash_func(regular_function_with_self, 4, y=3)
512
+
513
+ # Keys should not be the same because 'self' is not filtered
514
+ assert key1 != key2
port_ocean/utils/cache.py CHANGED
@@ -10,14 +10,50 @@ AsyncIteratorCallable = Callable[..., AsyncIterator[list[Any]]]
10
10
  AsyncCallable = Callable[..., Awaitable[Any]]
11
11
 
12
12
 
13
- def hash_func(function_name: str, *args: Any, **kwargs: Any) -> str:
14
- args_str = str(args)
15
- kwargs_str = str(kwargs)
16
- concatenated_string = args_str + kwargs_str
17
- hash_object = hashlib.sha256(concatenated_string.encode())
18
- short_hash = base64.urlsafe_b64encode(hash_object.digest()[:8]).decode("ascii")
13
+ def sanitize_identifier(name: str) -> str:
14
+ """
15
+ Sanitize a function identifier so it is safe for all cache backends:
16
+ - Replace non-alphanumeric character with "_".
17
+ - Convert to lowercase for consistency.
18
+ """
19
+ return (
20
+ name.replace(".", "_")
21
+ .replace("-", "_")
22
+ .replace(" ", "_")
23
+ .replace("<", "_")
24
+ .replace(">", "_")
25
+ .lower()
26
+ )
27
+
28
+
29
+ def hash_func(func: Callable[..., Any], *args: Any, **kwargs: Any) -> str:
30
+ """
31
+ Generate a backend-safe cache key.
32
+
33
+ - Drops first arg if it's instance/class methods.
34
+ - Keeps all args for static/free functions.
35
+ - Key = sanitized module+qualname + short hash of args/kwargs.
36
+ """
37
+
38
+ if args and hasattr(args[0], func.__name__):
39
+ filtered_args = args[1:]
40
+ else:
41
+ filtered_args = args
42
+
43
+ arg_string = repr(filtered_args)
44
+ kwarg_string = repr(sorted(kwargs.items()))
45
+ concatenated = arg_string + kwarg_string
46
+
47
+ # Short hash
48
+ digest = hashlib.sha256(concatenated.encode()).digest()[:8]
49
+ short_hash = base64.urlsafe_b64encode(digest).decode("ascii")
19
50
  short_hash = short_hash.rstrip("=").replace("-", "_").replace("+", "_")
20
- return f"{function_name}_{short_hash}"
51
+
52
+ # Unique function identifier
53
+ func_id = f"{func.__module__}_{func.__qualname__}"
54
+ safe_func_id = sanitize_identifier(func_id)
55
+
56
+ return f"{safe_func_id}_{short_hash}"
21
57
 
22
58
 
23
59
  def cache_iterator_result() -> Callable[[AsyncIteratorCallable], AsyncIteratorCallable]:
@@ -45,7 +81,7 @@ def cache_iterator_result() -> Callable[[AsyncIteratorCallable], AsyncIteratorCa
45
81
  def decorator(func: AsyncIteratorCallable) -> AsyncIteratorCallable:
46
82
  @functools.wraps(func)
47
83
  async def wrapper(*args: Any, **kwargs: Any) -> Any:
48
- cache_key = hash_func(func.__name__, *args, **kwargs)
84
+ cache_key = hash_func(func, *args, **kwargs)
49
85
 
50
86
  # Check if the result is already in the cache
51
87
  try:
@@ -98,7 +134,7 @@ def cache_coroutine_result() -> Callable[[AsyncCallable], AsyncCallable]:
98
134
  def decorator(func: AsyncCallable) -> AsyncCallable:
99
135
  @functools.wraps(func)
100
136
  async def wrapper(*args: Any, **kwargs: Any) -> Any:
101
- cache_key = hash_func(func.__name__, *args, **kwargs)
137
+ cache_key = hash_func(func, *args, **kwargs)
102
138
  try:
103
139
  if cache := await ocean.app.cache_provider.get(cache_key):
104
140
  return cache
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: port-ocean
3
- Version: 0.28.11
3
+ Version: 0.28.14
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,9 +1,9 @@
1
- integrations/_infra/Dockerfile.Deb,sha256=QNyStzc0Zov1e3sejWna84yhrdOPO8Ogc-r_he3fYT4,2549
1
+ integrations/_infra/Dockerfile.Deb,sha256=ZqAg-p3GbLaneWS0sIcUDHp1FLwLoxHLvsKT5H8sCLc,2562
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=FFX9RvFqlaHvhUrRnnzUl0zQp2oKDFVRGkXJQPMQ7cI,1650
6
+ integrations/_infra/Dockerfile.local,sha256=yLkNs8AB1QMsSXyb2OOo0F8cPXeNF9bb2pzAt2d9fZ8,1663
7
7
  integrations/_infra/Makefile,sha256=YgLKvuF_Dw4IA7X98Nus6zIW_3cJ60M1QFGs3imj5c4,2430
8
8
  integrations/_infra/README.md,sha256=ZtJFSMCTU5zTeM8ddRuW1ZL1ga8z7Ic2F3mxmgOSjgo,1195
9
9
  integrations/_infra/entry_local.sh,sha256=Sn2TexTEpruH2ixIAGsk-fZV6Y7pT3jd2Pi9TxBeFuw,633
@@ -61,7 +61,7 @@ port_ocean/clients/port/client.py,sha256=hBXgU0CDseN2F-vn20JqowfVkcd6oSVmYrjn6t4
61
61
  port_ocean/clients/port/mixins/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
62
62
  port_ocean/clients/port/mixins/blueprints.py,sha256=aMCG4zePsMSMjMLiGrU37h5z5_ElfMzTcTvqvOI5wXY,4683
63
63
  port_ocean/clients/port/mixins/entities.py,sha256=X2NqH00eK6TMJ3a3QEQRVQlKHzyj5l1FiPkIhonnbPg,24234
64
- port_ocean/clients/port/mixins/integrations.py,sha256=oBkO6OtRtos7KmjS-QUnudhrxHRoNOmaClVNnc1_EHU,12042
64
+ port_ocean/clients/port/mixins/integrations.py,sha256=8EhGms1_iOaAPEexmHGF4PJaSSL4O09GtXr_Q8UyaJI,12049
65
65
  port_ocean/clients/port/mixins/migrations.py,sha256=vdL_A_NNUogvzujyaRLIoZEu5vmKDY2BxTjoGP94YzI,1467
66
66
  port_ocean/clients/port/mixins/organization.py,sha256=A2cP5V49KnjoAXxjmnm_XGth4ftPSU0qURNfnyUyS_Y,1041
67
67
  port_ocean/clients/port/retry_transport.py,sha256=PtIZOAZ6V-ncpVysRUsPOgt8Sf01QLnTKB5YeKBxkJk,1861
@@ -101,11 +101,12 @@ 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=qvPMbIH1XRvaZ-TvW7lw9k4W27ZPCHcXGSdqnZ0wblw,12970
104
+ port_ocean/core/handlers/entity_processor/jq_entity_processor.py,sha256=VEL_aEme7gGrS0jvKgYMcBPIX02ntW7lT5V1KG12pJA,32003
105
+ port_ocean/core/handlers/entity_processor/jq_input_evaluator.py,sha256=hInrBMQBbOqZApB53CMLyTgLtC7FltRtqK9PqD0CgM0,4803
105
106
  port_ocean/core/handlers/port_app_config/__init__.py,sha256=8AAT5OthiVM7KCcM34iEgEeXtn2pRMrT4Dze5r1Ixbk,134
106
107
  port_ocean/core/handlers/port_app_config/api.py,sha256=r_Th66NEw38IpRdnXZcRvI8ACfvxW_A6V62WLwjWXlQ,1044
107
108
  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=J-dfd9fEcTA77zJKL_Qd3bvg-v3B_-vZe06Mo-V5ptE,3091
109
+ port_ocean/core/handlers/port_app_config/models.py,sha256=buDkw-LHtKJ6zCxlc6Yq7AUJFwzhhYHqLvgXgou-xbM,3084
109
110
  port_ocean/core/handlers/queue/__init__.py,sha256=yzgicE_jAR1wtljFKxgyG6j-HbLcG_Zze5qw1kkALUI,171
110
111
  port_ocean/core/handlers/queue/abstract_queue.py,sha256=SaivrYbqg8qsX6wtQlJZyxgcbdMD5B9NZG3byN9AvrI,782
111
112
  port_ocean/core/handlers/queue/group_queue.py,sha256=JvvJOwz9z_aI4CjPr7yQX-0rOgqLI5wMdxWk2x5x-34,4989
@@ -123,8 +124,8 @@ port_ocean/core/integrations/mixins/events.py,sha256=2L7P3Jhp8XBqddh2_o9Cn4N261n
123
124
  port_ocean/core/integrations/mixins/handler.py,sha256=mZ7-0UlG3LcrwJttFbMe-R4xcOU2H_g33tZar7PwTv8,3771
124
125
  port_ocean/core/integrations/mixins/live_events.py,sha256=zM24dhNc7uHx9XYZ6toVhDADPA90EnpOmZxgDegFZbA,4196
125
126
  port_ocean/core/integrations/mixins/sync.py,sha256=Vm_898pLKBwfVewtwouDWsXoxcOLicnAy6pzyqqk6U8,4053
126
- port_ocean/core/integrations/mixins/sync_raw.py,sha256=49P9b4Fc5L3NUYmv0W2fzwJ5hariuDqQ0frURw-9o54,40929
127
- port_ocean/core/integrations/mixins/utils.py,sha256=ytnFX7Lyv6N3CgBnOXxYaI1cRDq5Z4NDrVFiwE6bn-M,5250
127
+ port_ocean/core/integrations/mixins/sync_raw.py,sha256=Zga3fSxALuXmAMKmIS0hZYWRe22lSGhiSVFWUCI4f1U,40972
128
+ port_ocean/core/integrations/mixins/utils.py,sha256=vfKBwJFKI2zN5VgimOZQzCXE7bbpSCkBP8QT-9hJiBs,14516
128
129
  port_ocean/core/models.py,sha256=DNbKpStMINI2lIekKprTqBevqkw_wFuFayN19w1aDfQ,2893
129
130
  port_ocean/core/ocean_types.py,sha256=bkLlTd8XfJK6_JDl0eXUHfE_NygqgiInSMwJ4YJH01Q,1399
130
131
  port_ocean/core/utils/entity_topological_sorter.py,sha256=MDUjM6OuDy4Xj68o-7InNN0w1jqjxeDfeY8U02vySNI,3081
@@ -170,7 +171,8 @@ port_ocean/tests/core/conftest.py,sha256=0Oql7R1iTbjPyNdUoO6M21IKknLwnCIgDRz2JQ7
170
171
  port_ocean/tests/core/defaults/test_common.py,sha256=sR7RqB3ZYV6Xn6NIg-c8k5K6JcGsYZ2SCe_PYX5vLYM,5560
171
172
  port_ocean/tests/core/event_listener/test_kafka.py,sha256=PH90qk2fvdrQOSZD2QrvkGy8w_WoYb_KHGnqJ6PLHAo,2681
172
173
  port_ocean/tests/core/handlers/entities_state_applier/test_applier.py,sha256=7XWgwUB9uVYRov4VbIz1A-7n2YLbHTTYT-4rKJxjB0A,10711
173
- port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py,sha256=TjSj8ssIqH23VJlO5PGovbudCqDbuE2-54iNQsD9K-I,14099
174
+ port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py,sha256=7TpqaWcOYLb25SL7e282DmwryCUBllwi387dGHhCMqI,58493
175
+ port_ocean/tests/core/handlers/entity_processor/test_jq_input_evaluator.py,sha256=rCXen2k77BnA-p2E6ga2P3Tqo0SU5tQuMYKhB1v92d8,42076
174
176
  port_ocean/tests/core/handlers/mixins/test_live_events.py,sha256=Sbv9IZAGQoZDhf27xDjMMVYxUSie9mHltDtxLSqckmM,12548
175
177
  port_ocean/tests/core/handlers/mixins/test_sync_raw.py,sha256=-Jd2rUG63fZM8LuyKtCp1tt4WEqO2m5woESjs1c91sU,44428
176
178
  port_ocean/tests/core/handlers/port_app_config/test_api.py,sha256=eJZ6SuFBLz71y4ca3DNqKag6d6HUjNJS0aqQPwiLMTI,1999
@@ -197,11 +199,11 @@ port_ocean/tests/test_metric.py,sha256=gDdeJcqJDQ_o3VrYrW23iZyw2NuUsyATdrygSXhcD
197
199
  port_ocean/tests/test_ocean.py,sha256=bsXKGTVEjwLSbR7-qSmI4GZ-EzDo0eBE3TNSMsWzYxM,1502
198
200
  port_ocean/tests/test_smoke.py,sha256=uix2uIg_yOm8BHDgHw2hTFPy1fiIyxBGW3ENU_KoFlo,2557
199
201
  port_ocean/tests/utils/test_async_iterators.py,sha256=3PLk1emEXekb8LcC5GgVh3OicaX15i5WyaJT_eFnu_4,1336
200
- port_ocean/tests/utils/test_cache.py,sha256=MIYzHt1DeVJ_2KNpVfnUaivNlmdzXDBC5ZeixJPPKL8,8591
202
+ port_ocean/tests/utils/test_cache.py,sha256=AJrBRC1N0Yxq6ekYbZYUleb588GMK_4cGr41wcSI5bA,15561
201
203
  port_ocean/utils/__init__.py,sha256=KMGnCPXZJbNwtgxtyMycapkDz8tpSyw23MSYT3iVeHs,91
202
204
  port_ocean/utils/async_http.py,sha256=aDsw3gQIMwt6qLegbZtkHqD8em48tKvbITnblsrTY3g,1260
203
205
  port_ocean/utils/async_iterators.py,sha256=CPXskYWkhkZtAG-ducEwM8537t3z5usPEqXR9vcivzw,3715
204
- port_ocean/utils/cache.py,sha256=tRwPomG2VIxx8ZNi4QYH6Yc47d9yYV1A7Hx-L_fX4Dg,4494
206
+ port_ocean/utils/cache.py,sha256=WCKs6gV8uToLWOQtfw6LKlqE94dxf0TBHRz4ZaUyky4,5400
205
207
  port_ocean/utils/ipc.py,sha256=eTjTTvsKl6IXYeOkIjP5iyrw-8gLQ9rf15WeyxCqXog,912
206
208
  port_ocean/utils/misc.py,sha256=cQGBWL9IN7ER6s7xyHzeKvj60ntW70WiYIq9MyLe1nY,2123
207
209
  port_ocean/utils/queue_utils.py,sha256=KWWl8YVnG-glcfIHhM6nefY-2sou_C6DVP1VynQwzB4,2762
@@ -209,8 +211,8 @@ port_ocean/utils/repeat.py,sha256=U2OeCkHPWXmRTVoPV-VcJRlQhcYqPWI5NfmPlb1JIbc,32
209
211
  port_ocean/utils/signal.py,sha256=J1sI-e_32VHP_VUa5bskLMFoJjJOAk5isrnewKDikUI,2125
210
212
  port_ocean/utils/time.py,sha256=pufAOH5ZQI7gXvOvJoQXZXZJV-Dqktoj9Qp9eiRwmJ4,1939
211
213
  port_ocean/version.py,sha256=UsuJdvdQlazzKGD3Hd5-U7N69STh8Dq9ggJzQFnu9fU,177
212
- port_ocean-0.28.11.dist-info/LICENSE.md,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
213
- port_ocean-0.28.11.dist-info/METADATA,sha256=_DEW9DiFQmGDhG8llM9ln0bH4Bmg_rurx0SQ_FQSMPI,7016
214
- port_ocean-0.28.11.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
215
- port_ocean-0.28.11.dist-info/entry_points.txt,sha256=F_DNUmGZU2Kme-8NsWM5LLE8piGMafYZygRYhOVtcjA,54
216
- port_ocean-0.28.11.dist-info/RECORD,,
214
+ port_ocean-0.28.14.dist-info/LICENSE.md,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
215
+ port_ocean-0.28.14.dist-info/METADATA,sha256=_w_kDhykkm9LosWg6OOe8HhARPQXRoL4duh__TvB68U,7016
216
+ port_ocean-0.28.14.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
217
+ port_ocean-0.28.14.dist-info/entry_points.txt,sha256=F_DNUmGZU2Kme-8NsWM5LLE8piGMafYZygRYhOVtcjA,54
218
+ port_ocean-0.28.14.dist-info/RECORD,,