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

@@ -5,7 +5,7 @@ from urllib.parse import quote_plus
5
5
 
6
6
  import httpx
7
7
  from loguru import logger
8
-
8
+ from port_ocean.context.ocean import ocean
9
9
  from port_ocean.clients.port.authentication import PortAuthentication
10
10
  from port_ocean.clients.port.types import RequestOptions, UserAgentType
11
11
  from port_ocean.clients.port.utils import (
@@ -15,6 +15,8 @@ from port_ocean.clients.port.utils import (
15
15
  from port_ocean.core.models import Entity, PortAPIErrorMessage
16
16
  from starlette import status
17
17
 
18
+ from port_ocean.helpers.metric.metric import MetricPhase, MetricType
19
+
18
20
 
19
21
  class EntityClientMixin:
20
22
  def __init__(self, auth: PortAuthentication, client: httpx.AsyncClient):
@@ -81,6 +83,15 @@ class EntityClientMixin:
81
83
  f"blueprint: {entity.blueprint}"
82
84
  )
83
85
  result = response.json()
86
+ ocean.metrics.inc_metric(
87
+ name=MetricType.OBJECT_COUNT_NAME,
88
+ labels=[
89
+ ocean.metrics.current_resource_kind(),
90
+ MetricPhase.LOAD,
91
+ MetricPhase.LoadResult.FAILED,
92
+ ],
93
+ value=1,
94
+ )
84
95
 
85
96
  if (
86
97
  response.status_code == status.HTTP_404_NOT_FOUND
@@ -89,6 +100,17 @@ class EntityClientMixin:
89
100
  ):
90
101
  # Return false to differentiate from `result_entity.is_using_search_identifier`
91
102
  return False
103
+ else:
104
+ ocean.metrics.inc_metric(
105
+ name=MetricType.OBJECT_COUNT_NAME,
106
+ labels=[
107
+ ocean.metrics.current_resource_kind(),
108
+ MetricPhase.LOAD,
109
+ MetricPhase.LoadResult.LOADED,
110
+ ],
111
+ value=1,
112
+ )
113
+
92
114
  handle_port_status_code(response, should_raise)
93
115
  result = response.json()
94
116
 
@@ -103,7 +103,7 @@ class HttpEntitiesStateApplier(BaseEntitiesStateApplier):
103
103
  and deletion_rate <= entity_deletion_threshold
104
104
  ):
105
105
  await self._safe_delete(diff.deleted, kept_entities, user_agent_type)
