Skip to content

Commit cbba529

Browse files
Feature/24 support a quiet flag to silence output (#86)
* Add convenience functions for console printing * Implement quiet flag Enable "PT" Bump ruff * Pass tests, fix bug with removing bitbucket ci
1 parent 49dcb5e commit cbba529

File tree

18 files changed

+276
-153
lines changed

18 files changed

+276
-153
lines changed

pyproject.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ dev = [
4848
"import-linter>=2.1",
4949
"pre-commit>=4.0.1",
5050
"pyproject-fmt>=2.4.3",
51-
"ruff>=0.7.0",
51+
"ruff>=0.7.1",
5252
]
5353
test = [
5454
"coverage[toml]>=7.6.3",
@@ -72,7 +72,7 @@ source = "vcs"
7272
line-length = 88
7373

7474
src = [ "src" ]
75-
lint.select = [ "C4", "E4", "E7", "E9", "F", "FURB", "I", "PLE", "PLR", "RUF", "SIM", "UP" ]
75+
lint.select = ["C4", "E4", "E7", "E9", "F", "FURB", "I", "PLE", "PLR", "RUF", "SIM", "UP", "PT"]
7676

7777
[tool.pytest.ini_options]
7878
testpaths = [ "tests" ]
@@ -98,6 +98,7 @@ layers = [
9898
"_interface",
9999
"_tool",
100100
"_integrations",
101+
"_console",
101102
"_utils",
102103
]
103104
containers = [ "usethis" ]

src/usethis/_console.py

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,29 @@
1-
import typer
1+
from collections.abc import Generator
2+
from contextlib import contextmanager
3+
4+
from pydantic import BaseModel
25
from rich.console import Console
36

4-
console = Console()
7+
typer_console = Console()
8+
9+
10+
class UsethisConsole(BaseModel):
11+
quiet: bool
12+
13+
def tick_print(self, msg: str) -> None:
14+
if not self.quiet:
15+
typer_console.print(f"✔ {msg}", style="green")
16+
17+
def box_print(self, msg: str) -> None:
18+
if not self.quiet:
19+
typer_console.print(f"☐ {msg}", style="blue")
20+
21+
@contextmanager
22+
def set(self, *, quiet: bool) -> Generator[None, None, None]:
23+
"""Temporarily set the console to quiet mode."""
24+
self.quiet = quiet
25+
yield
26+
self.quiet = False
27+
528

6-
offline_opt = typer.Option(False, "--offline", help="Disable network access")
29+
console = UsethisConsole(quiet=False)

src/usethis/_integrations/bitbucket/config.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def add_bitbucket_pipeline_config() -> None:
2727
# Early exit; the file already exists
2828
return
2929

30-
console.print("✔ Writing 'bitbucket-pipelines.yml'.", style="green")
30+
console.tick_print("Writing 'bitbucket-pipelines.yml'.")
3131
yaml_contents = _YAML_CONTENTS
3232

3333
(Path.cwd() / "bitbucket-pipelines.yml").write_text(yaml_contents)
@@ -38,5 +38,5 @@ def remove_bitbucket_pipeline_config() -> None:
3838
# Early exit; the file already doesn't exist
3939
return
4040

41-
console.print("✔ Removing bitbucket-pipelines.yml file", style="green")
41+
console.tick_print("Removing 'bitbucket-pipelines.yml' file.")
4242
(Path.cwd() / "bitbucket-pipelines.yml").unlink()

src/usethis/_integrations/pre_commit/core.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ def add_pre_commit_config() -> None:
2121
# Early exit; the file already exists
2222
return
2323

24-
console.print("✔ Writing '.pre-commit-config.yaml'.", style="green")
24+
console.tick_print("Writing '.pre-commit-config.yaml'.")
2525
try:
2626
pkg_version = get_github_latest_tag("abravalheri", "validate-pyproject")
2727
except GitHubTagError:
@@ -37,12 +37,12 @@ def remove_pre_commit_config() -> None:
3737
# Early exit; the file already doesn't exist
3838
return
3939

40-
console.print("✔ Removing .pre-commit-config.yaml file", style="green")
40+
console.tick_print("Removing .pre-commit-config.yaml file.")
4141
(Path.cwd() / ".pre-commit-config.yaml").unlink()
4242

4343

4444
def install_pre_commit() -> None:
45-
console.print("✔ Ensuring pre-commit hooks are installed.", style="green")
45+
console.tick_print("Ensuring pre-commit hooks are installed.")
4646
subprocess.run(
4747
["uv", "run", "pre-commit", "install"],
4848
check=True,
@@ -51,7 +51,7 @@ def install_pre_commit() -> None:
5151

5252

5353
def uninstall_pre_commit() -> None:
54-
console.print("✔ Ensuring pre-commit hooks are uninstalled.", style="green")
54+
console.tick_print("Ensuring pre-commit hooks are uninstalled.")
5555
subprocess.run(
5656
["uv", "run", "pre-commit", "uninstall"],
5757
check=True,

src/usethis/_integrations/pytest/core.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@ def add_pytest_dir() -> None:
88
tests_dir = Path.cwd() / "tests"
99

1010
if not tests_dir.exists():
11-
console.print("✔ Creating '/tests'.", style="green")
11+
console.tick_print("Creating '/tests'.")
1212
tests_dir.mkdir()
1313

1414
if (tests_dir / "conftest.py").exists():
1515
# Early exit; conftest.py already exists
1616
return
1717

18-
console.print("✔ Writing '/tests/conftest.py'.", style="green")
18+
console.tick_print("Writing '/tests/conftest.py'.")
1919
(tests_dir / "conftest.py").write_text(
2020
"collect_ignore_glob = []\npytest_plugins = []\n"
2121
)
@@ -30,10 +30,8 @@ def remove_pytest_dir() -> None:
3030

3131
if set(tests_dir.iterdir()) <= {tests_dir / "conftest.py"}:
3232
# The only file in the directory is conftest.py
33-
console.print("✔ Removing '/tests'.", style="green")
33+
console.tick_print("Removing '/tests'.")
3434
shutil.rmtree(tests_dir)
3535
else:
36-
console.print(
37-
"☐ Reconfigure the /tests directory to run without pytest", style="blue"
38-
)
36+
console.box_print("Reconfigure the /tests directory to run without pytest.")
3937
# Note we don't actually remove the directory, just explain what needs to be done.

src/usethis/_integrations/ruff/rules.py

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,7 @@ def select_ruff_rules(rules: list[str]) -> None:
1515

1616
rules_str = ", ".join([f"'{rule}'" for rule in rules])
1717
s = "" if len(rules) == 1 else "s"
18-
console.print(
19-
f"✔ Enabling ruff rule{s} {rules_str} in 'pyproject.toml'.",
20-
style="green",
21-
)
18+
console.tick_print(f"Enabling ruff rule{s} {rules_str} in 'pyproject.toml'.")
2219

2320
append_config_list(["tool", "ruff", "lint", "select"], rules)
2421

@@ -33,10 +30,7 @@ def deselect_ruff_rules(rules: list[str]) -> None:
3330

3431
rules_str = ", ".join([f"'{rule}'" for rule in rules])
3532
s = "" if len(rules) == 1 else "s"
36-
console.print(
37-
f"✔ Disabling ruff rule{s} {rules_str} in 'pyproject.toml'.",
38-
style="green",
39-
)
33+
console.tick_print(f"Disabling ruff rule{s} {rules_str} in 'pyproject.toml'.")
4034

4135
remove_from_config_list(["tool", "ruff", "lint", "select"], rules)
4236

src/usethis/_integrations/uv/deps.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,7 @@ def add_deps_to_group(pypi_names: list[str], group: str, *, offline: bool) -> No
4444
# Early exit; the tool is already a dev dependency.
4545
continue
4646

47-
console.print(
48-
f"✔ Adding '{dep}' to the '{group}' dependency group.", style="green"
49-
)
47+
console.tick_print(f"Adding '{dep}' to the '{group}' dependency group.")
5048
if not offline:
5149
subprocess.run(
5250
["uv", "add", "--group", group, "--quiet", dep],
@@ -68,9 +66,7 @@ def remove_deps_from_group(pypi_names: list[str], group: str, *, offline: bool)
6866
# Early exit; the tool is already not a dependency.
6967
continue
7068

71-
console.print(
72-
f"✔ Removing '{dep}' from the '{group}' dependency group.", style="green"
73-
)
69+
console.tick_print(f"Removing '{dep}' from the '{group}' dependency group.")
7470
if not offline:
7571
subprocess.run(
7672
[

src/usethis/_interface/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
import typer
22

33
offline_opt = typer.Option(False, "--offline", help="Disable network access")
4+
quiet_opt = typer.Option(False, "--quiet", help="Suppress output")

src/usethis/_interface/browse.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import typer
22

33
from usethis._console import console
4+
from usethis._interface import offline_opt, quiet_opt
45

56
app = typer.Typer(help="Visit important project-related web pages.")
67

@@ -12,13 +13,18 @@ def pypi(
1213
browser: bool = typer.Option(
1314
False, "--browser", help="Open the URL in the default web browser."
1415
),
16+
offline: bool = offline_opt,
17+
quiet: bool = quiet_opt,
1518
) -> None:
16-
_pypi(package=package, browser=browser)
19+
with console.set(quiet=quiet):
20+
_pypi(package=package, browser=browser, offline=offline)
1721

1822

19-
def _pypi(*, package: str, browser: bool = False) -> None:
23+
def _pypi(*, package: str, browser: bool = False, offline: bool = False) -> None:
24+
_ = offline # Already no network access required
25+
2026
url = f"https://pypi.org/project/{package}/"
2127
if browser:
2228
typer.launch(url)
2329
else:
24-
console.print(f"Open URL <{url}>.", style="blue")
30+
console.box_print(f"Open URL <{url}>.")

src/usethis/_interface/ci.py

Lines changed: 40 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from usethis._integrations.pyproject.requires_python import (
1212
get_supported_major_python_versions,
1313
)
14-
from usethis._interface import offline_opt
14+
from usethis._interface import offline_opt, quiet_opt
1515
from usethis._tool import PreCommitTool, PytestTool
1616

1717
app = typer.Typer(help="Add config for Continuous Integration (CI) pipelines.")
@@ -23,62 +23,64 @@ def bitbucket(
2323
False, "--remove", help="Remove Bitbucket pipelines CI instead of adding it."
2424
),
2525
offline: bool = offline_opt,
26+
quiet: bool = quiet_opt,
2627
) -> None:
27-
_bitbucket(remove=remove, offline=offline)
28+
with console.set(quiet=quiet):
29+
_bitbucket(remove=remove, offline=offline)
2830

2931

3032
def _bitbucket(*, remove: bool = False, offline: bool = False) -> None:
3133
_ = offline # Already offline
3234

33-
config_yaml_path = Path.cwd() / "bitbucket-pipelines.yml"
34-
35-
if config_yaml_path.exists():
36-
if remove:
37-
remove_bitbucket_pipeline_config()
38-
else:
35+
if not remove:
36+
if (Path.cwd() / "bitbucket-pipelines.yml").exists():
3937
# Early exit; the file already exists so we will leave it alone.
4038
return
4139

42-
add_bitbucket_pipeline_config()
40+
add_bitbucket_pipeline_config()
4341

44-
steps = []
45-
if PreCommitTool().is_used():
46-
steps.append(
47-
Step(
48-
name="Run pre-commit hooks",
49-
caches=["uv", "pre-commit"],
50-
script=[
51-
StepRef(name="install-uv"),
52-
"uv run pre-commit run --all-files",
53-
],
54-
)
55-
)
56-
if PytestTool().is_used():
57-
matrix = get_supported_major_python_versions()
58-
for version in matrix:
42+
steps = []
43+
if PreCommitTool().is_used():
5944
steps.append(
6045
Step(
61-
name=f"Run tests with Python 3.{version}",
62-
caches=["uv"],
46+
name="Run pre-commit hooks",
47+
caches=["uv", "pre-commit"],
6348
script=[
6449
StepRef(name="install-uv"),
65-
f"uv run --python 3.{version} pytest",
50+
"uv run pre-commit run --all-files",
6651
],
6752
)
6853
)
54+
if PytestTool().is_used():
55+
matrix = get_supported_major_python_versions()
56+
for version in matrix:
57+
steps.append(
58+
Step(
59+
name=f"Run tests with Python 3.{version}",
60+
caches=["uv"],
61+
script=[
62+
StepRef(name="install-uv"),
63+
f"uv run --python 3.{version} pytest",
64+
],
65+
)
66+
)
6967

70-
if not steps:
71-
# Add a dummy step
72-
steps.append(
73-
Step(
74-
name="Placeholder - add your own steps!",
75-
caches=[],
76-
script=[StepRef(name="install-uv"), "echo 'Hello, world!'"],
68+
if not steps:
69+
# Add a dummy step
70+
steps.append(
71+
Step(
72+
name="Placeholder - add your own steps!",
73+
caches=[],
74+
script=[StepRef(name="install-uv"), "echo 'Hello, world!'"],
75+
)
7776
)
78-
)
7977

80-
console.print("☐ Populate the placeholder step in 'bitbucket-pipelines.yml'.")
78+
console.box_print(
79+
"Populate the placeholder step in 'bitbucket-pipelines.yml'."
80+
)
8181

82-
add_steps(steps, is_parallel=True)
82+
add_steps(steps, is_parallel=True)
8383

84-
console.print("☐ Run your first pipeline on the Bitbucket website.")
84+
console.box_print("Run your first pipeline on the Bitbucket website.")
85+
else:
86+
remove_bitbucket_pipeline_config()

0 commit comments

Comments
 (0)