From 4589d6fe9d976b491a86bdf0aca1d9972077b900 Mon Sep 17 00:00:00 2001 From: Eduardo Chiarotti Date: Fri, 25 Oct 2024 10:33:21 -0300 Subject: [PATCH] feat: add tomli so we can support 3.10 (#1506) * feat: add tomli so we can support 3.10 * feat: add validation for poetry data --- pyproject.toml | 1 + src/crewai/cli/run_crew.py | 13 ++++-------- src/crewai/cli/update_crew.py | 40 +++++++++++++++++------------------ src/crewai/cli/utils.py | 8 +++++++ uv.lock | 2 ++ 5 files changed, 35 insertions(+), 29 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 85a296867..ef8181cbc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,6 +28,7 @@ dependencies = [ "uv>=0.4.25", "tomli-w>=1.1.0", "chromadb>=0.4.24", + "tomli>=2.0.2", ] [project.urls] diff --git a/src/crewai/cli/run_crew.py b/src/crewai/cli/run_crew.py index 829d8ed95..20d6aed01 100644 --- a/src/crewai/cli/run_crew.py +++ b/src/crewai/cli/run_crew.py @@ -1,10 +1,9 @@ import subprocess import click -import tomllib from packaging import version -from crewai.cli.utils import get_crewai_version +from crewai.cli.utils import get_crewai_version, read_toml def run_crew() -> None: @@ -15,10 +14,9 @@ def run_crew() -> None: crewai_version = get_crewai_version() min_required_version = "0.71.0" - with open("pyproject.toml", "rb") as f: - data = tomllib.load(f) + pyproject_data = read_toml() - if data.get("tool", {}).get("poetry") and ( + if pyproject_data.get("tool", {}).get("poetry") and ( version.parse(crewai_version) < version.parse(min_required_version) ): click.secho( @@ -35,10 +33,7 @@ def run_crew() -> None: click.echo(f"An error occurred while running the crew: {e}", err=True) click.echo(e.output, err=True, nl=True) - with open("pyproject.toml", "rb") as f: - data = tomllib.load(f) - - if data.get("tool", {}).get("poetry"): + if pyproject_data.get("tool", {}).get("poetry"): click.secho( "It's possible that you are using an old version of crewAI that uses poetry, please run `crewai update` to update your pyproject.toml to use uv.", fg="yellow", diff --git a/src/crewai/cli/update_crew.py b/src/crewai/cli/update_crew.py index d38e11a25..e7ed69aa1 100644 --- a/src/crewai/cli/update_crew.py +++ b/src/crewai/cli/update_crew.py @@ -2,7 +2,8 @@ import os import shutil import tomli_w -import tomllib + +from crewai.cli.utils import read_toml def update_crew() -> None: @@ -18,10 +19,9 @@ def migrate_pyproject(input_file, output_file): And it will be used to migrate the pyproject.toml to the new format when uv is used. When the time comes that uv supports the new format, this function will be deprecated. """ - + poetry_data = {} # Read the input pyproject.toml - with open(input_file, "rb") as f: - pyproject = tomllib.load(f) + pyproject_data = read_toml() # Initialize the new project structure new_pyproject = { @@ -30,30 +30,30 @@ def migrate_pyproject(input_file, output_file): } # Migrate project metadata - if "tool" in pyproject and "poetry" in pyproject["tool"]: - poetry = pyproject["tool"]["poetry"] - new_pyproject["project"]["name"] = poetry.get("name") - new_pyproject["project"]["version"] = poetry.get("version") - new_pyproject["project"]["description"] = poetry.get("description") + if "tool" in pyproject_data and "poetry" in pyproject_data["tool"]: + poetry_data = pyproject_data["tool"]["poetry"] + new_pyproject["project"]["name"] = poetry_data.get("name") + new_pyproject["project"]["version"] = poetry_data.get("version") + new_pyproject["project"]["description"] = poetry_data.get("description") new_pyproject["project"]["authors"] = [ { "name": author.split("<")[0].strip(), "email": author.split("<")[1].strip(">").strip(), } - for author in poetry.get("authors", []) + for author in poetry_data.get("authors", []) ] - new_pyproject["project"]["requires-python"] = poetry.get("python") + new_pyproject["project"]["requires-python"] = poetry_data.get("python") else: # If it's already in the new format, just copy the project section - new_pyproject["project"] = pyproject.get("project", {}) + new_pyproject["project"] = pyproject_data.get("project", {}) # Migrate or copy dependencies if "dependencies" in new_pyproject["project"]: # If dependencies are already in the new format, keep them as is pass - elif "dependencies" in poetry: + elif poetry_data and "dependencies" in poetry_data: new_pyproject["project"]["dependencies"] = [] - for dep, version in poetry["dependencies"].items(): + for dep, version in poetry_data["dependencies"].items(): if isinstance(version, dict): # Handle extras extras = ",".join(version.get("extras", [])) new_dep = f"{dep}[{extras}]" @@ -67,10 +67,10 @@ def migrate_pyproject(input_file, output_file): new_pyproject["project"]["dependencies"].append(new_dep) # Migrate or copy scripts - if "scripts" in poetry: - new_pyproject["project"]["scripts"] = poetry["scripts"] - elif "scripts" in pyproject.get("project", {}): - new_pyproject["project"]["scripts"] = pyproject["project"]["scripts"] + if poetry_data and "scripts" in poetry_data: + new_pyproject["project"]["scripts"] = poetry_data["scripts"] + elif pyproject_data.get("project", {}) and "scripts" in pyproject_data["project"]: + new_pyproject["project"]["scripts"] = pyproject_data["project"]["scripts"] else: new_pyproject["project"]["scripts"] = {} @@ -87,8 +87,8 @@ def migrate_pyproject(input_file, output_file): new_pyproject["project"]["scripts"]["run_crew"] = f"{module_name}.main:run" # Migrate optional dependencies - if "extras" in poetry: - new_pyproject["project"]["optional-dependencies"] = poetry["extras"] + if poetry_data and "extras" in poetry_data: + new_pyproject["project"]["optional-dependencies"] = poetry_data["extras"] # Backup the old pyproject.toml backup_file = "pyproject-old.toml" diff --git a/src/crewai/cli/utils.py b/src/crewai/cli/utils.py index c32113faa..25da9e31a 100644 --- a/src/crewai/cli/utils.py +++ b/src/crewai/cli/utils.py @@ -6,6 +6,7 @@ from functools import reduce from typing import Any, Dict, List import click +import tomli from rich.console import Console from crewai.cli.authentication.utils import TokenManager @@ -54,6 +55,13 @@ def simple_toml_parser(content): return result +def read_toml(file_path: str = "pyproject.toml"): + """Read the content of a TOML file and return it as a dictionary.""" + with open(file_path, "rb") as f: + toml_dict = tomli.load(f) + return toml_dict + + def parse_toml(content): if sys.version_info >= (3, 11): return tomllib.loads(content) diff --git a/uv.lock b/uv.lock index f242185db..df2572402 100644 --- a/uv.lock +++ b/uv.lock @@ -625,6 +625,7 @@ dependencies = [ { name = "python-dotenv" }, { name = "pyvis" }, { name = "regex" }, + { name = "tomli" }, { name = "tomli-w" }, { name = "uv" }, ] @@ -679,6 +680,7 @@ requires-dist = [ { name = "python-dotenv", specifier = ">=1.0.0" }, { name = "pyvis", specifier = ">=0.3.2" }, { name = "regex", specifier = ">=2024.9.11" }, + { name = "tomli", specifier = ">=2.0.2" }, { name = "tomli-w", specifier = ">=1.1.0" }, { name = "uv", specifier = ">=0.4.25" }, ]