Skip to content

Commit f44669a

Browse files
Add --backend flag to over-ride manual detection of uv (#826)
* First draft of adding --backend flag to the usethis tool interface * Tweak backend selection logic to check whether uv is available. Fix add_* function when needing to remove Tweak test config * Move tests to reflect new package structure * Remove duplicated `Test` in `TestOpinionatedUVInit` name * Revert to importing module to pass mocked tests * Add tests for `is_uv_available` and for `get_backend` * Move tests module to reflect package restructure * Test `add_default_groups` for the `backend=BackendEnum.none` case * Remove empty file * Add some tests to the deps module * Document `ForbiddenBackendError` in docstring to `call_uv_subprocess` * Add `--backend` option to all interfaces where it makes sense * Fix broken test * Remove disclaimers regarding uv-centrism * Bump pyright from v1.1.399 -> v1.1.403 * Add some tests for the none backend when using requirements.txt * Implement `get_project_deps` and tests * Implement `Dependency.to_requirements_string` * Use `Dependency.to_requirements_string()` in `Dependency.__str__` * Remove duplicated code for `get_project_deps` * Fix broken references and rename `to_requirements_string` to `to_requirement_string` * Use `get_backend()` in `use_requirements_txt` This will resolve the "auto" case and allows for proper type checking using `assert_never` * Create correct requirements file using none backend * Generate expected messages for `use_requirements_txt` with none backend * Refactor to create abstract project init functions, making it backend agnostic * Collate UI modules into their own layer * Fix recursion issue in `ensure_pyproject_toml` by dispatching to `ensure_pyproject_toml_via_uv` instead of self * Update test to reflect new uv-detection heuristics * Skip test on rate limits * Catch exceptions in failing tests' CLI invocation * Support none backend in `ensure_pyproject_toml` * Simplify instructions for checking `uv` version in README * Fix issue with missing directory when subprocessing uv. * Add failing test `TestProjectInit.test_none_backend` in `tests\usethis\test_init.py` * Add `project_init` implementation for none backend * Fix broken imports for re-homed test * Sync README with docs * Rename uv+python integration functions for clarity * Support none backend in `install_pre_commit_hooks` Move `usethis._backend` to `usethis._integrations.backend.dispatch` * Support none backend in `uninstall_pre_commit_hooks` * Test all interfaces, add missing backend pass-through * Fix broken header in reference.md * Fix file manager issues in tests * Fix backend flag for `usethis status` * Don't create README in `use_ci_bitbucket` * Don't eagerly create `pyproject.toml` in `usethis tool codespell` * Break up the complexity of `Tool.add_configs` with a new helper method * Don't overwrite an alert-only state in `Tool.add_configs` and `RuffTool.apply_rule_config` This is something to watch out for in the future. * Display message when creating input files when adding config Pass all `test_none_backend` tests * Pass `test_none_backend` tests * Change test to reflect new behaviour * Respect backend in print-how-to-use messages * Don't use bitwise operators to avoid confusion * rework `is_uv_used` for robustness * Refactor `add_configs` for clarity
1 parent 5d0b818 commit f44669a

121 files changed

Lines changed: 1850 additions & 692 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,6 @@ usethis gives detailed messages about what it is doing (and what you need to do
2525

2626
Inspired by an [**R** package of the same name](https://usethis.r-lib.org/index.html), this package brings a similar experience to the Python ecosystem as a CLI tool.
2727

28-
> [!TIP]
29-
> usethis is great for fresh projects using [uv](https://docs.astral.sh/uv), but also supports updating existing projects. However, this should be considered experimental. If you encounter problems or have feedback, please [open an issue](https://github.com/usethis-python/usethis-python/issues/new?template=idea.md).
30-
3128
## Highlights
3229

3330
- 🧰 First-class support for state-of-the-practice tooling: uv, Ruff, pytest, pre-commit, and many more.
@@ -40,10 +37,7 @@ Inspired by an [**R** package of the same name](https://usethis.r-lib.org/index.
4037
## 🧭 Getting Started
4138

4239
First, it is strongly recommended you [install the uv package manager](https://docs.astral.sh/uv/getting-started/installation/): this is a simple, documented process. If you're already using uv, make sure you're using at least
43-
version v0.6.8. To check this, run `uv self version` to check (if available, otherwise `uv version`), and run `uv self update` to upgrade.
44-
45-
> [!TIP]
46-
> At the moment, usethis assumes you will have uv installed in some circumstances. Support for projects that don't use uv is planned for late 2025.
40+
version v0.6.8 (run `uv --version` to check, and `uv self update` to upgrade).
4741

4842
You can install usethis directly into the project environment:
4943

@@ -189,9 +183,8 @@ If you're using Cookiecutter, then you can update to a latest version of a templ
189183

190184
Major features planned for later in 2025 are:
191185

192-
- Support for users who aren't using uv, e.g. poetry users,
193-
- Support for automated GitHub Actions workflows ([#57](https://github.com/usethis-python/usethis-python/issues/57)), and
194-
- Support for a typechecker (likely Pyright, [#121](https://github.com/usethis-python/usethis-python/issues/121)).
186+
- Support for automated GitHub Actions workflows ([#57](https://github.com/usethis-python/usethis-python/issues/57)),
187+
- Support for a typechecker (likely Pyright, [#121](https://github.com/usethis-python/usethis-python/issues/121)), and
195188

196189
Other features are tracked in the [GitHub Issues](https://github.com/usethis-python/usethis-python/issues) page.
197190

docs/cli/reference.md

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ Supported options:
4040
- `--offline` to disable network access and rely on caches
4141
- `--quiet` to suppress output
4242
- `--frozen` to leave the virtual environment and lockfile unchanged (i.e. do not install dependencies, nor update lockfiles)
43+
- `--backend` to specify a package manager backend to use. The default is to auto-detect.
44+
Possible values:
45+
- `auto` to auto-detect the backend (default)
46+
- `uv` to use the [uv](https://docs.astral.sh/uv) package manager
47+
- `none` to not use a package manager backend and display messages for some operations.
4348

4449
## `usethis doc`
4550

@@ -78,6 +83,11 @@ Supported options:
7883
- `--offline` to disable network access and rely on caches
7984
- `--frozen` to leave the virtual environment and lockfile unchanged
8085
- `--quiet` to suppress output
86+
- `--backend` to specify a package manager backend to use. The default is to auto-detect.
87+
Possible values:
88+
- `auto` to auto-detect the backend (default)
89+
- `uv` to use the [uv](https://docs.astral.sh/uv) package manager
90+
- `none` to not use a package manager backend and display messages for some operations.
8191

8292
See [`usethis tool`](#usethis-tool) for more information.
8393

@@ -98,6 +108,11 @@ Supported options:
98108
- `--offline` to disable network access and rely on caches
99109
- `--frozen` to leave the virtual environment and lockfile unchanged
100110
- `--quiet` to suppress output
111+
- `--backend` to specify a package manager backend to use. The default is to auto-detect.
112+
Possible values:
113+
- `auto` to auto-detect the backend (default)
114+
- `uv` to use the [uv](https://docs.astral.sh/uv) package manager
115+
- `none` to not use a package manager backend and display messages for some operations.
101116

102117
See [`usethis tool`](#usethis-tool) for more information.
103118

@@ -118,6 +133,11 @@ Supported options:
118133
- `--offline` to disable network access and rely on caches
119134
- `--frozen` to leave the virtual environment and lockfile unchanged
120135
- `--quiet` to suppress output
136+
- `--backend` to specify a package manager backend to use. The default is to auto-detect.
137+
Possible values:
138+
- `auto` to auto-detect the backend (default)
139+
- `uv` to use the [uv](https://docs.astral.sh/uv) package manager
140+
- `none` to not use a package manager backend and display messages for some operations.
121141

122142
See [`usethis tool`](#usethis-tool) for more information.
123143

@@ -138,6 +158,11 @@ Supported options:
138158
- `--offline` to disable network access and rely on caches
139159
- `--frozen` to leave the virtual environment and lockfile unchanged
140160
- `--quiet` to suppress output
161+
- `--backend` to specify a package manager backend to use. The default is to auto-detect.
162+
Possible values:
163+
- `auto` to auto-detect the backend (default)
164+
- `uv` to use the [uv](https://docs.astral.sh/uv) package manager
165+
- `none` to not use a package manager backend and display messages for some operations.
141166

142167
See [`usethis tool`](#usethis-tool) for more information.
143168

@@ -183,6 +208,11 @@ Supported options:
183208
- `--offline` to disable network access and rely on caches
184209
- `--frozen` to leave the virtual environment and lockfile unchanged
185210
- `--quiet` to suppress output
211+
- `--backend` to specify a package manager backend to use. The default is to auto-detect.
212+
Possible values:
213+
- `auto` to auto-detect the backend (default)
214+
- `uv` to use the [uv](https://docs.astral.sh/uv) package manager
215+
- `none` to not use a package manager backend and display messages for some operations.
186216

187217
For `usethis tool ruff`, in addition to the above options, you can also specify:
188218

@@ -203,6 +233,11 @@ Supported options:
203233
- `--offline` to disable network access and rely on caches
204234
- `--quiet` to suppress output
205235
- `--frozen` to leave the virtual environment and lockfile unchanged (i.e. do not install dependencies, nor update lockfiles)
236+
- `--backend` to specify a package manager backend to use. The default is to auto-detect.
237+
Possible values:
238+
- `auto` to auto-detect the backend (default)
239+
- `uv` to use the [uv](https://docs.astral.sh/uv) package manager
240+
- `none` to not use a package manager backend and display messages for some operations.
206241

207242
## `usethis badge`
208243

@@ -229,8 +264,13 @@ Add a README.md file to the project.
229264

230265
Supported options:
231266

232-
- `--quiet` to suppress output
233267
- `--badges` to also add badges to the README.md file
268+
- `--quiet` to suppress output
269+
- `--backend` to specify a package manager backend to use. The default is to auto-detect.
270+
Possible values:
271+
- `auto` to auto-detect the backend (default)
272+
- `uv` to use the [uv](https://docs.astral.sh/uv) package manager
273+
- `none` to not use a package manager backend and display messages for some operations.
234274

235275
## `usethis author`
236276

@@ -245,6 +285,11 @@ Other supported options:
245285
- `--email` to set the author email address
246286
- `--overwrite` to overwrite all existing author information
247287
- `--quiet` to suppress output
288+
- `--backend` to specify a package manager backend to use. The default is to auto-detect.
289+
Possible values:
290+
- `auto` to auto-detect the backend (default)
291+
- `uv` to use the [uv](https://docs.astral.sh/uv) package manager
292+
- `none` to not use a package manager backend and display messages for some operations.
248293

249294
## `usethis docstyle <style>`
250295

@@ -267,6 +312,11 @@ Supported options:
267312
- `--offline` to disable network access and rely on caches
268313
- `--quiet` to suppress output
269314
- `--frozen` to leave the virtual environment and lockfile unchanged (i.e. do not install dependencies, nor update lockfiles)
315+
- `--backend` to specify a package manager backend to use. The default is to auto-detect.
316+
Possible values:
317+
- `auto` to auto-detect the backend (default)
318+
- `uv` to use the [uv](https://docs.astral.sh/uv) package manager
319+
- `none` to not use a package manager backend and display messages for some operations.
270320

271321
## `usethis rule <rulecode>`
272322

@@ -286,6 +336,11 @@ Supported options:
286336
- `--ignore` to add the rule to the ignore list (or remove it if --remove is specified).
287337
- `--offline` to disable network access and rely on caches
288338
- `--quiet` to suppress output
339+
- `--backend` to specify a package manager backend to use. The default is to auto-detect.
340+
Possible values:
341+
- `auto` to auto-detect the backend (default)
342+
- `uv` to use the [uv](https://docs.astral.sh/uv) package manager
343+
- `none` to not use a package manager backend and display messages for some operations.
289344

290345
## `usethis status <status>`
291346

@@ -303,8 +358,8 @@ Possible values (required):
303358

304359
Supported options:
305360

306-
- `--quiet` to suppress output
307361
- `--badges` to add an associated badge to the README file
362+
- `--quiet` to suppress output
308363

309364
## `usethis list`
310365

docs/getting-started.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
# 🧭 Getting Started
22

33
First, it is strongly recommended you [install the uv package manager](https://docs.astral.sh/uv/getting-started/installation/): this is a simple, documented process. If you're already using uv, make sure you're using at least
4-
version v0.6.8. To check this, run `uv self version` to check (if available, otherwise `uv version`), and run `uv self update` to upgrade.
5-
6-
At the moment, usethis assumes you will have uv installed in some circumstances. Support for projects that don't use uv is planned for late 2025.
4+
version v0.6.8 (run `uv --version` to check, and `uv self update` to upgrade).
75

86
You can install usethis directly into the project environment:
97

docs/index.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@ usethis gives detailed messages about what it is doing (and what you need to do
1212

1313
Inspired by an [**R** package of the same name](https://usethis.r-lib.org/index.html), this package brings a similar experience to the Python ecosystem as a CLI tool.
1414

15-
usethis is great for fresh projects using [uv](https://docs.astral.sh/uv), but also supports updating existing projects. However, this should be considered experimental. If you encounter problems or have feedback, please [open an issue](https://github.com/usethis-python/usethis-python/issues/new?template=idea.md).
16-
1715
## Highlights
1816

1917
- 🧰 First-class support for state-of-the-practice tooling: uv, Ruff, pytest, pre-commit, and many more.

pyproject.toml

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -183,29 +183,35 @@ name = "usethis"
183183
type = "layers"
184184
layers = [
185185
"_test | __main__",
186-
"_app",
187-
"_interface",
188-
"_options",
186+
"_ui",
187+
# Tool implementations
189188
"_toolset",
190189
"_core",
191190
"_tool",
191+
# Specific config file and backend implementations
192+
"_deps | _init",
192193
"_config_file",
193194
"_integrations",
194-
"_io | _pipeweld | _subprocess | _console",
195-
"_config | errors",
195+
"_io | _subprocess | _console",
196+
# Global state and constants
197+
"_config",
198+
"_types | errors",
199+
# Completely independent helper modules
200+
"_pipeweld",
196201
]
197202
containers = [ "usethis" ]
198203
exhaustive = true
199204
exhaustive_ignores = [ "_version" ]
200205

201206
[[tool.importlinter.contracts]]
202-
name = "usethis._interface"
207+
name = "usethis._ui"
203208
type = "layers"
204209
layers = [
205-
# Note; if you're adding an interface, make sure it's in the README too.
206-
"author | badge | browse | ci | doc | docstyle | format_ | init | lint | list | readme | rule | show | spellcheck | status | test | tool | version",
210+
"app",
211+
"interface",
212+
"options",
207213
]
208-
containers = [ "usethis._interface" ]
214+
containers = [ "usethis._ui" ]
209215
exhaustive = true
210216

211217
[[tool.importlinter.contracts]]
@@ -215,7 +221,6 @@ layers = [
215221
# docstyle uses (Ruff) tool, badge uses readme
216222
"badge | docstyle | list | rule",
217223
"author | browse | ci | readme | show | status | tool",
218-
"enums",
219224
]
220225
containers = [ "usethis._core" ]
221226
exhaustive = true
@@ -250,7 +255,7 @@ name = "usethis._integrations"
250255
type = "layers"
251256
layers = [
252257
"ci | pre_commit",
253-
"uv | mkdocs | pytest | pydantic | sonarqube",
258+
"backend | mkdocs | pytest | pydantic | sonarqube",
254259
"project | python",
255260
"file",
256261
]
@@ -268,6 +273,16 @@ layers = [
268273
containers = [ "usethis._integrations.file" ]
269274
exhaustive = true
270275

276+
[[tool.importlinter.contracts]]
277+
name = "usethis._ui.interface"
278+
type = "layers"
279+
layers = [
280+
# Note; if you're adding an interface, make sure it's in the README too.
281+
"author | badge | browse | ci | doc | docstyle | format_ | init | lint | list | readme | rule | show | spellcheck | status | test | tool | version",
282+
]
283+
containers = [ "usethis._ui.interface" ]
284+
exhaustive = true
285+
271286
[[tool.importlinter.contracts]]
272287
name = "usethis._pipeweld"
273288
type = "layers"

src/usethis/__main__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from __future__ import annotations
44

5-
from usethis._app import app
5+
from usethis._ui.app import app
66

77
app(prog_name="usethis")
88

src/usethis/_config.py

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,18 @@
55
from pathlib import Path
66
from typing import TYPE_CHECKING
77

8+
from usethis._types.backend import BackendEnum
9+
810
if TYPE_CHECKING:
911
from collections.abc import Generator
1012

13+
1114
HOW_DEFAULT = False
1215
REMOVE_DEFAULT = False
1316
FROZEN_DEFAULT = False
1417
OFFLINE_DEFAULT = False
1518
QUIET_DEFAULT = False
19+
BACKEND_DEFAULT = "auto"
1620

1721

1822
@dataclass
@@ -24,7 +28,8 @@ class UsethisConfig:
2428
quiet: Suppress all output, regardless of any other options.
2529
frozen: Do not install dependencies, nor update lockfiles.
2630
alert_only: Suppress all output except for warnings and errors.
27-
disable_uv_subprocess: Raise an error if a uv subprocess invocation is tried.
31+
backend: The package manager backend to use. Attempted subprocesses to other
32+
backends will raise an error.
2833
disable_pre_commit: Disable pre-commit integrations. Assume that pre-commit is
2934
never used (unless explicitly requested via a function whose
3035
purpose is to modify pre-commit configuration).
@@ -33,11 +38,11 @@ class UsethisConfig:
3338
working directory dynamically determined at runtime.
3439
"""
3540

36-
offline: bool = False
37-
quiet: bool = False
38-
frozen: bool = False
41+
offline: bool = OFFLINE_DEFAULT
42+
quiet: bool = QUIET_DEFAULT
43+
frozen: bool = FROZEN_DEFAULT
3944
alert_only: bool = False
40-
disable_uv_subprocess: bool = False
45+
backend: BackendEnum = BackendEnum(BACKEND_DEFAULT) # noqa: RUF009
4146
disable_pre_commit: bool = False
4247
subprocess_verbose: bool = False
4348
project_dir: Path | None = None
@@ -50,7 +55,7 @@ def set( # noqa: PLR0913
5055
quiet: bool | None = None,
5156
frozen: bool | None = None,
5257
alert_only: bool | None = None,
53-
disable_uv_subprocess: bool | None = None,
58+
backend: BackendEnum | None = None,
5459
disable_pre_commit: bool | None = None,
5560
subprocess_verbose: bool | None = None,
5661
project_dir: Path | str | None = None,
@@ -60,7 +65,7 @@ def set( # noqa: PLR0913
6065
old_quiet = self.quiet
6166
old_frozen = self.frozen
6267
old_alert_only = self.alert_only
63-
old_disable_uv_subprocess = self.disable_uv_subprocess
68+
old_backend = self.backend
6469
old_disable_pre_commit = self.disable_pre_commit
6570
old_subprocess_verbose = self.subprocess_verbose
6671
old_project_dir = self.project_dir
@@ -73,8 +78,8 @@ def set( # noqa: PLR0913
7378
frozen = old_frozen
7479
if alert_only is None:
7580
alert_only = self.alert_only
76-
if disable_uv_subprocess is None:
77-
disable_uv_subprocess = old_disable_uv_subprocess
81+
if backend is None:
82+
backend = self.backend
7883
if disable_pre_commit is None:
7984
disable_pre_commit = old_disable_pre_commit
8085
if subprocess_verbose is None:
@@ -86,7 +91,7 @@ def set( # noqa: PLR0913
8691
self.quiet = quiet
8792
self.frozen = frozen
8893
self.alert_only = alert_only
89-
self.disable_uv_subprocess = disable_uv_subprocess
94+
self.backend = backend
9095
self.disable_pre_commit = disable_pre_commit
9196
self.subprocess_verbose = subprocess_verbose
9297
if isinstance(project_dir, str):
@@ -97,7 +102,7 @@ def set( # noqa: PLR0913
97102
self.quiet = old_quiet
98103
self.frozen = old_frozen
99104
self.alert_only = old_alert_only
100-
self.disable_uv_subprocess = old_disable_uv_subprocess
105+
self.backend = old_backend
101106
self.disable_pre_commit = old_disable_pre_commit
102107
self.subprocess_verbose = old_subprocess_verbose
103108
self.project_dir = old_project_dir
@@ -109,12 +114,4 @@ def cpd(self) -> Path:
109114
return self.project_dir
110115

111116

112-
usethis_config = UsethisConfig(
113-
offline=OFFLINE_DEFAULT,
114-
quiet=QUIET_DEFAULT,
115-
frozen=FROZEN_DEFAULT,
116-
alert_only=False,
117-
disable_uv_subprocess=False,
118-
disable_pre_commit=False,
119-
subprocess_verbose=False,
120-
)
117+
usethis_config = UsethisConfig()

0 commit comments

Comments
 (0)