Skip to content

Commit

Permalink
Add --projects cli flag to black-primer
Browse files Browse the repository at this point in the history
Makes it possible to run a subset of projects on black primer
  • Loading branch information
nipunn1313 committed Oct 22, 2021
1 parent 2f3fa1f commit 553faf0
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 4 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
Expand Up @@ -7,6 +7,7 @@
- Add new `--workers` parameter (#2514)
- Fixed feature detection for positional-only arguments in lambdas (#2532)
- Bumped typed-ast version minimum to 1.4.3 for 3.10 compatiblity (#2519)
- Add primer support for --projects (#2555)

### _Blackd_

Expand Down
7 changes: 7 additions & 0 deletions src/black_primer/cli.py
Expand Up @@ -48,11 +48,13 @@ async def async_main(
keep: bool,
long_checkouts: bool,
no_diff: bool,
projects: str,
rebase: bool,
workdir: str,
workers: int,
) -> int:
work_path = Path(workdir)
projects_to_run = set(p for p in projects.split(",")) if projects else None
if not work_path.exists():
LOG.debug(f"Creating {work_path}")
work_path.mkdir()
Expand All @@ -70,6 +72,7 @@ async def async_main(
long_checkouts,
rebase,
no_diff,
projects_to_run,
)
return int(ret_val)
finally:
Expand Down Expand Up @@ -116,6 +119,10 @@ async def async_main(
show_default=True,
help="Disable showing source file changes in black output",
)
@click.option(
"--projects",
help="Comma separated list of projects to run (Default: run all)",
)
@click.option(
"-R",
"--rebase",
Expand Down
16 changes: 13 additions & 3 deletions src/black_primer/lib.py
Expand Up @@ -20,6 +20,7 @@
NamedTuple,
Optional,
Sequence,
Set,
Tuple,
Union,
)
Expand Down Expand Up @@ -283,17 +284,25 @@ def handle_PermissionError(

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

# TODO: Offer more options here
# e.g. Run on X random packages or specific sub list etc.
# e.g. Run on X random packages etc.
project_names = sorted(config["projects"].keys())
queue: asyncio.Queue = asyncio.Queue(maxsize=len(project_names))
for project in project_names:
await queue.put(project)
if projects_to_run is None or project in projects_to_run:
await queue.put(project)
if projects_to_run:
projects_to_run.remove(project)

if projects_to_run:
LOG.error(f"Project not found: {projects_to_run}")
LOG.error(f"Available projects: {project_names}")

return config, queue

Expand Down Expand Up @@ -369,6 +378,7 @@ async def process_queue(
long_checkouts: bool = False,
rebase: bool = False,
no_diff: bool = False,
projects_to_run: Optional[Set[str]] = None,
) -> int:
"""
Process the queue with X workers and evaluate results
Expand All @@ -383,7 +393,7 @@ async def process_queue(
results.stats["success"] = 0
results.stats["wrong_py_ver"] = 0

config, queue = await load_projects_queue(Path(config_file))
config, queue = await load_projects_queue(Path(config_file), projects_to_run)
project_count = queue.qsize()
s = "" if project_count == 1 else "s"
LOG.info(f"{project_count} project{s} to run Black over")
Expand Down
41 changes: 40 additions & 1 deletion tests/test_primer.py
Expand Up @@ -11,7 +11,7 @@
from platform import system
from subprocess import CalledProcessError
from tempfile import TemporaryDirectory, gettempdir
from typing import Any, Callable, Generator, Iterator, Tuple
from typing import Any, Callable, Generator, Iterator, List, Tuple, TypeVar
from unittest.mock import Mock, patch

from click.testing import CliRunner
Expand Down Expand Up @@ -87,6 +87,24 @@ async def return_zero(*args: Any, **kwargs: Any) -> int:
return 0


if sys.version_info >= (3, 9):
T = TypeVar("T")
Q = asyncio.Queue[T]
else:
T = Any
Q = asyncio.Queue


def collect(queue: Q) -> List[T]:
ret = []
while True:
try:
item = queue.get_nowait()
ret.append(item)
except asyncio.QueueEmpty:
return ret


class PrimerLibTests(unittest.TestCase):
def test_analyze_results(self) -> None:
fake_results = lib.Results(
Expand Down Expand Up @@ -200,6 +218,26 @@ def test_process_queue(self, mock_stdout: Mock) -> None:
)
self.assertEqual(0, return_val)

@event_loop()
def test_load_projects_queue(self) -> None:
"""Test the process queue on primer itself
- If you have non black conforming formatting in primer itself this can fail"""
loop = asyncio.get_event_loop()
config_path = Path(lib.__file__).parent / "primer.json"

config, projects_queue = loop.run_until_complete(
lib.load_projects_queue(config_path, None)
)
projects = collect(projects_queue)
self.assertEqual(len(config["projects"].keys()), 22)
self.assertEqual(set(projects), set(config["projects"].keys()))

config, projects_queue = loop.run_until_complete(
lib.load_projects_queue(config_path, set(["django", "pyramid", "nonsense"]))
)
projects = collect(projects_queue)
self.assertEqual(projects, ["django", "pyramid"])


class PrimerCLITests(unittest.TestCase):
@event_loop()
Expand All @@ -215,6 +253,7 @@ def test_async_main(self) -> None:
"workdir": str(work_dir),
"workers": 69,
"no_diff": False,
"projects": "",
}
with patch("black_primer.cli.lib.process_queue", return_zero):
return_val = loop.run_until_complete(cli.async_main(**args)) # type: ignore
Expand Down

0 comments on commit 553faf0

Please sign in to comment.