glob
模式¶
一些 PyPA 规范,例如 pyproject.toml 的 license-files,接受特定类型的 glob 模式 来匹配包含通配符和字符范围的给定字符串与文件和目录。本规范定义了哪些模式是可接受的以及应如何处理它们。
有效 glob 模式¶
出于 PyPA 目的,有效 glob 模式 必须是根据以下规定与文件系统条目匹配的字符串
字母数字字符、下划线 (
_
)、连字符 (-
) 和点 (.
) 必须按字面匹配。特殊 glob 字符:
*
、?
、**
和字符范围:[]
必须只包含按字面匹配的字符。在[...]
中,连字符表示不区分区域设置的范围(例如a-z
,顺序基于 Unicode 码点)。开头或结尾的连字符按字面匹配。路径分隔符必须是正斜杠字符 (
/
)。模式始终指 相对路径,例如,当在
pyproject.toml
中使用时,模式应始终相对于包含该文件的目录。因此,不得使用前导斜杠字符。不得使用父目录指示符 (
..
)。
本规范未涵盖的任何字符或字符序列都是无效的。项目不得使用此类值。处理 glob 模式的工具应拒绝带有错误的无效值。
字面路径(例如 LICENSE
)是有效的 glob,这意味着它们也可以定义。
处理 glob 模式的工具
必须将每个值视为 glob 模式,并且如果模式包含无效的 glob 语法,则必须引发错误。
如果任何单个用户指定的模式未匹配至少一个文件,则必须引发错误。
有效 glob 模式的示例
"LICEN[CS]E*"
"AUTHORS*"
"licenses/LICENSE.MIT"
"licenses/LICENSE.CC0"
"LICENSE.txt"
"licenses/*"
无效 glob 模式的示例
"..\LICENSE.MIT"
# .. must not be used.
# \ is an invalid path delimiter, / must be used.
"LICEN{CSE*"
# the { character is not allowed
Python 中的参考实现¶
可以将大部分模式匹配与文件系统匹配委托给 Python 标准库中的 glob
模块。但是,有必要执行额外的验证。
下面的代码是一个简单的参考实现
import os
import re
from glob import glob
def find_pattern(pattern: str) -> list[str]:
"""
>>> find_pattern("/LICENSE.MIT")
Traceback (most recent call last):
...
ValueError: Pattern '/LICENSE.MIT' should be relative...
>>> find_pattern("../LICENSE.MIT")
Traceback (most recent call last):
...
ValueError: Pattern '../LICENSE.MIT' cannot contain '..'...
>>> find_pattern("LICEN{CSE*")
Traceback (most recent call last):
...
ValueError: Pattern 'LICEN{CSE*' contains invalid characters...
"""
if ".." in pattern:
raise ValueError(f"Pattern {pattern!r} cannot contain '..'")
if pattern.startswith((os.sep, "/")) or ":\\" in pattern:
raise ValueError(
f"Pattern {pattern!r} should be relative and must not start with '/'"
)
if re.match(r'^[\w\-\.\/\*\?\[\]]+$', pattern) is None:
raise ValueError(f"Pattern '{pattern}' contains invalid characters.")
found = glob(pattern, recursive=True)
if not found:
raise ValueError(f"Pattern '{pattern}' did not match any files.")
return found