Skip to content

Commit c43a01a

Browse files
Merge pull request #813 from pyathena-dev/feat/812-benchmark-workspace
Manage the benchmark project as a uv workspace member
2 parents a2412cc + d25aa22 commit c43a01a

9 files changed

Lines changed: 133 additions & 676 deletions

File tree

‎.github/workflows/benchmarks.yaml‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ on:
1313
- 'benchmarks/**'
1414
- 'pyathena/**'
1515
- 'pyproject.toml'
16+
- 'uv.lock'
1617
- 'justfile'
1718
- '.github/workflows/benchmarks.yaml'
1819

@@ -24,6 +25,7 @@ jobs:
2425
runs-on: ubuntu-latest
2526
env:
2627
AWS_EC2_METADATA_DISABLED: 'true'
28+
UV_PROJECT_ENVIRONMENT: ${{ github.workspace }}/benchmarks/.venv
2729
steps:
2830
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
2931
with:
@@ -36,7 +38,7 @@ jobs:
3638
- uses: taiki-e/install-action@7a79fe8c3a13344501c80d99cae481c1c9085912 # v2.81.10
3739
with:
3840
tool: just
39-
- run: uv sync --project benchmarks --locked
41+
- run: uv sync --package pyathena-benchmarks --locked
4042
- run: just benchmark test
4143
- name: Build only the main distribution
4244
run: uv build -v

‎benchmarks/README.md‎

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,30 +34,33 @@ Neither workload converts every library's output into a common Python object rep
3434

3535
## Dependencies and local checks
3636

37-
The benchmark is an independent, non-packaged uv project for Python 3.12.
38-
Its lockfile and virtual environment are separate from the parent project; PyAthena is an editable path dependency on the parent checkout.
37+
The benchmark is a non-packaged member of the repository's uv workspace and runs on Python 3.12.
38+
It shares the root `uv.lock` with PyAthena, which it uses from the workspace checkout.
39+
Locally and in CI, its virtual environment is `benchmarks/.venv`, separate from the root `.venv`.
40+
On the EC2 instance, the dedicated checkout's root `/opt/pyathena/.venv` holds the benchmark environment.
3941
The root `uv build -v` still builds only PyAthena, including a wheel built from its sdist.
40-
Benchmark dependencies do not become PyAthena runtime dependencies.
42+
Benchmark dependencies do not become PyAthena runtime dependencies, and `uv sync --group dev` at the root does not install them.
4143

4244
From the repository root:
4345

4446
```bash
45-
uv sync --project benchmarks --locked
4647
just benchmark lint
4748
just benchmark test
4849
```
4950

51+
The recipes select `benchmarks/.venv` and Python 3.12, and sync that environment from the locked workspace.
5052
The tests use local data, fake AWS clients, and child processes.
5153
They do not execute Athena queries or create AWS resources.
5254
`just benchmark format` formats the benchmark separately from the parent project.
53-
After changing dependencies, extras, or dependency groups in either `pyproject.toml`, run `just benchmark lock` and commit `benchmarks/uv.lock`.
54-
The benchmark lock includes metadata for its editable parent dependency; CI intentionally rejects a stale lock.
55+
After changing dependencies, extras, or dependency groups in either `pyproject.toml`, run `uv lock` at the repository root and commit `uv.lock`.
5556

5657
Commands below run from `benchmarks/`.
58+
Set the environment variables first; without them, uv uses the root `.venv`.
5759
`plan` and `report` do not contact AWS or require `.env`.
5860

5961
```bash
6062
cd benchmarks
63+
export UV_PROJECT_ENVIRONMENT="$PWD/.venv" UV_PYTHON=3.12
6164
uv run --locked python -m pyathena_bench plan --suite single --scale small
6265
```
6366

@@ -95,8 +98,8 @@ The instance can write only to its scratch bucket and database, and can query th
9598
The supplied template assumes ordinary IAM access and SSE-S3 source objects; Lake Formation restrictions or a customer-managed KMS key require corresponding grants before execution.
9699

97100
The deployment identity needs permission to create these resources and pass the instance role.
98-
Use an immutable, remotely accessible commit that contains this directory and its lockfile.
99-
Bootstrap checks out that commit, installs pinned uv and Python versions, and runs `uv sync --locked --no-dev`.
101+
Use an immutable, remotely accessible commit that contains this directory and the root `uv.lock`.
102+
Bootstrap checks out that commit, installs pinned uv and Python versions, and runs `uv sync --locked --no-dev` for the benchmark into `/opt/pyathena/.venv`.
100103
It signals setup completion to CloudFormation but does not prepare data or start measurements.
101104
The EC2 commands use `--no-sync` to reuse this verified environment; they do not revalidate the lockfile on every invocation.
102105

‎benchmarks/pyathena_bench/cases.py‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,9 @@ def matrix(settings: Settings, suite: str, shape: str) -> list[Case]:
4747
cases.extend(Case(family, api, arraysize=a, shape=shape) for a in arraysizes)
4848
if family in {"pandas", "arrow", "polars"}:
4949
for transport in ("csv", "unload"):
50-
chunks = [None] if family == "arrow" else [None, *settings.chunksizes]
50+
chunks: list[int | None] = (
51+
[None] if family == "arrow" else [None, *settings.chunksizes]
52+
)
5153
for chunk in chunks:
5254
reason = None
5355
if family == "pandas" and transport == "unload" and chunk:

‎benchmarks/pyathena_bench/runner.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ def environment(settings: Settings) -> dict[str, Any]:
269269
"cpu_count": psutil.cpu_count(),
270270
"memory_bytes": psutil.virtual_memory().total,
271271
"dependencies": {d.metadata["Name"]: d.version for d in importlib.metadata.distributions()},
272-
"lock_sha256": hashlib.sha256((root / "benchmarks/uv.lock").read_bytes()).hexdigest(),
272+
"lock_sha256": hashlib.sha256((root / "uv.lock").read_bytes()).hexdigest(),
273273
"settings": asdict(settings),
274274
}
275275

‎benchmarks/pyproject.toml‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,24 @@
99
name = "pyathena-benchmarks"
1010
version = "0.1.0"
1111
description = "Reproducible Athena cursor measurements"
12-
requires-python = ">=3.12,<3.13"
12+
# The workspace lock covers the root's Python range; benchmark runs use Python 3.12.
13+
requires-python = ">=3.10"
1314
classifiers = ["Private :: Do Not Upload"]
1415
dependencies = [
1516
"PyAthena[pandas,arrow,polars]",
1617
"awswrangler>=3.17,<4",
17-
"polars>=1.37",
18+
"polars",
1819
"psutil>=7,<8",
1920
]
2021

2122
[tool.uv]
2223
package = false
2324

2425
[tool.uv.sources]
25-
pyathena = { path = "..", editable = true }
26+
pyathena = { workspace = true }
2627

2728
[dependency-groups]
28-
dev = ["pytest>=8", "pytest-asyncio>=1", "mypy>=1.19", "types-psutil", "cfn-lint>=1"]
29+
dev = ["pytest>=8", "pytest-asyncio>=1", "mypy", "types-psutil", "cfn-lint>=1"]
2930

3031
[tool.pytest.ini_options]
3132
testpaths = ["tests"]

0 commit comments

Comments
 (0)