fix: pass through unexpected format strings
Uses a regex-based solution instead of str.format
This commit is contained in:
committed by
Joe Rickerby
parent
b4882894ed
commit
97e3fbbd73
+39
-3
@@ -12,7 +12,7 @@ import urllib.request
|
|||||||
from enum import Enum
|
from enum import Enum
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from time import sleep
|
from time import sleep
|
||||||
from typing import Dict, Iterator, List, Optional
|
from typing import Any, Dict, Iterator, List, Optional
|
||||||
|
|
||||||
import bracex
|
import bracex
|
||||||
import certifi
|
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:
|
def prepare_command(command: str, **kwargs: PathOrStr) -> str:
|
||||||
"""
|
"""
|
||||||
Preprocesses a command by expanding variables like {python}.
|
Preprocesses a command by expanding variables like {python}.
|
||||||
|
|
||||||
For example, used in the test_command option to specify the path to the
|
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]:
|
def get_build_verbosity_extra_flags(level: int) -> List[str]:
|
||||||
|
|||||||
@@ -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]}"
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user