diff --git a/news/1708.feature.md b/news/1708.feature.md new file mode 100644 index 0000000000..b46a1fa10d --- /dev/null +++ b/news/1708.feature.md @@ -0,0 +1 @@ +Introduce `--lib` option to `init` command to create a library project without prompting. diff --git a/pdm.lock b/pdm.lock index 152eeda9c8..0943498f47 100644 --- a/pdm.lock +++ b/pdm.lock @@ -692,8 +692,8 @@ summary = "Backport of pathlib-compatible object wrapper for zip files" [metadata] lock_version = "4.2" -content_hash = "sha256:1ddea2924c2b5a57986d65734dc7c80bf286c4bb05e0ac714268312a8b1e43f5" groups = ["default", "doc", "pytest", "test", "tox", "workflow"] +content_hash = "sha256:1ddea2924c2b5a57986d65734dc7c80bf286c4bb05e0ac714268312a8b1e43f5" [metadata.files] "arpeggio 2.0.0" = [ diff --git a/src/pdm/cli/commands/init.py b/src/pdm/cli/commands/init.py index eecc7a64a8..08ee006206 100644 --- a/src/pdm/cli/commands/init.py +++ b/src/pdm/cli/commands/init.py @@ -38,6 +38,7 @@ def add_arguments(self, parser: argparse.ArgumentParser) -> None: ) parser.add_argument("--python", help="Specify the Python version/path to use") parser.add_argument("--backend", choices=list(_BACKENDS), help="Specify the build backend") + parser.add_argument("--lib", action="store_true", help="Create a library project") parser.set_defaults(search_parent=False) def handle(self, project: Project, options: argparse.Namespace) -> None: @@ -89,15 +90,13 @@ def handle(self, project: Project, options: argparse.Namespace) -> None: "For more info, please visit https://peps.python.org/pep-0582/", style="success", ) - is_library = ( - termui.confirm( + is_library = options.lib + if not is_library and self.interactive: + is_library = termui.confirm( "Is the project a library that is installable?\n" "A few more questions will be asked to include a project name " "and build backend" ) - if self.interactive - else False - ) build_backend: type[BuildBackend] | None = None if is_library: name = self.ask("Project name", project.root.name) diff --git a/src/pdm/cli/commands/install.py b/src/pdm/cli/commands/install.py index 226e767d26..374951b4f9 100644 --- a/src/pdm/cli/commands/install.py +++ b/src/pdm/cli/commands/install.py @@ -18,13 +18,7 @@ class Command(BaseCommand): """Install dependencies from lock file""" - arguments = BaseCommand.arguments + [ - groups_group, - install_group, - dry_run_option, - lockfile_option, - skip_option, - ] + arguments = [*BaseCommand.arguments, groups_group, install_group, dry_run_option, lockfile_option, skip_option] def add_arguments(self, parser: argparse.ArgumentParser) -> None: parser.add_argument( diff --git a/src/pdm/cli/commands/remove.py b/src/pdm/cli/commands/remove.py index 8d22c6c87f..698ccf1669 100644 --- a/src/pdm/cli/commands/remove.py +++ b/src/pdm/cli/commands/remove.py @@ -10,12 +10,7 @@ class Command(BaseCommand): """Remove packages from pyproject.toml""" - arguments = BaseCommand.arguments + [ - install_group, - dry_run_option, - lockfile_option, - skip_option, - ] + arguments = [*BaseCommand.arguments, install_group, dry_run_option, lockfile_option, skip_option] def add_arguments(self, parser: argparse.ArgumentParser) -> None: parser.add_argument( diff --git a/src/pdm/cli/commands/sync.py b/src/pdm/cli/commands/sync.py index 94efccde77..5912cfb2eb 100644 --- a/src/pdm/cli/commands/sync.py +++ b/src/pdm/cli/commands/sync.py @@ -17,7 +17,8 @@ class Command(BaseCommand): """Synchronize the current working set with lock file""" - arguments = BaseCommand.arguments + [ + arguments = [ + *BaseCommand.arguments, groups_group, dry_run_option, lockfile_option, diff --git a/src/pdm/cli/commands/venv/__init__.py b/src/pdm/cli/commands/venv/__init__.py index 97758f3b30..a9060b2a0e 100644 --- a/src/pdm/cli/commands/venv/__init__.py +++ b/src/pdm/cli/commands/venv/__init__.py @@ -23,9 +23,7 @@ class Command(BaseCommand): def add_arguments(self, parser: argparse.ArgumentParser) -> None: parser.add_argument("--path", help="Show the path to the given virtualenv") - parser.add_argument( - "--python", help="Show the python interpreter path for the given virtualenv" - ) + parser.add_argument("--python", help="Show the python interpreter path for the given virtualenv") subparser = parser.add_subparsers() CreateCommand.register_to(subparser, "create") ListCommand.register_to(subparser, "list") diff --git a/src/pdm/cli/completions/pdm.bash b/src/pdm/cli/completions/pdm.bash index de8b9c41ae..d478f2a054 100644 --- a/src/pdm/cli/completions/pdm.bash +++ b/src/pdm/cli/completions/pdm.bash @@ -61,7 +61,7 @@ _pdm_a919b69078acdf0a_complete() ;; (init) - opts="--backend --global --help --non-interactive --project --python --skip --verbose" + opts="--backend --global --help --lib --non-interactive --project --python --skip --verbose" ;; (install) diff --git a/src/pdm/cli/completions/pdm.fish b/src/pdm/cli/completions/pdm.fish index cebf746a51..d9aa4de1d9 100644 --- a/src/pdm/cli/completions/pdm.fish +++ b/src/pdm/cli/completions/pdm.fish @@ -136,6 +136,7 @@ complete -c pdm -A -n '__fish_seen_subcommand_from info' -l where -d 'Show the p complete -c pdm -A -n '__fish_seen_subcommand_from init' -l backend -d 'Specify the build backend' complete -c pdm -A -n '__fish_seen_subcommand_from init' -l global -d 'Use the global project, supply the project root with `-p` option' complete -c pdm -A -n '__fish_seen_subcommand_from init' -l help -d 'show this help message and exit' +complete -c pdm -A -n '__fish_seen_subcommand_from init' -l lib -d 'Create a library project' complete -c pdm -A -n '__fish_seen_subcommand_from init' -l non-interactive -d 'Don\'t ask questions but use default values' complete -c pdm -A -n '__fish_seen_subcommand_from init' -l project -d 'Specify another path as the project root, which changes the base of pyproject.toml and __pypackages__' complete -c pdm -A -n '__fish_seen_subcommand_from init' -l python -d 'Specify the Python version/path to use' diff --git a/src/pdm/cli/completions/pdm.ps1 b/src/pdm/cli/completions/pdm.ps1 index 6bdb351754..0921f236e2 100644 --- a/src/pdm/cli/completions/pdm.ps1 +++ b/src/pdm/cli/completions/pdm.ps1 @@ -272,7 +272,7 @@ function TabExpansion($line, $lastWord) { "init" { $completer.AddOpts( @( - [Option]::new(@("-g", "--global", "--non-interactive", "-n", "--python")), + [Option]::new(@("-g", "--global", "--non-interactive", "-n", "--python", "--lib")), $projectOption, $skipOption, [Option]::new(@("--backend")).WithValues(@("pdm-backend", "setuptools", "flit", "hatching", "pdm-pep517")) diff --git a/src/pdm/cli/completions/pdm.zsh b/src/pdm/cli/completions/pdm.zsh index cc73d6869e..e2ab8c56a5 100644 --- a/src/pdm/cli/completions/pdm.zsh +++ b/src/pdm/cli/completions/pdm.zsh @@ -173,6 +173,7 @@ _pdm() { {-n,--non-interactive}"[Don't ask questions but use default values]" {-k,--skip}'[Skip some tasks and/or hooks by their comma-separated names]' '--backend[Specify the build backend]:backend:(pdm-backend setuptools hatchling flit pdm-pep517)' + '--lib[Create a library project]' '--python[Specify the Python version/path to use]:python:' ) ;; diff --git a/src/pdm/cli/options.py b/src/pdm/cli/options.py index fb04544f65..51de813587 100644 --- a/src/pdm/cli/options.py +++ b/src/pdm/cli/options.py @@ -161,9 +161,7 @@ def from_splitted_env(name: str, separator: str) -> list[str] | None: dest="no_self", help="Don't install the project itself", ) -install_group.add_argument( - "--fail-fast", "-x", action="store_true", help="Abort on first installation error" -) +install_group.add_argument("--fail-fast", "-x", action="store_true", help="Abort on first installation error") def no_isolation_callback( diff --git a/src/pdm/formats/poetry.py b/src/pdm/formats/poetry.py index 4e703a67bd..7613844759 100644 --- a/src/pdm/formats/poetry.py +++ b/src/pdm/formats/poetry.py @@ -25,6 +25,7 @@ from argparse import Namespace from pdm._types import RequirementDict + from pdm.project import Project def check_fingerprint(project: Project | None, filename: Path | str) -> bool: diff --git a/src/pdm/project/core.py b/src/pdm/project/core.py index 6071dcc748..f78fbe3373 100644 --- a/src/pdm/project/core.py +++ b/src/pdm/project/core.py @@ -460,8 +460,8 @@ def get_lock_metadata(self, groups: Iterable[str] | None = None) -> dict[str, An groups = self.iter_groups() return { "lock_version": self.lockfile.spec_version, - "content_hash": content_hash, "groups": sorted(groups, key=lambda x: (x != "default", x)), + "content_hash": content_hash, } def write_lockfile( diff --git a/src/pdm/termui.py b/src/pdm/termui.py index 973ed7d36e..b5329f8eb4 100644 --- a/src/pdm/termui.py +++ b/src/pdm/termui.py @@ -61,7 +61,7 @@ def style(text: str, *args: str, style: str | None = None, **kwargs: Any) -> str return capture.get() -def confirm(*args: str, **kwargs: Any) -> str: +def confirm(*args: str, **kwargs: Any) -> bool: kwargs.setdefault("default", False) return Confirm.ask(*args, **kwargs)