dir-content-diff 1.11.0__tar.gz → 1.12.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/.copier-answers.yml +1 -1
  2. dir_content_diff-1.12.0/.copyright.tmpl +6 -0
  3. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/.github/workflows/run-tox.yml +11 -1
  4. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/.pre-commit-config.yaml +16 -4
  5. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/CHANGELOG.md +17 -0
  6. {dir_content_diff-1.11.0/dir_content_diff.egg-info → dir_content_diff-1.12.0}/PKG-INFO +12 -8
  7. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/dir_content_diff/__init__.py +51 -16
  8. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/dir_content_diff/base_comparators.py +137 -8
  9. dir_content_diff-1.12.0/dir_content_diff/cli/__init__.py +188 -0
  10. dir_content_diff-1.12.0/dir_content_diff/comparators/__init__.py +10 -0
  11. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/dir_content_diff/comparators/dependencies.json +1 -1
  12. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/dir_content_diff/comparators/morphio.py +9 -0
  13. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/dir_content_diff/comparators/pandas.py +9 -0
  14. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/dir_content_diff/comparators/voxcell.py +27 -4
  15. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/dir_content_diff/pytest_plugin.py +9 -0
  16. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/dir_content_diff/util.py +48 -13
  17. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0/dir_content_diff.egg-info}/PKG-INFO +12 -8
  18. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/dir_content_diff.egg-info/SOURCES.txt +3 -1
  19. dir_content_diff-1.12.0/dir_content_diff.egg-info/entry_points.txt +5 -0
  20. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/dir_content_diff.egg-info/requires.txt +8 -4
  21. dir_content_diff-1.12.0/docs/source/changelog.rst +2 -0
  22. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/docs/source/conf.py +22 -3
  23. dir_content_diff-1.12.0/docs/source/contributing.rst +2 -0
  24. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/docs/source/index.rst +2 -1
  25. dir_content_diff-1.12.0/pyproject.toml +94 -0
  26. dir_content_diff-1.12.0/setup.py +49 -0
  27. dir_content_diff-1.12.0/tests/__init__.py +10 -0
  28. dir_content_diff-1.12.0/tests/comparators/__init__.py +10 -0
  29. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/tests/comparators/test_morphio.py +10 -1
  30. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/tests/comparators/test_pandas.py +53 -10
  31. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/tests/comparators/test_voxcell.py +18 -3
  32. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/tests/conftest.py +17 -2
  33. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/tests/generate_test_files.py +9 -0
  34. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/tests/test_base.py +197 -33
  35. dir_content_diff-1.12.0/tests/test_cli.py +276 -0
  36. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/tests/test_missing_deps.py +9 -0
  37. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/tests/test_pytest_plugin.py +9 -0
  38. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/tests/test_util.py +9 -0
  39. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/tests/test_version.py +9 -0
  40. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/tox.ini +9 -1
  41. dir_content_diff-1.11.0/.flake8 +0 -7
  42. dir_content_diff-1.11.0/dir_content_diff/comparators/__init__.py +0 -1
  43. dir_content_diff-1.11.0/dir_content_diff.egg-info/entry_points.txt +0 -2
  44. dir_content_diff-1.11.0/docs/source/changelog.rst +0 -1
  45. dir_content_diff-1.11.0/docs/source/contributing.rst +0 -1
  46. dir_content_diff-1.11.0/pyproject.toml +0 -38
  47. dir_content_diff-1.11.0/setup.py +0 -81
  48. dir_content_diff-1.11.0/tests/__init__.py +0 -1
  49. dir_content_diff-1.11.0/tests/comparators/__init__.py +0 -1
  50. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/.auto-changelog +0 -0
  51. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/.auto-changelog-template.hbs +0 -0
  52. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/.codespellignorelines +0 -0
  53. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/.codespellrc +0 -0
  54. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/.coveragerc +0 -0
  55. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/.coveragerc_min_versions +0 -0
  56. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/.gitattributes +0 -0
  57. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/.github/ISSUE_TEMPLATE/bug_report.yaml +0 -0
  58. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  59. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/.github/ISSUE_TEMPLATE/feature_request.yaml +0 -0
  60. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/.github/ISSUE_TEMPLATE/how_to_use.yaml +0 -0
  61. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/.github/dependabot.yml +0 -0
  62. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/.github/pull_request_template.md +0 -0
  63. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/.github/workflows/commitlint.yml +0 -0
  64. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/.github/workflows/publish-sdist.yml +0 -0
  65. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/.gitignore +0 -0
  66. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/.gitreview +0 -0
  67. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/.pylintrc +0 -0
  68. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/.readthedocs.yml +0 -0
  69. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/AUTHORS.md +0 -0
  70. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/CONTRIBUTING.md +0 -0
  71. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/LICENSE.txt +0 -0
  72. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/MANIFEST.in +0 -0
  73. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/README.md +0 -0
  74. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/codecov.yml +0 -0
  75. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/commitlint.config.js +0 -0
  76. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/dir_content_diff.egg-info/dependency_links.txt +0 -0
  77. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/dir_content_diff.egg-info/top_level.txt +0 -0
  78. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/docs/Makefile +0 -0
  79. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/docs/source/.gitignore +0 -0
  80. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/docs/source/api_ref.rst +0 -0
  81. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/package.json +0 -0
  82. {dir_content_diff-1.11.0 → dir_content_diff-1.12.0}/setup.cfg +0 -0
