--- a +++ b/environment_setup.py @@ -0,0 +1,134 @@ +import subprocess +import sys +import logging +from typing import List, Tuple +import importlib.metadata + + +def setup_logging(): + """Configure logging for the installation process""" + logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(levelname)s - %(message)s', + handlers=[ + logging.StreamHandler(sys.stdout), + logging.FileHandler('logs/installation.log') + ] + ) + return logging.getLogger(__name__) + + +def parse_requirements(filename: str) -> List[Tuple[str, str]]: + """ + Parse requirements.txt and return list of (package_name, version) tuples + Ignores comments and empty lines + """ + requirements = [] + with open(filename, 'r') as file: + for line in file: + # Remove comments if they exist on the same line as a package + if '#' in line: + line = line[:line.index('#')] + + line = line.strip() + if line and not line.startswith('#'): + # Handle version specifiers + if '==' in line: + package, version = line.split('==') + requirements.append((package.strip(), version.strip())) + else: + requirements.append((line, '')) + return requirements + + +def is_package_installed(package_name: str, required_version: str = '') -> bool: + """Check if a package is installed with the required version""" + try: + installed_version = importlib.metadata.version(package_name) + if required_version: + return installed_version == required_version + return True + except importlib.metadata.PackageNotFoundError: + return False + + +def install_package(package_name: str, version: str, logger) -> bool: + """Install a package using pip""" + try: + package_spec = f"{package_name}=={version}" if version else package_name + subprocess.check_call([sys.executable, '-m', 'pip', 'install', package_spec]) + return True + except subprocess.CalledProcessError as e: + logger.error(f"Failed to install {package_name}: {str(e)}") + return False + + +def setup_nltk(logger): + """Download required NLTK data""" + try: + import nltk + nltk_packages = ['punkt', 'stopwords', 'wordnet'] + for package in nltk_packages: + logger.info(f"Downloading NLTK package: {package}") + nltk.download(package, quiet=True) + return True + except Exception as e: + logger.error(f"Failed to download NLTK packages: {str(e)}") + return False + + +def setup_spacy(logger): + """Download SpaCy English language model""" + try: + subprocess.check_call([sys.executable, '-m', 'spacy', 'download', 'en_core_web_sm']) + return True + except subprocess.CalledProcessError as e: + logger.error(f"Failed to download SpaCy model: {str(e)}") + return False + + +def check_and_install_dependencies(): + """Main function to check and install all dependencies""" + logger = setup_logging() + logger.info("Starting dependency check and installation...") + + # Parse requirements.txt + try: + requirements = parse_requirements('requirements.txt') + except FileNotFoundError: + logger.error("requirements.txt not found!") + return False + + # Check and install each package + all_successful = True + for package_name, version in requirements: + if not is_package_installed(package_name, version): + logger.info(f"Installing {package_name} {'version ' + version if version else ''}") + if not install_package(package_name, version, logger): + all_successful = False + else: + logger.info(f"{package_name} {'version ' + version if version else ''} is already installed") + + # Setup NLTK + if all_successful: + logger.info("Setting up NLTK...") + if not setup_nltk(logger): + all_successful = False + + # Setup SpaCy + if all_successful: + logger.info("Setting up SpaCy...") + if not setup_spacy(logger): + all_successful = False + + if all_successful: + logger.info("All dependencies installed successfully!") + else: + logger.error("Some installations failed. Check the logs for details.") + + return all_successful + + +if __name__ == "__main__": + success = check_and_install_dependencies() + sys.exit(0 if success else 1)