omnata-plugin-runtime 0.10.22a276__tar.gz → 0.10.23__tar.gz

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,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: omnata-plugin-runtime
3
- Version: 0.10.22a276
3
+ Version: 0.10.23
4
4
  Summary: Classes and common runtime components for building and running Omnata Plugins
5
5
  Author: James Weakley
6
6
  Author-email: james.weakley@omnata.com
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "omnata-plugin-runtime"
3
- version = "0.10.22-a276"
3
+ version = "0.10.23"
4
4
  description = "Classes and common runtime components for building and running Omnata Plugins"
5
5
  authors = ["James Weakley <james.weakley@omnata.com>"]
6
6
  readme = "README.md"
@@ -50,6 +50,8 @@ from tenacity import Retrying, stop_after_attempt, wait_fixed, retry_if_exceptio
50
50
 
51
51
  from .logging import OmnataPluginLogHandler, logger, tracer
52
52
  from opentelemetry import context
53
+ import math
54
+ import numpy as np
53
55
 
54
56
  from .api import (
55
57
  PluginMessage,
@@ -653,6 +655,21 @@ class HttpRateLimiting:
653
655
  def __exit__(self, exc_type, exc_value, traceback):
654
656
  http.client.HTTPConnection.putrequest = self.original_putrequest # type: ignore
655
657
 
658
+ def wrap_result_value(x):
659
+ # Check for NaN (float or numpy.nan)
660
+ if x is None:
661
+ return None
662
+ if isinstance(x, float) and math.isnan(x):
663
+ return None
664
+ if isinstance(x, str):
665
+ return json.dumps({"value": x})
666
+ try:
667
+ # Try to detect pandas NaN (which is float('nan'))
668
+ if isinstance(x, np.floating) and np.isnan(x):
669
+ return None
670
+ except ImportError:
671
+ return None
672
+ return json.dumps(x)
656
673
 
657
674
  class OutboundSyncRequest(SyncRequest):
658
675
  """
@@ -810,9 +827,7 @@ class OutboundSyncRequest(SyncRequest):
810
827
  if "LOADBATCH_ID" not in results_df:
811
828
  results_df["LOADBATCH_ID"] = self._get_next_loadbatch_id()
812
829
  # we dump the result data to a json string to make uploading to Snowflake less error prone, but only if it's not None
813
- results_df["RESULT"] = results_df["RESULT"].apply(
814
- lambda x: json.dumps(x) if x is not None else None
815
- )
830
+ results_df["RESULT"] = results_df["RESULT"].apply(wrap_result_value)
816
831
  # trim out the columns we don't need to return
817
832
  return results_df[
818
833
  results_df.columns.intersection(
@@ -1531,7 +1546,7 @@ class InboundSyncRequest(SyncRequest):
1531
1546
  Updates the SYNC table to have the latest stream states.
1532
1547
  TODO: This should be done in concert with the results, revisit
1533
1548
  """
1534
- if self._last_states_update is None or self._latest_states != self._last_states_update:
1549
+ if self._last_states_update is None or json.dumps(self._latest_states) != json.dumps(self._last_states_update):
1535
1550
  self._plugin_message(PluginMessageStreamState(stream_state=self._latest_states))
1536
1551
  self._last_states_update = self._latest_states
1537
1552