diff --git a/README.md b/README.md index 0cf14ba..ae1a8fa 100644 --- a/README.md +++ b/README.md @@ -324,7 +324,7 @@ If you're interested in contributing to **Code-Interpreter**, we'd love to have - **v2.1.4** - Added **GPT-4o** models they are most effecient and cost effective models from **OpenAI** - **v2.1.5** - Fixed OS type detection **Bug** for MacOS and feautre to open file with default editor. -# 🔥 **v2.2** +🔥 **v2.2** - Save/Execute _commands_ and _scripts_, Fixed **Logging** and **Package Manager**. - **Save/Execute**: Added support to **save and execute code, commands, and scripts** directly to external files. - **Updated Commands**: - Removed the `/debug` command and replaced it with the `/fix` command. diff --git a/libs/logger.py b/libs/logger.py index 1761fab..33273f6 100644 --- a/libs/logger.py +++ b/libs/logger.py @@ -10,7 +10,6 @@ class Logger: @staticmethod def initialize(filename: str): if Logger._logger is None: - # Create the root logger Logger._logger = logging.getLogger(filename) Logger._logger.setLevel(logging.DEBUG) @@ -18,13 +17,10 @@ def initialize(filename: str): Logger._logger.propagate = False # Define the logging format - log_format = ("%(asctime)s [%(levelname)s] [%(filename)s:%(lineno)d] " - "[%(funcName)s] - %(message)s") + log_format = ("%(asctime)s [%(levelname)s] [%(filename)s:%(lineno)d] [%(funcName)s] - %(message)s") # Create a rotating file handler to manage log file sizes and backups - Logger._file_handler = RotatingFileHandler( - filename, maxBytes=5*1024*1024, backupCount=5 - ) # 5MB per file + Logger._file_handler = RotatingFileHandler(filename, maxBytes=5*1024*1024, backupCount=5) # 5MB per file Logger._file_handler.setFormatter(logging.Formatter(log_format)) Logger._file_handler.setLevel(logging.DEBUG) diff --git a/libs/package_manager.py b/libs/package_manager.py index 49ed119..b131f08 100644 --- a/libs/package_manager.py +++ b/libs/package_manager.py @@ -3,18 +3,17 @@ import logging import requests import stdlib_list +from libs.logger import Logger + class PackageManager: + logger = None + def __init__(self): self.pip_command = "pip" self.pip3_command = "pip3" self.npm_command = "npm" - self.logger = logging.getLogger(__name__) - handler = logging.StreamHandler() - formatter = logging.Formatter('%(asctime)s [%(levelname)s] [%(name)s:%(lineno)d] [%(funcName)s] - %(message)s') - handler.setFormatter(formatter) - self.logger.addHandler(handler) - self.logger.setLevel(logging.INFO) + self.logger = Logger.initialize("logs/interpreter.log") def install_package(self, package_name, language): if language == "python": @@ -23,7 +22,7 @@ def install_package(self, package_name, language): self.logger.error(exception) raise exception - if not self._is_package_installed(package_name,"pip"): + if not self._is_package_installed(package_name, "pip"): try: # Try to install the package using pip self._install_package_with_pip(package_name) @@ -58,7 +57,7 @@ def install_package(self, package_name, language): self.logger.error(exception) raise exception - def extract_package_name(self,error,language): + def extract_package_name(self, error,language): if language == "python": return self._extract_python_package_name(error) elif language == "javascript": @@ -76,7 +75,7 @@ def get_system_modules(self): except Exception as exception: raise ValueError("An error occurred while getting module names") from exception - def _install_package_with_pip(self, package_name): + def _install_package_with_pip(self, package_name): try: subprocess.check_call([self.pip_command, "install", package_name]) self.logger.info(f"Successfully installed package with pip: {package_name}") @@ -84,7 +83,7 @@ def _install_package_with_pip(self, package_name): self.logger.error(f"Failed to install package with pip: {package_name}") raise exception - def _install_package_with_pip3(self, package_name): + def _install_package_with_pip3(self, package_name): try: subprocess.check_call([self.pip3_command, "install", package_name]) self.logger.info(f"Successfully installed package with pip3: {package_name}") @@ -92,7 +91,7 @@ def _install_package_with_pip3(self, package_name): self.logger.error(f"Failed to install package with pip3: {package_name}") raise exception - def _install_package_with_npm(self, package_name): + def _install_package_with_npm(self, package_name): try: subprocess.check_call([self.npm_command, "install", package_name]) self.logger.info(f"Successfully installed package with npm: {package_name}") @@ -100,7 +99,7 @@ def _install_package_with_npm(self, package_name): self.logger.error(f"Failed to install package with npm: {package_name}") raise exception - def _is_package_installed(self, package_name, package_manager): + def _is_package_installed(self, package_name, package_manager): if package_manager == "pip": try: subprocess.check_call([self.pip_command, "show", package_name]) @@ -126,17 +125,8 @@ def _is_package_installed(self, package_name, package_manager): exception = ValueError("Invalid package manager selected.") self.logger.error(exception) raise exception - - def _install_package_with_npm(self, package_name): - try: - subprocess.check_call([self.npm_command, "install", package_name]) - self.logger.info(f"Successfully installed package with npm: {package_name}") - except subprocess.CalledProcessError as exception: - self.logger.error(f"Failed to install package with npm: {package_name}") - raise exception - - - def _extract_python_package_name(self, error_message): + + def _extract_python_package_name(self, error_message): # Regular expression pattern to match the error message pattern = r"ModuleNotFoundError: No module named '(\w+)'|ModuleNotFoundError: '(\w+)'" match = re.search(pattern, error_message) @@ -150,7 +140,7 @@ def _extract_python_package_name(self, error_message): self.logger.error(exception) raise exception - def _extract_javascript_package_name(self,error_message): + def _extract_javascript_package_name(self, error_message): try: lines = error_message.split('\n') for line in lines: @@ -162,32 +152,22 @@ def _extract_javascript_package_name(self,error_message): self.logger.error(f"Failed to extract package name from error message: {exception}") raise exception - def _check_package_exists_pip(self,package_name): - import requests - from bs4 import BeautifulSoup - + def _check_package_exists_pip(self, package_name): try: - # Send a GET request to the PyPI search page - response = requests.get(f"https://pypi.org/search/?q={package_name}") - response.raise_for_status() - - # Parse the HTML content of the page - soup = BeautifulSoup(response.text, 'html.parser') - - # Search for the package name in the parsed HTML - search_results = soup.find_all('span', class_='package-snippet__name') - for result in search_results: - if result.text.strip() == package_name: - return True - - # If the package name was not found in the search results, log an error and raise an exception - exception = ValueError(f"Package {package_name} does not exist on PyPI") - self.logger.error(exception) - raise exception - except requests.exceptions.RequestException as exception: - raise exception + api_url = f"https://pypi.org/pypi/{package_name}/json" + self.logger.info("API Url is {}".format(api_url)) + response = requests.get(api_url) + if response.status_code == 200: + return True + else: + error_message = f"Package {package_name} does not exist on PyPI" + self.logger.error(error_message) + raise ValueError(error_message) + except requests.exceptions.RequestException as request_exception: + self.logger.error(f"Request failed: {request_exception}") + raise request_exception - def _check_package_exists_npm(self, package_name): + def _check_package_exists_npm(self, package_name): try: response = requests.get(f"https://www.npmjs.com/package/{package_name}") if response.status_code == 200: diff --git a/requirements.txt b/requirements.txt index 0ac4a6e..e1d2752 100644 --- a/requirements.txt +++ b/requirements.txt @@ -15,6 +15,3 @@ plotly # Libraries for standard libries stdlib_list - -# Beatiful Soup library -beautifulsoup4 \ No newline at end of file