diff --git a/cibuildwheel/util.py b/cibuildwheel/util.py
index 135ea1d95..2b1c28447 100644
--- a/cibuildwheel/util.py
+++ b/cibuildwheel/util.py
@@ -48,14 +48,56 @@
)
+def format_safe(template: str, **kwargs: Any) -> str:
+ """
+ Works similarly to `template.format(**kwargs)`, except that unmatched
+ fields in `template` are passed through untouched.
+
+ >>> format_safe('{a} {b}', a='123')
+ '123 {b}'
+ >>> format_safe('{a} {b[4]:3f}', a='123')
+ '123 {b[4]:3f}'
+
+ To avoid variable expansion, precede with a single backslash e.g.
+ >>> format_safe('\\{a} {b}', a='123')
+ '{a} {b}'
+ """
+
+ result = template
+
+ for key, value in kwargs.items():
+ find_pattern = re.compile(
+ fr"""
+ (? str:
"""
Preprocesses a command by expanding variables like {python}.
For example, used in the test_command option to specify the path to the
- project's root.
+ project's root. Unmatched syntax will mostly be allowed through.
"""
- return command.format(python="python", pip="pip", **kwargs)
+ return format_safe(command, python="python", pip="pip", **kwargs)
def get_build_verbosity_extra_flags(level: int) -> List[str]:
diff --git a/docs/options.md b/docs/options.md
index 3b9aaeb36..53ff1c4f5 100644
--- a/docs/options.md
+++ b/docs/options.md
@@ -1259,6 +1259,10 @@ Platform-specific environment variables are also available:
« subprocess_run("cibuildwheel", "--help") »
```
+## Placeholders
+
+Some options support placeholders, like `{project}`, `{package}` or `{wheel}`, that are substituted by cibuildwheel before they are used. If, for some reason, you need to write the literal name of a placeholder, e.g. literally `{project}` in a command that would ordinarily substitute `{project}`, prefix it with a hash character - `#{project}`. This is only necessary in commands where the specific string between the curly brackets would be substituted - otherwise, strings not modified.
+