Spaces:
Sleeping
Sleeping
| """ | |
| Import management utilities for ChordMini Flask application. | |
| This module provides utilities for managing imports, lazy loading, | |
| and handling optional dependencies. | |
| """ | |
| import sys | |
| import importlib | |
| from utils.logging import log_info, log_error, log_debug | |
| def lazy_import_librosa(): | |
| """ | |
| Lazy import librosa with patches applied. | |
| This function ensures that scipy patches are applied before importing librosa | |
| to avoid compatibility issues with certain versions of scipy and librosa. | |
| Returns: | |
| module: The librosa module | |
| """ | |
| # Check if librosa is already imported | |
| if 'librosa' in globals(): | |
| return globals()['librosa'] | |
| try: | |
| # Apply scipy patches before importing librosa | |
| from scipy_patch import apply_scipy_patches, patch_librosa_beat_tracker, monkey_patch_beat_track | |
| apply_scipy_patches() | |
| patch_librosa_beat_tracker() | |
| monkey_patch_beat_track() | |
| # Now it's safe to import librosa | |
| import librosa as _librosa | |
| globals()['librosa'] = _librosa | |
| log_debug("Successfully imported librosa with patches applied") | |
| return _librosa | |
| except ImportError as e: | |
| log_error(f"Failed to import librosa: {e}") | |
| raise ImportError(f"librosa is required but not available: {e}") | |
| except Exception as e: | |
| log_error(f"Error applying patches or importing librosa: {e}") | |
| raise | |
| def safe_import(module_name, package=None, fallback=None): | |
| """ | |
| Safely import a module with optional fallback. | |
| Args: | |
| module_name: Name of the module to import | |
| package: Package name for relative imports | |
| fallback: Fallback value if import fails | |
| Returns: | |
| module or fallback: The imported module or fallback value | |
| """ | |
| try: | |
| if package: | |
| module = importlib.import_module(module_name, package) | |
| else: | |
| module = importlib.import_module(module_name) | |
| log_debug(f"Successfully imported {module_name}") | |
| return module | |
| except ImportError as e: | |
| log_debug(f"Failed to import {module_name}: {e}") | |
| if fallback is not None: | |
| log_debug(f"Using fallback for {module_name}") | |
| return fallback | |
| raise | |
| def check_optional_dependency(module_name, feature_name=None): | |
| """ | |
| Check if an optional dependency is available. | |
| Args: | |
| module_name: Name of the module to check | |
| feature_name: Human-readable feature name (optional) | |
| Returns: | |
| dict: Status information about the dependency | |
| """ | |
| try: | |
| importlib.import_module(module_name) | |
| return { | |
| 'available': True, | |
| 'module': module_name, | |
| 'feature': feature_name or module_name, | |
| 'error': None | |
| } | |
| except ImportError as e: | |
| return { | |
| 'available': False, | |
| 'module': module_name, | |
| 'feature': feature_name or module_name, | |
| 'error': str(e) | |
| } | |
| def get_module_version(module_name): | |
| """ | |
| Get the version of an installed module. | |
| Args: | |
| module_name: Name of the module | |
| Returns: | |
| str or None: Version string or None if not available | |
| """ | |
| try: | |
| module = importlib.import_module(module_name) | |
| # Try different version attributes | |
| version_attrs = ['__version__', 'version', 'VERSION'] | |
| for attr in version_attrs: | |
| if hasattr(module, attr): | |
| version = getattr(module, attr) | |
| if isinstance(version, str): | |
| return version | |
| elif hasattr(version, '__str__'): | |
| return str(version) | |
| # Try using importlib.metadata for newer Python versions | |
| try: | |
| import importlib.metadata | |
| return importlib.metadata.version(module_name) | |
| except (ImportError, importlib.metadata.PackageNotFoundError): | |
| pass | |
| return None | |
| except ImportError: | |
| return None | |
| def lazy_import_with_fallback(primary_module, fallback_modules=None, feature_name=None): | |
| """ | |
| Lazy import with fallback options. | |
| Args: | |
| primary_module: Primary module to try importing | |
| fallback_modules: List of fallback module names | |
| feature_name: Human-readable feature name | |
| Returns: | |
| dict: Import result with module and metadata | |
| """ | |
| fallback_modules = fallback_modules or [] | |
| # Try primary module first | |
| try: | |
| module = importlib.import_module(primary_module) | |
| return { | |
| 'success': True, | |
| 'module': module, | |
| 'used_module': primary_module, | |
| 'feature': feature_name or primary_module, | |
| 'is_fallback': False, | |
| 'error': None | |
| } | |
| except ImportError as primary_error: | |
| log_debug(f"Primary module {primary_module} not available: {primary_error}") | |
| # Try fallback modules | |
| for fallback in fallback_modules: | |
| try: | |
| module = importlib.import_module(fallback) | |
| log_info(f"Using fallback module {fallback} for {feature_name or primary_module}") | |
| return { | |
| 'success': True, | |
| 'module': module, | |
| 'used_module': fallback, | |
| 'feature': feature_name or primary_module, | |
| 'is_fallback': True, | |
| 'error': None | |
| } | |
| except ImportError as fallback_error: | |
| log_debug(f"Fallback module {fallback} not available: {fallback_error}") | |
| continue | |
| # No modules available | |
| error_msg = f"Neither {primary_module} nor fallbacks {fallback_modules} are available" | |
| log_error(error_msg) | |
| return { | |
| 'success': False, | |
| 'module': None, | |
| 'used_module': None, | |
| 'feature': feature_name or primary_module, | |
| 'is_fallback': False, | |
| 'error': error_msg | |
| } | |
| def ensure_module_in_path(module_path): | |
| """ | |
| Ensure a module path is in sys.path. | |
| Args: | |
| module_path: Path to add to sys.path | |
| Returns: | |
| bool: True if path was added or already present | |
| """ | |
| try: | |
| import os | |
| if not os.path.exists(module_path): | |
| log_error(f"Module path does not exist: {module_path}") | |
| return False | |
| abs_path = os.path.abspath(module_path) | |
| if abs_path not in sys.path: | |
| sys.path.insert(0, abs_path) | |
| log_debug(f"Added {abs_path} to sys.path") | |
| else: | |
| log_debug(f"Path {abs_path} already in sys.path") | |
| return True | |
| except Exception as e: | |
| log_error(f"Error adding module path {module_path}: {e}") | |
| return False | |
| def get_import_diagnostics(): | |
| """ | |
| Get diagnostic information about the import environment. | |
| Returns: | |
| dict: Diagnostic information | |
| """ | |
| try: | |
| import platform | |
| diagnostics = { | |
| 'python_version': platform.python_version(), | |
| 'python_executable': sys.executable, | |
| 'sys_path_length': len(sys.path), | |
| 'sys_path_first_10': sys.path[:10], | |
| 'loaded_modules_count': len(sys.modules), | |
| 'key_modules': {} | |
| } | |
| # Check key modules | |
| key_modules = [ | |
| 'numpy', 'scipy', 'librosa', 'torch', 'tensorflow', | |
| 'flask', 'requests', 'soundfile', 'matplotlib' | |
| ] | |
| for module_name in key_modules: | |
| status = check_optional_dependency(module_name) | |
| if status['available']: | |
| version = get_module_version(module_name) | |
| diagnostics['key_modules'][module_name] = { | |
| 'available': True, | |
| 'version': version | |
| } | |
| else: | |
| diagnostics['key_modules'][module_name] = { | |
| 'available': False, | |
| 'error': status['error'] | |
| } | |
| return diagnostics | |
| except Exception as e: | |
| log_error(f"Error getting import diagnostics: {e}") | |
| return { | |
| 'error': str(e), | |
| 'python_version': sys.version, | |
| 'python_executable': sys.executable | |
| } | |