Skip to content

Commit 04e4ae0

Browse files
Feat: Add 'patterns' entry in specific_args (#52)
1 parent 2589c00 commit 04e4ae0

File tree

5 files changed

+121
-2
lines changed

5 files changed

+121
-2
lines changed

.pylintrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
disable=
33
arguments-differ,
44
invalid-name,
5+
too-many-lines,
56

67
[FORMAT]
78
# Regexp for a line that is allowed to be longer than the limit.

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,18 @@ specific_args = {
163163
}
164164
```
165165

166+
And last but not least, it's possible to use regular expressions to associate specific arguments to
167+
a set of files:
168+
169+
```python
170+
specific_args = {
171+
"all files with *.a of *.b extensions": {
172+
"patterns": [r".*\.[a,b]$"],
173+
"comparator": dir_content_diff.BaseComparator(),
174+
}
175+
}
176+
```
177+
166178

167179
### Export formatted data
168180

dir_content_diff/__init__.py

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import copy
66
import importlib.metadata
77
import logging
8+
import re
89
from pathlib import Path
910

1011
from dir_content_diff.base_comparators import DefaultComparator
@@ -240,9 +241,19 @@ def compare_trees(
240241
kwarg_name_2: kwarg_value_2,
241242
}
242243
},
243-
<another_file_path>: {...}
244+
<another_file_path>: {...},
245+
<a name for this category>: {
246+
"patterns": ["regex1", "regex2", ...],
247+
... (other arguments)
248+
}
244249
}
245250
251+
If the "patterns" entry is present, then the name is not considered and is only used as
252+
a helper for the user. When a "patterns" entry is detected, the other arguments are
253+
applied to all files whose relative name matches one of the given regular expression
254+
patterns. If a file could match multiple patterns of different groups, only the first
255+
one is considered.
256+
246257
Note that all entries in this ``dict`` are optional.
247258
return_raw_diffs (bool): If set to ``True``, only the raw differences are returned instead
248259
of a formatted report.
@@ -275,6 +286,11 @@ def compare_trees(
275286
else:
276287
specific_args = copy.deepcopy(specific_args)
277288

289+
pattern_specific_args = {}
290+
for v in specific_args.values():
291+
for pattern in v.pop("patterns", []):
292+
pattern_specific_args[re.compile(pattern)] = v
293+
278294
# Loop over all files and call the correct comparator
279295
different_files = {}
280296
for ref_file in ref_path.glob("**/*"):
@@ -285,7 +301,14 @@ def compare_trees(
285301
comp_file = comp_path / relative_path
286302

287303
if comp_file.exists():
288-
specific_file_args = specific_args.get(relative_path, {})
304+
specific_file_args = specific_args.get(relative_path, None)
305+
if specific_file_args is None:
306+
for pattern, pattern_args in pattern_specific_args.items():
307+
if pattern.match(relative_path):
308+
specific_file_args = copy.deepcopy(pattern_args)
309+
break
310+
if specific_file_args is None:
311+
specific_file_args = {}
289312
comparator = specific_file_args.pop(
290313
"comparator",
291314
comparators.get(

tests/conftest.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,12 @@ def dict_diff():
125125
return diff
126126

127127

128+
@pytest.fixture
129+
def base_diff():
130+
"""The diff that should be reported for the XML files."""
131+
return r"The files '\S*/file\..{3,4}' and '\S*/file\..{3,4}' are different\."
132+
133+
128134
@pytest.fixture
129135
def xml_diff(dict_diff):
130136
"""The diff that should be reported for the XML files."""

tests/test_base.py

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -716,6 +716,41 @@ def test_specific_comparator(self, ref_tree, res_tree_equal):
716716

717717
assert res == {}
718718

719+
def test_specific_patterns(self, ref_tree, res_tree_equal, base_diff):
720+
"""Test specific args."""
721+
specific_args = {
722+
"all yaml files": {
723+
"args": [None, None, None, False, 0, False],
724+
"patterns": [r".*\.yaml"],
725+
},
726+
"all json files": {
727+
"comparator": dir_content_diff.DefaultComparator(),
728+
"patterns": [r".*\.json"],
729+
},
730+
}
731+
res = compare_trees(ref_tree, res_tree_equal, specific_args=specific_args)
732+
733+
assert res == {}
734+
735+
# Test pattern override
736+
specific_args["all json files"]["comparator"] = dir_content_diff.PdfComparator()
737+
specific_args["file.json"] = {"comparator": dir_content_diff.DefaultComparator()}
738+
res = compare_trees(ref_tree, res_tree_equal, specific_args=specific_args)
739+
740+
assert res == {}
741+
742+
# Test pattern multiple matches
743+
specific_args = {
744+
"all files": {
745+
"comparator": dir_content_diff.DefaultComparator(),
746+
"patterns": [r"file\..*"],
747+
},
748+
}
749+
res = compare_trees(ref_tree, res_tree_equal, specific_args=specific_args)
750+
751+
assert list(res.keys()) == ["file.pdf"]
752+
assert re.match(base_diff, res["file.pdf"]) is not None
753+
719754

720755
class TestDiffTrees:
721756
"""Tests that should return differences."""
@@ -851,6 +886,48 @@ def test_specific_args(self, ref_tree, res_tree_diff, dict_diff, xml_diff, ini_d
851886
for match_i in [match_res_0, match_res_1, match_res_2, match_res_3]:
852887
assert match_i is not None
853888

889+
def test_specific_patterns(self, ref_tree, res_tree_diff, base_diff, dict_diff):
890+
"""Test specific args."""
891+
specific_args = {
892+
"all yaml files": {
893+
"args": [None, None, None, False, 0, False],
894+
"patterns": [r".*\.yaml"],
895+
},
896+
"all json files": {
897+
"comparator": dir_content_diff.DefaultComparator(),
898+
"patterns": [r".*\.json"],
899+
},
900+
}
901+
res = compare_trees(ref_tree, res_tree_diff, specific_args=specific_args)
902+
903+
assert re.match(base_diff, res["file.json"]) is not None
904+
905+
# Test pattern override
906+
specific_args["all json files"]["comparator"] = dir_content_diff.DefaultComparator()
907+
specific_args["file.json"] = {"comparator": dir_content_diff.JsonComparator()}
908+
res = compare_trees(ref_tree, res_tree_diff, specific_args=specific_args)
909+
910+
assert re.match(dict_diff, res["file.json"]) is not None
911+
912+
# Test pattern multiple matches
913+
specific_args = {
914+
"all files": {
915+
"comparator": dir_content_diff.DefaultComparator(),
916+
"patterns": [r"file\..*"],
917+
},
918+
}
919+
res = compare_trees(ref_tree, res_tree_diff, specific_args=specific_args)
920+
921+
assert sorted(res.keys()) == [
922+
"file.ini",
923+
"file.json",
924+
"file.pdf",
925+
"file.xml",
926+
"file.yaml",
927+
]
928+
for v in res.values():
929+
assert re.match(base_diff, v)
930+
854931
def test_unknown_comparator(self, ref_tree, res_tree_diff, registry_reseter):
855932
"""Test with an unknown extension."""
856933
dir_content_diff.unregister_comparator(".yaml")

0 commit comments

Comments
 (0)