From f6fed08e267517d95e68fc2bda18104a41a761f3 Mon Sep 17 00:00:00 2001 From: Tim Van Baak Date: Sun, 14 Aug 2022 00:34:07 -0700 Subject: [PATCH] Refactor provider verification logic into intake.provider --- server/intake/cli.py | 108 +++++++++++++++++++------------------- server/intake/provider.py | 89 +++++++++++++++++++++++++++++++ 2 files changed, 142 insertions(+), 55 deletions(-) diff --git a/server/intake/cli.py b/server/intake/cli.py index 05af4c7..78168ca 100644 --- a/server/intake/cli.py +++ b/server/intake/cli.py @@ -4,7 +4,17 @@ import os from signal import signal, SIGPIPE, SIG_DFL import sys -from intake.provider import BaseSettings, load_provider +from intake.provider import ( + AttributeTypeError, + FunctionSignatureError, + load_provider, + RequiredAttributeMissingError, + verify_action, + verify_oncreate, + verify_ondelete, + verify_settings, + verify_update, +) def command_test(args): @@ -40,72 +50,60 @@ def command_test(args): ret = 1 continue # Settings class - if not hasattr(provider, "Settings"): + try: + verify_settings(provider) + print(" o Settings") + except RequiredAttributeMissingError: print(" x Missing Settings class") ret = 1 - else: - settings = getattr(provider, "Settings") - if not issubclass(settings, BaseSettings): - print(" x Settings class does not inherit from intake.BaseSettings") - ret = 1 - else: - print(" o Settings") + except AttributeTypeError: + print(" x Settings class does not inherit from intake.BaseSettings") + ret = 1 # update function - if not hasattr(provider, "Settings"): + try: + verify_update(provider) + print(" o update") + except RequiredAttributeMissingError: print(" x Missing update(config, state)") ret = 1 - else: - update = getattr(provider, "update") - if not callable(update): - print(" x update is not callable") - ret = 1 - else: - update_sig = inspect.signature(update) - if list(update_sig.parameters) != ["config", "state"]: - print(" x update does not have signature (config, state)") - ret = 1 - else: - print(" o update") + except AttributeTypeError: + print(" x update is not callable") + ret = 1 + except FunctionSignatureError: + print(" x update does not have signature (config, state)") + ret = 1 # on-create hook - if hasattr(provider, "on_create"): - on_create = getattr(provider, "on_create") - if not callable(on_create): - print(" x on_create is not callable") - ret = 1 - else: - create_sig = inspect.signature(on_create) - if list(create_sig.parameters) != ["config", "state", "item"]: - print(" x on_create does not have signature (config, state, item)") - ret = 1 - else: - print(" o on_create") + try: + if verify_oncreate(provider): + print(" o on_create") + except AttributeTypeError: + print(" x on_create is not callable") + ret = 1 + except FunctionSignatureError: + print(" x on_create does not have signature (config, state, item)") + ret = 1 # on-delete hook - if hasattr(provider, "on_delete"): - on_delete = getattr(provider, "on_delete") - if not callable(on_delete): - print(" x on_delete is not callable") - ret = 1 - else: - delete_sig = inspect.signature(on_delete) - if list(delete_sig.parameters) != ["config", "state", "item"]: - print(" x on_delete does not have signature (config, state, item)") - ret = 1 - else: - print(" o on_delete") + try: + if verify_ondelete(provider): + print(" o on_delete") + except AttributeTypeError: + print(" x on_delete is not callable") + ret = 1 + except FunctionSignatureError: + print(" x on_delete does not have signature (config, state, item)") + ret = 1 # actions actions = [name for name in vars(provider) if name.startswith("action_")] for action_name in actions: - action = getattr(provider, action_name) - if not callable(action): + try: + if verify_action(provider, action_name): + print(f" o {action_name}") + except AttributeTypeError: print(f" x {action_name} is not callable") ret = 1 - else: - action_sig = inspect.signature(action) - if list(action_sig.parameters) != ["config", "state", "item"]: - print(f" x {action_name} does not have signature (config, state, item)") - ret = 1 - else: - print(f" o {action_name}") + except FunctionSignatureError: + print(f" x {action_name} does not have signature (config, state, item)") + ret = 1 print("Done") return ret diff --git a/server/intake/provider.py b/server/intake/provider.py index fa2dc52..1402686 100644 --- a/server/intake/provider.py +++ b/server/intake/provider.py @@ -1,4 +1,5 @@ import importlib.util +import inspect import os import sys @@ -98,3 +99,91 @@ def load_provider(search_paths, provider_name): return provider return None + +class ProviderError(Exception): + """A provider's attributes are incorrect.""" + + +class RequiredAttributeMissingError(ProviderError): + """A provider is missing a required attribute.""" + + +class AttributeTypeError(ProviderError): + """A provider has an attribute with a wrong type.""" + + +class FunctionSignatureError(ProviderError): + """A provider has a function attribute with the wrong signature.""" + + +def verify_settings(provider): + """ + Verify that a provider's Settings is valid. + """ + if not hasattr(provider, "Settings"): + raise RequiredAttributeMissingError() + settings = getattr(provider, "Settings") + if not issubclass(settings, BaseSettings): + raise AttributeTypeError() + return True + + +def verify_update(provider): + """ + Verify that a provider's update() is valid. + """ + if not hasattr(provider, "update"): + raise RequiredAttributeMissingError() + update = getattr(provider, "update") + if not callable(update): + raise AttributeTypeError() + update_sig = inspect.signature(update) + if list(update_sig.parameters) != ["config", "state"]: + raise FunctionSignatureError() + return True + + +def verify_oncreate(provider): + """ + Verify that a provider's on_create() is valid. + """ + if not hasattr(provider, "on_create"): + return False + on_create = getattr(provider, "on_create") + if not callable(on_create): + raise AttributeTypeError() + create_sig = inspect.signature(on_create) + if list(create_sig.parameters) != ["config", "state", "item"]: + raise FunctionSignatureError() + return True + + +def verify_ondelete(provider): + """ + Verify that a provider's on_delete() is valid. + """ + if not hasattr(provider, "on_delete"): + return False + on_delete = getattr(provider, "on_delete") + if not callable(on_delete): + raise AttributeTypeError() + delete_sig = inspect.signature(on_delete) + if list(delete_sig.parameters) != ["config", "state", "item"]: + raise FunctionSignatureError() + return True + + +def verify_action(provider, name): + """ + Verify that a provider's action_*() is valid. + """ + action_name = name if name.startswith("action_") else f"action_{name}" + if not hasattr(provider, "action_name"): + return False + action = getattr(provider, action_name) + if not callable(action): + raise AttributeTypeError() + action_sig = inspect.signature(action) + if list(action_sig.parameters) != ["config", "state", "item"]: + raise FunctionSignatureError() + return True