azure_functions_worker/utils/common.py (69 lines of code) (raw):

# Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. import importlib import os import re import sys from types import ModuleType from typing import Callable, Optional from azure_functions_worker.constants import ( CUSTOMER_PACKAGES_PATH, PYTHON_EXTENSIONS_RELOAD_FUNCTIONS, ) def is_true_like(setting: str) -> bool: if setting is None: return False return setting.lower().strip() in {'1', 'true', 't', 'yes', 'y'} def is_false_like(setting: str) -> bool: if setting is None: return False return setting.lower().strip() in {'0', 'false', 'f', 'no', 'n'} def is_envvar_true(env_key: str) -> bool: if os.getenv(env_key) is None: return False return is_true_like(os.environ[env_key]) def is_envvar_false(env_key: str) -> bool: if os.getenv(env_key) is None: return False return is_false_like(os.environ[env_key]) def is_python_version(version: str) -> bool: current_version = f'{sys.version_info.major}.{sys.version_info.minor}' return current_version == version def get_app_setting( setting: str, default_value: Optional[str] = None, validator: Optional[Callable[[str], bool]] = None ) -> Optional[str]: """Returns the application setting from environment variable. Parameters ---------- setting: str The name of the application setting (e.g. FUNCTIONS_RUNTIME_VERSION) default_value: Optional[str] The expected return value when the application setting is not found, or the app setting does not pass the validator. validator: Optional[Callable[[str], bool]] A function accepts the app setting value and should return True when the app setting value is acceptable. Returns ------- Optional[str] A string value that is set in the application setting """ app_setting_value = os.getenv(setting) # If an app setting is not configured, we return the default value if app_setting_value is None: return default_value # If there's no validator, we should return the app setting value directly if validator is None: return app_setting_value # If the app setting is set with a validator, # On True, should return the app setting value # On False, should return the default value if validator(app_setting_value): return app_setting_value return default_value def get_sdk_version(module: ModuleType) -> str: """Check the version of azure.functions sdk. Parameters ---------- module: ModuleType The azure.functions SDK module Returns ------- str The SDK version that our customer has installed. """ return getattr(module, '__version__', 'undefined') def get_sdk_from_sys_path() -> ModuleType: """Get the azure.functions SDK from the latest sys.path defined. This is to ensure the extension loaded from SDK coming from customer's site-packages. Returns ------- ModuleType The azure.functions that is loaded from the first sys.path entry """ if is_envvar_true(PYTHON_EXTENSIONS_RELOAD_FUNCTIONS): backup_azure_functions = None backup_azure = None if 'azure.functions' in sys.modules: backup_azure_functions = sys.modules.pop('azure.functions') if 'azure' in sys.modules: backup_azure = sys.modules.pop('azure') module = importlib.import_module('azure.functions') if backup_azure: sys.modules['azure'] = backup_azure if backup_azure_functions: sys.modules['azure.functions'] = backup_azure_functions return module if CUSTOMER_PACKAGES_PATH not in sys.path: sys.path.insert(0, CUSTOMER_PACKAGES_PATH) return importlib.import_module('azure.functions') class InvalidFileNameError(Exception): def __init__(self, file_name: str) -> None: super().__init__( f'Invalid file name: {file_name}') def validate_script_file_name(file_name: str): # First character can be a letter, number, or underscore # Following characters can be a letter, number, underscore, hyphen, or dash # Ending must be .py pattern = re.compile(r'^[a-zA-Z0-9_][a-zA-Z0-9_\-]*\.py$') if not pattern.match(file_name): raise InvalidFileNameError(file_name)