ruff/scripts/ty_benchmark/src/benchmark/projects.py
2025-05-03 19:49:15 +02:00

145 lines
4.3 KiB
Python

import logging
import subprocess
import typing
from pathlib import Path
class Project(typing.NamedTuple):
name: str
"""The name of the project to benchmark."""
repository: str
"""The git repository to clone."""
revision: str
dependencies: list[str]
"""List of type checking dependencies.
Dependencies are pinned using a `--exclude-newer` flag when installing them
into the virtual environment; see the `Venv.install()` method for details.
"""
include: list[str] = []
"""The directories and files to check. If empty, checks the current directory"""
pyright_arguments: list[str] | None = None
"""The arguments passed to pyright. Overrides `include` if set."""
mypy_arguments: list[str] | None = None
"""The arguments passed to mypy. Overrides `include` if set."""
def clone(self, checkout_dir: Path) -> None:
# Skip cloning if the project has already been cloned (the script doesn't yet support updating)
if (checkout_dir / ".git").exists():
return
logging.debug(f"Cloning {self.repository} to {checkout_dir}")
try:
# git doesn't support cloning a specific revision.
# This is the closest that I found to a "shallow clone with a specific revision"
subprocess.run(
[
"git",
"init",
"--quiet",
],
env={"GIT_TERMINAL_PROMPT": "0"},
cwd=checkout_dir,
check=True,
capture_output=True,
text=True,
)
subprocess.run(
["git", "remote", "add", "origin", str(self.repository), "--no-fetch"],
env={"GIT_TERMINAL_PROMPT": "0"},
cwd=checkout_dir,
check=True,
capture_output=True,
text=True,
)
subprocess.run(
[
"git",
"fetch",
"origin",
self.revision,
"--quiet",
"--depth",
"1",
"--no-tags",
],
check=True,
cwd=checkout_dir,
capture_output=True,
text=True,
)
subprocess.run(
["git", "reset", "--hard", "FETCH_HEAD", "--quiet"],
check=True,
cwd=checkout_dir,
capture_output=True,
text=True,
)
except subprocess.CalledProcessError as e:
raise RuntimeError(f"Failed to clone {self.name}: {e.stderr}")
logging.info(f"Cloned {self.name} to {checkout_dir}.")
# Selection of projects taken from
# [mypy-primer](https://github.com/hauntsaninja/mypy_primer/blob/0ea6cc614b3e91084059b9a3acc58f94c066a211/mypy_primer/projects.py#L71).
# May require frequent updating, especially the dependencies list
ALL = [
Project(
name="black",
repository="https://github.com/psf/black",
revision="ac28187bf4a4ac159651c73d3a50fe6d0f653eac",
include=["src"],
dependencies=[
"aiohttp",
"click",
"pathspec",
"tomli",
"platformdirs",
"packaging",
],
),
Project(
name="jinja",
repository="https://github.com/pallets/jinja",
revision="b490da6b23b7ad25dc969976f64dc4ffb0a2c182",
include=[],
dependencies=["markupsafe"],
),
Project(
name="pandas",
repository="https://github.com/pandas-dev/pandas",
revision="7945e563d36bcf4694ccc44698829a6221905839",
include=["pandas"],
dependencies=[
"numpy",
"types-python-dateutil",
"types-pytz",
"types-PyMySQL",
"types-setuptools",
"pytest",
],
),
Project(
name="isort",
repository="https://github.com/pycqa/isort",
revision="7de182933fd50e04a7c47cc8be75a6547754b19c",
mypy_arguments=["--ignore-missing-imports", "isort"],
include=["isort"],
dependencies=["types-setuptools"],
),
]
DEFAULT: list[str] = ["black", "jinja", "isort"]