omnata-plugin-runtime 0.4.11__py3-none-any.whl → 0.5.0a112__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.
- omnata_plugin_runtime/api.py +8 -8
- omnata_plugin_runtime/configuration.py +10 -10
- omnata_plugin_runtime/forms.py +2 -2
- omnata_plugin_runtime/omnata_plugin.py +6 -9
- omnata_plugin_runtime/plugin_entrypoints.py +31 -45
- omnata_plugin_runtime/rate_limiting.py +20 -5
- {omnata_plugin_runtime-0.4.11.dist-info → omnata_plugin_runtime-0.5.0a112.dist-info}/METADATA +16 -15
- omnata_plugin_runtime-0.5.0a112.dist-info/RECORD +12 -0
- omnata_plugin_runtime-0.4.11.dist-info/RECORD +0 -12
- {omnata_plugin_runtime-0.4.11.dist-info → omnata_plugin_runtime-0.5.0a112.dist-info}/LICENSE +0 -0
- {omnata_plugin_runtime-0.4.11.dist-info → omnata_plugin_runtime-0.5.0a112.dist-info}/WHEEL +0 -0
    
        omnata_plugin_runtime/api.py
    CHANGED
    
    | @@ -67,8 +67,8 @@ class PluginMessageStreamProgressUpdate(BaseModel): | |
| 67 67 | 
             
                stream_total_counts: Dict[str, int]
         | 
| 68 68 | 
             
                completed_streams: List[str]
         | 
| 69 69 | 
             
                # older runtime versions didn't have these, so the sync engine can't expect it
         | 
| 70 | 
            -
                stream_errors: Optional[Dict[str,str]]
         | 
| 71 | 
            -
                total_records_estimate: Optional[Dict[str,int]]
         | 
| 70 | 
            +
                stream_errors: Optional[Dict[str,str]] = None
         | 
| 71 | 
            +
                total_records_estimate: Optional[Dict[str,int]] = None
         | 
| 72 72 |  | 
| 73 73 |  | 
| 74 74 | 
             
            class PluginMessageCancelledStreams(BaseModel):
         | 
| @@ -120,14 +120,14 @@ class OutboundSyncRequestPayload(BaseModel): | |
| 120 120 | 
             
                logging_level: str
         | 
| 121 121 | 
             
                connection_method: str
         | 
| 122 122 | 
             
                connection_parameters: Dict[str, StoredConfigurationValue]
         | 
| 123 | 
            -
                oauth_secret_name: Optional[str]
         | 
| 124 | 
            -
                other_secrets_name: Optional[str]
         | 
| 123 | 
            +
                oauth_secret_name: Optional[str] = None
         | 
| 124 | 
            +
                other_secrets_name: Optional[str] = None
         | 
| 125 125 | 
             
                sync_direction: Literal["outbound"] = "outbound"
         | 
| 126 126 | 
             
                sync_strategy: OutboundSyncStrategy
         | 
| 127 127 | 
             
                sync_parameters: Dict[str, StoredConfigurationValue]
         | 
| 128 128 | 
             
                api_limit_overrides: List[ApiLimits]
         | 
| 129 129 | 
             
                rate_limits_state: Dict[int,Dict[str,Dict[str,RateLimitState]]]
         | 
| 130 | 
            -
                field_mappings: Optional[StoredMappingValue]
         | 
| 130 | 
            +
                field_mappings: Optional[StoredMappingValue] = None
         | 
| 131 131 | 
             
                time_limit_mins: int = 60 * 4
         | 
| 132 132 |  | 
| 133 133 |  | 
| @@ -138,7 +138,7 @@ class InboundSyncRequestPayload(BaseModel): | |
| 138 138 |  | 
| 139 139 | 
             
                sync_id: int  # only used by log handler
         | 
| 140 140 | 
             
                sync_branch_name: str = 'main' # only used by rate limit updater
         | 
| 141 | 
            -
                sync_branch_id: Optional[int]  # only used by log handler
         | 
| 141 | 
            +
                sync_branch_id: Optional[int] = None  # only used by log handler
         | 
| 142 142 | 
             
                connection_id: int  # only used by log handler
         | 
| 143 143 | 
             
                run_id: int  # used by log handler and for reporting back run status updates
         | 
| 144 144 | 
             
                source_app_name: str  # the name of the app which is invoking this plugin
         | 
| @@ -147,8 +147,8 @@ class InboundSyncRequestPayload(BaseModel): | |
| 147 147 | 
             
                logging_level: str
         | 
| 148 148 | 
             
                connection_method: str
         | 
| 149 149 | 
             
                connection_parameters: Dict[str, StoredConfigurationValue]
         | 
| 150 | 
            -
                oauth_secret_name: Optional[str]
         | 
| 151 | 
            -
                other_secrets_name: Optional[str]
         | 
| 150 | 
            +
                oauth_secret_name: Optional[str] = None
         | 
| 151 | 
            +
                other_secrets_name: Optional[str] = None
         | 
| 152 152 | 
             
                sync_direction: Literal["inbound"] = "inbound"
         | 
| 153 153 | 
             
                sync_parameters: Dict[str, StoredConfigurationValue]
         | 
| 154 154 | 
             
                api_limit_overrides: List[ApiLimits]
         | 
