From fa937bf3a79c8bf4f9f3fba45c86eebc0cf98330 Mon Sep 17 00:00:00 2001 From: Thiago Moretto Date: Thu, 29 Aug 2024 10:22:54 -0300 Subject: [PATCH] Add Python 3.10 support to CLI --- src/crewai/cli/deploy/utils.py | 55 ++++++++++++++++++++---- tests/cli/deploy/test_deploy_main.py | 62 +++++++++++++++++++++++++++- 2 files changed, 107 insertions(+), 10 deletions(-) diff --git a/src/crewai/cli/deploy/utils.py b/src/crewai/cli/deploy/utils.py index 8fe1851df..5a701e675 100644 --- a/src/crewai/cli/deploy/utils.py +++ b/src/crewai/cli/deploy/utils.py @@ -1,11 +1,40 @@ +import sys import re import subprocess -import tomllib - from ..authentication.utils import TokenManager +if sys.version_info >= (3, 11): + import tomllib + + +def simple_toml_parser(content): + result = {} + current_section = result + for line in content.split('\n'): + line = line.strip() + if line.startswith('[') and line.endswith(']'): + # New section + section = line[1:-1].split('.') + current_section = result + for key in section: + current_section = current_section.setdefault(key, {}) + elif '=' in line: + key, value = line.split('=', 1) + key = key.strip() + value = value.strip().strip('"') + current_section[key] = value + return result + + +def parse_toml(content): + if sys.version_info >= (3, 11): + return tomllib.loads(content) + else: + return simple_toml_parser(content) + + def get_git_remote_url() -> str: """Get the Git repository's remote URL.""" try: @@ -37,7 +66,7 @@ def get_project_name(pyproject_path: str = "pyproject.toml"): try: # Read the pyproject.toml file with open(pyproject_path, "rb") as f: - pyproject_content = tomllib.load(f) + pyproject_content = parse_toml(f.read()) # Extract the project name project_name = pyproject_content["tool"]["poetry"]["name"] @@ -51,8 +80,12 @@ def get_project_name(pyproject_path: str = "pyproject.toml"): print(f"Error: {pyproject_path} not found.") except KeyError: print(f"Error: {pyproject_path} is not a valid pyproject.toml file.") - except tomllib.TOMLDecodeError: - print(f"Error: {pyproject_path} is not a valid TOML file.") + except tomllib.TOMLDecodeError if sys.version_info >= (3, 11) else Exception as e: + print( + f"Error: {pyproject_path} is not a valid TOML file." + if sys.version_info >= (3, 11) + else f"Error reading the pyproject.toml file: {e}" + ) except Exception as e: print(f"Error reading the pyproject.toml file: {e}") @@ -63,8 +96,8 @@ def get_crewai_version(pyproject_path: str = "pyproject.toml") -> str: """Get the version number of crewai from the pyproject.toml file.""" try: # Read the pyproject.toml file - with open("pyproject.toml", "rb") as f: - pyproject_content = tomllib.load(f) + with open(pyproject_path, "rb") as f: + pyproject_content = parse_toml(f.read()) # Extract the version number of crewai crewai_version = pyproject_content["tool"]["poetry"]["dependencies"]["crewai"][ @@ -77,8 +110,12 @@ def get_crewai_version(pyproject_path: str = "pyproject.toml") -> str: print(f"Error: {pyproject_path} not found.") except KeyError: print(f"Error: {pyproject_path} is not a valid pyproject.toml file.") - except tomllib.TOMLDecodeError: - print(f"Error: {pyproject_path} is not a valid TOML file.") + except tomllib.TOMLDecodeError if sys.version_info >= (3, 11) else Exception as e: + print( + f"Error: {pyproject_path} is not a valid TOML file." + if sys.version_info >= (3, 11) + else f"Error reading the pyproject.toml file: {e}" + ) except Exception as e: print(f"Error reading the pyproject.toml file: {e}") diff --git a/tests/cli/deploy/test_deploy_main.py b/tests/cli/deploy/test_deploy_main.py index f4b08d877..52171459a 100644 --- a/tests/cli/deploy/test_deploy_main.py +++ b/tests/cli/deploy/test_deploy_main.py @@ -1,9 +1,10 @@ import unittest from io import StringIO from unittest.mock import MagicMock, patch +import sys from crewai.cli.deploy.main import DeployCommand - +from crewai.cli.deploy.utils import parse_toml class TestDeployCommand(unittest.TestCase): @patch("crewai.cli.deploy.main.get_auth_token") @@ -151,3 +152,62 @@ class TestDeployCommand(unittest.TestCase): self.assertIn( "Crew 'test_project' removed successfully", fake_out.getvalue() ) + + @patch('crewai.cli.deploy.utils.sys.version_info', (3, 10)) + def test_parse_toml_python_310(self): + toml_content = """ + [tool.poetry] + name = "test_project" + version = "0.1.0" + + [tool.poetry.dependencies] + python = "^3.10" + crewai = "^0.1.0" + """ + parsed = parse_toml(toml_content) + self.assertEqual(parsed['tool']['poetry']['name'], 'test_project') + self.assertEqual(parsed['tool']['poetry']['dependencies']['crewai'], '^0.1.0') + + @unittest.skipIf(sys.version_info < (3, 11), "Requires Python 3.11+") + def test_parse_toml_python_311_plus(self): + toml_content = """ + [tool.poetry] + name = "test_project" + version = "0.1.0" + + [tool.poetry.dependencies] + python = "^3.11" + crewai = "^0.1.0" + """ + parsed = parse_toml(toml_content) + self.assertEqual(parsed['tool']['poetry']['name'], 'test_project') + self.assertEqual(parsed['tool']['poetry']['dependencies']['crewai'], '^0.1.0') + + @patch('builtins.open', new_callable=unittest.mock.mock_open, read_data=""" + [tool.poetry] + name = "test_project" + version = "0.1.0" + + [tool.poetry.dependencies] + python = "^3.10" + crewai = "^0.1.0" + """) + def test_get_project_name_python_310(self, mock_open): + from crewai.cli.deploy.utils import get_project_name + project_name = get_project_name() + self.assertEqual(project_name, 'test_project') + + @unittest.skipIf(sys.version_info < (3, 11), "Requires Python 3.11+") + @patch('builtins.open', new_callable=unittest.mock.mock_open, read_data=""" + [tool.poetry] + name = "test_project" + version = "0.1.0" + + [tool.poetry.dependencies] + python = "^3.11" + crewai = "^0.1.0" + """) + def test_get_project_name_python_311_plus(self, mock_open): + from crewai.cli.deploy.utils import get_project_name + project_name = get_project_name() + self.assertEqual(project_name, 'test_project')