diff --git a/README.md b/README.md index 2dd3237c8..21ab34390 100644 --- a/README.md +++ b/README.md @@ -46,13 +46,7 @@ To get started with CrewAI, follow these simple steps: Ensure you have Python >=3.10 <=3.13 installed on your system. CrewAI uses [UV](https://docs.astral.sh/uv/) for dependency management and package handling, offering a seamless setup and execution experience. -First, if you haven't already, install uv: - -```bash -pip install uv -``` - -Then, install CrewAI: +First, install CrewAI: ```shell pip install crewai @@ -243,7 +237,7 @@ Lock the dependencies and install them by using the CLI command but first, navig ```shell cd my_project -crewai install +crewai install (Optional) ``` To run your crew, execute the following command in the root of your project: diff --git a/src/crewai/cli/templates/tool/README.md b/src/crewai/cli/templates/tool/README.md index 65cb0ffb2..43b1d721a 100644 --- a/src/crewai/cli/templates/tool/README.md +++ b/src/crewai/cli/templates/tool/README.md @@ -6,13 +6,13 @@ custom tools to power up your crews. ## Installing Ensure you have Python >=3.10 <=3.13 installed on your system. This project -uses [Poetry](https://python-poetry.org/) for dependency management and package +uses [UV](https://docs.astral.sh/uv/) for dependency management and package handling, offering a seamless setup and execution experience. -First, if you haven't already, install Poetry: +First, if you haven't already, install `uv`: ```bash -pip install poetry +pip install uv ``` Next, navigate to your project directory and install the dependencies with: diff --git a/src/crewai/cli/tools/main.py b/src/crewai/cli/tools/main.py index 4897dc761..497a1bc4d 100644 --- a/src/crewai/cli/tools/main.py +++ b/src/crewai/cli/tools/main.py @@ -93,7 +93,7 @@ class ToolCommand(BaseCommand, PlusAPIMixin): ) if not tarball_filename: console.print( - "Project build failed. Please ensure that the command `poetry build -f sdist` completes successfully.", + "Project build failed. Please ensure that the command `uv build -f sdist` completes successfully.", style="bold red", ) raise SystemExit @@ -151,15 +151,13 @@ class ToolCommand(BaseCommand, PlusAPIMixin): login_response_json = login_response.json() for repository in login_response_json["repositories"]: - self._add_repository_to_poetry( - repository, login_response_json["credential"] - ) + self._add_repository_to_uv(repository, login_response_json["credential"]) console.print( "Succesfully authenticated to the tool repository.", style="bold green" ) - def _add_repository_to_poetry(self, repository, credentials): + def _add_repository_to_uv(self, repository, credentials): repository_handle = f"crewai-{repository['handle']}" add_repository_command = [ diff --git a/src/crewai/cli/utils.py b/src/crewai/cli/utils.py index 8d03841eb..0d40ea60c 100644 --- a/src/crewai/cli/utils.py +++ b/src/crewai/cli/utils.py @@ -56,17 +56,14 @@ def simple_toml_parser(content): def parse_toml(content): if sys.version_info >= (3, 11): return tomllib.loads(content) - else: - return simple_toml_parser(content) + return simple_toml_parser(content) def get_project_name( pyproject_path: str = "pyproject.toml", require: bool = False ) -> str | None: """Get the project name from the pyproject.toml file.""" - return _get_project_attribute( - pyproject_path, ["tool", "poetry", "name"], require=require - ) + return _get_project_attribute(pyproject_path, ["project", "name"], require=require) def get_project_version( @@ -74,7 +71,7 @@ def get_project_version( ) -> str | None: """Get the project version from the pyproject.toml file.""" return _get_project_attribute( - pyproject_path, ["tool", "poetry", "version"], require=require + pyproject_path, ["project", "version"], require=require ) @@ -83,7 +80,7 @@ def get_project_description( ) -> str | None: """Get the project description from the pyproject.toml file.""" return _get_project_attribute( - pyproject_path, ["tool", "poetry", "description"], require=require + pyproject_path, ["project", "description"], require=require ) @@ -98,8 +95,7 @@ def _get_project_attribute( pyproject_content = parse_toml(f.read()) dependencies = ( - _get_nested_value(pyproject_content, ["tool", "poetry", "dependencies"]) - or {} + _get_nested_value(pyproject_content, ["project", "dependencies"]) or {} ) if "crewai" not in dependencies: raise Exception("crewai is not in the dependencies.") diff --git a/tests/cli/deploy/test_deploy_main.py b/tests/cli/deploy/test_deploy_main.py index b30883be3..0d30b4af7 100644 --- a/tests/cli/deploy/test_deploy_main.py +++ b/tests/cli/deploy/test_deploy_main.py @@ -1,12 +1,12 @@ -import pytest -import requests import sys import unittest - from io import StringIO -from requests.exceptions import JSONDecodeError from unittest.mock import MagicMock, Mock, patch +import pytest +import requests +from requests.exceptions import JSONDecodeError + from crewai.cli.deploy.main import DeployCommand from crewai.cli.utils import parse_toml diff --git a/tests/cli/test_crew_test.py b/tests/cli/test_crew_test.py index 578e413bc..83bcd55cc 100644 --- a/tests/cli/test_crew_test.py +++ b/tests/cli/test_crew_test.py @@ -18,12 +18,12 @@ from crewai.cli import evaluate_crew def test_crew_success(mock_subprocess_run, n_iterations, model): """Test the crew function for successful execution.""" mock_subprocess_run.return_value = subprocess.CompletedProcess( - args=f"poetry run test {n_iterations} {model}", returncode=0 + args=f"uv run test {n_iterations} {model}", returncode=0 ) result = evaluate_crew.evaluate_crew(n_iterations, model) mock_subprocess_run.assert_called_once_with( - ["poetry", "run", "test", str(n_iterations), model], + ["uv", "run", "test", str(n_iterations), model], capture_output=False, text=True, check=True, @@ -55,14 +55,14 @@ def test_test_crew_called_process_error(mock_subprocess_run, click): n_iterations = 5 mock_subprocess_run.side_effect = subprocess.CalledProcessError( returncode=1, - cmd=["poetry", "run", "test", str(n_iterations), "gpt-4o"], + cmd=["uv", "run", "test", str(n_iterations), "gpt-4o"], output="Error", stderr="Some error occurred", ) evaluate_crew.evaluate_crew(n_iterations, "gpt-4o") mock_subprocess_run.assert_called_once_with( - ["poetry", "run", "test", "5", "gpt-4o"], + ["uv", "run", "test", "5", "gpt-4o"], capture_output=False, text=True, check=True, @@ -70,7 +70,7 @@ def test_test_crew_called_process_error(mock_subprocess_run, click): click.echo.assert_has_calls( [ mock.call.echo( - "An error occurred while testing the crew: Command '['poetry', 'run', 'test', '5', 'gpt-4o']' returned non-zero exit status 1.", + "An error occurred while testing the crew: Command '['uv', 'run', 'test', '5', 'gpt-4o']' returned non-zero exit status 1.", err=True, ), mock.call.echo("Error", err=True), @@ -87,7 +87,7 @@ def test_test_crew_unexpected_exception(mock_subprocess_run, click): evaluate_crew.evaluate_crew(n_iterations, "gpt-4o") mock_subprocess_run.assert_called_once_with( - ["poetry", "run", "test", "5", "gpt-4o"], + ["uv", "run", "test", "5", "gpt-4o"], capture_output=False, text=True, check=True, diff --git a/tests/cli/tools/test_main.py b/tests/cli/tools/test_main.py index 354d98865..b4a99ea06 100644 --- a/tests/cli/tools/test_main.py +++ b/tests/cli/tools/test_main.py @@ -1,13 +1,15 @@ +import os import tempfile import unittest import unittest.mock -import os from contextlib import contextmanager +from io import StringIO +from unittest.mock import MagicMock, patch from pytest import raises + from crewai.cli.tools.main import ToolCommand -from io import StringIO -from unittest.mock import patch, MagicMock + @contextmanager def in_temp_dir(): @@ -19,6 +21,7 @@ def in_temp_dir(): finally: os.chdir(original_dir) + @patch("crewai.cli.tools.main.subprocess.run") def test_create_success(mock_subprocess): with in_temp_dir(): @@ -38,9 +41,7 @@ def test_create_success(mock_subprocess): ) assert os.path.isfile(os.path.join("test_tool", "src", "test_tool", "tool.py")) - with open( - os.path.join("test_tool", "src", "test_tool", "tool.py"), "r" - ) as f: + with open(os.path.join("test_tool", "src", "test_tool", "tool.py"), "r") as f: content = f.read() assert "class TestTool" in content @@ -49,6 +50,7 @@ def test_create_success(mock_subprocess): assert "Creating custom tool test_tool..." in output + @patch("crewai.cli.tools.main.subprocess.run") @patch("crewai.cli.plus_api.PlusAPI.get_tool") def test_install_success(mock_get, mock_subprocess_run): @@ -69,7 +71,7 @@ def test_install_success(mock_get, mock_subprocess_run): mock_get.assert_called_once_with("sample-tool") mock_subprocess_run.assert_any_call( - ["poetry", "add", "--source", "crewai-sample-repo", "sample-tool"], + ["uv", "add", "--source", "crewai-sample-repo", "sample-tool"], capture_output=False, text=True, check=True, @@ -77,6 +79,7 @@ def test_install_success(mock_get, mock_subprocess_run): assert "Succesfully installed sample-tool" in output + @patch("crewai.cli.plus_api.PlusAPI.get_tool") def test_install_tool_not_found(mock_get): mock_get_response = MagicMock() @@ -95,6 +98,7 @@ def test_install_tool_not_found(mock_get): mock_get.assert_called_once_with("non-existent-tool") assert "No tool found with this name" in output + @patch("crewai.cli.plus_api.PlusAPI.get_tool") def test_install_api_error(mock_get): mock_get_response = MagicMock() @@ -113,15 +117,16 @@ def test_install_api_error(mock_get): mock_get.assert_called_once_with("error-tool") assert "Failed to get tool details" in output + @patch("crewai.cli.tools.main.git.Repository.is_synced", return_value=False) def test_publish_when_not_in_sync(mock_is_synced): - with patch("sys.stdout", new=StringIO()) as fake_out, \ - raises(SystemExit): + with patch("sys.stdout", new=StringIO()) as fake_out, raises(SystemExit): tool_command = ToolCommand() tool_command.publish(is_public=True) assert "Local changes need to be resolved before publishing" in fake_out.getvalue() + @patch("crewai.cli.tools.main.get_project_name", return_value="sample-tool") @patch("crewai.cli.tools.main.get_project_version", return_value="1.0.0") @patch("crewai.cli.tools.main.get_project_description", return_value="A sample tool") @@ -156,7 +161,7 @@ def test_publish_when_not_in_sync_and_force( mock_get_project_version.assert_called_with(require=True) mock_get_project_description.assert_called_with(require=False) mock_subprocess_run.assert_called_with( - ["poetry", "build", "-f", "sdist", "--output", unittest.mock.ANY], + ["uv", "build", "-f", "sdist", "--output", unittest.mock.ANY], check=True, capture_output=False, ) @@ -169,6 +174,7 @@ def test_publish_when_not_in_sync_and_force( encoded_file=unittest.mock.ANY, ) + @patch("crewai.cli.tools.main.get_project_name", return_value="sample-tool") @patch("crewai.cli.tools.main.get_project_version", return_value="1.0.0") @patch("crewai.cli.tools.main.get_project_description", return_value="A sample tool") @@ -203,7 +209,7 @@ def test_publish_success( mock_get_project_version.assert_called_with(require=True) mock_get_project_description.assert_called_with(require=False) mock_subprocess_run.assert_called_with( - ["poetry", "build", "-f", "sdist", "--output", unittest.mock.ANY], + ["uv", "build", "-f", "sdist", "--output", unittest.mock.ANY], check=True, capture_output=False, ) @@ -216,6 +222,7 @@ def test_publish_success( encoded_file=unittest.mock.ANY, ) + @patch("crewai.cli.tools.main.get_project_name", return_value="sample-tool") @patch("crewai.cli.tools.main.get_project_version", return_value="1.0.0") @patch("crewai.cli.tools.main.get_project_description", return_value="A sample tool") @@ -254,6 +261,7 @@ def test_publish_failure( assert "Failed to complete operation" in output assert "Name is already taken" in output + @patch("crewai.cli.tools.main.get_project_name", return_value="sample-tool") @patch("crewai.cli.tools.main.get_project_version", return_value="1.0.0") @patch("crewai.cli.tools.main.get_project_description", return_value="A sample tool") @@ -292,6 +300,7 @@ def test_publish_api_error( mock_publish.assert_called_once() assert "Request to Enterprise API failed" in output + @patch("crewai.cli.plus_api.PlusAPI.login_to_tool_repository") @patch("crewai.cli.tools.main.subprocess.run") def test_login_success(mock_subprocess_run, mock_login): @@ -319,7 +328,7 @@ def test_login_success(mock_subprocess_run, mock_login): mock_login.assert_called_once() mock_subprocess_run.assert_any_call( [ - "poetry", + "uv", "source", "add", "--priority=explicit", @@ -331,7 +340,7 @@ def test_login_success(mock_subprocess_run, mock_login): ) mock_subprocess_run.assert_any_call( [ - "poetry", + "uv", "config", "http-basic.crewai-tools", "user", diff --git a/tests/cli/train_crew_test.py b/tests/cli/train_crew_test.py index 036dd7c2f..f1694472f 100644 --- a/tests/cli/train_crew_test.py +++ b/tests/cli/train_crew_test.py @@ -8,7 +8,7 @@ from crewai.cli.train_crew import train_crew def test_train_crew_positive_iterations(mock_subprocess_run): n_iterations = 5 mock_subprocess_run.return_value = subprocess.CompletedProcess( - args=["poetry", "run", "train", str(n_iterations)], + args=["uv", "run", "train", str(n_iterations)], returncode=0, stdout="Success", stderr="", @@ -17,7 +17,7 @@ def test_train_crew_positive_iterations(mock_subprocess_run): train_crew(n_iterations, "trained_agents_data.pkl") mock_subprocess_run.assert_called_once_with( - ["poetry", "run", "train", str(n_iterations), "trained_agents_data.pkl"], + ["uv", "run", "train", str(n_iterations), "trained_agents_data.pkl"], capture_output=False, text=True, check=True, @@ -48,14 +48,14 @@ def test_train_crew_called_process_error(mock_subprocess_run, click): n_iterations = 5 mock_subprocess_run.side_effect = subprocess.CalledProcessError( returncode=1, - cmd=["poetry", "run", "train", str(n_iterations)], + cmd=["uv", "run", "train", str(n_iterations)], output="Error", stderr="Some error occurred", ) train_crew(n_iterations, "trained_agents_data.pkl") mock_subprocess_run.assert_called_once_with( - ["poetry", "run", "train", str(n_iterations), "trained_agents_data.pkl"], + ["uv", "run", "train", str(n_iterations), "trained_agents_data.pkl"], capture_output=False, text=True, check=True, @@ -63,7 +63,7 @@ def test_train_crew_called_process_error(mock_subprocess_run, click): click.echo.assert_has_calls( [ mock.call.echo( - "An error occurred while training the crew: Command '['poetry', 'run', 'train', '5']' returned non-zero exit status 1.", + "An error occurred while training the crew: Command '['uv', 'run', 'train', '5']' returned non-zero exit status 1.", err=True, ), mock.call.echo("Error", err=True), @@ -79,7 +79,7 @@ def test_train_crew_unexpected_exception(mock_subprocess_run, click): train_crew(n_iterations, "trained_agents_data.pkl") mock_subprocess_run.assert_called_once_with( - ["poetry", "run", "train", str(n_iterations), "trained_agents_data.pkl"], + ["uv", "run", "train", str(n_iterations), "trained_agents_data.pkl"], capture_output=False, text=True, check=True, diff --git a/uv.lock b/uv.lock index dfa2d2e6c..e1dfa5eac 100644 --- a/uv.lock +++ b/uv.lock @@ -1,7 +1,8 @@ version = 1 requires-python = ">=3.10, <=3.13" resolution-markers = [ - "python_full_version < '3.11'", + "python_full_version < '3.11' and platform_python_implementation == 'PyPy'", + "python_full_version < '3.11' and platform_python_implementation != 'PyPy'", "python_full_version == '3.11.*'", "python_full_version >= '3.12' and python_full_version < '3.12.4'", "python_full_version >= '3.12.4' and python_full_version < '3.13'", @@ -227,19 +228,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e4/0e/38cb7b781371e79e9c697fb78f3ccd18fda8bd547d0a2e76e616561a3792/auth0_python-4.7.2-py3-none-any.whl", hash = "sha256:df2224f9b1e170b3aa12d8bc7ff02eadb7cc229307a09ec6b8a55fd1e0e05dc8", size = 131834 }, ] -[[package]] -name = "autoflake" -version = "2.3.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pyflakes" }, - { name = "tomli", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/2a/cb/486f912d6171bc5748c311a2984a301f4e2d054833a1da78485866c71522/autoflake-2.3.1.tar.gz", hash = "sha256:c98b75dc5b0a86459c4f01a1d32ac7eb4338ec4317a4469515ff1e687ecd909e", size = 27642 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a2/ee/3fd29bf416eb4f1c5579cf12bf393ae954099258abd7bde03c4f9716ef6b/autoflake-2.3.1-py3-none-any.whl", hash = "sha256:3ae7495db9084b7b32818b4140e6dc4fc280b712fb414f5b8fe57b0a8e85a840", size = 32483 }, -] - [[package]] name = "babel" version = "2.16.0" @@ -664,9 +652,16 @@ dependencies = [ { name = "uv" }, ] +[package.optional-dependencies] +agentops = [ + { name = "agentops" }, +] +tools = [ + { name = "crewai-tools" }, +] + [package.dev-dependencies] dev = [ - { name = "autoflake" }, { name = "cairosvg" }, { name = "crewai-tools" }, { name = "mkdocs" }, @@ -677,15 +672,23 @@ dev = [ { name = "mypy" }, { name = "pillow" }, { name = "pre-commit" }, + { name = "pytest" }, + { name = "pytest-asyncio" }, + { name = "pytest-subprocess" }, + { name = "pytest-vcr" }, + { name = "python-dotenv" }, + { name = "ruff" }, ] [package.metadata] requires-dist = [ { name = "agentops", specifier = ">=0.3.0" }, + { name = "agentops", marker = "extra == 'agentops'", specifier = ">=0.3.0" }, { name = "appdirs", specifier = ">=1.4.4" }, { name = "auth0-python", specifier = ">=4.7.1" }, { name = "click", specifier = ">=8.1.7" }, { name = "crewai-tools", specifier = ">=0.12.1" }, + { name = "crewai-tools", marker = "extra == 'tools'", specifier = ">=0.12.1" }, { name = "embedchain", specifier = ">=0.1.114" }, { name = "instructor", specifier = ">=1.3.3" }, { name = "json-repair", specifier = ">=0.25.2" }, @@ -705,7 +708,6 @@ requires-dist = [ [package.metadata.requires-dev] dev = [ - { name = "autoflake", specifier = ">=2.2.1" }, { name = "cairosvg", specifier = ">=2.7.1" }, { name = "crewai-tools", specifier = ">=0.12.1" }, { name = "mkdocs", specifier = ">=1.4.3" }, @@ -716,6 +718,12 @@ dev = [ { name = "mypy", specifier = ">=1.10.0" }, { name = "pillow", specifier = ">=10.2.0" }, { name = "pre-commit", specifier = ">=3.6.0" }, + { name = "pytest", specifier = ">=8.0.0" }, + { name = "pytest-asyncio", specifier = ">=0.23.7" }, + { name = "pytest-subprocess", specifier = ">=1.5.2" }, + { name = "pytest-vcr", specifier = ">=1.0.2" }, + { name = "python-dotenv", specifier = ">=1.0.0" }, + { name = "ruff", specifier = ">=0.4.10" }, ] [[package]] @@ -3377,15 +3385,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a9/f9/b6bcaf874f410564a78908739c80861a171788ef4d4f76f5009656672dfe/pydantic_core-2.23.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:9a5bce9d23aac8f0cf0836ecfc033896aa8443b501c58d0602dbfd5bd5b37753", size = 1920344 }, ] -[[package]] -name = "pyflakes" -version = "3.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/57/f9/669d8c9c86613c9d568757c7f5824bd3197d7b1c6c27553bc5618a27cce2/pyflakes-3.2.0.tar.gz", hash = "sha256:1c61603ff154621fb2a9172037d84dca3500def8c8b630657d1701f026f8af3f", size = 63788 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d4/d7/f1b7db88d8e4417c5d47adad627a93547f44bdc9028372dbd2313f34a855/pyflakes-3.2.0-py2.py3-none-any.whl", hash = "sha256:84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a", size = 62725 }, -] - [[package]] name = "pygments" version = "2.18.0" @@ -3516,6 +3515,44 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/6b/77/7440a06a8ead44c7757a64362dd22df5760f9b12dc5f11b6188cd2fc27a0/pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2", size = 342341 }, ] +[[package]] +name = "pytest-asyncio" +version = "0.24.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/52/6d/c6cf50ce320cf8611df7a1254d86233b3df7cc07f9b5f5cbcb82e08aa534/pytest_asyncio-0.24.0.tar.gz", hash = "sha256:d081d828e576d85f875399194281e92bf8a68d60d72d1a2faf2feddb6c46b276", size = 49855 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/96/31/6607dab48616902f76885dfcf62c08d929796fc3b2d2318faf9fd54dbed9/pytest_asyncio-0.24.0-py3-none-any.whl", hash = "sha256:a811296ed596b69bf0b6f3dc40f83bcaf341b155a269052d82efa2b25ac7037b", size = 18024 }, +] + +[[package]] +name = "pytest-subprocess" +version = "1.5.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3d/02/0c8323e6013ea967f0461ef5653bd129b2d673d74f070c681c7a8663285c/pytest_subprocess-1.5.2.tar.gz", hash = "sha256:ad3ca8a35e798bf9c82d9f16d88700b30d98c5a28236117b86c5d6e581a8ed97", size = 40468 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/77/a80e8f9126b95ffd5ad4d04bd14005c68dcbf0d88f53b2b14893f6cc7232/pytest_subprocess-1.5.2-py3-none-any.whl", hash = "sha256:23ac7732aa8bd45f1757265b1316eb72a7f55b41fb21e2ca22e149ba3629fa46", size = 20886 }, +] + +[[package]] +name = "pytest-vcr" +version = "1.0.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest" }, + { name = "vcrpy", version = "5.1.0", source = { registry = "https://pypi.org/simple" }, marker = "platform_python_implementation == 'PyPy' or python_full_version >= '3.11'" }, + { name = "vcrpy", version = "6.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11' and platform_python_implementation != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1a/60/104c619483c1a42775d3f8b27293f1ecfc0728014874d065e68cb9702d49/pytest-vcr-1.0.2.tar.gz", hash = "sha256:23ee51b75abbcc43d926272773aae4f39f93aceb75ed56852d0bf618f92e1896", size = 3810 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9d/d3/ff520d11e6ee400602711d1ece8168dcfc5b6d8146fb7db4244a6ad6a9c3/pytest_vcr-1.0.2-py2.py3-none-any.whl", hash = "sha256:2f316e0539399bea0296e8b8401145c62b6f85e9066af7e57b6151481b0d6d9c", size = 4137 }, +] + [[package]] name = "python-dateutil" version = "2.9.0.post0" @@ -3912,6 +3949,31 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/49/97/fa78e3d2f65c02c8e1268b9aba606569fe97f6c8f7c2d74394553347c145/rsa-4.9-py3-none-any.whl", hash = "sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7", size = 34315 }, ] +[[package]] +name = "ruff" +version = "0.6.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/26/0d/6148a48dab5662ca1d5a93b7c0d13c03abd3cc7e2f35db08410e47cef15d/ruff-0.6.9.tar.gz", hash = "sha256:b076ef717a8e5bc819514ee1d602bbdca5b4420ae13a9cf61a0c0a4f53a2baa2", size = 3095355 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6e/8f/f7a0a0ef1818662efb32ed6df16078c95da7a0a3248d64c2410c1e27799f/ruff-0.6.9-py3-none-linux_armv6l.whl", hash = "sha256:064df58d84ccc0ac0fcd63bc3090b251d90e2a372558c0f057c3f75ed73e1ccd", size = 10440526 }, + { url = "https://files.pythonhosted.org/packages/8b/69/b179a5faf936a9e2ab45bb412a668e4661eded964ccfa19d533f29463ef6/ruff-0.6.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:140d4b5c9f5fc7a7b074908a78ab8d384dd7f6510402267bc76c37195c02a7ec", size = 10034612 }, + { url = "https://files.pythonhosted.org/packages/c7/ef/fd1b4be979c579d191eeac37b5cfc0ec906de72c8bcd8595e2c81bb700c1/ruff-0.6.9-py3-none-macosx_11_0_arm64.whl", hash = "sha256:53fd8ca5e82bdee8da7f506d7b03a261f24cd43d090ea9db9a1dc59d9313914c", size = 9706197 }, + { url = "https://files.pythonhosted.org/packages/29/61/b376d775deb5851cb48d893c568b511a6d3625ef2c129ad5698b64fb523c/ruff-0.6.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:645d7d8761f915e48a00d4ecc3686969761df69fb561dd914a773c1a8266e14e", size = 10751855 }, + { url = "https://files.pythonhosted.org/packages/13/d7/def9e5f446d75b9a9c19b24231a3a658c075d79163b08582e56fa5dcfa38/ruff-0.6.9-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eae02b700763e3847595b9d2891488989cac00214da7f845f4bcf2989007d577", size = 10200889 }, + { url = "https://files.pythonhosted.org/packages/6c/d6/7f34160818bcb6e84ce293a5966cba368d9112ff0289b273fbb689046047/ruff-0.6.9-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d5ccc9e58112441de8ad4b29dcb7a86dc25c5f770e3c06a9d57e0e5eba48829", size = 11038678 }, + { url = "https://files.pythonhosted.org/packages/13/34/a40ff8ae62fb1b26fb8e6fa7e64bc0e0a834b47317880de22edd6bfb54fb/ruff-0.6.9-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:417b81aa1c9b60b2f8edc463c58363075412866ae4e2b9ab0f690dc1e87ac1b5", size = 11808682 }, + { url = "https://files.pythonhosted.org/packages/2e/6d/25a4386ae4009fc798bd10ba48c942d1b0b3e459b5403028f1214b6dd161/ruff-0.6.9-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3c866b631f5fbce896a74a6e4383407ba7507b815ccc52bcedabb6810fdb3ef7", size = 11330446 }, + { url = "https://files.pythonhosted.org/packages/f7/f6/bdf891a9200d692c94ebcd06ae5a2fa5894e522f2c66c2a12dd5d8cb2654/ruff-0.6.9-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7b118afbb3202f5911486ad52da86d1d52305b59e7ef2031cea3425142b97d6f", size = 12483048 }, + { url = "https://files.pythonhosted.org/packages/a7/86/96f4252f41840e325b3fa6c48297e661abb9f564bd7dcc0572398c8daa42/ruff-0.6.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a67267654edc23c97335586774790cde402fb6bbdb3c2314f1fc087dee320bfa", size = 10936855 }, + { url = "https://files.pythonhosted.org/packages/45/87/801a52d26c8dbf73424238e9908b9ceac430d903c8ef35eab1b44fcfa2bd/ruff-0.6.9-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:3ef0cc774b00fec123f635ce5c547dac263f6ee9fb9cc83437c5904183b55ceb", size = 10713007 }, + { url = "https://files.pythonhosted.org/packages/be/27/6f7161d90320a389695e32b6ebdbfbedde28ccbf52451e4b723d7ce744ad/ruff-0.6.9-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:12edd2af0c60fa61ff31cefb90aef4288ac4d372b4962c2864aeea3a1a2460c0", size = 10274594 }, + { url = "https://files.pythonhosted.org/packages/00/52/dc311775e7b5f5b19831563cb1572ecce63e62681bccc609867711fae317/ruff-0.6.9-py3-none-musllinux_1_2_i686.whl", hash = "sha256:55bb01caeaf3a60b2b2bba07308a02fca6ab56233302406ed5245180a05c5625", size = 10608024 }, + { url = "https://files.pythonhosted.org/packages/98/b6/be0a1ddcbac65a30c985cf7224c4fce786ba2c51e7efeb5178fe410ed3cf/ruff-0.6.9-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:925d26471fa24b0ce5a6cdfab1bb526fb4159952385f386bdcc643813d472039", size = 10982085 }, + { url = "https://files.pythonhosted.org/packages/bb/a4/c84bc13d0b573cf7bb7d17b16d6d29f84267c92d79b2f478d4ce322e8e72/ruff-0.6.9-py3-none-win32.whl", hash = "sha256:eb61ec9bdb2506cffd492e05ac40e5bc6284873aceb605503d8494180d6fc84d", size = 8522088 }, + { url = "https://files.pythonhosted.org/packages/74/be/fc352bd8ca40daae8740b54c1c3e905a7efe470d420a268cd62150248c91/ruff-0.6.9-py3-none-win_amd64.whl", hash = "sha256:785d31851c1ae91f45b3d8fe23b8ae4b5170089021fbb42402d811135f0b7117", size = 9359275 }, + { url = "https://files.pythonhosted.org/packages/3e/14/fd026bc74ded05e2351681545a5f626e78ef831f8edce064d61acd2e6ec7/ruff-0.6.9-py3-none-win_arm64.whl", hash = "sha256:a9641e31476d601f83cd602608739a0840e348bda93fec9f1ee816f8b6798b93", size = 8679879 }, +] + [[package]] name = "s3transfer" version = "0.10.2" @@ -4529,6 +4591,45 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/6f/52/deb4be09060637ef4752adaa0b75bf770c20c823e8108705792f99cd4a6f/uvloop-0.20.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:aea15c78e0d9ad6555ed201344ae36db5c63d428818b4b2a42842b3870127c00", size = 4115980 }, ] +[[package]] +name = "vcrpy" +version = "5.1.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version < '3.11' and platform_python_implementation == 'PyPy'", + "python_full_version == '3.11.*'", + "python_full_version >= '3.12' and python_full_version < '3.12.4'", + "python_full_version >= '3.12.4' and python_full_version < '3.13'", + "python_full_version >= '3.13'", +] +dependencies = [ + { name = "pyyaml", marker = "platform_python_implementation == 'PyPy' or python_full_version >= '3.11'" }, + { name = "wrapt", marker = "platform_python_implementation == 'PyPy' or python_full_version >= '3.11'" }, + { name = "yarl", marker = "platform_python_implementation == 'PyPy' or python_full_version >= '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a5/ea/a166a3cce4ac5958ba9bbd9768acdb1ba38ae17ff7986da09fa5b9dbc633/vcrpy-5.1.0.tar.gz", hash = "sha256:bbf1532f2618a04f11bce2a99af3a9647a32c880957293ff91e0a5f187b6b3d2", size = 84576 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/5b/3f70bcb279ad30026cc4f1df0a0491a0205a24dddd88301f396c485de9e7/vcrpy-5.1.0-py2.py3-none-any.whl", hash = "sha256:605e7b7a63dcd940db1df3ab2697ca7faf0e835c0852882142bafb19649d599e", size = 41969 }, +] + +[[package]] +name = "vcrpy" +version = "6.0.2" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version < '3.11' and platform_python_implementation != 'PyPy'", +] +dependencies = [ + { name = "pyyaml", marker = "python_full_version < '3.11' and platform_python_implementation != 'PyPy'" }, + { name = "urllib3", marker = "python_full_version < '3.11' and platform_python_implementation != 'PyPy'" }, + { name = "wrapt", marker = "python_full_version < '3.11' and platform_python_implementation != 'PyPy'" }, + { name = "yarl", marker = "python_full_version < '3.11' and platform_python_implementation != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/16/4e/fff59599826793f9e3460c22c0af0377abb27dc9781a7d5daca8cb03da25/vcrpy-6.0.2.tar.gz", hash = "sha256:88e13d9111846745898411dbc74a75ce85870af96dd320d75f1ee33158addc09", size = 85472 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/da/ed/25d19705791d3fccc84423d564695421a75b4e08e8ab15a004a49068742d/vcrpy-6.0.2-py2.py3-none-any.whl", hash = "sha256:40370223861181bc76a5e5d4b743a95058bb1ad516c3c08570316ab592f56cad", size = 42431 }, +] + [[package]] name = "virtualenv" version = "20.26.6"