diff --git a/README.md b/README.md index cd770e7..b0fa662 100644 --- a/README.md +++ b/README.md @@ -141,8 +141,8 @@ Parsing output: `pathbase` also includes a lightweight CLI: ```bash -pathbase format --template '${ROOT}/{project}/{name}_v{version:03d}.txt' \ - ROOT=/mnt/projects project=demo name=report version=1 +ROOT=/mnt/projects pathbase format --template '${ROOT}/{project}/{name}_v{version:03d}.txt' \ + project=demo name=report version=1 ENVPATH=./examples/vfx/ pathbase parse \ '/mnt/projects/bigbuckbunny/seq001/shot010/lighting/render_beauty_v001.1001.exr' diff --git a/docs/examples.md b/docs/examples.md index 2f7f08b..ed8e86d 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -451,8 +451,8 @@ The `pathbase` CLI provides a thin wrapper around the same template operations. Format a path from fields: ```bash -pathbase format --template '${ROOT}/{project}/{name}_v{version:03d}.txt' \ - ROOT=/mnt/projects project=demo name=report version=1 +ROOT=/mnt/projects pathbase format --template '${ROOT}/{project}/{name}_v{version:03d}.txt' \ + project=demo name=report version=1 ``` Expected output: diff --git a/docs/index.md b/docs/index.md index 97a094d..224b7cf 100644 --- a/docs/index.md +++ b/docs/index.md @@ -134,8 +134,8 @@ Parsing output: `pathbase` also includes a lightweight CLI: ```bash -pathbase format --template '${ROOT}/{project}/{name}_v{version:03d}.txt' \ - ROOT=/mnt/projects project=demo name=report version=1 +ROOT=/mnt/projects pathbase format --template '${ROOT}/{project}/{name}_v{version:03d}.txt' \ + project=demo name=report version=1 ENVPATH=./examples/vfx/ pathbase parse \ '/mnt/projects/bigbuckbunny/seq001/shot010/lighting/render_beauty_v001.1001.exr' diff --git a/lib/pathbase/__init__.py b/lib/pathbase/__init__.py index 385af63..6c1d109 100644 --- a/lib/pathbase/__init__.py +++ b/lib/pathbase/__init__.py @@ -63,4 +63,4 @@ "__version__", ] -__version__ = "0.1.1" +__version__ = "0.1.2" diff --git a/lib/pathbase/template.py b/lib/pathbase/template.py index 7b0c427..b60b337 100644 --- a/lib/pathbase/template.py +++ b/lib/pathbase/template.py @@ -88,6 +88,7 @@ def _default_scope(path: PathInput) -> str: def _iter_template_items(env: Mapping[str, Any]) -> List[Tuple[str, str]]: """Return environment entries that look like path templates.""" + formatter = string.Formatter() items = [] for key, value in env.items(): if not isinstance(value, str) or not value: @@ -96,6 +97,12 @@ def _iter_template_items(env: Mapping[str, Any]) -> List[Tuple[str, str]]: continue if "/" not in value and "\\" not in value: continue + try: + parts = tuple(formatter.parse(_escape_env_vars(value))) + except ValueError: + continue + if not any(field_name is not None for _, field_name, _, _ in parts): + continue items.append((key, value)) return items @@ -186,7 +193,10 @@ def __init__( raise InvalidTemplateError(str(err)) from err self._fields: List[str] = [] self._formats: Dict[str, FieldType] = {} - self._pattern: Pattern[str] = self._compile_pattern() + try: + self._pattern = self._compile_pattern() + except re.error as err: + raise InvalidTemplateError(str(err)) from err def __repr__(self) -> str: return f"Template({self._template!r})" diff --git a/tests/test_template.py b/tests/test_template.py index 7069539..97b0ec2 100644 --- a/tests/test_template.py +++ b/tests/test_template.py @@ -245,6 +245,37 @@ def test_find_matching_templates_from_environment(): assert [name for name, _ in matches] == ["FILEPATH"] +def test_find_matching_templates_ignores_shell_env_values(): + env = { + "FILEPATH": "/mnt/projects/{project}/shots/{sequence}/{shot}/{name}.mp4", + "BASH_FUNC_module%%": ( + " () { typeset swfound=1;\n" + " if [ \"${MODULES_USE_COMPAT_VERSION:-0}\" = '1' ]; then\n" + " typeset swname='main';\n" + " if [ -e /usr/share/Modules/libexec/modulecmd.tcl ]; then\n" + " typeset swfound=0;\n" + " unset MODULES_USE_COMPAT_VERSION;\n" + " fi;\n" + " else\n" + " typeset swname='compatibility';\n" + " if [ -e /usr/share/Modules/libexec/modulecmd-compat ]; then\n" + " typeset swfound=0;\n" + " MODULES_USE_COMPAT_VERSION=1;\n" + " export MODULES_USE_COMPAT_VERSION;\n" + " fi;\n" + " fi\n" + "}" + ), + } + + matches = find_matching_templates( + "/mnt/projects/demo/shots/seq001/shot010/shot010_plate.mp4", + env=env, + ) + + assert [name for name, _ in matches] == ["FILEPATH"] + + def test_match_template_returns_unique_match(): env = { "FILEPATH": "{project}/{name}_v{version:03d}.txt",