Skip to content

Commit 8454ce1

Browse files
authored
Rewrite Black Check Without Tox (#42899)
* initial black script * clean * typo * add check=true * use install_into_venv * refactor install_into_venv, use in pylint * replace pip in sphinx * refactor install_into_venv, removing extras and editable args * add log to black * replace pip in whl
1 parent 2f59429 commit 8454ce1

File tree

8 files changed

+109
-31
lines changed

8 files changed

+109
-31
lines changed

eng/tools/azure-sdk-tools/azpysdk/Check.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ def create_venv(self, isolate: bool, venv_location: str) -> str:
6565

6666
# TODO: we should reuse part of build_whl_for_req to integrate with PREBUILT_WHL_DIR so that we don't have to fresh build for each
6767
# venv
68-
install_into_venv(venv_location, os.path.join(REPO_ROOT, "eng/tools/azure-sdk-tools"), False, "build")
68+
install_into_venv(venv_location, [os.path.join(REPO_ROOT, "eng/tools/azure-sdk-tools[build]")])
6969
venv_python_exe = get_venv_python(venv_location)
7070

7171
return venv_python_exe
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import argparse
2+
import os
3+
import sys
4+
import subprocess
5+
6+
from typing import Optional, List
7+
from subprocess import CalledProcessError
8+
9+
from ci_tools.functions import install_into_venv
10+
from ci_tools.variables import in_ci, discover_repo_root, set_envvar_defaults
11+
from ci_tools.environment_exclusions import is_check_enabled
12+
from ci_tools.logging import logger
13+
14+
from .Check import Check
15+
16+
BLACK_VERSION = "24.4.0"
17+
REPO_ROOT = discover_repo_root()
18+
19+
20+
class black(Check):
21+
def __init__(self) -> None:
22+
super().__init__()
23+
24+
def register(
25+
self, subparsers: "argparse._SubParsersAction", parent_parsers: Optional[List[argparse.ArgumentParser]] = None
26+
) -> None:
27+
"""Register the `black` check. The black check installs black and runs black against the target package."""
28+
parents = parent_parsers or []
29+
p = subparsers.add_parser("black", parents=parents, help="Run the code formatter black check")
30+
p.set_defaults(func=self.run)
31+
32+
def run(self, args: argparse.Namespace) -> int:
33+
"""Run the black check command."""
34+
logger.info("Running black check...")
35+
36+
set_envvar_defaults()
37+
38+
targeted = self.get_targeted_directories(args)
39+
40+
results: List[int] = []
41+
42+
for parsed in targeted:
43+
package_dir = parsed.folder
44+
package_name = parsed.name
45+
46+
executable, staging_directory = self.get_executable(args.isolate, args.command, sys.executable, package_dir)
47+
logger.info(f"Processing {package_name} for black check")
48+
49+
# install black
50+
try:
51+
install_into_venv(executable, [f"black=={BLACK_VERSION}"])
52+
except CalledProcessError as e:
53+
logger.error("Failed to install black:", e)
54+
return e.returncode
55+
56+
logger.info(f"Running black against {package_name}")
57+
58+
config_file_location = os.path.join(REPO_ROOT, "eng/black-pyproject.toml")
59+
60+
if in_ci():
61+
if not is_check_enabled(package_dir, "black"):
62+
logger.info(f"Package {package_name} opts-out of black check.")
63+
continue
64+
try:
65+
run_result = subprocess.run(
66+
[
67+
executable,
68+
"-m",
69+
"black",
70+
f"--config={config_file_location}",
71+
package_dir,
72+
],
73+
stdout=subprocess.PIPE,
74+
stderr=subprocess.PIPE,
75+
check=True,
76+
)
77+
if run_result.stderr and "reformatted" in run_result.stderr.decode("utf-8"):
78+
if in_ci():
79+
logger.info(f"The package {package_name} needs reformat. Run `black` locally to reformat.")
80+
results.append(1)
81+
else:
82+
logger.info(f"The package {package_name} was reformatted.")
83+
else:
84+
logger.info(f"The package {package_name} is properly formatted, no files changed.")
85+
86+
except subprocess.CalledProcessError as e:
87+
logger.error(f"Unable to invoke black for {package_name}. Ran into exception {e}.")
88+
89+
return max(results) if results else 0

eng/tools/azure-sdk-tools/azpysdk/main.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from .mypy import mypy
1818
from .pylint import pylint
1919
from .sphinx import sphinx
20+
from .black import black
2021

2122
from ci_tools.logging import configure_logging, logger
2223

@@ -76,6 +77,7 @@ def build_parser() -> argparse.ArgumentParser:
7677
mypy().register(subparsers, [common])
7778
pylint().register(subparsers, [common])
7879
sphinx().register(subparsers, [common])
80+
black().register(subparsers, [common])
7981

8082
return parser
8183

eng/tools/azure-sdk-tools/azpysdk/mypy.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,9 @@ def run(self, args: argparse.Namespace) -> int:
5353
try:
5454
if args.next:
5555
# use latest version of mypy
56-
install_into_venv(executable, "mypy", False)
56+
install_into_venv(executable, ["mypy"])
5757
else:
58-
install_into_venv(executable, f"mypy=={MYPY_VERSION}", False)
58+
install_into_venv(executable, [f"mypy=={MYPY_VERSION}"])
5959
except CalledProcessError as e:
6060
logger.error("Failed to install mypy:", e)
6161
return e.returncode

eng/tools/azure-sdk-tools/azpysdk/pylint.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from subprocess import CalledProcessError, check_call
77

88
from .Check import Check
9-
from ci_tools.functions import pip_install
9+
from ci_tools.functions import install_into_venv
1010
from ci_tools.variables import discover_repo_root, in_ci, set_envvar_defaults, in_ci, set_envvar_defaults
1111
from ci_tools.environment_exclusions import is_check_enabled
1212
from ci_tools.logging import logger
@@ -49,9 +49,7 @@ def run(self, args: argparse.Namespace) -> int:
4949

5050
# install dependencies
5151
try:
52-
pip_install([
53-
"azure-pylint-guidelines-checker==0.5.6", "--index-url=https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-python/pypi/simple/"
54-
], True, executable, package_dir)
52+
install_into_venv(executable, ["azure-pylint-guidelines-checker==0.5.6", "--index-url=https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-python/pypi/simple/"])
5553
except CalledProcessError as e:
5654
logger.error("Failed to install dependencies:", e)
5755
return e.returncode
@@ -60,9 +58,9 @@ def run(self, args: argparse.Namespace) -> int:
6058
try:
6159
if args.next:
6260
# use latest version of pylint
63-
pip_install(["pylint"], True, executable, package_dir)
61+
install_into_venv(executable, ["pylint"])
6462
else:
65-
pip_install([f"pylint=={PYLINT_VERSION}"], True, executable, package_dir)
63+
install_into_venv(executable, [f"pylint=={PYLINT_VERSION}"])
6664
except CalledProcessError as e:
6765
logger.error("Failed to install pylint:", e)
6866
return e.returncode

eng/tools/azure-sdk-tools/azpysdk/sphinx.py

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from pathlib import Path
1010

1111
from .Check import Check
12-
from ci_tools.functions import pip_install
12+
from ci_tools.functions import install_into_venv
1313
from ci_tools.scenario.generation import create_package_and_install
1414
from ci_tools.variables import in_ci, set_envvar_defaults
1515
from ci_tools.variables import discover_repo_root
@@ -279,23 +279,18 @@ def run(self, args: argparse.Namespace) -> int:
279279
# install sphinx
280280
try:
281281
if args.next:
282-
pip_install(
283-
["sphinx", "sphinx_rtd_theme", "myst_parser", "sphinxcontrib-jquery"],
284-
True,
285-
executable,
286-
package_dir,
282+
install_into_venv(
283+
executable, ["sphinx", "sphinx_rtd_theme", "myst_parser", "sphinxcontrib-jquery"],
287284
)
288285
else:
289-
pip_install(
286+
install_into_venv(
287+
executable,
290288
[
291289
f"sphinx=={SPHINX_VERSION}",
292290
f"sphinx_rtd_theme=={SPHINX_RTD_THEME_VERSION}",
293291
f"myst_parser=={MYST_PARSER_VERSION}",
294292
f"sphinxcontrib-jquery=={SPHINX_CONTRIB_JQUERY_VERSION}",
295293
],
296-
True,
297-
executable,
298-
package_dir,
299294
)
300295
except CalledProcessError as e:
301296
logger.error("Failed to install sphinx:", e)

eng/tools/azure-sdk-tools/azpysdk/whl.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
from .Check import Check
99

10-
from ci_tools.functions import is_error_code_5_allowed, pip_install
10+
from ci_tools.functions import is_error_code_5_allowed, install_into_venv
1111
from ci_tools.variables import set_envvar_defaults
1212
from ci_tools.parsing import ParsedSetup
1313
from ci_tools.scenario.generation import create_package_and_install
@@ -45,7 +45,7 @@ def run(self, args: argparse.Namespace) -> int:
4545

4646
if os.path.exists(dev_requirements):
4747
print(f"Installing dev_requirements at {dev_requirements}")
48-
pip_install([f"-r", f"{dev_requirements}"], True, executable, pkg)
48+
install_into_venv(executable, [f"{dev_requirements}"])
4949
else:
5050
print("Skipping installing dev_requirements")
5151

eng/tools/azure-sdk-tools/ci_tools/functions.py

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -509,10 +509,10 @@ def get_venv_python(venv_path: str) -> str:
509509

510510

511511
def install_into_venv(
512-
venv_path_or_executable: str, installation_target: str, editable: bool = True, extras: Optional[str] = None
512+
venv_path_or_executable: str, requirements: List[str]
513513
) -> None:
514514
"""
515-
Install the package into an existing venv (venv_path) without activating it.
515+
Install the requirements into an existing venv (venv_path) without activating it.
516516
517517
- Uses get_pip_command(get_venv_python) per request.
518518
- If get_pip_command returns the 'uv' wrapper, we fall back to get_venv_python -m pip
@@ -521,14 +521,8 @@ def install_into_venv(
521521
py = get_venv_python(venv_path_or_executable)
522522
pip_cmd = get_pip_command(py)
523523

524-
install_target = installation_target
525-
if extras:
526-
install_target = f"{installation_target}[{extras}]"
527-
528-
if editable:
529-
cmd = pip_cmd + ["install", "-e", install_target]
530-
else:
531-
cmd = pip_cmd + ["install", install_target]
524+
install_targets = [r.strip() for r in requirements]
525+
cmd = pip_cmd + ["install"] + install_targets
532526

533527
if pip_cmd[0] == "uv":
534528
cmd += ["--python", py]

0 commit comments

Comments
 (0)