106
- ocean.metrics.set_metric(
106
+ ocean.metrics.inc_metric(
107
107
  name=MetricType.DELETION_COUNT_NAME,
108
108
  labels=[ocean.metrics.current_resource_kind(), MetricPhase.DELETE],
109
109
  value=len(diff.deleted),
@@ -31,7 +31,7 @@ from port_ocean.core.ocean_types import (
31
31
  )
32
32
  from port_ocean.core.utils.utils import resolve_entities_diff, zip_and_sum, gather_and_split_errors_from_results
33
33
  from port_ocean.exceptions.core import OceanAbortException
34
- from port_ocean.helpers.metric.metric import MetricType, MetricPhase
34
+ from port_ocean.helpers.metric.metric import SyncState, MetricType, MetricPhase
35
35
  from port_ocean.helpers.metric.utils import TimeMetric
36
36
 
37
37
  SEND_RAW_DATA_EXAMPLES_AMOUNT = 5
@@ -238,11 +238,21 @@ class SyncRawMixin(HandlerMixin, EventsMixin):
238
238
  if changed_entities:
239
239
  logger.info("Upserting changed entities", changed_entities=len(changed_entities),
240
240
  total_entities=len(objects_diff[0].entity_selector_diff.passed))
241
+ ocean.metrics.inc_metric(
242
+ name=MetricType.OBJECT_COUNT_NAME,
243
+ labels=[ocean.metrics.current_resource_kind(), MetricPhase.LOAD, MetricPhase.LoadResult.SKIPPED],
244
+ value=len(objects_diff[0].entity_selector_diff.passed) - len(changed_entities)
245
+ )
241
246
  await self.entities_state_applier.upsert(
242
247
  changed_entities, user_agent_type
243
248
  )
244
249
  else:
245
250
  logger.info("Entities in batch didn't changed since last sync, skipping", total_entities=len(objects_diff[0].entity_selector_diff.passed))
251
+ ocean.metrics.inc_metric(
252
+ name=MetricType.OBJECT_COUNT_NAME,
253
+ labels=[ocean.metrics.current_resource_kind(), MetricPhase.LOAD, MetricPhase.LoadResult.SKIPPED],
254
+ value=len(objects_diff[0].entity_selector_diff.passed)
255
+ )
246
256
  modified_objects = [ocean.port_client._reduce_entity(entity) for entity in objects_diff[0].entity_selector_diff.passed]
247
257
  except Exception as e:
248
258
  logger.warning(f"Failed to resolve batch entities with Port, falling back to upserting all entities: {str(e)}")
@@ -335,6 +345,7 @@ class SyncRawMixin(HandlerMixin, EventsMixin):
335
345
  passed_entities.extend(calculation_result.entity_selector_diff.passed)
336
346
  number_of_transformed_entities += calculation_result.number_of_transformed_entities
337
347
  except* OceanAbortException as error:
348
+ ocean.metrics.sync_state = SyncState.FAILED
338
349
  errors.append(error)
339
350
 
340
351
  logger.info(
@@ -347,18 +358,30 @@ class SyncRawMixin(HandlerMixin, EventsMixin):
347
358
  value=int(not errors)
348
359
  )
349
360
 
350
- ocean.metrics.set_metric(
361
+ ocean.metrics.inc_metric(
351
362
  name=MetricType.OBJECT_COUNT_NAME,
352
- labels=[ocean.metrics.current_resource_kind(), MetricPhase.EXTRACT],
363
+ labels=[ocean.metrics.current_resource_kind(), MetricPhase.EXTRACT , MetricPhase.ExtractResult.EXTRACTED],
353
364
  value=number_of_raw_results
354
365
  )
355
366
 
356
- ocean.metrics.set_metric(
367
+ ocean.metrics.inc_metric(
357
368
  name=MetricType.OBJECT_COUNT_NAME,
358
- labels=[ocean.metrics.current_resource_kind(), MetricPhase.TRANSFORM],
369
+ labels=[ocean.metrics.current_resource_kind(), MetricPhase.TRANSFORM , MetricPhase.TransformResult.TRANSFORMED],
359
370
  value=number_of_transformed_entities
360
371
  )
361
372
 
373
+ ocean.metrics.inc_metric(
374
+ name=MetricType.OBJECT_COUNT_NAME,
375
+ labels=[ocean.metrics.current_resource_kind(), MetricPhase.TRANSFORM , MetricPhase.TransformResult.FILTERED_OUT],
376
+ value=number_of_raw_results -number_of_transformed_entities
377
+ )
378
+
379
+ ocean.metrics.inc_metric(
380
+ name=MetricType.OBJECT_COUNT_NAME,
381
+ labels=[ocean.metrics.current_resource_kind(), MetricPhase.TRANSFORM , MetricPhase.TransformResult.FAILED],
382
+ value=len(errors)
383
+ )
384
+
362
385
  return passed_entities, errors
363
386
 
364
387
  async def register_raw(
@@ -558,7 +581,6 @@ class SyncRawMixin(HandlerMixin, EventsMixin):
558
581
  for entity in event.entity_topological_sorter.get_entities(False):
559
582
  await self.entities_state_applier.context.port_client.upsert_entity(entity,event.port_app_config.get_port_request_options(),user_agent_type,should_raise=False)
560
583
 
561
-
562
584
  @TimeMetric(MetricPhase.RESYNC)
563
585
  async def sync_raw_all(
564
586
  self,
@@ -584,12 +606,16 @@ class SyncRawMixin(HandlerMixin, EventsMixin):
584
606
  EventType.RESYNC,
585
607
  trigger_type=trigger_type,
586
608
  ):
609
+ ocean.metrics.event_id = event.id
610
+
587
611
  # If a resync is triggered due to a mappings change, we want to make sure that we have the updated version
588
612
  # rather than the old cache
589
613
  app_config = await self.port_app_config_handler.get_port_app_config(
590
614
  use_cache=False
591
615
  )
592
616
  logger.info(f"Resync will use the following mappings: {app_config.dict()}")
617
+ ocean.metrics.initialize_metrics([f"{resource.kind}-{index}" for index, resource in enumerate(app_config.resources)])
618
+ await ocean.metrics.flush()
593
619
 
594
620
  # Execute resync_start hooks
595
621
  for resync_start_fn in self.event_strategy["resync_start"]:
@@ -616,20 +642,19 @@ class SyncRawMixin(HandlerMixin, EventsMixin):
616
642
  # config as we might have multiple resources in the same event
617
643
  async with resource_context(resource,index):
618
644
  resource_kind_id = f"{resource.kind}-{index}"
645
+ ocean.metrics.sync_state = SyncState.SYNCING
646
+ await ocean.metrics.flush(kind=resource_kind_id)
647
+
619
648
  task = asyncio.create_task(
620
649
  self._register_in_batches(resource, user_agent_type)
621
650
  )
622
651
 
623
652
  event.on_abort(lambda: task.cancel())
624
653
  kind_results: tuple[list[Entity], list[Exception]] = await task
625
- ocean.metrics.set_metric(
626
- name=MetricType.OBJECT_COUNT_NAME,
627
- labels=[ocean.metrics.current_resource_kind(), MetricPhase.LOAD],
628
- value=len(kind_results[0])
629
- )
630
654
 
631
655
  creation_results.append(kind_results)
632
-
656
+ if ocean.metrics.sync_state != SyncState.FAILED:
657
+ ocean.metrics.sync_state = SyncState.COMPLETED
633
658
  await ocean.metrics.flush(kind=resource_kind_id)
634
659
 
635
660
  await self.sort_and_upsert_failed_entities(user_agent_type)
@@ -22,6 +22,19 @@ class MetricPhase:
22
22
  RESYNC = "resync"
23
23
  DELETE = "delete"
24
24
 
25
+ class TransformResult:
26
+ TRANSFORMED = "transformed"
27
+ FILTERED_OUT = "filtered_out"
28
+ FAILED = "failed"
29
+
30
+ class LoadResult:
31
+ LOADED = "loaded"
32
+ FAILED = "failed"
33
+ SKIPPED = "skipped"
34
+
35
+ class ExtractResult:
36
+ EXTRACTED = "raw_extracted"
37
+
25
38
 
26
39
  class MetricType:
27
40
  # Define metric names as constants
@@ -33,6 +46,13 @@ class MetricType:
33
46
  DELETION_COUNT_NAME = "deletion_count"
34
47
 
35
48
 
49
+ class SyncState:
50
+ SYNCING = "syncing"
51
+ COMPLETED = "completed"
52
+ QUEUED = "queued"
53
+ FAILED = "failed"
54
+
55
+
36
56
  # Registry for core and custom metrics
37
57
  _metrics_registry: Dict[str, Tuple[str, str, List[str]]] = {
38
58
  MetricType.DURATION_NAME: (
@@ -43,7 +63,7 @@ _metrics_registry: Dict[str, Tuple[str, str, List[str]]] = {
43
63
  MetricType.OBJECT_COUNT_NAME: (
44
64
  MetricType.OBJECT_COUNT_NAME,
45
65
  "object_count description",
46
- ["kind", "phase"],
66
+ ["kind", "phase", "object_count_type"],
47
67
  ),
48
68
  MetricType.ERROR_COUNT_NAME: (
49
69
  MetricType.ERROR_COUNT_NAME,
@@ -86,6 +106,9 @@ class EmptyMetric:
86
106
  def labels(self, *args: Any) -> None:
87
107
  return None
88
108
 
109
+ def inc(self, *args: Any) -> None:
110
+ return None
111
+
89
112
 
90
113
  class Metrics:
91
114
  def __init__(
@@ -100,6 +123,24 @@ class Metrics:
100
123
  self.load_metrics()
101
124
  self._integration_version: Optional[str] = None
102
125
  self._ocean_version: Optional[str] = None
126
+ self.event_id = ""
127
+ self.sync_state = SyncState.QUEUED
128
+
129
+ @property
130
+ def event_id(self) -> str:
131
+ return self._event_id
132
+
133
+ @event_id.setter
134
+ def event_id(self, value: str) -> None:
135
+ self._event_id = value
136
+
137
+ @property
138
+ def sync_state(self) -> str:
139
+ return self._sync_state
140
+
141
+ @sync_state.setter
142
+ def sync_state(self, value: str) -> None:
143
+ self._sync_state = value
103
144
 
104
145
  @property
105
146
  def integration_version(self) -> str:
@@ -139,6 +180,19 @@ class Metrics:
139
180
  return EmptyMetric()
140
181
  return metrics.labels(*labels)
141
182
 
183
+ def inc_metric(self, name: str, labels: list[str], value: float) -> None:
184
+ """Increment a metric value in a single method call.
185
+
186
+ Args:
187
+ name (str): The metric name to inc.
188
+ labels (list[str]): The labels to apply to the metric.
189
+ value (float): The value to inc.
190
+ """
191
+ if not self.enabled:
192
+ return None
193
+
194
+ self.get_metric(name, labels).inc(value)
195
+
142
196
  def set_metric(self, name: str, labels: list[str], value: float) -> None:
143
197
  """Set a metric value in a single method call.
144
198
 
@@ -152,6 +206,49 @@ class Metrics:
152
206
 
153
207
  self.get_metric(name, labels).set(value)
154
208
 
209
+ def initialize_metrics(self, kind_blockes: list[str]) -> None:
210
+ for kind in kind_blockes:
211
+ self.set_metric(MetricType.SUCCESS_NAME, [kind, MetricPhase.RESYNC], 0)
212
+ self.set_metric(MetricType.DURATION_NAME, [kind, MetricPhase.RESYNC], 0)
213
+
214
+ self.set_metric(
215
+ MetricType.OBJECT_COUNT_NAME,
216
+ [kind, MetricPhase.EXTRACT, MetricPhase.ExtractResult.EXTRACTED],
217
+ 0,
218
+ )
219
+
220
+ self.set_metric(
221
+ MetricType.OBJECT_COUNT_NAME,
222
+ [kind, MetricPhase.TRANSFORM, MetricPhase.TransformResult.TRANSFORMED],
223
+ 0,
224
+ )
225
+ self.set_metric(
226
+ MetricType.OBJECT_COUNT_NAME,
227
+ [kind, MetricPhase.TRANSFORM, MetricPhase.TransformResult.FILTERED_OUT],
228
+ 0,
229
+ )
230
+ self.set_metric(
231
+ MetricType.OBJECT_COUNT_NAME,
232
+ [kind, MetricPhase.TRANSFORM, MetricPhase.TransformResult.FAILED],
233
+ 0,
234
+ )
235
+
236
+ self.set_metric(
237
+ MetricType.OBJECT_COUNT_NAME,
238
+ [kind, MetricPhase.LOAD, MetricPhase.LoadResult.LOADED],
239
+ 0,
240
+ )
241
+ self.set_metric(
242
+ MetricType.OBJECT_COUNT_NAME,
243
+ [kind, MetricPhase.LOAD, MetricPhase.LoadResult.FAILED],
244
+ 0,
245
+ )
246
+ self.set_metric(
247
+ MetricType.OBJECT_COUNT_NAME,
248
+ [kind, MetricPhase.LOAD, MetricPhase.LoadResult.SKIPPED],
249
+ 0,
250
+ )
251
+
155
252
  def create_mertic_router(self) -> APIRouter:
156
253
  if not self.enabled:
157
254
  return APIRouter()
@@ -201,14 +298,21 @@ class Metrics:
201
298
  if kind and sample.labels.get("kind") != kind:
202
299
  continue
203
300
 
204
- # Create nested dictionary structure based on labels
205
- for key, value in sample.labels.items():
206
- if key not in current_level:
207
- current_level[key] = {}
208
- current_level = current_level[key]
209
- if value not in current_level:
210
- current_level[value] = {}
211
- current_level = current_level[value]
301
+ # Get the ordered labels from the registry
302
+ ordered_labels = _metrics_registry.get(
303
+ sample.name, (None, None, [])
304
+ )[2]
305
+
306
+ # Create nested dictionary structure based on ordered labels
307
+ for label_name in ordered_labels:
308
+ if label_name in sample.labels:
309
+ value = sample.labels[label_name]
310
+ if label_name not in current_level:
311
+ current_level[label_name] = {}
312
+ current_level = current_level[label_name]
313
+ if value not in current_level:
314
+ current_level[value] = {}
315
+ current_level = current_level[value]
212
316
 
213
317
  current_level[sample.name] = sample.value
214
318
 
@@ -228,6 +332,8 @@ class Metrics:
228
332
  "ocean_version": self.ocean_version,
229
333
  "kind_identifier": kind_key,
230
334
  "kind": "-".join(kind_key.split("-")[:-1]),
335
+ "event_id": self.event_id,
336
+ "sync_state": self.sync_state,
231
337
  "metrics": metrics,
232
338
  }
233
339
  logger.info(f"Sending metrics to webhook {kind_key}: {event}")
@@ -17,7 +17,7 @@ def TimeMetric(phase: str) -> Any:
17
17
  res = await func(*args, **kwargs)
18
18
  end = time.monotonic()
19
19
  duration = end - start
20
- ocean.metrics.set_metric(
20
+ ocean.metrics.inc_metric(
21
21
  name=MetricType.DURATION_NAME,
22
22
  labels=[ocean.metrics.current_resource_kind(), phase],
23
23
  value=duration,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: port-ocean
3
- Version: 0.22.8
3
+ Version: 0.22.10
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
@@ -52,7 +52,7 @@ port_ocean/clients/port/authentication.py,sha256=r7r8Ag9WuwXy-CmgeOoj-PHbmJAQxhb
52
52
  port_ocean/clients/port/client.py,sha256=dv0mxIOde6J-wFi1FXXZkoNPVHrZzY7RSMhNkDD9xgA,3566
53
53
  port_ocean/clients/port/mixins/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
54
54
  port_ocean/clients/port/mixins/blueprints.py,sha256=aMCG4zePsMSMjMLiGrU37h5z5_ElfMzTcTvqvOI5wXY,4683
55
- port_ocean/clients/port/mixins/entities.py,sha256=MaJjkp16wxc2fkd2BwgVIhHU05fi-7pM9OgX_cV3VmA,10901
55
+ port_ocean/clients/port/mixins/entities.py,sha256=-1Gs74z_8eviWItHIpveQhKdA7gnjbqZ3STS4jgGONs,11668
56
56
  port_ocean/clients/port/mixins/integrations.py,sha256=tvuP8jxgbDyTwGfp8hd0-NXfnsMjZFJXDEDzXroctnY,9381
57
57
  port_ocean/clients/port/mixins/migrations.py,sha256=vdL_A_NNUogvzujyaRLIoZEu5vmKDY2BxTjoGP94YzI,1467
58
58
  port_ocean/clients/port/mixins/organization.py,sha256=A2cP5V49KnjoAXxjmnm_XGth4ftPSU0qURNfnyUyS_Y,1041
@@ -87,7 +87,7 @@ port_ocean/core/handlers/base.py,sha256=cTarblazu8yh8xz2FpB-dzDKuXxtoi143XJgPbV_
87
87
  port_ocean/core/handlers/entities_state_applier/__init__.py,sha256=kgLZDCeCEzi4r-0nzW9k78haOZNf6PX7mJOUr34A4c8,173
88
88
  port_ocean/core/handlers/entities_state_applier/base.py,sha256=5wHL0icfFAYRPqk8iV_wN49GdJ3aRUtO8tumSxBi4Wo,2268
89
89
  port_ocean/core/handlers/entities_state_applier/port/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
90
- port_ocean/core/handlers/entities_state_applier/port/applier.py,sha256=CcYSTMa4nA-fDX_9ZswthoyK8jMkupS1v-LMB-XxYBk,6254
90
+ port_ocean/core/handlers/entities_state_applier/port/applier.py,sha256=Glw-iSZvN0WaaQL3qfOSb9uEXcy88_mSOzifMLNhhOc,6254
91
91
  port_ocean/core/handlers/entities_state_applier/port/get_related_entities.py,sha256=1zncwCbE-Gej0xaWKlzZgoXxOBe9bgs_YxlZ8QW3NdI,1751
92
92
  port_ocean/core/handlers/entities_state_applier/port/order_by_entities_dependencies.py,sha256=lyv6xKzhYfd6TioUgR3AVRSJqj7JpAaj1LxxU2xAqeo,1720
93
93
  port_ocean/core/handlers/entity_processor/__init__.py,sha256=FvFCunFg44wNQoqlybem9MthOs7p1Wawac87uSXz9U8,156
@@ -113,7 +113,7 @@ port_ocean/core/integrations/mixins/events.py,sha256=2L7P3Jhp8XBqddh2_o9Cn4N261n
113
113
  port_ocean/core/integrations/mixins/handler.py,sha256=mZ7-0UlG3LcrwJttFbMe-R4xcOU2H_g33tZar7PwTv8,3771
114
114
  port_ocean/core/integrations/mixins/live_events.py,sha256=8HklZmlyffYY_LeDe8xbt3Tb08rlLkqVhFF-2NQeJP4,4126
115
115
  port_ocean/core/integrations/mixins/sync.py,sha256=Vm_898pLKBwfVewtwouDWsXoxcOLicnAy6pzyqqk6U8,4053
116
- port_ocean/core/integrations/mixins/sync_raw.py,sha256=uATzik6gSmkpKlIhbcRavlDo-xtkUvMwNp1wZltJj-I,27487
116
+ port_ocean/core/integrations/mixins/sync_raw.py,sha256=ezjfpxZJ-0IjxppP6nKu4lSWjsh_8HPNghSgsQRayR8,29100
117
117
  port_ocean/core/integrations/mixins/utils.py,sha256=oN4Okz6xlaefpid1_Pud8HPSw9BwwjRohyNsknq-Myg,2309
118
118
  port_ocean/core/models.py,sha256=YpJ2XOB3Zt9_M-rcMrMjugFNzBDg2hCUKgqvEt7now0,2348
119
119
  port_ocean/core/ocean_types.py,sha256=4VipWFOHEh_d9LmWewQccwx1p2dtrRYW0YURVgNsAjo,1398
@@ -131,8 +131,8 @@ port_ocean/exceptions/utils.py,sha256=gjOqpi-HpY1l4WlMFsGA9yzhxDhajhoGGdDDyGbLnq
131
131
  port_ocean/exceptions/webhook_processor.py,sha256=yQYazg53Y-ohb7HfViwq1opH_ZUuUdhHSRxcUNveFpI,114
132
132
  port_ocean/helpers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
133
133
  port_ocean/helpers/async_client.py,sha256=SRlP6o7_FCSY3UHnRlZdezppePVxxOzZ0z861vE3K40,1783
134
- port_ocean/helpers/metric/metric.py,sha256=EQstAxlsC-lsp8VFw4GgxCh3SGV9t2Y-j1Z1qbXyy-I,8014
135
- port_ocean/helpers/metric/utils.py,sha256=1DlLR9FmUOpSlWSfY_tUEGcxRQY6ckAfbD3dnMnxd4c,874
134
+ port_ocean/helpers/metric/metric.py,sha256=Eg8t7k3hDumnUHe2TvE5xus3cWoROwJPjoviW4QrGoE,11440
135
+ port_ocean/helpers/metric/utils.py,sha256=_qj9-PfsrMHoXVscEsIdnylLVZJnupg8ofHYaKc5-t8,874
136
136
  port_ocean/helpers/retry.py,sha256=gmS4YxM6N4fboFp7GSgtOzyBJemxs46bnrz4L4rDS6Y,16136
137
137
  port_ocean/log/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
138
138
  port_ocean/log/handlers.py,sha256=ncVjgqrZRh6BhyRrA6DQG86Wsbxph1yWYuEC0cWfe-Q,3631
@@ -188,8 +188,8 @@ port_ocean/utils/repeat.py,sha256=U2OeCkHPWXmRTVoPV-VcJRlQhcYqPWI5NfmPlb1JIbc,32
188
188
  port_ocean/utils/signal.py,sha256=mMVq-1Ab5YpNiqN4PkiyTGlV_G0wkUDMMjTZp5z3pb0,1514
189
189
  port_ocean/utils/time.py,sha256=pufAOH5ZQI7gXvOvJoQXZXZJV-Dqktoj9Qp9eiRwmJ4,1939
190
190
  port_ocean/version.py,sha256=UsuJdvdQlazzKGD3Hd5-U7N69STh8Dq9ggJzQFnu9fU,177
191
- port_ocean-0.22.8.dist-info/LICENSE.md,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
192
- port_ocean-0.22.8.dist-info/METADATA,sha256=o8OYwTwdxk24xZt7KB8kXJLN_ukZNrnu3lMZOPTlbW8,6764
193
- port_ocean-0.22.8.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
194
- port_ocean-0.22.8.dist-info/entry_points.txt,sha256=F_DNUmGZU2Kme-8NsWM5LLE8piGMafYZygRYhOVtcjA,54
195
- port_ocean-0.22.8.dist-info/RECORD,,
191
+ port_ocean-0.22.10.dist-info/LICENSE.md,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
192
+ port_ocean-0.22.10.dist-info/METADATA,sha256=ixe0DL4U9Vy7fbJ7HmdFpkht_yjFwJL5ANw8ZahOv2U,6765
193
+ port_ocean-0.22.10.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
194
+ port_ocean-0.22.10.dist-info/entry_points.txt,sha256=F_DNUmGZU2Kme-8NsWM5LLE8piGMafYZygRYhOVtcjA,54
195
+ port_ocean-0.22.10.dist-info/RECORD,,