melody-backend / utils /import_utils.py
mfaydin's picture
Initial songformer deploy
77a71b4
Raw
History Blame Contribute Delete
8.53 kB
"""
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
}