Skip to content

Commit 5675feb

Browse files
committed
Add --projects cli flag to black-primer
Makes it possible to run a subset of projects on black primer
1 parent 62ed538 commit 5675feb

File tree

6 files changed

+68
-4
lines changed

6 files changed

+68
-4
lines changed

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
- Add new `--workers` parameter (#2514)
99
- Fixed feature detection for positional-only arguments in lambdas (#2532)
1010
- Bumped typed-ast version minimum to 1.4.3 for 3.10 compatiblity (#2519)
11+
- Add primer support for --projects (#2555)
1112

1213
### _Blackd_
1314

mypy.ini

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,7 @@ cache_dir=/dev/null
3535
[mypy-black_primer.*]
3636
# Until we're not supporting 3.6 primer needs this
3737
disallow_any_generics=False
38+
39+
[mypy-tests.test_primer]
40+
# Until we're not supporting 3.6 primer needs this
41+
disallow_any_generics=False

src/black_primer/cli.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,13 @@ async def async_main(
4848
keep: bool,
4949
long_checkouts: bool,
5050
no_diff: bool,
51+
projects: str,
5152
rebase: bool,
5253
workdir: str,
5354
workers: int,
5455
) -> int:
5556
work_path = Path(workdir)
57+
projects_to_run = set(p for p in projects.split(",")) if projects else None
5658
if not work_path.exists():
5759
LOG.debug(f"Creating {work_path}")
5860
work_path.mkdir()
@@ -70,6 +72,7 @@ async def async_main(
7072
long_checkouts,
7173
rebase,
7274
no_diff,
75+
projects_to_run,
7376
)
7477
return int(ret_val)
7578
finally:
@@ -116,6 +119,10 @@ async def async_main(
116119
show_default=True,
117120
help="Disable showing source file changes in black output",
118121
)
122+
@click.option(
123+
"--projects",
124+
help="Comma separated list of projects to run (Default: run all)",
125+
)
119126
@click.option(
120127
"-R",
121128
"--rebase",

src/black_primer/lib.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
NamedTuple,
2121
Optional,
2222
Sequence,
23+
Set,
2324
Tuple,
2425
Union,
2526
)
@@ -283,17 +284,26 @@ def handle_PermissionError(
283284

284285
async def load_projects_queue(
285286
config_path: Path,
287+
projects_to_run: Optional[Set[str]],
286288
) -> Tuple[Dict[str, Any], asyncio.Queue]:
287289
"""Load project config and fill queue with all the project names"""
288290
with config_path.open("r") as cfp:
289291
config = json.load(cfp)
290292

291293
# TODO: Offer more options here
292-
# e.g. Run on X random packages or specific sub list etc.
294+
# e.g. Run on X random packages etc.
293295
project_names = sorted(config["projects"].keys())
296+
projects_to_run = projects_to_run or set(project_names)
294297
queue: asyncio.Queue = asyncio.Queue(maxsize=len(project_names))
295298
for project in project_names:
296-
await queue.put(project)
299+
if project in projects_to_run:
300+
await queue.put(project)
301+
projects_to_run.remove(project)
302+
303+
if projects_to_run:
304+
LOG.error(
305+
f"Project not found: {projects_to_run}. Available projects: {project_names}"
306+
)
297307

298308
return config, queue
299309

@@ -369,6 +379,7 @@ async def process_queue(
369379
long_checkouts: bool = False,
370380
rebase: bool = False,
371381
no_diff: bool = False,
382+
projects_to_run: Optional[Set[str]] = None,
372383
) -> int:
373384
"""
374385
Process the queue with X workers and evaluate results
@@ -383,7 +394,7 @@ async def process_queue(
383394
results.stats["success"] = 0
384395
results.stats["wrong_py_ver"] = 0
385396

386-
config, queue = await load_projects_queue(Path(config_file))
397+
config, queue = await load_projects_queue(Path(config_file), projects_to_run)
387398
project_count = queue.qsize()
388399
s = "" if project_count == 1 else "s"
389400
LOG.info(f"{project_count} project{s} to run Black over")

tests/test_format.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@
9393
"src/black/strings.py",
9494
"src/black/trans.py",
9595
"src/blackd/__init__.py",
96+
"src/black_primer/cli.py",
97+
"src/black_primer/lib.py",
9698
"src/blib2to3/pygram.py",
9799
"src/blib2to3/pytree.py",
98100
"src/blib2to3/pgen2/conv.py",

tests/test_primer.py

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from platform import system
1212
from subprocess import CalledProcessError
1313
from tempfile import TemporaryDirectory, gettempdir
14-
from typing import Any, Callable, Iterator, Tuple
14+
from typing import Any, Callable, Iterator, List, Tuple, TypeVar
1515
from unittest.mock import Mock, patch
1616

1717
from click.testing import CliRunner
@@ -89,6 +89,24 @@ async def return_zero(*args: Any, **kwargs: Any) -> int:
8989
return 0
9090

9191

92+
if sys.version_info >= (3, 9):
93+
T = TypeVar("T")
94+
Q = asyncio.Queue[T]
95+
else:
96+
T = Any
97+
Q = asyncio.Queue
98+
99+
100+
def collect(queue: Q) -> List[T]:
101+
ret = []
102+
while True:
103+
try:
104+
item = queue.get_nowait()
105+
ret.append(item)
106+
except asyncio.QueueEmpty:
107+
return ret
108+
109+
92110
class PrimerLibTests(unittest.TestCase):
93111
def test_analyze_results(self) -> None:
94112
fake_results = lib.Results(
@@ -202,6 +220,26 @@ def test_process_queue(self, mock_stdout: Mock) -> None:
202220
)
203221
self.assertEqual(0, return_val)
204222

223+
@event_loop()
224+
def test_load_projects_queue(self) -> None:
225+
"""Test the process queue on primer itself
226+
- If you have non black conforming formatting in primer itself this can fail"""
227+
loop = asyncio.get_event_loop()
228+
config_path = Path(lib.__file__).parent / "primer.json"
229+
230+
config, projects_queue = loop.run_until_complete(
231+
lib.load_projects_queue(config_path, None)
232+
)
233+
projects = collect(projects_queue)
234+
self.assertEqual(len(config["projects"].keys()), 22)
235+
self.assertEqual(set(projects), set(config["projects"].keys()))
236+
237+
config, projects_queue = loop.run_until_complete(
238+
lib.load_projects_queue(config_path, set(["django", "pyramid", "nonsense"]))
239+
)
240+
projects = collect(projects_queue)
241+
self.assertEqual(projects, ["django", "pyramid"])
242+
205243

206244
class PrimerCLITests(unittest.TestCase):
207245
@event_loop()
@@ -217,6 +255,7 @@ def test_async_main(self) -> None:
217255
"workdir": str(work_dir),
218256
"workers": 69,
219257
"no_diff": False,
258+
"projects": "",
220259
}
221260
with patch("black_primer.cli.lib.process_queue", return_zero):
222261
return_val = loop.run_until_complete(cli.async_main(**args)) # type: ignore

0 commit comments

Comments
 (0)