omnata-plugin-runtime 0.6.9a179__tar.gz → 0.7.0__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: omnata-plugin-runtime
3
- Version: 0.6.9a179
3
+ Version: 0.7.0
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
@@ -33,7 +33,7 @@ Requires-Dist: pyyaml (<=6.0.1)
33
33
  Requires-Dist: requests (>=2,<=2.32.3)
34
34
  Requires-Dist: setuptools (<=72.1.0)
35
35
  Requires-Dist: snowflake-connector-python (>=3,<=3.12.0)
36
- Requires-Dist: snowflake-snowpark-python (==1.19.0)
36
+ Requires-Dist: snowflake-snowpark-python (==1.23.0)
37
37
  Requires-Dist: tenacity (>=8,<=8.2.3)
38
38
  Requires-Dist: tomlkit (<=0.11.1)
39
39
  Requires-Dist: urllib3 (<=2.2.2)
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "omnata-plugin-runtime"
3
- version = "0.6.9-a179"
3
+ version = "0.7.0"
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"
@@ -8,7 +8,7 @@ packages = [{include = "omnata_plugin_runtime", from = "src"}]
8
8
 
9
9
  [tool.poetry.dependencies]
10
10
  python = ">=3.8, <3.11"
11
- snowflake-snowpark-python = "1.19.0" # fixes an issue
11
+ snowflake-snowpark-python = "1.23.0" # latest version available on Snowflake Anaconda
12
12
  snowflake-connector-python = "^3, <=3.12.0" # latest version available on Snowflake Anaconda
13
13
  cryptography = "<=43.0.0"
14
14
  annotated-types = "<=0.6.0"
@@ -22,6 +22,7 @@ from .configuration import (
22
22
  OutboundSyncStrategy,
23
23
  StoredConfigurationValue,
24
24
  StoredMappingValue,
25
+ ConnectivityOption
25
26
  )
26
27
  from .rate_limiting import ApiLimits, RateLimitState
27
28
 
@@ -119,6 +120,7 @@ class OutboundSyncRequestPayload(BaseModel):
119
120
  results_table_name: str # used to stage results back to the engine, resides in the main Omnata app database
120
121
  logging_level: str
121
122
  connection_method: str
123
+ connectivity_option: ConnectivityOption = Field(default=ConnectivityOption.DIRECT)
122
124
  connection_parameters: Dict[str, StoredConfigurationValue]
123
125
  oauth_secret_name: Optional[str] = None
124
126
  other_secrets_name: Optional[str] = None
@@ -146,6 +148,7 @@ class InboundSyncRequestPayload(BaseModel):
146
148
  results_table_name: str # used to stage results back to the engine, resides in the main Omnata app database
147
149
  logging_level: str
148
150
  connection_method: str
151
+ connectivity_option: ConnectivityOption = Field(default=ConnectivityOption.DIRECT)
149
152
  connection_parameters: Dict[str, StoredConfigurationValue]
150
153
  oauth_secret_name: Optional[str] = None
151
154
  other_secrets_name: Optional[str] = None
@@ -37,6 +37,14 @@ class InboundStorageBehaviour(str, Enum):
37
37
  MERGE = "merge"
38
38
  REPLACE = "replace" # now deprecated, full refreshes now use merge
39
39
 
40
+ class ConnectivityOption(str, Enum):
41
+ """
42
+ Describes the connectivity options available to a plugin.
43
+ These result in slightly different network rules and connection onboarding.
44
+ """
45
+ DIRECT = "direct"
46
+ NGROK = "ngrok"
47
+ PRIVATELINK = "privatelink"
40
48
 
41
49
  class InboundSyncStrategy(str, Enum):
42
50
  FULL_REFRESH = "Full Refresh"
