| """Utilities for extracting module names from file paths.""" | |
| import os | |
| import site | |
| import sys | |
| from pathlib import Path | |
| def get_python_path_info(): | |
| """Get information about Python's search paths. | |
| Returns: | |
| dict: Dictionary containing stdlib path, site-packages paths, and sys.path entries. | |
| """ | |
| info = { | |
| 'stdlib': None, | |
| 'site_packages': [], | |
| 'sys_path': [] | |
| } | |
| # Get standard library path from os module location | |
| try: | |
| if hasattr(os, '__file__') and os.__file__: | |
| info['stdlib'] = Path(os.__file__).parent | |
| except (AttributeError, OSError): | |
| pass # Silently continue if we can't determine stdlib path | |
| # Get site-packages directories | |
| site_packages = [] | |
| try: | |
| site_packages.extend(Path(p) for p in site.getsitepackages()) | |
| except (AttributeError, OSError): | |
| pass # Continue without site packages if unavailable | |
| # Get user site-packages | |
| try: | |
| user_site = site.getusersitepackages() | |
| if user_site and Path(user_site).exists(): | |
| site_packages.append(Path(user_site)) | |
| except (AttributeError, OSError): | |
| pass # Continue without user site packages | |
| info['site_packages'] = site_packages | |
| info['sys_path'] = [Path(p) for p in sys.path if p] | |
| return info | |
| def extract_module_name(filename, path_info): | |
| """Extract Python module name and type from file path. | |
| Args: | |
| filename: Path to the Python file | |
| path_info: Dictionary from get_python_path_info() | |
| Returns: | |
| tuple: (module_name, module_type) where module_type is one of: | |
| 'stdlib', 'site-packages', 'project', or 'other' | |
| """ | |
| if not filename: | |
| return ('unknown', 'other') | |
| try: | |
| file_path = Path(filename) | |
| except (ValueError, OSError): | |
| return (str(filename), 'other') | |
| # Check if it's in stdlib | |
| if path_info['stdlib'] and file_path.is_relative_to(path_info['stdlib']): | |
| return (_path_to_module(file_path.relative_to(path_info['stdlib'])), 'stdlib') | |
| # Check site-packages | |
| for site_pkg in path_info['site_packages']: | |
| if file_path.is_relative_to(site_pkg): | |
| return (_path_to_module(file_path.relative_to(site_pkg)), 'site-packages') | |
| # Check other sys.path entries (project files) | |
| if not str(file_path).startswith(('<', '[')): # Skip special files | |
| for path_entry in path_info['sys_path']: | |
| if file_path.is_relative_to(path_entry): | |
| return (_path_to_module(file_path.relative_to(path_entry)), 'project') | |
| # Fallback: just use the filename | |
| return (_path_to_module(file_path), 'other') | |
| def _path_to_module(path): | |
| if isinstance(path, str): | |
| path = Path(path) | |
| # Remove .py extension | |
| if path.suffix == '.py': | |
| path = path.with_suffix('') | |
| # Convert path separators to dots, stripping root/drive (e.g. "/" or "C:\") | |
| parts = [p for p in path.parts if p != path.root and p != path.drive] | |
| # Handle __init__ files - they represent the package itself | |
| if parts and parts[-1] == '__init__': | |
| parts = parts[:-1] | |
| return '.'.join(parts) if parts else path.stem |