-
-
Notifications
You must be signed in to change notification settings - Fork 690
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Use the standard pathlib instead of pathtools (fixes #556)
- Loading branch information
Showing
11 changed files
with
140 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
#!/usr/bin/env python | ||
# -*- coding: utf-8 -*- | ||
# patterns.py: Common wildcard searching/filtering functionality for files. | ||
# | ||
# Copyright (C) 2010 Yesudeep Mangalapilly <yesudeep@gmail.com> | ||
# | ||
# Written by Boris Staletic <boris.staletic@gmail.com> | ||
|
||
# Non-pure path objects are only allowed on their respective OS's. | ||
# Thus, these utilities require "pure" path objects that don't access the filesystem. | ||
# Since pathlib doesn't have a `case_sensitive` parameter, we have to approximate it | ||
# by converting input paths to `PureWindowsPath` and `PurePosixPath` where: | ||
# - `PureWindowsPath` is always case-insensitive. | ||
# - `PurePosixPath` is always case-sensitive. | ||
# Reference: https://docs.python.org/3/library/pathlib.html#pathlib.PurePath.match | ||
from pathlib import PureWindowsPath, PurePosixPath | ||
|
||
|
||
def _match_path(path, included_patterns, excluded_patterns, case_sensitive): | ||
"""Internal function same as :func:`match_path` but does not check arguments.""" | ||
if case_sensitive: | ||
path = PurePosixPath(path) | ||
else: | ||
included_patterns = {pattern.lower() for pattern in included_patterns} | ||
excluded_patterns = {pattern.lower() for pattern in excluded_patterns} | ||
path = PureWindowsPath(path) | ||
|
||
common_patterns = included_patterns & excluded_patterns | ||
if common_patterns: | ||
raise ValueError('conflicting patterns `{}` included and excluded'.format(common_patterns)) | ||
return (any(path.match(p) for p in included_patterns) | ||
and not any(path.match(p) for p in excluded_patterns)) | ||
|
||
|
||
def filter_paths(paths, included_patterns=None, excluded_patterns=None, case_sensitive=True): | ||
""" | ||
Filters from a set of paths based on acceptable patterns and | ||
ignorable patterns. | ||
:param pathnames: | ||
A list of path names that will be filtered based on matching and | ||
ignored patterns. | ||
:param included_patterns: | ||
Allow filenames matching wildcard patterns specified in this list. | ||
If no pattern list is specified, ["*"] is used as the default pattern, | ||
which matches all files. | ||
:param excluded_patterns: | ||
Ignores filenames matching wildcard patterns specified in this list. | ||
If no pattern list is specified, no files are ignored. | ||
:param case_sensitive: | ||
``True`` if matching should be case-sensitive; ``False`` otherwise. | ||
:returns: | ||
A list of pathnames that matched the allowable patterns and passed | ||
through the ignored patterns. | ||
""" | ||
included = ["*"] if included_patterns is None else included_patterns | ||
excluded = [] if excluded_patterns is None else excluded_patterns | ||
|
||
for path in paths: | ||
if _match_path(path, set(included), set(excluded), case_sensitive): | ||
yield path | ||
|
||
|
||
def match_any_paths(paths, included_patterns=None, excluded_patterns=None, case_sensitive=True): | ||
""" | ||
Matches from a set of paths based on acceptable patterns and | ||
ignorable patterns. | ||
:param pathnames: | ||
A list of path names that will be filtered based on matching and | ||
ignored patterns. | ||
:param included_patterns: | ||
Allow filenames matching wildcard patterns specified in this list. | ||
If no pattern list is specified, ["*"] is used as the default pattern, | ||
which matches all files. | ||
:param excluded_patterns: | ||
Ignores filenames matching wildcard patterns specified in this list. | ||
If no pattern list is specified, no files are ignored. | ||
:param case_sensitive: | ||
``True`` if matching should be case-sensitive; ``False`` otherwise. | ||
:returns: | ||
``True`` if any of the paths matches; ``False`` otherwise. | ||
""" | ||
included = ["*"] if included_patterns is None else included_patterns | ||
excluded = [] if excluded_patterns is None else excluded_patterns | ||
|
||
for path in paths: | ||
if _match_path(path, set(included), set(excluded), case_sensitive): | ||
return True | ||
return False |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
# -*- coding: utf-8 -*- | ||
# | ||
# Copyright (C) 2010 Yesudeep Mangalapilly <yesudeep@gmail.com> | ||
# Copyright 2020 Boris Staletic <boris.staletic@gmail.com> | ||
|
||
import pytest | ||
from watchdog.utils.patterns import _match_path, filter_paths, match_any_paths | ||
|
||
|
||
@pytest.mark.parametrize("input, included_patterns, excluded_patterns, case_sensitive, expected", [ | ||
("/users/gorakhargosh/foobar.py", {"*.py"}, {"*.PY"}, True, True), | ||
("/users/gorakhargosh/foobar.py", {"*.py"}, {"*.PY"}, True, True), | ||
("/users/gorakhargosh/", {"*.py"}, {"*.txt"}, False, False), | ||
("/users/gorakhargosh/foobar.py", {"*.py"}, {"*.PY"}, False, ValueError), | ||
]) | ||
def test_match_path(input, included_patterns, excluded_patterns, case_sensitive, expected): | ||
if expected == ValueError: | ||
with pytest.raises(expected): | ||
_match_path(input, included_patterns, excluded_patterns, case_sensitive) | ||
else: | ||
assert _match_path(input, included_patterns, excluded_patterns, case_sensitive) is expected | ||
|
||
|
||
@pytest.mark.parametrize("included_patterns, excluded_patterns, case_sensitive, expected", [ | ||
(None, None, True, None), | ||
(None, None, False, None), | ||
(["*.py", "*.conf"], ["*.status"], True, {"/users/gorakhargosh/foobar.py", "/etc/pdnsd.conf"}), | ||
]) | ||
def test_filter_paths(included_patterns, excluded_patterns, case_sensitive, expected): | ||
pathnames = {"/users/gorakhargosh/foobar.py", "/var/cache/pdnsd.status", "/etc/pdnsd.conf", "/usr/local/bin/python"} | ||
actual = set(filter_paths(pathnames, included_patterns, excluded_patterns, case_sensitive)) | ||
assert actual == expected if expected else pathnames | ||
|
||
|
||
@pytest.mark.parametrize("included_patterns, excluded_patterns, case_sensitive, expected", [ | ||
(None, None, True, True), | ||
(None, None, False, True), | ||
(["*py", "*.conf"], ["*.status"], True, True), | ||
(["*.txt"], None, False, False), | ||
(["*.txt"], None, True, False), | ||
]) | ||
def test_match_any_paths(included_patterns, excluded_patterns, case_sensitive, expected): | ||
pathnames = {"/users/gorakhargosh/foobar.py", "/var/cache/pdnsd.status", "/etc/pdnsd.conf", "/usr/local/bin/python"} | ||
assert match_any_paths(pathnames, included_patterns, excluded_patterns, case_sensitive) == expected |