@@ -543,6 +551,7 @@ class ConnectionConfigurationParameters(SubscriptableBaseModel):
543
551
  """
544
552
 
545
553
  connection_method: str
554
+ connectivity_option: ConnectivityOption = Field(default=ConnectivityOption.DIRECT)
546
555
  connection_parameters: Optional[Dict[str, StoredConfigurationValue]] = Field(default=None)
547
556
  connection_secrets: Optional[Dict[str, StoredConfigurationValue]] = Field(default=None)
548
557
  ngrok_tunnel_settings: Optional[NgrokTunnelSettings] = Field(default=None)
@@ -552,11 +561,9 @@ class ConnectionConfigurationParameters(SubscriptableBaseModel):
552
561
  default=None
553
562
  )
554
563
 
555
- @validator("ngrok_tunnel_settings", always=True)
556
- def validate_ngrok_tunnel_settings(cls, v: str, values: dict[str, Any]) -> Optional[NgrokTunnelSettings]:
557
- """
558
- A validator which picks out the ngrok tunnel configuration from the secrets and provides it as a typed object.
559
- """
564
+ @field_validator('ngrok_tunnel_settings',mode='before')
565
+ @classmethod
566
+ def validate_ngrok_tunnel_settings(cls, values: Optional[dict[str, Any]]) -> Optional[NgrokTunnelSettings]:
560
567
  if "connection_secrets" in values:
561
568
  connection_secrets:Dict[str, StoredConfigurationValue] = values["connection_secrets"]
562
569
  if "ngrok_client_certificate" in connection_secrets and \
@@ -489,5 +489,6 @@ class ConnectionMethod(SubscriptableBaseModel):
489
489
  name: str
490
490
  fields: List[FormFieldBase]
491
491
  oauth_template: Optional[SecurityIntegrationTemplate] = Field(default=None)
492
+ # This is now deprecated, instead signal ngrok support via the plugin manifest
492
493
  ngrok_tunnel_configuration: Optional[NGrokMTLSTunnel] = Field(default=None)
493
494
  description: str = Field(default="")
@@ -72,7 +72,8 @@ from .configuration import (
72
72
  StreamConfiguration,
73
73
  SubscriptableBaseModel,
74
74
  SyncConfigurationParameters,
75
- get_secrets
75
+ get_secrets,
76
+ ConnectivityOption
76
77
  )
77
78
  from .forms import (
78
79
  ConnectionMethod,
@@ -101,6 +102,7 @@ class PluginManifest(SubscriptableBaseModel):
101
102
  :param str docs_url: The URL where plugin documentation can be found, e.g. "https://docs.omnata.com"
102
103
  :param bool supports_inbound: A flag to indicate whether or not the plugin supports inbound sync. Support for inbound sync behaviours (full/incremental) is defined per inbound stream.
103
104
  :param List[OutboundSyncStrategy] supported_outbound_strategies: A list of sync strategies that the plugin can support, e.g. create,upsert.
105
+ :param List[ConnectivityOption] supported_connectivity_options: A list of connectivity options that the plugin can support, e.g. direct,ngrok,privatelink
104
106
  """
105
107
 
106
108
  plugin_id: str
@@ -110,6 +112,9 @@ class PluginManifest(SubscriptableBaseModel):
110
112
  docs_url: str
111
113
  supports_inbound: bool
112
114
  supported_outbound_strategies: List[OutboundSyncStrategy]
115
+ supported_connectivity_options: List[ConnectivityOption] = Field(
116
+ default_factory=lambda: [ConnectivityOption.DIRECT]
117
+ )
113
118
 
114
119
 
115
120
  class SnowflakeFunctionParameter(BaseModel):
@@ -1643,7 +1648,7 @@ class OmnataPlugin(ABC):
1643
1648
  )
1644
1649
 
1645
1650
  @abstractmethod
