A port of FNMatcher from py.path.common which works with PurePath() instances. The difference between this algorithm and PurePath.match() is that the latter matches "**" glob expressions for each part of the path, while this algorithm uses the whole path instead. For example:
(pattern: str, path: str | os.PathLike[str])
| 430 | |
| 431 | |
| 432 | def fnmatch_ex(pattern: str, path: str | os.PathLike[str]) -> bool: |
| 433 | """A port of FNMatcher from py.path.common which works with PurePath() instances. |
| 434 | |
| 435 | The difference between this algorithm and PurePath.match() is that the |
| 436 | latter matches "**" glob expressions for each part of the path, while |
| 437 | this algorithm uses the whole path instead. |
| 438 | |
| 439 | For example: |
| 440 | "tests/foo/bar/doc/test_foo.py" matches pattern "tests/**/doc/test*.py" |
| 441 | with this algorithm, but not with PurePath.match(). |
| 442 | |
| 443 | This algorithm was ported to keep backward-compatibility with existing |
| 444 | settings which assume paths match according this logic. |
| 445 | |
| 446 | References: |
| 447 | * https://bugs.python.org/issue29249 |
| 448 | * https://bugs.python.org/issue34731 |
| 449 | """ |
| 450 | path = PurePath(path) |
| 451 | iswin32 = sys.platform.startswith("win") |
| 452 | |
| 453 | if iswin32 and sep not in pattern and posix_sep in pattern: |
| 454 | # Running on Windows, the pattern has no Windows path separators, |
| 455 | # and the pattern has one or more Posix path separators. Replace |
| 456 | # the Posix path separators with the Windows path separator. |
| 457 | pattern = pattern.replace(posix_sep, sep) |
| 458 | |
| 459 | if sep not in pattern: |
| 460 | name = path.name |
| 461 | else: |
| 462 | name = str(path) |
| 463 | if path.is_absolute() and not os.path.isabs(pattern): |
| 464 | pattern = f"*{os.sep}{pattern}" |
| 465 | return fnmatch.fnmatch(name, pattern) |
| 466 | |
| 467 | |
| 468 | def parts(s: str) -> set[str]: |