@@ -21,7 +21,7 @@ setup_codeql: false
21
21
  ssh_url: git@github.com:BlueBrain/dir-content-diff.git
22
22
  team_name: ''
23
23
  tracker_url: https://github.com/BlueBrain/dir-content-diff/issues
24
- use_pyproject_toml: false
24
+ use_pyproject_toml: true
25
25
  version: 1.1.0
26
26
 
27
27
  # End of Copier answers
@@ -0,0 +1,6 @@
1
+ Copyright (c) 2023-${edit_year} Blue Brain Project, EPFL.
2
+
3
+ This file is part of dir-content-diff.
4
+ See https://github.com/BlueBrain/dir-content-diff for further info.
5
+
6
+ SPDX-License-Identifier: Apache-2.0
@@ -64,13 +64,23 @@ jobs:
64
64
  with:
65
65
  report_paths: 'reports/pytest-*.xml'
66
66
  - name: Upload to codecov
67
- uses: codecov/codecov-action@v4
67
+ uses: codecov/codecov-action@v5
68
68
  with:
69
69
  fail_ci_if_error: false
70
70
  directory: ./reports
71
71
  flags: pytest
72
72
  name: "dir-content-diff-py${{ matrix.python-version }}-${{ matrix.min_versions }}"
73
73
  token: ${{ secrets.CODECOV_TOKEN }}
74
+ - name: Upload to codecov results
75
+ uses: codecov/test-results-action@v1
76
+ with:
77
+ fail_ci_if_error: false
78
+ flags: pytest
79
+ directory: ./reports
80
+ name: "dir-content-diff-py${{ matrix.python-version }}-${{ matrix.min_versions }}-test-results"
81
+ token: ${{ secrets.CODECOV_TOKEN }}
82
+ env:
83
+ CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
74
84
  - name: Upload test artifacts
75
85
  uses: actions/upload-artifact@v4
76
86
  if: always()
@@ -1,4 +1,10 @@
1
1
  repos:
2
+ - repo: https://github.com/astral-sh/ruff-pre-commit
3
+ rev: v0.7.0
4
+ hooks:
5
+ - id: ruff
6
+ args: ["--fix", "--exit-non-zero-on-fix"]
7
+ - id: ruff-format
2
8
  - repo: https://github.com/pre-commit/pre-commit-hooks
3
9
  rev: v5.0.0
4
10
  hooks:
@@ -21,10 +27,6 @@ repos:
21
27
  rev: 5.13.2
22
28
  hooks:
23
29
  - id: isort
24
- - repo: https://github.com/psf/black
25
- rev: 24.10.0
26
- hooks:
27
- - id: black
28
30
  - repo: https://github.com/codespell-project/codespell
29
31
  rev: v2.3.0
30
32
  hooks:
@@ -39,3 +41,13 @@ repos:
39
41
  rev: 7.1.1
40
42
  hooks:
41
43
  - id: flake8