1646
- def connection_form(self) -> List[ConnectionMethod]:
1651
+ def connection_form(self,connectivity_option:ConnectivityOption) -> List[ConnectionMethod]:
1647
1652
  """
1648
1653
  Returns a form definition so that user input can be collected, in order to connect to an app
1649
1654
 
@@ -20,7 +20,8 @@ from .configuration import (
20
20
  OutboundSyncStrategy,
21
21
  StoredConfigurationValue,
22
22
  StoredMappingValue,
23
- get_secrets
23
+ get_secrets,
24
+ ConnectivityOption
24
25
  )
25
26
  from .forms import ConnectionMethod, FormInputField, FormOption
26
27
  from .logging import OmnataPluginLogHandler
@@ -98,6 +99,7 @@ class PluginEntrypoint:
98
99
  # construct some connection parameters for the purpose of getting the api limits
99
100
  connection_parameters = ConnectionConfigurationParameters(
100
101
  connection_method=request.connection_method,
102
+ connectivity_option=request.connectivity_option,
101
103
  connection_parameters=request.connection_parameters,
102
104
  connection_secrets=connection_secrets
103
105
  )
@@ -138,6 +140,7 @@ class PluginEntrypoint:
138
140
  if request.sync_direction == "outbound":
139
141
  parameters = OutboundSyncConfigurationParameters(
140
142
  connection_method=request.connection_method,
143
+ connectivity_option=request.connectivity_option,
141
144
  connection_parameters=request.connection_parameters,
142
145
  connection_secrets=connection_secrets,
143
146
  sync_parameters=request.sync_parameters,
@@ -193,6 +196,7 @@ class PluginEntrypoint:
193
196
  logger.info("Running inbound sync")
194
197
  parameters = InboundSyncConfigurationParameters(
195
198
  connection_method=request.connection_method,
199
+ connectivity_option=request.connectivity_option,
196
200
  connection_parameters=request.connection_parameters,
197
201
  connection_secrets=connection_secrets,
198
202
  sync_parameters=request.sync_parameters,
@@ -268,6 +272,7 @@ class PluginEntrypoint:
268
272
 
269
273
  def configuration_form(
270
274
  self,
275
+ connectivity_option:str,
271
276
  connection_method: str,
272
277
  connection_parameters: Dict,
273
278
  oauth_secret_name: Optional[str],
@@ -283,6 +288,7 @@ class PluginEntrypoint:
283
288
  oauth_secret_name = normalise_nulls(oauth_secret_name)
284
289
  other_secrets_name = normalise_nulls(other_secrets_name)
285
290
  connection_secrets = get_secrets(oauth_secret_name, other_secrets_name)
291
+ connectivity_option = TypeAdapter(ConnectivityOption).validate_python(connectivity_option)
286
292
  connection_parameters = TypeAdapter(
287
293
  Dict[str, StoredConfigurationValue]).validate_python(connection_parameters)
288
294
  sync_parameters = TypeAdapter(
@@ -298,6 +304,7 @@ class PluginEntrypoint:
298
304
  sync_strategy=sync_strat,
299
305
  sync_parameters=sync_parameters,
300
306
  connection_method=connection_method,
307
+ connectivity_option=connectivity_option,
301
308
  current_form_parameters=form_parameters,
302
309
  )
303
310
  elif sync_direction == "inbound":
@@ -306,6 +313,7 @@ class PluginEntrypoint:
306
313
  connection_secrets=connection_secrets,
307
314
  sync_parameters=sync_parameters,
308
315
  connection_method=connection_method,
316
+ connectivity_option=connectivity_option,
309
317
  current_form_parameters=form_parameters,
310
318
  )
311
319
  else:
@@ -326,6 +334,7 @@ class PluginEntrypoint:
326
334
 
327
335
  def inbound_list_streams(
328
336
  self,
337
+ connectivity_option:str,
329
338
  connection_method: str,
330
339
  connection_parameters: Dict,
331
340
  oauth_secret_name: Optional[str],
@@ -337,6 +346,7 @@ class PluginEntrypoint:
337
346
  oauth_secret_name = normalise_nulls(oauth_secret_name)
338
347
  other_secrets_name = normalise_nulls(other_secrets_name)
339
348
  connection_secrets = get_secrets(oauth_secret_name, other_secrets_name)
349
+ connectivity_option = TypeAdapter(ConnectivityOption).validate_python(connectivity_option)
340
350
  connection_parameters = TypeAdapter(
341
351
  Dict[str, StoredConfigurationValue]).validate_python(connection_parameters)
342
352
  sync_parameters = TypeAdapter(
@@ -345,6 +355,7 @@ class PluginEntrypoint:
345
355
  connection_parameters=connection_parameters,
346
356
  connection_secrets=connection_secrets,
347
357
  sync_parameters=sync_parameters,
358
+ connectivity_option=connectivity_option,
348
359
  connection_method=connection_method,
349
360
  current_form_parameters=None,
350
361
  currently_selected_streams=selected_streams
@@ -381,9 +392,13 @@ class PluginEntrypoint:
381
392
  results.append(script_result.model_dump())
382
393
  return results
383
394
 
384
- def connection_form(self):
395
+ def connection_form(self,connectivity_option: str):
396
+ connectivity_option = TypeAdapter(ConnectivityOption).validate_python(connectivity_option)
385
397
  logger.info("Entered connection_form method")
386
- form: List[ConnectionMethod] = self._plugin_instance.connection_form()
398
+ if self._plugin_instance.connection_form.__code__.co_argcount==1:
399
+ form: List[ConnectionMethod] = self._plugin_instance.connection_form()
400
+ else:
401
+ form: List[ConnectionMethod] = self._plugin_instance.connection_form(connectivity_option)
387
402
  return [f.model_dump() for f in form]
388
403
 
389
404
  def create_billing_events(self, session, event_request: Dict):
@@ -431,30 +446,9 @@ class PluginEntrypoint:
431
446
  other_secrets_name: Optional[str],
432
447
  function_name: str,
433
448
  ) -> List[FormInputField]:
434
- logger.info("Entered ngrok_post_tunnel_fields method")
435
- oauth_secret_name = normalise_nulls(oauth_secret_name)
436
- other_secrets_name = normalise_nulls(other_secrets_name)
437
- connection_secrets = get_secrets(oauth_secret_name, other_secrets_name)
438
- connection_parameters = TypeAdapter(
439
- Dict[str, StoredConfigurationValue]).validate_python(connection_parameters)
440
- parameters = ConnectionConfigurationParameters(
441
- connection_method=connection_method,
442
- connection_parameters=connection_parameters,
443
- connection_secrets=connection_secrets
444
- )
445
- the_function = getattr(
446
- self._plugin_instance,
447
- function_name,
448
- )
449
- script_result = the_function(parameters)
450
- if isinstance(script_result, List):
451
- if len(script_result) > 0 and isinstance(script_result[0], BaseModel):
452
- script_result = [r.model_dump() for r in script_result]
453
- else:
454
- raise ValueError(f"Expected a List from function {function_name}, got {type(script_result)}")
455
- return script_result
449
+ raise ValueError(f"ngrok_post_tunnel_fields is deprecated")
456
450
 
457
- def network_addresses(self, method: str, connection_parameters: Dict) -> List[str]:
451
+ def network_addresses(self, connectivity_option:str, method: str, connection_parameters: Dict) -> List[str]:
458
452
  logger.info("Entered network_addresses method")
459
453
  logger.info(f"Connection parameters: {connection_parameters}")
460
454
  from omnata_plugin_runtime.omnata_plugin import (
@@ -463,6 +457,7 @@ class PluginEntrypoint:
463
457
 
464
458
  return self._plugin_instance.network_addresses(
465
459
  ConnectionConfigurationParameters(
460
+ connectivity_option=TypeAdapter(ConnectivityOption).validate_python(connectivity_option),
466
461
  connection_method=method,
467
462
  connection_parameters=TypeAdapter(
468
463
  Dict[str, StoredConfigurationValue]).validate_python(connection_parameters),
@@ -472,6 +467,7 @@ class PluginEntrypoint:
472
467
 
473
468
  def connect(
474
469
  self,
470
+ connectivity_option:str,
475
471
  method:str,
476
472
  connection_parameters: Dict,
477
473
  network_rule_name: str,
@@ -486,6 +482,7 @@ class PluginEntrypoint:
486
482
  ConnectionConfigurationParameters,
487
483
  )
488
484
  parameters = ConnectionConfigurationParameters(
485
+ connectivity_option=TypeAdapter(ConnectivityOption).validate_python(connectivity_option),
489
486
  connection_method=method,
490
487
  connection_parameters=TypeAdapter(
491
488
  Dict[str, StoredConfigurationValue]).validate_python(connection_parameters),
@@ -522,6 +519,7 @@ class PluginEntrypoint:
522
519
  return connect_response.model_dump()
523
520
 
524
521
  def api_limits(self,
522
+ connectivity_option:str,
525
523
  method:str,
526
524
  connection_parameters: Dict,
527
525
  oauth_secret_name: Optional[str],
@@ -532,6 +530,7 @@ class PluginEntrypoint:
532
530
  ConnectionConfigurationParameters,
533
531
  )
534
532
  connection_parameters = ConnectionConfigurationParameters(
533
+ connectivity_option=TypeAdapter(ConnectivityOption).validate_python(connectivity_option),
535
534
  connection_method=method,
536
535
  connection_parameters=TypeAdapter(
537
536
  Dict[str, StoredConfigurationValue]).validate_python(connection_parameters),