Migrate to uv and poe for workspace management and task running (#424)

* Migrate to uv and poe for workspace management and task running

* install python

* try fix

* ensure workspace venv in used

* package dir

* move nbqa to mypy task

* separate sync, clarify docs
This commit is contained in:
Jack Gerrits 2024-08-29 09:46:06 -04:00 committed by GitHub
parent 6ef4a9a617
commit 4ff5610853
10 changed files with 320 additions and 357 deletions

View File

@ -11,96 +11,112 @@ on:
jobs:
format:
runs-on: ubuntu-latest
strategy:
matrix:
working-directory:
["./python/packages/autogen-core", "./python/packages/team-one", "./python/packages/agbench"]
steps:
- uses: actions/checkout@v4
- name: Install Hatch
uses: pypa/hatch@install
- run: hatch run ruff format --check
working-directory: ${{ matrix.working-directory }}
- run: curl -LsSf https://astral.sh/uv/install.sh | sh
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- run: uv sync
working-directory: ./python
- name: Run task
run: |
source ${{ github.workspace }}/python/.venv/bin/activate
poe fmt --check
working-directory: ./python
lint:
runs-on: ubuntu-latest
strategy:
matrix:
working-directory:
["./python/packages/autogen-core", "./python/packages/team-one", "./python/packages/agbench"]
steps:
- uses: actions/checkout@v4
- name: Install Hatch
uses: pypa/hatch@install
- run: hatch run ruff check
working-directory: ${{ matrix.working-directory }}
- run: curl -LsSf https://astral.sh/uv/install.sh | sh
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- run: uv sync
working-directory: ./python
- name: Run task
run: |
source ${{ github.workspace }}/python/.venv/bin/activate
poe lint
working-directory: ./python
mypy:
runs-on: ubuntu-latest
strategy:
matrix:
working-directory:
["./python/packages/autogen-core", "./python/packages/team-one", "./python/packages/agbench"]
package:
["./packages/autogen-core", "./packages/team-one", "./packages/agbench"]
steps:
- uses: actions/checkout@v4
- name: Install Hatch
uses: pypa/hatch@install
- run: hatch run mypy
working-directory: ${{ matrix.working-directory }}
- run: curl -LsSf https://astral.sh/uv/install.sh | sh
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- run: uv sync
working-directory: ./python
- name: Run task
run: |
source ${{ github.workspace }}/python/.venv/bin/activate
poe --directory ${{ matrix.package }} mypy
working-directory: ./python
pyright:
runs-on: ubuntu-latest
strategy:
matrix:
working-directory:
["./python/packages/autogen-core", "./python/packages/team-one", "./python/packages/agbench"]
package:
["./packages/autogen-core", "./packages/team-one", "./packages/agbench"]
steps:
- uses: actions/checkout@v4
- name: Install Hatch
uses: pypa/hatch@install
- run: hatch run pyright
working-directory: ${{ matrix.working-directory }}
- run: curl -LsSf https://astral.sh/uv/install.sh | sh
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- run: uv sync
working-directory: ./python
- name: Run task
run: |
source ${{ github.workspace }}/python/.venv/bin/activate
poe --directory ${{ matrix.package }} pyright
working-directory: ./python
test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.10", "3.11", "3.12"]
package:
["./packages/autogen-core", "./packages/team-one"]
steps:
- uses: actions/checkout@v4
- name: Install Hatch
uses: pypa/hatch@install
- run: hatch run +python=${{ matrix.python-version }} test-matrix:pytest -n auto
working-directory: ./python/packages/autogen-core
team-one-test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.10", "3.11", "3.12"]
steps:
- uses: actions/checkout@v4
- name: Install Hatch
uses: pypa/hatch@install
- run: |
hatch run +python=${{ matrix.python-version }} teamone-test-matrix:playwright install
hatch run +python=${{ matrix.python-version }} teamone-test-matrix:pytest -n auto
working-directory: ./python/packages/team-one
mypy-notebooks:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Hatch
uses: pypa/hatch@install
- run: hatch run nbqa mypy docs/src
working-directory: ./python/packages/autogen-core
- run: curl -LsSf https://astral.sh/uv/install.sh | sh
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- run: uv sync
working-directory: ./python
- name: Run task
run: |
source ${{ github.workspace }}/python/.venv/bin/activate
poe --directory ${{ matrix.package }} test
working-directory: ./python
docs:
runs-on: ubuntu-latest
strategy:
matrix:
package:
["./packages/autogen-core"]
steps:
- uses: actions/checkout@v4
- name: Install Hatch
uses: pypa/hatch@install
- run: hatch run docs:check
working-directory: ./python/packages/autogen-core
- run: curl -LsSf https://astral.sh/uv/install.sh | sh
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- run: uv sync
working-directory: ./python
- name: Run task
run: |
source ${{ github.workspace }}/python/.venv/bin/activate
poe --directory ${{ matrix.package }} pyright
working-directory: ./python

View File

@ -30,10 +30,15 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Hatch
uses: pypa/hatch@install
- run: hatch run docs:build
working-directory: ./python/packages/autogen-core
- run: curl -LsSf https://astral.sh/uv/install.sh | sh
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- run: |
uv sync
source .venv/bin/activate
poe --directory ./packages/autogen-core docs-build
working-directory: ./python
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:

View File

@ -1,3 +1,43 @@
# AutoGen Python packages
See [`autogen-core`](./packages/autogen-core/) package for main functionality.
## Development
**TL;DR**, run all checks with:
```sh
uv sync
source .venv/bin/activate
poe all
```
### Setup
- [Install `uv`](https://docs.astral.sh/uv/getting-started/installation/).
### Virtual environment
To get a shell with the package available (virtual environment),
in the current directory,
run:
```sh
uv sync
source .venv/bin/activate
```
### Common tasks
- Format: `poe format`
- Lint: `poe lint`
- Test: `poe test`
- Mypy: `poe mypy`
- Pyright: `poe pyright`
- Build docs: `poe --directory ./packages/autogen-core/ docs-build`
- Auto rebuild+serve docs: `poe --directory ./packages/autogen-core/ docs-serve`
> [!NOTE]
> These need to be run in the virtual environment.

View File

@ -26,30 +26,12 @@ dependencies = [
"pandas"
]
[tool.hatch.envs.default]
installer = "uv"
dependencies = [
"pyright==1.1.368",
"mypy==1.10.0",
"ruff==0.4.8",
[tool.uv]
dev-dependencies = [
"types-tabulate",
"types-docker"
]
[tool.hatch.envs.default.extra-scripts]
pip = "{env:HATCH_UV} pip {args}"
[tool.hatch.envs.default.scripts]
fmt = "ruff format"
lint = "ruff check"
check = [
"ruff format",
"ruff check --fix",
"pyright",
"mypy",
]
[tool.hatch.version]
path = "src/agbench/version.py"
@ -57,41 +39,19 @@ path = "src/agbench/version.py"
agbench = "agbench.cli:main"
[tool.ruff]
line-length = 120
fix = true
exclude = ["build", "dist", "src/agbench/res/*", "src/agbench/template/*",]
target-version = "py310"
include = ["src/**"]
[tool.ruff.lint]
select = ["E", "F", "W", "B", "Q", "I", "ASYNC"]
ignore = ["F401", "E501"]
[tool.ruff.lint.flake8-tidy-imports]
[tool.ruff.lint.flake8-tidy-imports.banned-api]
"unittest".msg = "Use `pytest` instead."
[tool.mypy]
files = ["src"]
strict = true
python_version = "3.10"
ignore_missing_imports = true
# from https://blog.wolt.com/engineering/2021/09/30/professional-grade-mypy-configuration/
disallow_untyped_defs = true
no_implicit_optional = true
check_untyped_defs = true
warn_return_any = true
show_error_codes = true
warn_unused_ignores = false
disallow_incomplete_defs = true
disallow_untyped_decorators = true
disallow_any_unimported = true
extend = "../../pyproject.toml"
exclude = ["build", "dist", "page_script.js", "src/agbench/res/Dockerfile", "src/agbench/template/global_init.sh"]
include = [
"src/**",
"examples/*.py",
]
[tool.pyright]
extend = "../../pyproject.toml"
include = ["src"]
typeCheckingMode = "strict"
reportUnnecessaryIsInstance = false
reportMissingTypeStubs = false
[tool.poe]
include = "../../shared_tasks.toml"
[tool.poe.tasks]
mypy = "mypy --config-file ../../pyproject.toml src"

View File

@ -8,54 +8,3 @@
- `base` are the the foundational generic interfaces upon which all else is built. This module must not depend on any other module.
- `application` are implementations of core components that are used to compose an application.
- `components` are the building blocks for creating agents.
## Development
**TL;DR**, run all checks with:
```sh
hatch run check
```
### Setup
- [Install `hatch`](https://hatch.pypa.io/1.12/install/).
### Virtual environment
To get a shell with the package available (virtual environment),
in the current directory,
run:
```sh
hatch shell
```
### Common tasks
- Format: `hatch run check`
- Lint: `hatch run lint`
- Test: `hatch run pytest -n auto`
- Mypy: `hatch run mypy`
- Pyright: `hatch run pyright`
- Build docs: `hatch run docs:build`
- Auto rebuild+serve docs: `hatch run docs:serve`
> [!NOTE]
> These don't need to be run in a virtual environment, `hatch` will automatically manage it for you.
#### IntelliJ Support
To enable the `hatch` virtual environment in IntelliJ, follow these steps:
Under the `[tool.hatch.envs.default]` heading in `pyproject.toml`, add this:
```toml
[tool.hatch.envs.default]
type = "virtual"
path = ".venv"
```
Run `hatch shell` in the terminal to create the virtual environment.
Then, in IntelliJ, go to `File` -> `Project Structure` -> `Project Settings` -> `Project` -> `Project SDK` and select the Python interpreter in the `.venv` directory.
Once complete, your IDE should be able to resolve, run, and debug code.

View File

@ -19,16 +19,14 @@ dependencies = [
"aiohttp",
"typing-extensions",
"pydantic>=1.10,<3",
"types-aiofiles",
"grpcio",
"protobuf",
"tiktoken",
"azure-core"
]
[tool.hatch.envs.default]
installer = "uv"
dependencies = [
[tool.uv]
dev-dependencies = [
"azure-identity",
"aiofiles",
"chess",
@ -46,7 +44,6 @@ dependencies = [
"mypy==1.10.0",
"pip",
"polars",
"pyright==1.1.368",
"pytest-asyncio",
"pytest-mock",
"pytest-xdist",
@ -64,35 +61,7 @@ dependencies = [
"types-protobuf",
"types-requests",
"wikipedia",
"nbqa"
]
[tool.hatch.envs.default.extra-scripts]
pip = "{env:HATCH_UV} pip {args}"
[tool.hatch.envs.default.scripts]
fmt = "ruff format"
lint = "ruff check"
test = "pytest -n auto"
check = [
"ruff format",
"ruff check --fix",
"pyright",
"mypy --non-interactive --install-types",
"pytest -n auto",
# Only checking notebooks with mypy for now due to the fact pyright doesn't seem to be able to ignore the top level await
"nbqa mypy docs/src",
]
[tool.hatch.envs.test-matrix]
template = "default"
[[tool.hatch.envs.test-matrix.matrix]]
python = ["3.10", "3.11", "3.12"]
[tool.hatch.envs.docs]
template = "default"
dependencies = [
"nbqa",
"sphinx",
"furo",
"sphinxcontrib-apidoc",
@ -100,96 +69,36 @@ dependencies = [
"sphinx-autobuild",
]
[tool.hatch.envs.docs.scripts]
build = "sphinx-build docs/src docs/build"
serve = "sphinx-autobuild --watch src docs/src docs/build"
check = [
"sphinx-build --fail-on-warning docs/src docs/build"
]
# Benchmark environments
[tool.hatch.envs.bench-humaneval-teamone]
installer = "uv"
detached = true
dependencies = [
"autogen_core@{root:uri}",
"agbench@{root:uri}/tools/agbench",
"team-one@{root:uri}/teams/team-one",
]
[tool.hatch.envs.bench-humaneval-twoagents]
installer = "uv"
detached = true
dependencies = [
"autogen_core@{root:uri}",
"agbench@{root:uri}/tools/agbench",
]
[tool.ruff]
line-length = 120
fix = true
extend = "../../pyproject.toml"
exclude = ["build", "dist", "src/autogen_core/application/protos"]
target-version = "py310"
include = ["src/**", "samples/*.py", "docs/**/*.ipynb"]
[tool.ruff.format]
docstring-code-format = true
[tool.ruff.lint]
select = ["E", "F", "W", "B", "Q", "I", "ASYNC"]
ignore = ["F401", "E501"]
[tool.ruff.lint.flake8-tidy-imports]
[tool.ruff.lint.flake8-tidy-imports.banned-api]
"unittest".msg = "Use `pytest` instead."
[tool.mypy]
files = ["src", "samples", "tests"]
exclude = ["src/autogen_core/application/protos"]
strict = true
python_version = "3.10"
ignore_missing_imports = true
# from https://blog.wolt.com/engineering/2021/09/30/professional-grade-mypy-configuration/
disallow_untyped_defs = true
no_implicit_optional = true
check_untyped_defs = true
warn_return_any = true
show_error_codes = true
warn_unused_ignores = false
disallow_incomplete_defs = true
disallow_untyped_decorators = true
disallow_any_unimported = true
[tool.pyright]
extend = "../../pyproject.toml"
include = ["src", "tests", "samples"]
typeCheckingMode = "strict"
reportUnnecessaryIsInstance = false
reportMissingTypeStubs = false
exclude = ["src/autogen_core/application/protos"]
[tool.pytest.ini_options]
minversion = "6.0"
testpaths = ["tests"]
[tool.hatch.build.hooks.protobuf]
dependencies = ["hatch-protobuf", "mypy-protobuf~=3.0"]
generate_pyi = false
proto_paths = ["../protos"]
output_path = "src/autogen_core/application/protos"
[[tool.hatch.build.hooks.protobuf.generators]]
name = "mypy"
outputs = ["{proto_path}/{proto_name}_pb2.pyi"]
[[tool.hatch.build.hooks.protobuf.generators]]
name = "mypy_grpc"
outputs = ["{proto_path}/{proto_name}_pb2_grpc.pyi"]
[tool.nbqa.addopts]
mypy = [
"--disable-error-code=top-level-await"
]
[tool.poe]
include = "../../shared_tasks.toml"
[tool.poe.tasks]
test = "pytest -n auto"
mypy.default_item_type = "cmd"
mypy.sequence = [
"mypy --config-file ../../pyproject.toml --exclude src/autogen_core/application/protos src tests",
"nbqa mypy docs/src --config-file ../../pyproject.toml",
]
docs-build = "sphinx-build docs/src docs/build"
docs-serve = "sphinx-autobuild --watch src docs/src docs/build"
docs-check = "sphinx-build --fail-on-warning docs/src docs/build"

View File

@ -15,15 +15,15 @@ classifiers = [
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
]
dependencies = [
"autogen-core@{root:parent:uri}/autogen-core",
"autogen-core",
"aiofiles",
"requests",
"mammoth",
"markdownify",
"numpy",
"python-pptx",
"easyocr",
"pandas",
"pdfminer.six",
"puremagic",
@ -35,15 +35,14 @@ dependencies = [
"playwright",
]
[tool.hatch.envs.default]
installer = "uv"
dependencies = [
"pyright==1.1.368",
"mypy==1.10.0",
"ruff==0.4.8",
"pytest",
"pytest-asyncio",
"pytest-xdist",
[project.optional-dependencies]
ocr = [
"easyocr",
"torchvision>=0.12",
]
[tool.uv]
dev-dependencies = [
"aiofiles",
"types-aiofiles",
"types-requests",
@ -52,83 +51,26 @@ dependencies = [
"openpyxl",
]
[tool.hatch.envs.default.extra-scripts]
pip = "{env:HATCH_UV} pip {args}"
[tool.hatch.envs.default.scripts]
fmt = "ruff format"
lint = "ruff check"
test = [
[tool.poe]
include = "../../shared_tasks.toml"
[tool.poe.tasks]
test.sequence = [
"playwright install",
"pytest -n auto",
]
check = [
"ruff format",
"ruff check --fix",
"pyright",
"mypy --non-interactive --install-types",
"playwright install",
"pytest",
]
[tool.hatch.envs.teamone-test-matrix]
template = "default"
[[tool.hatch.envs.teamone-test-matrix.matrix]]
python = ["3.10", "3.11", "3.12"]
[tool.hatch.metadata]
allow-direct-references = true
test.default_item_type = "cmd"
[tool.ruff]
line-length = 120
fix = true
extend = "../../pyproject.toml"
exclude = ["build", "dist", "page_script.js"]
target-version = "py310"
include = [
"src/**",
"examples/*.py",
"../../benchmarks/HumanEval/Templates/TeamOne/scenario.py",
"../../benchmarks/HumanEval/Templates/TwoAgents/scenario.py",
"../../benchmarks/GAIA/TeamOne/TwoAgents/scenario.py",
]
[tool.ruff.format]
docstring-code-format = true
[tool.ruff.lint]
select = ["E", "F", "W", "B", "Q", "I", "ASYNC"]
ignore = ["F401", "E501"]
[tool.mypy]
files = [
"src",
"tests",
"examples",
]
strict = true
python_version = "3.10"
ignore_missing_imports = true
# from https://blog.wolt.com/engineering/2021/09/30/professional-grade-mypy-configuration/
disallow_untyped_defs = true
no_implicit_optional = true
check_untyped_defs = true
warn_return_any = true
show_error_codes = true
warn_unused_ignores = false
disallow_incomplete_defs = true
disallow_untyped_decorators = true
disallow_any_unimported = true
[tool.pyright]
include = [
"src",
"tests",
"examples",
]
typeCheckingMode = "strict"
reportUnnecessaryIsInstance = false
reportMissingTypeStubs = false
extend = "../../pyproject.toml"
include = ["src", "tests"]

70
python/pyproject.toml Normal file
View File

@ -0,0 +1,70 @@
[tool.uv.workspace]
members = ["packages/*"]
[tool.uv]
dev-dependencies = [
"pyright==1.1.378",
"mypy==1.10.0",
"ruff==0.4.8",
"pytest",
"pytest-asyncio",
"pytest-xdist",
"typer",
"rich",
"polars",
"pytest_mock",
"poethepoet"
]
[tool.uv.sources]
autogen-core = { workspace = true }
[tool.ruff]
line-length = 120
fix = true
target-version = "py310"
[tool.ruff.format]
docstring-code-format = true
[tool.ruff.lint]
select = ["E", "F", "W", "B", "Q", "I", "ASYNC"]
ignore = ["F401", "E501"]
[tool.ruff.lint.flake8-tidy-imports]
[tool.ruff.lint.flake8-tidy-imports.banned-api]
"unittest".msg = "Use `pytest` instead."
[tool.mypy]
strict = true
python_version = "3.10"
ignore_missing_imports = true
# from https://blog.wolt.com/engineering/2021/09/30/professional-grade-mypy-configuration/
disallow_untyped_defs = true
no_implicit_optional = true
check_untyped_defs = true
warn_return_any = true
show_error_codes = true
warn_unused_ignores = false
disallow_incomplete_defs = true
disallow_untyped_decorators = true
disallow_any_unimported = true
[tool.pyright]
include = ["src", "tests", "samples"]
typeCheckingMode = "strict"
reportUnnecessaryIsInstance = false
reportMissingTypeStubs = false
exclude = ["src/autogen_core/application/protos"]
[tool.poe.tasks]
fmt = "python run_task_in_pkgs_if_exist.py fmt"
lint = "python run_task_in_pkgs_if_exist.py lint"
pyright = "python run_task_in_pkgs_if_exist.py pyright"
mypy = "python run_task_in_pkgs_if_exist.py mypy"
test = "python run_task_in_pkgs_if_exist.py test"
check = ["fmt", "lint", "pyright", "mypy", "test"]

View File

@ -0,0 +1,67 @@
import glob
import sys
from pathlib import Path
from typing import List
import tomllib
from poethepoet.app import PoeThePoet
from rich import print
def discover_projects(workspace_pyproject_file: Path) -> List[Path]:
with workspace_pyproject_file.open("rb") as f:
data = tomllib.load(f)
projects = data["tool"]["uv"]["workspace"]["members"]
all_projects: List[Path] = []
for project in projects:
if "*" in project:
globbed = glob.glob(str(project), root_dir=workspace_pyproject_file.parent)
globbed_paths = [Path(p) for p in globbed]
all_projects.extend(globbed_paths)
else:
all_projects.append(Path(project))
return all_projects
def extract_poe_tasks(file: Path) -> set[str]:
with file.open("rb") as f:
data = tomllib.load(f)
tasks = set(data.get("tool", {}).get("poe", {}).get("tasks", {}).keys())
# Check if there is an include too
include: str | None = data.get("tool", {}).get("poe", {}).get("include", None)
if include:
include_file = file.parent / include
if include_file.exists():
tasks = tasks.union(extract_poe_tasks(include_file))
return tasks
def main() -> None:
pyproject_file = Path(__file__).parent / "pyproject.toml"
projects = discover_projects(pyproject_file)
if len(sys.argv) < 2:
print("Please provide a task name")
sys.exit(1)
task_name = sys.argv[1]
for project in projects:
tasks = extract_poe_tasks(project / "pyproject.toml")
if task_name in tasks:
print(f"Running task {task_name} in {project}")
app = PoeThePoet(cwd=project)
result = app(cli_args=sys.argv[1:])
if result:
sys.exit(result)
else:
print(f"Task {task_name} not found in {project}")
if __name__ == "__main__":
main()

5
python/shared_tasks.toml Normal file
View File

@ -0,0 +1,5 @@
[tool.poe.tasks]
fmt = "ruff format"
lint = "ruff check"
mypy = "mypy --config-file $POE_ROOT/../../pyproject.toml src tests"
pyright = "pyright"