44
+ additional_dependencies: ['flake8-pyproject']
45
+ - repo: https://github.com/arkinmodi/add-license-header
46
+ rev: v2.2.0
47
+ hooks:
48
+ - id: add-license-header
49
+ args:
50
+ - --unmanaged
51
+ - --license-file
52
+ - .copyright.tmpl
53
+ files: \.py$
@@ -1,5 +1,22 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.12.0](https://github.com/BlueBrain/dir-content-diff/compare/1.11.0..1.12.0)
4
+
5
+ > 18 November 2024
6
+
7
+ ### New Features
8
+
9
+ - Add CLI (Adrien Berchet - [#70](https://github.com/BlueBrain/dir-content-diff/pull/70))
10
+ - Intercept 'tempfile' argument of the PdfComparator to improve it (Adrien Berchet - [#69](https://github.com/BlueBrain/dir-content-diff/pull/69))
11
+
12
+ ### Chores And Housekeeping
13
+
14
+ - Add license headers, use pyproject.toml file and migrate docs to MyST parser (Adrien Berchet - [#68](https://github.com/BlueBrain/dir-content-diff/pull/68))
15
+
16
+ ### CI Improvements
17
+
18
+ - Push test results to Codecov (Adrien Berchet - [#73](https://github.com/BlueBrain/dir-content-diff/pull/73))
19
+
3
20
  ## [1.11.0](https://github.com/BlueBrain/dir-content-diff/compare/1.10.0..1.11.0)
4
21
 
5
22
  > 6 November 2024
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dir-content-diff
3
- Version: 1.11.0
3
+ Version: 1.12.0
4
4
  Summary: Simple tool to compare directory contents.
5
- Home-page: https://dir-content-diff.readthedocs.io
6
5
  Author: Blue Brain Project, EPFL
7
6
  License: Apache License 2.0
7
+ Project-URL: Homepage, https://dir-content-diff.readthedocs.io
8
+ Project-URL: Repository, https://github.com/BlueBrain/dir-content-diff
8
9
  Project-URL: Tracker, https://github.com/BlueBrain/dir-content-diff/issues
9
- Project-URL: Source, https://github.com/BlueBrain/dir-content-diff
10
10
  Classifier: Development Status :: 5 - Production/Stable
11
11
  Classifier: Intended Audience :: Developers
12
12
  Classifier: License :: OSI Approved :: Apache Software License
@@ -16,15 +16,17 @@ Classifier: Programming Language :: Python :: 3.9
16
16
  Classifier: Programming Language :: Python :: 3.10
17
17
  Classifier: Programming Language :: Python :: 3.11
18
18
  Classifier: Programming Language :: Python :: 3.12
19
- Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
19
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
20
20
  Requires-Python: >=3.9
21
21
  Description-Content-Type: text/markdown
22
22
  License-File: LICENSE.txt
23
23
  License-File: AUTHORS.md
24
+ Requires-Dist: click>=8
24
25
  Requires-Dist: dictdiffer>=0.8
25
26
  Requires-Dist: dicttoxml>=1.7.12
26
27
  Requires-Dist: diff_pdf_visually>=1.7
27
28
  Requires-Dist: jsonpath-ng>=1.5
29
+ Requires-Dist: packaging>=20
28
30
  Requires-Dist: PyYaml>=6
29
31
  Provides-Extra: all-comparators
30
32
  Requires-Dist: pandas>=1.4; extra == "all-comparators"
@@ -33,19 +35,20 @@ Requires-Dist: tables>=3.7; extra == "all-comparators"
33
35
  Requires-Dist: morphio>=3.3.6; extra == "all-comparators"
34
36
  Requires-Dist: morph_tool>=2.9; extra == "all-comparators"
35
37
  Requires-Dist: voxcell>=3.1.1; extra == "all-comparators"
38
+ Requires-Dist: pynrrd<1.1,>=0.4; extra == "all-comparators"
36
39
  Provides-Extra: docs
37
- Requires-Dist: docutils<0.21; extra == "docs"
38
- Requires-Dist: m2r2; extra == "docs"
40
+ Requires-Dist: myst_parser; extra == "docs"
39
41
  Requires-Dist: sphinx; extra == "docs"
40
42
  Requires-Dist: sphinx-bluebrain-theme; extra == "docs"
41
43
  Provides-Extra: test
42
- Requires-Dist: coverage>=7.2; extra == "test"
43
44
  Requires-Dist: dicttoxml>=1.7.16; extra == "test"
44
45
  Requires-Dist: matplotlib>=3.4; extra == "test"
45
46
  Requires-Dist: rst2pdf>=0.99; extra == "test"
46
- Requires-Dist: packaging>=20; extra == "test"
47
47
  Requires-Dist: pandas>=1.4; extra == "test"
48
48
  Requires-Dist: pytest>=6.2; extra == "test"
49
+ Requires-Dist: pytest-click>=1.1; extra == "test"
50
+ Requires-Dist: pytest-console-scripts>=1.4; extra == "test"
51
+ Requires-Dist: pytest-cov>=4.1; extra == "test"
49
52
  Requires-Dist: pytest-html>=3.2; extra == "test"
50
53
  Provides-Extra: pandas
51
54
  Requires-Dist: pandas>=1.4; extra == "pandas"
@@ -56,6 +59,7 @@ Requires-Dist: morphio>=3.3.6; extra == "morphio"
56
59
  Requires-Dist: morph_tool>=2.9; extra == "morphio"
57
60
  Provides-Extra: voxcell
58
61
  Requires-Dist: voxcell>=3.1.1; extra == "voxcell"
62
+ Requires-Dist: pynrrd<1.1,>=0.4; extra == "voxcell"
59
63
 
60
64
  [![Version](https://img.shields.io/pypi/v/dir-content-diff)](https://github.com/BlueBrain/dir-content-diff/releases)
61
65
  [![Build status](https://github.com/BlueBrain/dir-content-diff/actions/workflows/run-tox.yml/badge.svg?branch=main)](https://github.com/BlueBrain/dir-content-diff/actions)
@@ -3,11 +3,21 @@
3
3
  Simple tool to compare directory contents.
4
4
  """
5
5
 
6
+ # LICENSE HEADER MANAGED BY add-license-header
7
+ # Copyright (c) 2023-2024 Blue Brain Project, EPFL.
8
+ #
9
+ # This file is part of dir-content-diff.
10
+ # See https://github.com/BlueBrain/dir-content-diff for further info.
11
+ #
12
+ # SPDX-License-Identifier: Apache-2.0
13
+ # LICENSE HEADER MANAGED BY add-license-header
14
+
6
15
  import copy
7
16
  import importlib.metadata
8
17
  import re
9
18
  from pathlib import Path
10
19
 
20
+ from dir_content_diff.base_comparators import BaseComparator
11
21
  from dir_content_diff.base_comparators import DefaultComparator
12
22
  from dir_content_diff.base_comparators import IniComparator
13
23
  from dir_content_diff.base_comparators import JsonComparator
@@ -20,7 +30,6 @@ from dir_content_diff.util import format_ext
20
30
 
21
31
  __version__ = importlib.metadata.version("dir-content-diff")
22
32
 
23
-
24
33
  _DEFAULT_COMPARATORS = {
25
34
  None: DefaultComparator(),
26
35
  ".cfg": IniComparator(), # luigi config files
@@ -106,7 +115,9 @@ def unregister_comparator(ext, quiet=False):
106
115
  return _COMPARATORS.pop(ext, None)
107
116
 
108
117
 
109
- def compare_files(ref_file, comp_file, comparator, *args, return_raw_diffs=False, **kwargs):
118
+ def compare_files(
119
+ ref_file, comp_file, comparator, *args, return_raw_diffs=False, **kwargs
120
+ ):
110
121
  """Compare 2 files and return the difference.
111
122
 
112
123
  Args:
@@ -127,7 +138,9 @@ def compare_files(ref_file, comp_file, comparator, *args, return_raw_diffs=False
127
138
  LOGGER.debug("Compare: %s and %s", ref_file, comp_file)
128
139
 
129
140
  try:
130
- return comparator(ref_file, comp_file, *args, return_raw_diffs=return_raw_diffs, **kwargs)
141
+ return comparator(
142
+ ref_file, comp_file, *args, return_raw_diffs=return_raw_diffs, **kwargs
143
+ )
131
144
  except Exception as exception: # pylint: disable=broad-except
132
145
  load_kwargs = kwargs.pop("load_kwargs", None)
133
146
  format_data_kwargs = kwargs.pop("format_data_kwargs", None)
@@ -139,7 +152,9 @@ def compare_files(ref_file, comp_file, comparator, *args, return_raw_diffs=False
139
152
  try:
140
153
  exception_args = "\n".join(str(i) for i in exception.args)
141
154
  except Exception: # pylint: disable=broad-exception-caught
142
- exception_args = "UNKNOWN ERROR: Could not get information from the exception"
155
+ exception_args = (
156
+ "UNKNOWN ERROR: Could not get information from the exception"
157
+ )
143
158
  exc_type = type(exception).__name__
144
159
  return diff_msg_formatter(
145
160
  ref_file,
@@ -209,9 +224,32 @@ def export_formatted_file(file, formatted_file, comparator, **kwargs):
209
224
  ),
210
225
  )
211
226
  else:
212
- LOGGER.info(
213
- "Skip formatting for '%s' because the comparator has no saving capability.", file
227
+ LOGGER.debug(
228
+ "Skip formatting for '%s' because the comparator has no saving capability.",
229
+ file,
230
+ )
231
+
232
+
233
+ def pick_comparator(comparator=None, suffix=None, comparators=None):
234
+ """Pick a comparator based on its name or a file suffix."""
235
+ if isinstance(comparator, BaseComparator):
236
+ return comparator
237
+ if comparators is None:
238
+ comparators = get_comparators()
239
+ if comparator is not None:
240
+ for i in comparators.values(): # pragma: no branch
241
+ if i.__class__.__name__ == comparator:
242
+ return i
243
+ LOGGER.debug(
244
+ "Could not find the comparator named '%s' in the given comparators",
245
+ comparator,
214
246
  )
247
+ if suffix is not None:
248
+ if suffix in comparators:
249
+ return comparators.get(suffix)
250
+ LOGGER.debug("Could not find the comparator for the '%s' suffix", suffix)
251
+ LOGGER.debug("Returning the default comparator")
252
+ return _COMPARATORS.get(None)
215
253
 
216
254
 
217
255
  def compare_trees(
@@ -274,9 +312,6 @@ def compare_trees(
274
312
  difference messages. If the directories are considered as equal, an empty ``dict`` is
275
313
  returned.
276
314
  """
277
- if comparators is None:
278
- comparators = _COMPARATORS
279
-
280
315
  ref_path = Path(ref_path)
281
316
  comp_path = Path(comp_path)
282
317
  formatted_data_path = comp_path.with_name(
@@ -316,12 +351,10 @@ def compare_trees(
316
351
  break
317
352
  if specific_file_args is None:
318
353
  specific_file_args = {}
319
- comparator = specific_file_args.pop(
320
- "comparator",
321
- comparators.get(
322
- ref_file.suffix,
323
- _COMPARATORS.get(None),
324
- ),
354
+ comparator = pick_comparator(
355
+ comparator=specific_file_args.pop("comparator", None),
356
+ suffix=ref_file.suffix,
357
+ comparators=comparators,
325
358
  )
326
359
  comparator_args = specific_file_args.pop("args", [])
327
360
  res = compare_files(
@@ -376,7 +409,9 @@ def assert_equal_trees(*args, export_formatted_files=False, **kwargs):
376
409
  if export_formatted_files is True and assert_equal_trees._pytest_export_suffix:
377
410
  export_formatted_files = assert_equal_trees._pytest_export_suffix
378
411
 
379
- different_files = compare_trees(*args, export_formatted_files=export_formatted_files, **kwargs)
412
+ different_files = compare_trees(
413
+ *args, export_formatted_files=export_formatted_files, **kwargs
414
+ )
380
415
 
381
416
  # Sort the files according to their relative paths
382
417
  sorted_items = sorted(different_files.items(), key=lambda x: x[0])
@@ -1,18 +1,29 @@
1
1
  """Module containing the base comparators."""
2
2
 
3
+ # LICENSE HEADER MANAGED BY add-license-header
4
+ # Copyright (c) 2023-2024 Blue Brain Project, EPFL.
5
+ #
6
+ # This file is part of dir-content-diff.
7
+ # See https://github.com/BlueBrain/dir-content-diff for further info.
8
+ #
9
+ # SPDX-License-Identifier: Apache-2.0
10
+ # LICENSE HEADER MANAGED BY add-license-header
11
+
3
12
  import configparser
4
13
  import filecmp
5
14
  import json
6
15
  import re
7
16
  from abc import ABC
8
17
  from abc import abstractmethod
18
+ from pathlib import Path
9
19
  from xml.etree import ElementTree
10
20
 
11
21
  import dictdiffer
22
+ import diff_pdf_visually
12
23
  import jsonpath_ng
13
24
  import yaml
14
25
  from dicttoxml import dicttoxml
15
- from diff_pdf_visually import pdf_similar
26
+ from diff_pdf_visually import pdfdiff_pages
16
27
 
17
28
  from dir_content_diff.util import diff_msg_formatter
18
29
 
@@ -222,7 +233,10 @@ class BaseComparator(ABC):
222
233
  if hasattr(filtered_diffs, "items"):
223
234
  formatted_diffs = self.concatenate(
224
235
  self.sort(
225
- [self.format_diff(i, **format_diff_kwargs) for i in filtered_diffs.items()],
236
+ [
237
+ self.format_diff(i, **format_diff_kwargs)
238
+ for i in filtered_diffs.items()
239
+ ],
226
240
  **sort_kwargs,
227
241
  ),
228
242
  **concat_kwargs,
@@ -230,7 +244,10 @@ class BaseComparator(ABC):
230
244
  else:
231
245
  formatted_diffs = self.concatenate(
232
246
  self.sort(
233
- [self.format_diff(i, **format_diff_kwargs) for i in filtered_diffs],
247
+ [
248
+ self.format_diff(i, **format_diff_kwargs)
249
+ for i in filtered_diffs
250
+ ],
234
251
  **sort_kwargs,
235
252
  ),
236
253
  **concat_kwargs,
@@ -254,7 +271,10 @@ class BaseComparator(ABC):
254
271
 
255
272
  def __eq__(self, other):
256
273
  """Compare 2 :class:`dir_content_diff.base_comparators.BaseComparator` instances."""
257
- if type(self) is not type(other) or self.__dict__.keys() != other.__dict__.keys():
274
+ if (
275
+ type(self) is not type(other)
276
+ or self.__dict__.keys() != other.__dict__.keys()
277
+ ):
258
278
  return False
259
279
 
260
280
  for k, v in self.__dict__.items():
@@ -363,7 +383,8 @@ class DictComparator(BaseComparator):
363
383
  for i in path.find(data):
364
384
  if isinstance(i.value, str):
365
385
  i.full_path.update(
366
- data, re.sub(pattern, new_value, i.value, count, flags)
386
+ data,
387
+ re.sub(pattern, new_value, i.value, count, flags),
367
388
  )
368
389
  return data
369
390
 
@@ -510,7 +531,13 @@ class XmlComparator(DictComparator):
510
531
  def add_to_output(obj, child):
511
532
  """Add entry from :class:`xml.etree.ElementTree.Element` object into the given object."""
512
533
  if isinstance(obj, dict):
513
- obj.update({child.tag: XmlComparator._cast_from_attribute(child.text, child.attrib)})
534
+ obj.update(
535
+ {
536
+ child.tag: XmlComparator._cast_from_attribute(
537
+ child.text, child.attrib
538
+ )
539
+ }
540
+ )
514
541
  for sub in child:
515
542
  XmlComparator.add_to_output(obj[child.tag], sub)
516
543
  elif isinstance(obj, list):
@@ -592,7 +619,8 @@ class PdfComparator(BaseComparator):
592
619
 
593
620
  Keyword Args:
594
621
  threshold (int): The threshold used to compare the images.
595
- tempdir (pathlib.Path): Empty directory where the temporary images will be exported.
622
+ tempdir (pathlib.Path): Directory in which a new ``dir-diff`` directory will be created
623
+ to export the debug images.
596
624
  dpi (int): The resolution used to convert the PDF files into images.
597
625
  verbosity (int): The log verbosity.
598
626
  max_report_pagenos (int): Only this number of the different pages will be logged (only
@@ -600,4 +628,105 @@ class PdfComparator(BaseComparator):
600
628
  num_threads (int): If set to 2 (the default), the image conversion are processed in
601
629
  parallel. If set to 1 it is processed sequentially.
602
630
  """
603
- return not pdf_similar(ref, comp, *args, **kwargs)
631
+ res = pdfdiff_pages(ref, comp, *args, **kwargs)
632
+ if not res:
633
+ return False
634
+ return res
635
+
636
+ def __call__(self, ref_file, comp_file, *args, **kwargs):
637
+ """Process arguments before calling the diff method."""
638
+ tempdir = kwargs.pop("tempdir", None)
639
+ if tempdir is not None:
640
+ relative_parts = []
641
+ for i, j in zip(
642
+ ref_file.parts[::-1], comp_file.parts[::-1]
643
+ ): # pragma: no branch
644
+ if i != j:
645
+ break
646
+ relative_parts.append(i)
647
+ if relative_parts and relative_parts[-1] == Path(tempdir).root:
648
+ relative_parts.pop()
649
+ if not relative_parts:
650
+ relative_parts.append(comp_file.name)
651
+ relative_parts.append("diff-pdf")
652
+ new_tempdir = Path(tempdir) / Path(*relative_parts[::-1])
653
+
654
+ # Deduplicate name if needed
655
+ last_part = str(relative_parts[-1])
656
+ num = 1
657
+ while True:
658
+ root = Path(tempdir) / relative_parts[-1]
659
+ if not root.exists():
660
+ new_tempdir.mkdir(parents=True, exist_ok=False)
661
+ break
662
+ relative_parts[-1] = last_part + f"_{num}"
663
+ new_tempdir = Path(tempdir) / Path(*relative_parts[::-1])
664
+ num += 1
665
+
666
+ kwargs["tempdir"] = new_tempdir
667
+
668
+ try:
669
+ # Update default verbosity
670
+ if "verbosity" not in kwargs: # pragma: no branch
671
+ current_default_verbosity = int(
672
+ diff_pdf_visually.constants.DEFAULT_VERBOSITY
673
+ )
674
+ try:
675
+ if (
676
+ diff_pdf_visually.diff.pdfdiff_pages.__defaults__[1] is None
677
+ ): # pragma: no cover
678
+ diff_pdf_visually.constants.DEFAULT_VERBOSITY = 0
679
+ else:
680
+ kwargs["verbosity"] = 0
681
+ finally:
682
+ diff_pdf_visually.constants.DEFAULT_VERBOSITY = (
683
+ current_default_verbosity
684
+ )
685
+ return super().__call__(ref_file, comp_file, *args, **kwargs)
686
+ finally:
687
+ diff_pdf_visually.constants.DEFAULT_VERBOSITY = current_default_verbosity
688
+
689
+ def report(
690
+ self,
691
+ ref_file,
692
+ comp_file,
693
+ formatted_differences,
694
+ diff_args,
695
+ diff_kwargs,
696
+ load_kwargs=None,
697
+ format_data_kwargs=None,
698
+ filter_kwargs=None,
699
+ format_diff_kwargs=None,
700
+ sort_kwargs=None,
701
+ concat_kwargs=None,
702
+ **kwargs,
703
+ ): # pylint: disable=too-many-arguments
704
+ """Add specific information before calling the default method."""
705
+ if formatted_differences and isinstance(formatted_differences, str):
706
+ formatted_differences = (
707
+ "The following pages are the most different: "
708
+ + formatted_differences.replace("\n", ", ")
709
+ )
710
+ if "tempdir" in diff_kwargs:
711
+ formatted_differences += (
712
+ "\nThe visual differences can be found here: "
713
+ + str(diff_kwargs["tempdir"])
714
+ )
715
+ return super().report(
716
+ ref_file,
717
+ comp_file,
718
+ formatted_differences,
719
+ diff_args,
720
+ diff_kwargs,
721
+ load_kwargs=load_kwargs,
722
+ format_data_kwargs=format_data_kwargs,
723
+ filter_kwargs=filter_kwargs,
724
+ format_diff_kwargs=format_diff_kwargs,
725
+ sort_kwargs=sort_kwargs,
726
+ concat_kwargs=concat_kwargs,
727
+ **kwargs,
728
+ )
729
+
730
+ def format_diff(self, difference, **kwargs):
731
+ """Format one element difference."""
732
+ return str(difference)