| @@ -8,7 +8,7 @@ from typing import Any, List, Dict, Literal, Union, Optional | |
| 8 8 | 
             
            from enum import Enum
         | 
| 9 9 |  | 
| 10 10 | 
             
            from abc import ABC
         | 
| 11 | 
            -
            from pydantic import BaseModel, Field, validator  # pylint: disable=no-name-in-module
         | 
| 11 | 
            +
            from pydantic import BaseModel, Field, PrivateAttr, validator  # pylint: disable=no-name-in-module
         | 
| 12 12 |  | 
| 13 13 | 
             
            if tuple(sys.version_info[:2]) >= (3, 9):
         | 
| 14 14 | 
             
                # Python 3.9 and above
         | 
| @@ -424,8 +424,8 @@ class InboundSyncStreamsConfiguration(SubscriptableBaseModel): | |
| 424 424 | 
             
                """
         | 
| 425 425 |  | 
| 426 426 | 
             
                include_new_streams: bool
         | 
| 427 | 
            -
                new_stream_sync_strategy: Optional[InboundSyncStrategy]
         | 
| 428 | 
            -
                new_stream_storage_behaviour: Optional[InboundStorageBehaviour]
         | 
| 427 | 
            +
                new_stream_sync_strategy: Optional[InboundSyncStrategy] = None
         | 
| 428 | 
            +
                new_stream_storage_behaviour: Optional[InboundStorageBehaviour] = None
         | 
| 429 429 | 
             
                included_streams: Dict[str, StoredStreamConfiguration]
         | 
| 430 430 | 
             
                excluded_streams: List[str]
         | 
| 431 431 | 
             
                bulk_configuration: InboundSyncBulkConfiguration = InboundSyncBulkConfiguration.CUSTOMIZE
         | 
| @@ -536,10 +536,10 @@ class ConnectionConfigurationParameters(SubscriptableBaseModel): | |
| 536 536 | 
             
                connection_secrets: Dict[str, StoredConfigurationValue] = None
         | 
| 537 537 | 
             
                ngrok_tunnel_settings: Optional[NgrokTunnelSettings] = None
         | 
| 538 538 | 
             
                access_token_secret_name: Optional[str] = None
         | 
| 539 | 
            -
                _snowflake: Optional[Any] = None
         | 
| 540 539 |  | 
| 541 | 
            -
                 | 
| 542 | 
            -
                     | 
| 540 | 
            +
                _snowflake: Optional[Any] = PrivateAttr(  # or use Any to annotate the type and use Field to initialize
         | 
| 541 | 
            +
                    default=None
         | 
| 542 | 
            +
                )
         | 
| 543 543 |  | 
| 544 544 | 
             
                @validator("ngrok_tunnel_settings", always=True)
         | 
| 545 545 | 
             
                def validate_ngrok_tunnel_settings(cls, v: str, values: dict[str, Any]) -> Optional[NgrokTunnelSettings]:
         | 
| @@ -849,7 +849,7 @@ class StoredFieldMapping(SubscriptableBaseModel): | |
| 849 849 | 
             
                app_metadata: dict = Field(default_factory=dict)
         | 
| 850 850 |  | 
| 851 851 |  | 
| 852 | 
            -
            StoredStreamConfiguration. | 
| 853 | 
            -
            InboundSyncStreamsConfiguration. | 
| 854 | 
            -
            StoredFieldMappings. | 
| 855 | 
            -
            OutboundSyncConfigurationParameters. | 
| 852 | 
            +
            StoredStreamConfiguration.model_rebuild()
         | 
| 853 | 
            +
            InboundSyncStreamsConfiguration.model_rebuild()
         | 
| 854 | 
            +
            StoredFieldMappings.model_rebuild()
         | 
| 855 | 
            +
            OutboundSyncConfigurationParameters.model_rebuild()
         | 
    
        omnata_plugin_runtime/forms.py
    CHANGED
    
    | @@ -389,8 +389,8 @@ class NewOptionCreator(SubscriptableBaseModel): | |
| 389 389 | 
             
                    return v.__name__ if isinstance(v, MethodType) else v
         | 
| 390 390 |  | 
| 391 391 |  | 
| 392 | 
            -
            StaticFormOptionsDataSource. | 
| 393 | 
            -
            DynamicFormOptionsDataSource. | 
| 392 | 
            +
            StaticFormOptionsDataSource.model_rebuild()
         | 
| 393 | 
            +
            DynamicFormOptionsDataSource.model_rebuild()
         | 
| 394 394 |  | 
| 395 395 |  | 
| 396 396 | 
             
            class FormFieldMappingSelector(FormFieldWithDataSource, BaseModel):
         | 
| @@ -30,13 +30,10 @@ from typing import Any, Callable, Dict, Iterable, List, Literal, Optional, Type, | |
| 30 30 |  | 
| 31 31 | 
             
            import jinja2
         | 
| 32 32 | 
             
            import pandas
         | 
| 33 | 
            -
            import  | 
| 34 | 
            -
            import  | 
| 35 | 
            -
            from pydantic import Field, parse_obj_as, root_validator
         | 
| 33 | 
            +
            from pydantic_core import to_jsonable_python
         | 
| 34 | 
            +
            from pydantic import Field, TypeAdapter, root_validator, BaseModel
         | 
| 36 35 | 
             
            from dateutil.parser import parse
         | 
| 37 36 | 
             
            from jinja2 import Environment
         | 
| 38 | 
            -
            from pydantic import BaseModel  # pylint: disable=no-name-in-module
         | 
| 39 | 
            -
            from pandas import set_option
         | 
| 40 37 | 
             
            from snowflake.connector.pandas_tools import write_pandas
         | 
| 41 38 | 
             
            from snowflake.connector.version import VERSION
         | 
| 42 39 | 
             
            from snowflake.snowpark import Session
         | 
| @@ -127,7 +124,7 @@ class PluginInfo(BaseModel): | |
| 127 124 | 
             
                manifest: PluginManifest
         | 
| 128 125 | 
             
                anaconda_packages: List[str]
         | 
| 129 126 | 
             
                bundled_packages: List[str]
         | 
| 130 | 
            -
                icon_source: Optional[str]
         | 
| 127 | 
            +
                icon_source: Optional[str] = None
         | 
| 131 128 | 
             
                plugin_class_name: str
         | 
| 132 129 | 
             
                has_custom_validator: bool
         | 
| 133 130 | 
             
                plugin_runtime_version: str
         | 
| @@ -368,7 +365,7 @@ class SyncRequest(ABC): | |
| 368 365 | 
             
                        if update_rate_limit_result is not None:
         | 
| 369 366 | 
             
                            sync_id:int = update_rate_limit_result["sync_id"]
         | 
| 370 367 | 
             
                            sync_branch_name:str = update_rate_limit_result["sync_branch_name"]
         | 
| 371 | 
            -
                            latest_state | 
| 368 | 
            +
                            latest_state = TypeAdapter(Dict[int,Dict[str,Dict[str,RateLimitState]]]).validate_python(update_rate_limit_result["latest_state"])
         | 
| 372 369 | 
             
                            (rate_limit_state_all, rate_limit_state_this_branch) = RateLimitState.collapse(latest_state,sync_id, sync_branch_name)
         | 
| 373 370 | 
             
                            self.rate_limit_state_all = rate_limit_state_all
         | 
| 374 371 | 
             
                            self.rate_limit_state_this_sync_and_branch = rate_limit_state_this_branch
         | 
| @@ -466,7 +463,7 @@ class SyncRequest(ABC): | |
| 466 463 | 
             
                                self._session.sql(
         | 
| 467 464 | 
             
                                    f"""call {self._source_app_name}.API.PLUGIN_MESSAGE(
         | 
| 468 465 | 
             
                                              {self._run_id},
         | 
| 469 | 
            -
                                              PARSE_JSON($${json.dumps(message | 
| 466 | 
            +
                                              PARSE_JSON($${json.dumps(to_jsonable_python(message))}$$))"""
         | 
| 470 467 | 
             
                                ).collect()
         | 
| 471 468 | 
             
                            )
         | 
| 472 469 | 
             
                        except Exception as e:
         | 
| @@ -1955,7 +1952,7 @@ def managed_outbound_processing(concurrency: int, batch_size: int): | |
| 1955 1952 | 
             
                            dataframe_arg = method_args[0]
         | 
| 1956 1953 | 
             
                            if dataframe_arg.__class__.__name__ != "DataFrame" and not hasattr(dataframe_arg, "__next__"):
         | 
| 1957 1954 | 
             
                                raise ValueError(
         | 
| 1958 | 
            -
                                    f"The first argument to a @managed_outbound_processing method must be a DataFrame or DataFrame generator (from outbound_sync_request.get_records). Instead, a { | 
| 1955 | 
            +
                                    f"The first argument to a @managed_outbound_processing method must be a DataFrame or DataFrame generator (from outbound_sync_request.get_records). Instead, a {dataframe_arg.__class__.__name__} was provided. Alternatively, you can provide these via the 'dataframe' or 'dataframe_generator' named arguments."
         | 
| 1959 1956 | 
             
                                )
         | 
| 1960 1957 | 
             
                            method_args = method_args[1:]
         | 
| 1961 1958 |  | 
| @@ -8,8 +8,8 @@ import time | |
| 8 8 | 
             
            import threading
         | 
| 9 9 | 
             
            from typing import Dict, List, Optional
         | 
| 10 10 |  | 
| 11 | 
            -
            from pydantic import BaseModel, | 
| 12 | 
            -
            import  | 
| 11 | 
            +
            from pydantic import BaseModel,TypeAdapter  # pylint: disable=no-name-in-module
         | 
| 12 | 
            +
            from pydantic_core import to_jsonable_python
         | 
| 13 13 | 
             
            from snowflake.snowpark import Session
         | 
| 14 14 |  | 
| 15 15 | 
             
            from .api import PluginMessageStreamProgressUpdate, SyncRequestPayload, handle_proc_result
         | 
| @@ -69,7 +69,7 @@ class PluginEntrypoint: | |
| 69 69 |  | 
| 70 70 | 
             
                def sync(self, sync_request: Dict):
         | 
| 71 71 | 
             
                    logger.info("Entered sync method")
         | 
| 72 | 
            -
                    request =  | 
| 72 | 
            +
                    request = TypeAdapter(SyncRequestPayload).validate_python(sync_request)
         | 
| 73 73 | 
             
                    connection_secrets = self.get_secrets(
         | 
| 74 74 | 
             
                        request.oauth_secret_name, request.other_secrets_name
         | 
| 75 75 | 
             
                    )
         | 
| @@ -93,7 +93,7 @@ class PluginEntrypoint: | |
| 93 93 | 
             
                        connection_parameters.access_token_secret_name = request.oauth_secret_name
         | 
| 94 94 | 
             
                    all_api_limits = self._plugin_instance.api_limits(connection_parameters)
         | 
| 95 95 | 
             
                    logger.info(
         | 
| 96 | 
            -
                        f"Default API limits: {json.dumps(all_api_limits | 
| 96 | 
            +
                        f"Default API limits: {json.dumps(to_jsonable_python(all_api_limits))}"
         | 
| 97 97 | 
             
                    )
         | 
| 98 98 | 
             
                    all_api_limits_by_category = {
         | 
| 99 99 | 
             
                        api_limit.endpoint_category: api_limit for api_limit in all_api_limits
         | 
| @@ -109,7 +109,7 @@ class PluginEntrypoint: | |
| 109 109 | 
             
                    api_limits = list(all_api_limits_by_category.values())
         | 
| 110 110 | 
             
                    return_dict = {}
         | 
| 111 111 | 
             
                    logger.info(
         | 
| 112 | 
            -
                        f"Rate limits state: {json.dumps(request.rate_limits_state | 
| 112 | 
            +
                        f"Rate limits state: {json.dumps(to_jsonable_python(request.rate_limits_state))}"
         | 
| 113 113 | 
             
                    )
         | 
| 114 114 | 
             
                    (rate_limit_state_all, rate_limit_state_this_branch) = RateLimitState.collapse(request.rate_limits_state,request.sync_id, request.sync_branch_name)
         | 
| 115 115 | 
             
                    # if any endpoint categories have no state, give them an empty state
         | 
| @@ -270,19 +270,15 @@ class PluginEntrypoint: | |
| 270 270 | 
             
                    oauth_secret_name = normalise_nulls(oauth_secret_name)
         | 
| 271 271 | 
             
                    other_secrets_name = normalise_nulls(other_secrets_name)
         | 
| 272 272 | 
             
                    connection_secrets = self.get_secrets(oauth_secret_name, other_secrets_name)
         | 
| 273 | 
            -
                    connection_parameters =  | 
| 274 | 
            -
                        Dict[str, StoredConfigurationValue] | 
| 275 | 
            -
                     | 
| 276 | 
            -
             | 
| 277 | 
            -
                        Dict[str, StoredConfigurationValue], sync_parameters
         | 
| 278 | 
            -
                    )
         | 
| 273 | 
            +
                    connection_parameters = TypeAdapter(
         | 
| 274 | 
            +
                        Dict[str, StoredConfigurationValue]).validate_python(connection_parameters)
         | 
| 275 | 
            +
                    sync_parameters = TypeAdapter(
         | 
| 276 | 
            +
                        Dict[str, StoredConfigurationValue]).validate_python(sync_parameters)
         | 
| 279 277 | 
             
                    form_parameters = None
         | 
| 280 278 | 
             
                    if current_form_parameters is not None:
         | 
| 281 | 
            -
                        form_parameters =  | 
| 282 | 
            -
                            Dict[str, StoredConfigurationValue], current_form_parameters
         | 
| 283 | 
            -
                        )
         | 
| 279 | 
            +
                        form_parameters = TypeAdapter(Dict[str, StoredConfigurationValue]).validate_python(current_form_parameters)
         | 
| 284 280 | 
             
                    if sync_direction == "outbound":
         | 
| 285 | 
            -
                        sync_strat = OutboundSyncStrategy. | 
| 281 | 
            +
                        sync_strat = OutboundSyncStrategy.model_validate(sync_strategy) if sync_strategy is not None else None
         | 
| 286 282 | 
             
                        parameters = OutboundSyncConfigurationParameters(
         | 
| 287 283 | 
             
                            connection_parameters=connection_parameters,
         | 
| 288 284 | 
             
                            connection_secrets=connection_secrets,
         | 
| @@ -328,12 +324,10 @@ class PluginEntrypoint: | |
| 328 324 | 
             
                    oauth_secret_name = normalise_nulls(oauth_secret_name)
         | 
| 329 325 | 
             
                    other_secrets_name = normalise_nulls(other_secrets_name)
         | 
| 330 326 | 
             
                    connection_secrets = self.get_secrets(oauth_secret_name, other_secrets_name)
         | 
| 331 | 
            -
                    connection_parameters =  | 
| 332 | 
            -
                        Dict[str, StoredConfigurationValue] | 
| 333 | 
            -
                     | 
| 334 | 
            -
             | 
| 335 | 
            -
                        Dict[str, StoredConfigurationValue], sync_parameters
         | 
| 336 | 
            -
                    )
         | 
| 327 | 
            +
                    connection_parameters = TypeAdapter(
         | 
| 328 | 
            +
                        Dict[str, StoredConfigurationValue]).validate_python(connection_parameters)
         | 
| 329 | 
            +
                    sync_parameters = TypeAdapter(
         | 
| 330 | 
            +
                        Dict[str, StoredConfigurationValue]).validate_python(sync_parameters)
         | 
| 337 331 | 
             
                    parameters = InboundSyncConfigurationParameters(
         | 
| 338 332 | 
             
                        connection_parameters=connection_parameters,
         | 
| 339 333 | 
             
                        connection_secrets=connection_secrets,
         | 
| @@ -360,9 +354,8 @@ class PluginEntrypoint: | |
| 360 354 | 
             
                    stored_values: List[Dict],
         | 
| 361 355 | 
             
                ):
         | 
| 362 356 | 
             
                    logger.info("Entered construct_form_option method")
         | 
| 363 | 
            -
                    stored_values_parsed =  | 
| 364 | 
            -
                        List[StoredConfigurationValue] | 
| 365 | 
            -
                    )
         | 
| 357 | 
            +
                    stored_values_parsed = TypeAdapter(
         | 
| 358 | 
            +
                        List[StoredConfigurationValue]).validate_python(stored_values)
         | 
| 366 359 | 
             
                    the_function = getattr(
         | 
| 367 360 | 
             
                        self._plugin_instance,
         | 
| 368 361 | 
             
                        function_name,
         | 
| @@ -382,7 +375,7 @@ class PluginEntrypoint: | |
| 382 375 |  | 
| 383 376 | 
             
                def create_billing_events(self, session, event_request: Dict):
         | 
| 384 377 | 
             
                    logger.info("Entered create_billing_events method")
         | 
| 385 | 
            -
                    request =  | 
| 378 | 
            +
                    request = BillingEventRequest.model_validate(event_request)
         | 
| 386 379 | 
             
                    events: List[SnowflakeBillingEvent] = self._plugin_instance.create_billing_events(
         | 
| 387 380 | 
             
                        request
         | 
| 388 381 | 
             
                    )
         | 
| @@ -435,7 +428,7 @@ class PluginEntrypoint: | |
| 435 428 | 
             
                                other_secrets = json.loads(secret_string_content)
         | 
| 436 429 | 
             
                                connection_secrets = {
         | 
| 437 430 | 
             
                                    **connection_secrets,
         | 
| 438 | 
            -
                                    ** | 
| 431 | 
            +
                                    **TypeAdapter(Dict[str, StoredConfigurationValue]).validate_python(other_secrets),
         | 
| 439 432 | 
             
                                }
         | 
| 440 433 | 
             
                        except Exception as exception:
         | 
| 441 434 | 
             
                            logger.error(f"Error parsing secrets content for secret {other_secrets_name}: {str(exception)}")
         | 
| @@ -454,9 +447,8 @@ class PluginEntrypoint: | |
| 454 447 | 
             
                    oauth_secret_name = normalise_nulls(oauth_secret_name)
         | 
| 455 448 | 
             
                    other_secrets_name = normalise_nulls(other_secrets_name)
         | 
| 456 449 | 
             
                    connection_secrets = self.get_secrets(oauth_secret_name, other_secrets_name)
         | 
| 457 | 
            -
                    connection_parameters =  | 
| 458 | 
            -
                        Dict[str, StoredConfigurationValue] | 
| 459 | 
            -
                    )
         | 
| 450 | 
            +
                    connection_parameters = TypeAdapter(
         | 
| 451 | 
            +
                        Dict[str, StoredConfigurationValue]).validate_python(connection_parameters)
         | 
| 460 452 | 
             
                    parameters = ConnectionConfigurationParameters(
         | 
| 461 453 | 
             
                        connection_method=connection_method,
         | 
| 462 454 | 
             
                        connection_parameters=connection_parameters,
         | 
| @@ -484,9 +476,8 @@ class PluginEntrypoint: | |
| 484 476 | 
             
                    return self._plugin_instance.network_addresses(
         | 
| 485 477 | 
             
                        ConnectionConfigurationParameters(
         | 
| 486 478 | 
             
                            connection_method=method,
         | 
| 487 | 
            -
                            connection_parameters= | 
| 488 | 
            -
                                Dict[str, StoredConfigurationValue], | 
| 489 | 
            -
                            ),
         | 
| 479 | 
            +
                            connection_parameters=TypeAdapter(
         | 
| 480 | 
            +
                                Dict[str, StoredConfigurationValue]).validate_python(connection_parameters),
         | 
| 490 481 | 
             
                            connection_secrets={},
         | 
| 491 482 | 
             
                        )
         | 
| 492 483 | 
             
                    )
         | 
| @@ -508,9 +499,8 @@ class PluginEntrypoint: | |
| 508 499 | 
             
                    )
         | 
| 509 500 | 
             
                    parameters = ConnectionConfigurationParameters(
         | 
| 510 501 | 
             
                        connection_method=method,
         | 
| 511 | 
            -
                        connection_parameters= | 
| 512 | 
            -
                            Dict[str, StoredConfigurationValue], | 
| 513 | 
            -
                        ),
         | 
| 502 | 
            +
                        connection_parameters=TypeAdapter(
         | 
| 503 | 
            +
                            Dict[str, StoredConfigurationValue]).validate_python(connection_parameters),
         | 
| 514 504 | 
             
                        connection_secrets=connection_secrets
         | 
| 515 505 | 
             
                    )
         | 
| 516 506 | 
             
                    if oauth_secret_name is not None:
         | 
| @@ -555,15 +545,14 @@ class PluginEntrypoint: | |
| 555 545 | 
             
                    )
         | 
| 556 546 | 
             
                    connection_parameters = ConnectionConfigurationParameters(
         | 
| 557 547 | 
             
                        connection_method=method,
         | 
| 558 | 
            -
                        connection_parameters= | 
| 559 | 
            -
                            Dict[str, StoredConfigurationValue], | 
| 560 | 
            -
                        ),
         | 
| 548 | 
            +
                        connection_parameters=TypeAdapter(
         | 
| 549 | 
            +
                            Dict[str, StoredConfigurationValue]).validate_python(connection_parameters),
         | 
| 561 550 | 
             
                        connection_secrets=connection_secrets
         | 
| 562 551 | 
             
                    )
         | 
| 563 552 | 
             
                    if oauth_secret_name is not None:
         | 
| 564 553 | 
             
                        connection_parameters.access_token_secret_name = oauth_secret_name
         | 
| 565 554 | 
             
                    response: List[ApiLimits] = self._plugin_instance.api_limits(connection_parameters)
         | 
| 566 | 
            -
                    return [api_limit. | 
| 555 | 
            +
                    return [api_limit.model_dump() for api_limit in response]
         | 
| 567 556 |  | 
| 568 557 | 
             
                def outbound_record_validator(
         | 
| 569 558 | 
             
                    self,
         | 
| @@ -573,12 +562,9 @@ class PluginEntrypoint: | |
| 573 562 | 
             
                    source_types: Dict[str, str],
         | 
| 574 563 | 
             
                ):
         | 
| 575 564 | 
             
                    # There's a bit of parsing here that could possibly be done outside of the handler function, but this shouldn't be too expensive
         | 
| 576 | 
            -
                    sync_parameters: Dict[str, StoredConfigurationValue] =  | 
| 577 | 
            -
                        Dict[str, StoredConfigurationValue] | 
| 578 | 
            -
                    )
         | 
| 579 | 
            -
                    field_mappings: StoredMappingValue = parse_obj_as(
         | 
| 580 | 
            -
                        StoredMappingValue, field_mappings
         | 
| 581 | 
            -
                    )
         | 
| 565 | 
            +
                    sync_parameters: Dict[str, StoredConfigurationValue] = TypeAdapter(
         | 
| 566 | 
            +
                        Dict[str, StoredConfigurationValue]).validate_python(sync_parameters)
         | 
| 567 | 
            +
                    field_mappings: StoredMappingValue = StoredMappingValue.model_validate(field_mappings)
         | 
| 582 568 | 
             
                    return self._plugin_instance.outbound_record_validator(
         | 
| 583 569 | 
             
                        sync_parameters, field_mappings, transformed_record, source_types
         | 
| 584 570 | 
             
                    )
         | 
| @@ -12,8 +12,8 @@ from typing import Any, List, Literal, Optional, Dict, Tuple | |
| 12 12 | 
             
            import requests
         | 
| 13 13 | 
             
            import time
         | 
| 14 14 | 
             
            import logging
         | 
| 15 | 
            -
            from pydantic import Field, root_validator
         | 
| 16 | 
            -
            from  | 
| 15 | 
            +
            from pydantic import Field, root_validator, PrivateAttr, field_serializer
         | 
| 16 | 
            +
            from pydantic_core import to_jsonable_python
         | 
| 17 17 | 
             
            from .configuration import SubscriptableBaseModel
         | 
| 18 18 | 
             
            import pytz
         | 
| 19 19 | 
             
            from requests.adapters import HTTPAdapter
         | 
| @@ -160,7 +160,7 @@ def epoch_milliseconds_to_datetime(epoch: int) -> datetime.datetime: | |
| 160 160 | 
             
            def datetimes_as_ints_encoder(obj):
         | 
| 161 161 | 
             
                if isinstance(obj, datetime.datetime):
         | 
| 162 162 | 
             
                    return datetime_to_epoch_milliseconds(obj)
         | 
| 163 | 
            -
                return  | 
| 163 | 
            +
                return to_jsonable_python(obj)
         | 
| 164 164 |  | 
| 165 165 |  | 
| 166 166 | 
             
            class RateLimitState(SubscriptableBaseModel):
         | 
| @@ -178,7 +178,22 @@ class RateLimitState(SubscriptableBaseModel): | |
| 178 178 | 
             
                    [],
         | 
| 179 179 | 
             
                    description="A list of timestamps where previous requests have been made, used to calculate the next request time",
         | 
| 180 180 | 
             
                )
         | 
| 181 | 
            -
                 | 
| 181 | 
            +
                
         | 
| 182 | 
            +
                _request_timestamps_lock: threading.Lock = PrivateAttr(  # or use Any to annotate the type and use Field to initialize
         | 
| 183 | 
            +
                    default_factory=lambda: threading.Lock()
         | 
| 184 | 
            +
                )
         | 
| 185 | 
            +
             | 
| 186 | 
            +
                @field_serializer('wait_until',when_used='always')
         | 
| 187 | 
            +
                def serialize_wait_until(self, value:Optional[datetime.datetime]) -> Optional[int]:
         | 
| 188 | 
            +
                    # if a datetime is provided, convert it to epoch milliseconds
         | 
| 189 | 
            +
                    if value is not None:
         | 
| 190 | 
            +
                        return datetime_to_epoch_milliseconds(value)
         | 
| 191 | 
            +
             | 
| 192 | 
            +
                @field_serializer('previous_request_timestamps',when_used='always')
         | 
| 193 | 
            +
                def serialize_previous_request_timestamps(self, value:List[datetime.datetime]) -> List[int]:
         | 
| 194 | 
            +
                    # if a list of datetimes is provided, convert them to epoch milliseconds
         | 
| 195 | 
            +
                    return [datetime_to_epoch_milliseconds(ts) if ts else None for ts in value]
         | 
| 196 | 
            +
             | 
| 182 197 |  | 
| 183 198 | 
             
                # Combined root validator
         | 
| 184 199 | 
             
                @root_validator(pre=True)
         | 
| @@ -545,4 +560,4 @@ def too_many_requests_hook( | |
| 545 560 | 
             
                return hook
         | 
| 546 561 |  | 
| 547 562 |  | 
| 548 | 
            -
            ApiLimits. | 
| 563 | 
            +
            ApiLimits.model_rebuild()
         | 
    
        {omnata_plugin_runtime-0.4.11.dist-info → omnata_plugin_runtime-0.5.0a112.dist-info}/METADATA
    RENAMED
    
    | @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            Metadata-Version: 2.1
         | 
| 2 2 | 
             
            Name: omnata-plugin-runtime
         | 
| 3 | 
            -
            Version: 0. | 
| 3 | 
            +
            Version: 0.5.0a112
         | 
| 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
         | 
| @@ -9,26 +9,27 @@ Classifier: Programming Language :: Python :: 3 | |
| 9 9 | 
             
            Classifier: Programming Language :: Python :: 3.8
         | 
| 10 10 | 
             
            Classifier: Programming Language :: Python :: 3.9
         | 
| 11 11 | 
             
            Classifier: Programming Language :: Python :: 3.10
         | 
| 12 | 
            -
            Requires-Dist: certifi (<= | 
| 12 | 
            +
            Requires-Dist: certifi (<=2024.7.4)
         | 
| 13 13 | 
             
            Requires-Dist: charset-normalizer (<=2.0.4)
         | 
| 14 | 
            -
            Requires-Dist: idna (<=3. | 
| 14 | 
            +
            Requires-Dist: idna (<=3.7)
         | 
| 15 15 | 
             
            Requires-Dist: jinja2 (>=3.1.2,<=3.1.4)
         | 
| 16 16 | 
             
            Requires-Dist: markupsafe (<=2.1.3)
         | 
| 17 | 
            -
            Requires-Dist: numpy (<=1.26. | 
| 18 | 
            -
            Requires-Dist: packaging (<= | 
| 19 | 
            -
            Requires-Dist: pandas (<=2. | 
| 17 | 
            +
            Requires-Dist: numpy (<=1.26.4)
         | 
| 18 | 
            +
            Requires-Dist: packaging (<=24.1)
         | 
| 19 | 
            +
            Requires-Dist: pandas (<=2.2.2)
         | 
| 20 20 | 
             
            Requires-Dist: platformdirs (<=3.10.0)
         | 
| 21 | 
            -
            Requires-Dist: pydantic (>= | 
| 22 | 
            -
            Requires-Dist: pyjwt (<=2. | 
| 23 | 
            -
            Requires-Dist: pyopenssl (<= | 
| 24 | 
            -
            Requires-Dist: pytz (<= | 
| 25 | 
            -
            Requires-Dist: requests (>=2,<=2. | 
| 21 | 
            +
            Requires-Dist: pydantic (>=2,<=2.5.3)
         | 
| 22 | 
            +
            Requires-Dist: pyjwt (<=2.8.0)
         | 
| 23 | 
            +
            Requires-Dist: pyopenssl (<=24.0.0)
         | 
| 24 | 
            +
            Requires-Dist: pytz (<=2024.1)
         | 
| 25 | 
            +
            Requires-Dist: requests (>=2,<=2.32.2)
         | 
| 26 26 | 
             
            Requires-Dist: setuptools (<=69.5.1)
         | 
| 27 | 
            -
            Requires-Dist: snowflake- | 
| 28 | 
            -
            Requires-Dist:  | 
| 27 | 
            +
            Requires-Dist: snowflake-connector-python (>=3,<=3.12.0)
         | 
| 28 | 
            +
            Requires-Dist: snowflake-snowpark-python (==1.19.0)
         | 
| 29 | 
            +
            Requires-Dist: tenacity (>=8,<=8.2.3)
         | 
| 29 30 | 
             
            Requires-Dist: tomlkit (<=0.11.1)
         | 
| 30 | 
            -
            Requires-Dist: urllib3 (<=2. | 
| 31 | 
            -
            Requires-Dist: wheel (<=0. | 
| 31 | 
            +
            Requires-Dist: urllib3 (<=2.2.2)
         | 
| 32 | 
            +
            Requires-Dist: wheel (<=0.43.0)
         | 
| 32 33 | 
             
            Description-Content-Type: text/markdown
         | 
| 33 34 |  | 
| 34 35 | 
             
            # omnata-plugin-runtime
         | 
| @@ -0,0 +1,12 @@ | |
| 1 | 
            +
            omnata_plugin_runtime/__init__.py,sha256=MS9d1whnfT_B3-ThqZ7l63QeC_8OEKTuaYV5wTwRpBA,1576
         | 
| 2 | 
            +
            omnata_plugin_runtime/api.py,sha256=FxzTqri4no8ClkOm7vZADG8aD47jcGBCTTQDEORmOJM,6326
         | 
| 3 | 
            +
            omnata_plugin_runtime/configuration.py,sha256=LvQVIKwo8XlfHf-9Jkj1GDH0U6sOKDKi3IMDyAwAnHE,35781
         | 
| 4 | 
            +
            omnata_plugin_runtime/forms.py,sha256=hV6jVaizex20Pb9NxPx11TBPK-Yy8pREAnTtCxHo4Qo,18409
         | 
| 5 | 
            +
            omnata_plugin_runtime/logging.py,sha256=bn7eKoNWvtuyTk7RTwBS9UARMtqkiICtgMtzq3KA2V0,3272
         | 
| 6 | 
            +
            omnata_plugin_runtime/omnata_plugin.py,sha256=zIk8dS5m4pXsVy_2im-Cd-t1uQV9hf1seosb1T2jGGs,110880
         | 
| 7 | 
            +
            omnata_plugin_runtime/plugin_entrypoints.py,sha256=xlPTI25N5G3l0bRFSkga98TIHM44NRaN2g7T5jSsqX0,29181
         | 
| 8 | 
            +
            omnata_plugin_runtime/rate_limiting.py,sha256=BzN8CkI8dxel1PERDpuSZek7vo6QeCHwbZEtcO21IR4,25479
         | 
| 9 | 
            +
            omnata_plugin_runtime-0.5.0a112.dist-info/LICENSE,sha256=IMF9i4xIpgCADf0U-V1cuf9HBmqWQd3qtI3FSuyW4zE,26526
         | 
| 10 | 
            +
            omnata_plugin_runtime-0.5.0a112.dist-info/METADATA,sha256=KIWIJS75ax78BJ4cIKQGU3qQtSrv7zRwgdA6duIT5so,1699
         | 
| 11 | 
            +
            omnata_plugin_runtime-0.5.0a112.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
         | 
| 12 | 
            +
            omnata_plugin_runtime-0.5.0a112.dist-info/RECORD,,
         | 
| @@ -1,12 +0,0 @@ | |
| 1 | 
            -
            omnata_plugin_runtime/__init__.py,sha256=MS9d1whnfT_B3-ThqZ7l63QeC_8OEKTuaYV5wTwRpBA,1576
         | 
| 2 | 
            -
            omnata_plugin_runtime/api.py,sha256=W79CsAcl127Dzy-XVS9CzvzsbS3IigVH4QAhFFDkaXg,6270
         | 
| 3 | 
            -
            omnata_plugin_runtime/configuration.py,sha256=7cMekoY8CeZAJHpASU6tCMidF55Hzfr7CD74jtebqIY,35742
         | 
| 4 | 
            -
            omnata_plugin_runtime/forms.py,sha256=pw_aKVsXSz47EP8PFBI3VDwdSN5IjvZxp8JTjO1V130,18421
         | 
| 5 | 
            -
            omnata_plugin_runtime/logging.py,sha256=bn7eKoNWvtuyTk7RTwBS9UARMtqkiICtgMtzq3KA2V0,3272
         | 
| 6 | 
            -
            omnata_plugin_runtime/omnata_plugin.py,sha256=SKdtUOsJWVG-WtartrdSxOJUPfZrnmp0sf0WQduj7gk,110997
         | 
| 7 | 
            -
            omnata_plugin_runtime/plugin_entrypoints.py,sha256=JAGEdVcy9QEXv7TO5zt7co64LTP8nqGusOc0sJG9GtU,29149
         | 
| 8 | 
            -
            omnata_plugin_runtime/rate_limiting.py,sha256=BOxyjERDG46iPY7coYu79jdZ9JqHMYPG-BNyXYOIJmk,24678
         | 
| 9 | 
            -
            omnata_plugin_runtime-0.4.11.dist-info/LICENSE,sha256=IMF9i4xIpgCADf0U-V1cuf9HBmqWQd3qtI3FSuyW4zE,26526
         | 
| 10 | 
            -
            omnata_plugin_runtime-0.4.11.dist-info/METADATA,sha256=HDZk_7-6eAWyKZXCZ7jzkO3Sbp0asC2Tu6QvbThbR5o,1647
         | 
| 11 | 
            -
            omnata_plugin_runtime-0.4.11.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
         | 
| 12 | 
            -
            omnata_plugin_runtime-0.4.11.dist-info/RECORD,,
         | 
    
        {omnata_plugin_runtime-0.4.11.dist-info → omnata_plugin_runtime-0.5.0a112.dist-info}/LICENSE
    RENAMED
    
    | 
            File without changes
         | 
| 
            File without changes
         |