Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add support for {pdm} placeholder in scripts #2408

Merged
merged 5 commits into from
Nov 16, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions docs/docs/usage/scripts.md
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,31 @@ $ pdm run test
`call` scripts don't support the `{args}` placeholder as they have
access to `sys.argv` directly to handle such complexe cases and more.

### `{pdm}` placeholder

Sometimes you may have multiple PDM installations, or `pdm` installed with a different name. This
could for example occur in a CI/CD situation, or when working with different PDM versions in
different repos. To make your scripts more robust you can use `{pdm}` to use the PDM entrypoint
executing the script. This will expand to `{sys.executable} -m pdm`.

```toml
[tool.pdm.scripts]
whoami = { shell = "echo `{pdm} -V` was called as '{pdm} -V'" }
```
will produce the following output:
```shell
$ pdm whoami
PDM, version 0.1.dev2501+g73651b7.d20231115 was called as /usr/bin/python3 -m pdm -V

$ pdm2.8 whoami
PDM, version 2.8.0 was called as <snip>/venvs/pdm2-8/bin/python -m pdm -V
```

!!! note
While the above example uses PDM 2.8, this functionality was introduced in the 2.10 series and only backported for the showcase.



## Show the List of Scripts

Use `pdm run --list/-l` to show the list of available script shortcuts:
Expand Down
1 change: 1 addition & 0 deletions news/2408.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add support for {pdm} placeholder in script definitions to call the same PDM entrypoint
22 changes: 21 additions & 1 deletion src/pdm/cli/commands/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,10 @@ def exec_opts(*options: TaskOptions | None) -> dict[str, Any]:


RE_ARGS_PLACEHOLDER = re.compile(r"{args(?::(?P<default>[^}]*))?}")
RE_PDM_PLACEHOLDER = re.compile(r"{pdm}")


def interpolate(script: str, args: Sequence[str]) -> tuple[str, bool]:
def _interpolate_args(script: str, args: Sequence[str]) -> tuple[str, bool]:
"""Interpolate the `{args:[defaults]} placeholder in a string"""

def replace(m: re.Match[str]) -> str:
Expand All @@ -58,6 +59,24 @@ def replace(m: re.Match[str]) -> str:
return interpolated, count > 0


def _interpolate_pdm(script: str) -> tuple[str, bool]:
"""Interpolate the `{pdm} placeholder in a string"""

def replace(m: re.Match[str]) -> str:
return sh_join([sys.executable, "-m", "pdm"])

interpolated, count = RE_PDM_PLACEHOLDER.subn(replace, script)
return interpolated, count > 0


def interpolate(script: str, args: Sequence[str]) -> tuple[str, bool]:
"""Interpolate the `{args:[defaults]} placeholder in a string"""

script, args_interpolated = _interpolate_args(script, args)
script, pdm_interpolated = _interpolate_pdm(script)
return script, args_interpolated or pdm_interpolated
frostming marked this conversation as resolved.
Show resolved Hide resolved
frostming marked this conversation as resolved.
Show resolved Hide resolved


class Task(NamedTuple):
kind: str
name: str
Expand Down Expand Up @@ -251,6 +270,7 @@ def run_task(self, task: Task, args: Sequence[str] = (), opts: TaskOptions | Non
if kind == "composite":
args = list(args)
should_interpolate = any(RE_ARGS_PLACEHOLDER.search(script) for script in value)
should_interpolate = should_interpolate or any(RE_PDM_PLACEHOLDER.search(script) for script in value)
code = 0
for script in value:
if should_interpolate:
Expand Down
14 changes: 14 additions & 0 deletions tests/cli/test_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,20 @@ def test_run_script_with_args_placeholder_with_default(project, pdm, capfd, scri
assert out.strip().splitlines()[1:] == expected


def test_run_shell_script_with_pdm_placeholder(project, pdm):
project.pyproject.settings["scripts"] = {
"test_script": {
"shell": "{pdm} -V > output.txt",
"help": "test it won't fail",
}
}
project.pyproject.write()
with cd(project.root):
result = pdm(["run", "test_script"], obj=project)
assert result.exit_code == 0
assert (project.root / "output.txt").read_text().strip().startswith("PDM, version")


def test_run_expand_env_vars(project, pdm, capfd, monkeypatch):
(project.root / "test_script.py").write_text("import os; print(os.getenv('FOO'))")
project.pyproject.settings["scripts"] = {
Expand Down
Loading