fix: pass through unexpected format strings

Uses a regex-based solution instead of str.format
This commit is contained in:
Henry Schreiner
2021-10-23 14:54:20 +01:00
committed by Joe Rickerby
parent b4882894ed
commit 97e3fbbd73
2 changed files with 75 additions and 3 deletions
+39 -3
View File
@@ -12,7 +12,7 @@ import urllib.request
from enum import Enum
from pathlib import Path
from time import sleep
from typing import Dict, Iterator, List, Optional
from typing import Any, Dict, Iterator, List, Optional
import bracex
import certifi
@@ -48,14 +48,50 @@ MUSLLINUX_ARCHS = (
)
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"""
(?<!\\) # don't match if preceded by a backslash
{{ # literal open curly bracket
{re.escape(key)} # the field name
}} # literal close curly bracket
""",
re.VERBOSE,
)
result = re.sub(find_pattern, str(value), result)
# transform escaped sequences into their literal equivalents
result = result.replace(f"\\{{{key}}}", f"{{{key}}}")
return result
def prepare_command(command: str, **kwargs: PathOrStr) -> 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]:
+36
View File
@@ -0,0 +1,36 @@
from cibuildwheel.util import format_safe, prepare_command
def test_format_safe():
assert format_safe("{wheel}", wheel="filename.whl") == "filename.whl"
assert format_safe("command \\{wheel}", wheel="filename.whl") == "command {wheel}"
assert format_safe("{command \\{wheel}}", wheel="filename.whl") == "{command {wheel}}"
# check unmatched brackets
assert format_safe("{command {wheel}", wheel="filename.whl") == "{command filename.whl"
# check positional-style arguments i.e. {}
assert (
format_safe("find . -name * -exec ls -a {} \\;", project="/project")
== "find . -name * -exec ls -a {} \\;"
)
def test_prepare_command():
assert prepare_command("python -m {project}", project="project") == "python -m project"
assert prepare_command("python -m {something}", project="project") == "python -m {something}"
assert (
prepare_command("python -m {something.abc}", project="project")
== "python -m {something.abc}"
)
assert (
prepare_command("python -m {something.abc[4]:3f}", project="project")
== "python -m {something.abc[4]:3f}"
)
# test some unusual syntax that used to trip up the str.format approach
assert (
prepare_command("{a}{a,b}{b:.2e}{c}{d%s}{e:3}{f[0]}", a="42", b="3.14159")
== "42{a,b}{b:.2e}{c}{d%s}{e:3}{f[0]}"
)