omnata-plugin-runtime 0.10.22a276__tar.gz → 0.12.2a340__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.
Potentially problematic release.
This version of omnata-plugin-runtime might be problematic. Click here for more details.
- omnata_plugin_runtime-0.12.2a340/PKG-INFO +56 -0
- omnata_plugin_runtime-0.12.2a340/pyproject.toml +57 -0
- {omnata_plugin_runtime-0.10.22a276 → omnata_plugin_runtime-0.12.2a340}/src/omnata_plugin_runtime/api.py +4 -4
- {omnata_plugin_runtime-0.10.22a276 → omnata_plugin_runtime-0.12.2a340}/src/omnata_plugin_runtime/configuration.py +49 -1
- {omnata_plugin_runtime-0.10.22a276 → omnata_plugin_runtime-0.12.2a340}/src/omnata_plugin_runtime/json_schema.py +354 -118
- {omnata_plugin_runtime-0.10.22a276 → omnata_plugin_runtime-0.12.2a340}/src/omnata_plugin_runtime/logging.py +2 -1
- {omnata_plugin_runtime-0.10.22a276 → omnata_plugin_runtime-0.12.2a340}/src/omnata_plugin_runtime/omnata_plugin.py +459 -125
- {omnata_plugin_runtime-0.10.22a276 → omnata_plugin_runtime-0.12.2a340}/src/omnata_plugin_runtime/plugin_entrypoints.py +18 -3
- omnata_plugin_runtime-0.12.2a340/src/omnata_plugin_runtime/threading_utils.py +27 -0
- omnata_plugin_runtime-0.10.22a276/PKG-INFO +0 -55
- omnata_plugin_runtime-0.10.22a276/pyproject.toml +0 -57
- {omnata_plugin_runtime-0.10.22a276 → omnata_plugin_runtime-0.12.2a340}/LICENSE +0 -0
- {omnata_plugin_runtime-0.10.22a276 → omnata_plugin_runtime-0.12.2a340}/README.md +0 -0
- {omnata_plugin_runtime-0.10.22a276 → omnata_plugin_runtime-0.12.2a340}/src/omnata_plugin_runtime/__init__.py +0 -0
- {omnata_plugin_runtime-0.10.22a276 → omnata_plugin_runtime-0.12.2a340}/src/omnata_plugin_runtime/forms.py +0 -0
- {omnata_plugin_runtime-0.10.22a276 → omnata_plugin_runtime-0.12.2a340}/src/omnata_plugin_runtime/rate_limiting.py +0 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: omnata-plugin-runtime
|
|
3
|
+
Version: 0.12.2a340
|
|
4
|
+
Summary: Classes and common runtime components for building and running Omnata Plugins
|
|
5
|
+
License-File: LICENSE
|
|
6
|
+
Author: James Weakley
|
|
7
|
+
Author-email: james.weakley@omnata.com
|
|
8
|
+
Requires-Python: >=3.10,<=3.13
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Requires-Dist: annotated-types (<=0.6.0)
|
|
15
|
+
Requires-Dist: certifi (<=2025.1.31)
|
|
16
|
+
Requires-Dist: cffi (<=2.0.0)
|
|
17
|
+
Requires-Dist: charset-normalizer (<=3.4.4)
|
|
18
|
+
Requires-Dist: cryptography (<=46.0.3)
|
|
19
|
+
Requires-Dist: filelock (<=3.20.0)
|
|
20
|
+
Requires-Dist: idna (<=3.11)
|
|
21
|
+
Requires-Dist: jinja2 (>=3.1.2,<=3.1.6)
|
|
22
|
+
Requires-Dist: markupsafe (<=3.0.2)
|
|
23
|
+
Requires-Dist: numpy (<=2.3.5)
|
|
24
|
+
Requires-Dist: opentelemetry-api (<=1.38.0)
|
|
25
|
+
Requires-Dist: packaging (<=25.0)
|
|
26
|
+
Requires-Dist: pandas (<=2.3.3)
|
|
27
|
+
Requires-Dist: platformdirs (<=4.5.0)
|
|
28
|
+
Requires-Dist: protobuf (<=6.33.0)
|
|
29
|
+
Requires-Dist: pyarrow (<=21.0.0)
|
|
30
|
+
Requires-Dist: pycparser (<=2.23)
|
|
31
|
+
Requires-Dist: pydantic (>=2,<=2.12.4)
|
|
32
|
+
Requires-Dist: pydantic-core (<=2.41.5)
|
|
33
|
+
Requires-Dist: pyjwt (<=2.10.1)
|
|
34
|
+
Requires-Dist: pyopenssl (<=225.3.0)
|
|
35
|
+
Requires-Dist: pytz (<=2025.2)
|
|
36
|
+
Requires-Dist: pyyaml (<=6.0.3)
|
|
37
|
+
Requires-Dist: requests (>=2,<=2.32.5)
|
|
38
|
+
Requires-Dist: setuptools (<=80.9.0)
|
|
39
|
+
Requires-Dist: snowflake-connector-python (>=3,<4)
|
|
40
|
+
Requires-Dist: snowflake-snowpark-python (>=1.20.0,<=1.43.0)
|
|
41
|
+
Requires-Dist: snowflake-telemetry-python (<=0.5.0)
|
|
42
|
+
Requires-Dist: tenacity (>=8,<9)
|
|
43
|
+
Requires-Dist: tomlkit (<=0.13.3)
|
|
44
|
+
Requires-Dist: urllib3 (<=2.5.0)
|
|
45
|
+
Requires-Dist: wheel (<=0.45.1)
|
|
46
|
+
Requires-Dist: wrapt (<=2.0.1)
|
|
47
|
+
Description-Content-Type: text/markdown
|
|
48
|
+
|
|
49
|
+
# omnata-plugin-runtime
|
|
50
|
+
This package is a runtime dependency for [Omnata Plugins](https://docs.omnata.com/omnata-product-documentation/omnata-sync-for-snowflake/plugins).
|
|
51
|
+
|
|
52
|
+
It contains data classes, interfaces and application logic used to perform plugin operations.
|
|
53
|
+
|
|
54
|
+
For instructions on creating plugins, visit our [docs site](https://docs.omnata.com/omnata-product-documentation/omnata-sync-for-snowflake/plugins/creating-plugins).
|
|
55
|
+
|
|
56
|
+
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
[tool.poetry]
|
|
2
|
+
name = "omnata-plugin-runtime"
|
|
3
|
+
version = "0.12.2a340"
|
|
4
|
+
description = "Classes and common runtime components for building and running Omnata Plugins"
|
|
5
|
+
authors = ["James Weakley <james.weakley@omnata.com>"]
|
|
6
|
+
readme = "README.md"
|
|
7
|
+
packages = [{include = "omnata_plugin_runtime", from = "src"}]
|
|
8
|
+
|
|
9
|
+
[tool.poetry.dependencies]
|
|
10
|
+
python = ">=3.10, <=3.13"
|
|
11
|
+
snowflake-snowpark-python = ">=1.20.0,<=1.43.0" # latest version available on Snowflake Anaconda, but allow pinning to 1.20.0 for to_pandas_batches workaround
|
|
12
|
+
snowflake-connector-python = "^3, <=4.1.0" # latest version available on Snowflake Anaconda
|
|
13
|
+
cryptography = "<=46.0.3"
|
|
14
|
+
annotated-types = "<=0.6.0"
|
|
15
|
+
pycparser = "<=2.23"
|
|
16
|
+
filelock = "<=3.20.0"
|
|
17
|
+
pydantic-core = "<=2.41.5"
|
|
18
|
+
# had to relax some of these thanks to snowcli pinning newer versions
|
|
19
|
+
certifi = "<=2025.1.31" # latest version available on Snowflake Anaconda which doesn't break the Snowflake connector
|
|
20
|
+
charset-normalizer = "<=3.4.4" # latest version available on Snowflake Anaconda
|
|
21
|
+
idna = "<=3.11" # latest version available on Snowflake Anaconda
|
|
22
|
+
jinja2 = ">=3.1.2,<=3.1.6" # 3.1.6 was latest version available on Snowflake Anaconda
|
|
23
|
+
markupsafe = "<=3.0.2" # latest version available on Snowflake Anaconda
|
|
24
|
+
numpy = "<=2.3.5" # latest version available on Snowflake Anaconda
|
|
25
|
+
packaging = "<=25.0" # latest version available on Snowflake Anaconda
|
|
26
|
+
pandas = "<=2.3.3" # latest version available on Snowflake Anaconda
|
|
27
|
+
platformdirs = "<=4.5.0" # latest version available on Snowflake Anaconda
|
|
28
|
+
pydantic = "^2, <=2.12.4" # latest version available on Snowflake Anaconda
|
|
29
|
+
pyjwt = "<=2.10.1" # latest version available on Snowflake Anaconda
|
|
30
|
+
pyopenssl = "<=225.3.0" # latest version available on Snowflake Anaconda
|
|
31
|
+
pytz = "<=2025.2" # latest version available on Snowflake Anaconda
|
|
32
|
+
requests = "^2, <=2.32.5" # latest version available on Snowflake Anaconda
|
|
33
|
+
setuptools = "<=80.9.0" # latest version available on Snowflake Anaconda
|
|
34
|
+
tomlkit = "<=0.13.3" # latest version available on Snowflake Anaconda
|
|
35
|
+
tenacity = "^8, <=9.1.2" # latest version available on Snowflake Anaconda
|
|
36
|
+
urllib3 = "<=2.5.0" # latest version available on Snowflake Anaconda
|
|
37
|
+
wheel = "<=0.45.1" # latest version available on Snowflake Anaconda
|
|
38
|
+
pyyaml = "<=6.0.3" # latest version available on Snowflake Anaconda
|
|
39
|
+
cffi = "<=2.0.0" # latest version available on Snowflake Anaconda
|
|
40
|
+
pyarrow = "<=21.0.0" # latest version available on Snowflake Anaconda
|
|
41
|
+
wrapt = "<=2.0.1" # latest version available on Snowflake Anaconda
|
|
42
|
+
opentelemetry-api = "<=1.38.0" # latest version available on Snowflake Anaconda
|
|
43
|
+
snowflake-telemetry-python = "<=0.5.0" # latest version available on Snowflake Anaconda
|
|
44
|
+
protobuf = "<=6.33.0" # latest version available on Snowflake Anaconda
|
|
45
|
+
|
|
46
|
+
[tool.poetry.dev-dependencies]
|
|
47
|
+
pytest = "^6.2.4"
|
|
48
|
+
deepdiff = "^6"
|
|
49
|
+
requests-mock = ">=1.9.3"
|
|
50
|
+
|
|
51
|
+
[tool.pytest.ini_options]
|
|
52
|
+
addopts = ["--import-mode=importlib"]
|
|
53
|
+
testpaths = ["tests"]
|
|
54
|
+
|
|
55
|
+
[build-system]
|
|
56
|
+
requires = ["poetry-core"]
|
|
57
|
+
build-backend = "poetry.core.masonry.api"
|
|
@@ -108,9 +108,9 @@ class OutboundSyncRequestPayload(BaseModel):
|
|
|
108
108
|
Encapsulates the payload that is sent to the plugin when it is invoked to perform an outbound sync.
|
|
109
109
|
"""
|
|
110
110
|
|
|
111
|
-
sync_id: int
|
|
111
|
+
sync_id: int
|
|
112
112
|
sync_branch_name: str = 'main'
|
|
113
|
-
sync_branch_id: Optional[int]
|
|
113
|
+
sync_branch_id: Optional[int]
|
|
114
114
|
connection_id: int # only used by log handler
|
|
115
115
|
run_id: int # used by log handler and for reporting back run status updates
|
|
116
116
|
source_app_name: str # the name of the app which is invoking this plugin
|
|
@@ -139,8 +139,8 @@ class InboundSyncRequestPayload(BaseModel):
|
|
|
139
139
|
Encapsulates the payload that is sent to the plugin when it is invoked to perform an inbound sync.
|
|
140
140
|
"""
|
|
141
141
|
|
|
142
|
-
sync_id: int
|
|
143
|
-
sync_branch_name: str = 'main'
|
|
142
|
+
sync_id: int
|
|
143
|
+
sync_branch_name: str = 'main'
|
|
144
144
|
sync_branch_id: Optional[int] = None # only used by log handler
|
|
145
145
|
connection_id: int # only used by log handler
|
|
146
146
|
run_id: int # used by log handler and for reporting back run status updates
|
|
@@ -614,6 +614,10 @@ class StreamConfiguration(SubscriptableBaseModel):
|
|
|
614
614
|
None,
|
|
615
615
|
description="Marks the stream as requiring another stream to be selected"
|
|
616
616
|
)
|
|
617
|
+
mandatory: bool = Field(
|
|
618
|
+
False,
|
|
619
|
+
description="Marks the stream as mandatory, meaning it cannot be excluded from the sync configuration"
|
|
620
|
+
)
|
|
617
621
|
|
|
618
622
|
|
|
619
623
|
class StoredConfigurationValue(SubscriptableBaseModel):
|
|
@@ -689,6 +693,9 @@ class ConnectionConfigurationParameters(SubscriptableBaseModel):
|
|
|
689
693
|
_snowflake: Optional[Any] = PrivateAttr( # or use Any to annotate the type and use Field to initialize
|
|
690
694
|
default=None
|
|
691
695
|
)
|
|
696
|
+
_sync_request: Optional[Any] = PrivateAttr( # Reference to SyncRequest for worker thread access
|
|
697
|
+
default=None
|
|
698
|
+
)
|
|
692
699
|
|
|
693
700
|
@model_validator(mode='after')
|
|
694
701
|
def validate_ngrok_tunnel_settings(self) -> Self:
|
|
@@ -735,6 +742,23 @@ class ConnectionConfigurationParameters(SubscriptableBaseModel):
|
|
|
735
742
|
"""
|
|
736
743
|
if parameter_name=='access_token' and self.access_token_secret_name is not None:
|
|
737
744
|
import _snowflake # pylint: disable=import-error, import-outside-toplevel # type: ignore
|
|
745
|
+
from .threading_utils import is_managed_worker_thread
|
|
746
|
+
|
|
747
|
+
# Check if we're in a worker thread using the explicit flag
|
|
748
|
+
# This is more reliable than checking thread names
|
|
749
|
+
if is_managed_worker_thread() and self._sync_request is not None:
|
|
750
|
+
logger.debug(f"Worker thread requesting access_token via secrets service")
|
|
751
|
+
try:
|
|
752
|
+
secrets = self._sync_request.request_secrets_from_main_thread(
|
|
753
|
+
self.access_token_secret_name, None
|
|
754
|
+
)
|
|
755
|
+
if 'access_token' in secrets:
|
|
756
|
+
return secrets['access_token']
|
|
757
|
+
except Exception as e:
|
|
758
|
+
logger.error(f"Error requesting access_token from main thread: {e}")
|
|
759
|
+
raise
|
|
760
|
+
|
|
761
|
+
# Otherwise, call _snowflake directly (main thread)
|
|
738
762
|
return StoredConfigurationValue(
|
|
739
763
|
value=_snowflake.get_oauth_access_token(self.access_token_secret_name)
|
|
740
764
|
)
|
|
@@ -1001,10 +1025,34 @@ StoredFieldMappings.model_rebuild()
|
|
|
1001
1025
|
OutboundSyncConfigurationParameters.model_rebuild()
|
|
1002
1026
|
|
|
1003
1027
|
@tracer.start_as_current_span("get_secrets")
|
|
1004
|
-
def get_secrets(oauth_secret_name: Optional[str], other_secrets_name: Optional[str]
|
|
1028
|
+
def get_secrets(oauth_secret_name: Optional[str], other_secrets_name: Optional[str],
|
|
1029
|
+
sync_request: Optional[Any] = None
|
|
1005
1030
|
) -> Dict[str, StoredConfigurationValue]:
|
|
1031
|
+
"""
|
|
1032
|
+
Get secrets from Snowflake. This function can be called from the main thread or worker threads.
|
|
1033
|
+
When called from worker threads (e.g., within @managed_inbound_processing), it will automatically
|
|
1034
|
+
route the request through the secrets service to avoid threading issues with _snowflake.get_oauth_access_token.
|
|
1035
|
+
|
|
1036
|
+
:param oauth_secret_name: The name of the OAuth secret to retrieve
|
|
1037
|
+
:param other_secrets_name: The name of other secrets to retrieve
|
|
1038
|
+
:param sync_request: Optional SyncRequest instance for worker threads. If not provided, will attempt to detect.
|
|
1039
|
+
:return: Dictionary of StoredConfigurationValue objects
|
|
1040
|
+
"""
|
|
1041
|
+
from .threading_utils import is_managed_worker_thread
|
|
1006
1042
|
connection_secrets = {}
|
|
1007
1043
|
import _snowflake # pylint: disable=import-error, import-outside-toplevel # type: ignore
|
|
1044
|
+
|
|
1045
|
+
# Check if we're in a worker thread using the explicit flag
|
|
1046
|
+
# This is more reliable than checking thread names
|
|
1047
|
+
if is_managed_worker_thread() and sync_request is not None:
|
|
1048
|
+
logger.debug(f"Worker thread requesting secrets via secrets service")
|
|
1049
|
+
try:
|
|
1050
|
+
return sync_request.request_secrets_from_main_thread(oauth_secret_name, other_secrets_name)
|
|
1051
|
+
except Exception as e:
|
|
1052
|
+
logger.error(f"Error requesting secrets from main thread: {e}")
|
|
1053
|
+
raise
|
|
1054
|
+
|
|
1055
|
+
# Otherwise, call _snowflake functions directly (main thread)
|
|
1008
1056
|
if oauth_secret_name is not None:
|
|
1009
1057
|
connection_secrets["access_token"] = StoredConfigurationValue(
|
|
1010
1058
|
value=_snowflake.get_oauth_access_token(oauth_secret_name)
|