dir-content-diff 1.10.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 (83) hide show
  1. dir_content_diff-1.12.0/.codespellrc +2 -0
  2. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/.copier-answers.yml +2 -2
  3. dir_content_diff-1.12.0/.copyright.tmpl +6 -0
  4. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/.github/workflows/commitlint.yml +3 -1
  5. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/.github/workflows/run-tox.yml +12 -2
  6. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/.pre-commit-config.yaml +21 -11
  7. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/.pylintrc +1 -0
  8. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/.readthedocs.yml +2 -2
  9. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/CHANGELOG.md +26 -1
  10. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/CONTRIBUTING.md +1 -1
  11. {dir_content_diff-1.10.0/dir_content_diff.egg-info → dir_content_diff-1.12.0}/PKG-INFO +13 -9
  12. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/dir_content_diff/__init__.py +67 -25
  13. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/dir_content_diff/base_comparators.py +138 -8
  14. dir_content_diff-1.12.0/dir_content_diff/cli/__init__.py +188 -0
  15. dir_content_diff-1.12.0/dir_content_diff/comparators/__init__.py +10 -0
  16. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/dir_content_diff/comparators/dependencies.json +1 -1
  17. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/dir_content_diff/comparators/morphio.py +10 -0
  18. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/dir_content_diff/comparators/pandas.py +10 -0
  19. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/dir_content_diff/comparators/voxcell.py +28 -4
  20. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/dir_content_diff/pytest_plugin.py +10 -0
  21. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/dir_content_diff/util.py +49 -13
  22. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0/dir_content_diff.egg-info}/PKG-INFO +13 -9
  23. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/dir_content_diff.egg-info/SOURCES.txt +3 -1
  24. dir_content_diff-1.12.0/dir_content_diff.egg-info/entry_points.txt +5 -0
  25. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/dir_content_diff.egg-info/requires.txt +9 -5
  26. dir_content_diff-1.12.0/docs/source/changelog.rst +2 -0
  27. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/docs/source/conf.py +27 -7
  28. dir_content_diff-1.12.0/docs/source/contributing.rst +2 -0
  29. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/docs/source/index.rst +2 -1
  30. dir_content_diff-1.12.0/pyproject.toml +94 -0
  31. dir_content_diff-1.12.0/setup.py +49 -0
  32. dir_content_diff-1.12.0/tests/__init__.py +10 -0
  33. dir_content_diff-1.12.0/tests/comparators/__init__.py +10 -0
  34. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/tests/comparators/test_morphio.py +11 -1
  35. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/tests/comparators/test_pandas.py +54 -10
  36. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/tests/comparators/test_voxcell.py +19 -3
  37. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/tests/conftest.py +18 -2
  38. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/tests/generate_test_files.py +10 -0
  39. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/tests/test_base.py +198 -33
  40. dir_content_diff-1.12.0/tests/test_cli.py +276 -0
  41. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/tests/test_missing_deps.py +10 -0
  42. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/tests/test_pytest_plugin.py +10 -0
  43. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/tests/test_util.py +10 -0
  44. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/tests/test_version.py +10 -0
  45. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/tox.ini +13 -3
  46. dir_content_diff-1.10.0/.codespellrc +0 -2
  47. dir_content_diff-1.10.0/.flake8 +0 -7
  48. dir_content_diff-1.10.0/dir_content_diff/comparators/__init__.py +0 -1
  49. dir_content_diff-1.10.0/dir_content_diff.egg-info/entry_points.txt +0 -2
  50. dir_content_diff-1.10.0/docs/source/changelog.rst +0 -1
  51. dir_content_diff-1.10.0/docs/source/contributing.rst +0 -1
  52. dir_content_diff-1.10.0/pyproject.toml +0 -38
  53. dir_content_diff-1.10.0/setup.py +0 -80
  54. dir_content_diff-1.10.0/tests/__init__.py +0 -1
  55. dir_content_diff-1.10.0/tests/comparators/__init__.py +0 -1
  56. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/.auto-changelog +0 -0
  57. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/.auto-changelog-template.hbs +0 -0
  58. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/.codespellignorelines +0 -0
  59. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/.coveragerc +0 -0
  60. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/.coveragerc_min_versions +0 -0
  61. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/.gitattributes +0 -0
  62. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/.github/ISSUE_TEMPLATE/bug_report.yaml +0 -0
  63. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  64. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/.github/ISSUE_TEMPLATE/feature_request.yaml +0 -0
  65. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/.github/ISSUE_TEMPLATE/how_to_use.yaml +0 -0
  66. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/.github/dependabot.yml +0 -0
  67. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/.github/pull_request_template.md +0 -0
  68. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/.github/workflows/publish-sdist.yml +0 -0
  69. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/.gitignore +0 -0
  70. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/.gitreview +0 -0
  71. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/AUTHORS.md +0 -0
  72. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/LICENSE.txt +0 -0
  73. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/MANIFEST.in +0 -0
  74. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/README.md +0 -0
  75. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/codecov.yml +0 -0
  76. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/commitlint.config.js +0 -0
  77. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/dir_content_diff.egg-info/dependency_links.txt +0 -0
  78. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/dir_content_diff.egg-info/top_level.txt +0 -0
  79. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/docs/Makefile +0 -0
  80. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/docs/source/.gitignore +0 -0
  81. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/docs/source/api_ref.rst +0 -0
  82. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/package.json +0 -0
  83. {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/setup.cfg +0 -0
@@ -0,0 +1,2 @@
1
+ [codespell]
2
+ skip = .git/*,*.pdf
@@ -1,6 +1,6 @@
1
1
  # Changes here will be overwritten by Copier
2
2
 
3
- _commit: 0.1.54
3
+ _commit: 0.1.67
4
4
  _src_path: git@bbpgitlab.epfl.ch:neuromath/python-template.git
5
5
  author_email: ''
6
6
  author_name: Blue Brain Project, EPFL
@@ -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
@@ -8,6 +8,8 @@ jobs:
8
8
  check-pr-title:
9
9
  name: Check PR title
10
10
  runs-on: ubuntu-latest
11
+ env:
12
+ PR_TITLE: ${{ github.event.pull_request.title }}
11
13
  steps:
12
14
  - uses: actions/checkout@v4
13
15
  - uses: actions/setup-node@v4
@@ -16,4 +18,4 @@ jobs:
16
18
  - run: npm install -g --force commitlint @commitlint/cli commitlint-plugin-cleanfeet
17
19
  - run: npm install conventional-changelog-conventionalcommits
18
20
  - run: touch .git/COMMIT_EDITMSG
19
- - run: echo "${{ github.event.pull_request.title }}" | commitlint
21
+ - run: echo "$PR_TITLE" | commitlint
@@ -59,18 +59,28 @@ jobs:
59
59
  pip install tox
60
60
  tox run -e min_versions
61
61
  - name: JUnit Report Action
62
- uses: mikepenz/action-junit-report@v4
62
+ uses: mikepenz/action-junit-report@v5
63
63
  if: always() # always run even if the previous step fails
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,8 +1,12 @@
1
- default_language_version:
2
- python: python3.10
3
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
4
8
  - repo: https://github.com/pre-commit/pre-commit-hooks
5
- rev: v4.4.0
9
+ rev: v5.0.0
6
10
  hooks:
7
11
  - id: check-added-large-files
8
12
  - id: check-case-conflict
@@ -13,22 +17,18 @@ repos:
13
17
  - id: end-of-file-fixer
14
18
  - id: trailing-whitespace
15
19
  - repo: https://github.com/alessandrojcm/commitlint-pre-commit-hook
16
- rev: v9.13.0
20
+ rev: v9.18.0
17
21
  hooks:
18
22
  - id: commitlint
19
23
  stages:
20
24
  - commit-msg
21
25
  additional_dependencies: ['conventional-changelog-conventionalcommits']
22
26
  - repo: https://github.com/pycqa/isort
23
- rev: 5.12.0
27
+ rev: 5.13.2
24
28
  hooks:
25
29
  - id: isort
26
- - repo: https://github.com/psf/black
27
- rev: 23.9.1
28
- hooks:
29
- - id: black
30
30
  - repo: https://github.com/codespell-project/codespell
31
- rev: v2.2.5
31
+ rev: v2.3.0
32
32
  hooks:
33
33
  - id: codespell
34
34
  args: ["-x", ".codespellignorelines"]
@@ -38,6 +38,16 @@ repos:
38
38
  - id: pydocstyle
39
39
  additional_dependencies: ["tomli"]
40
40
  - repo: https://github.com/PyCQA/flake8
41
- rev: 6.1.0
41
+ rev: 7.1.1
42
42
  hooks:
43
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$
@@ -3,6 +3,7 @@ disable=
3
3
  arguments-differ,
4
4
  invalid-name,
5
5
  too-many-lines,
6
+ too-many-positional-arguments
6
7
 
7
8
  [FORMAT]
8
9
  # Regexp for a line that is allowed to be longer than the limit.
@@ -6,9 +6,9 @@
6
6
  version: 2
7
7
 
8
8
  build:
9
- os: ubuntu-20.04
9
+ os: ubuntu-22.04
10
10
  tools:
11
- python: "3.9"
11
+ python: "3.11"
12
12
 
13
13
  sphinx:
14
14
  configuration: docs/source/conf.py
@@ -1,8 +1,33 @@
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
+
20
+ ## [1.11.0](https://github.com/BlueBrain/dir-content-diff/compare/1.10.0..1.11.0)
21
+
22
+ > 6 November 2024
23
+
24
+ ### Build
25
+
26
+ - Drop support for Python 3.8 (dependabot[bot] - [#66](https://github.com/BlueBrain/dir-content-diff/pull/66))
27
+
3
28
  ## [1.10.0](https://github.com/BlueBrain/dir-content-diff/compare/1.9.1..1.10.0)
4
29
 
5
- > 9 September 2024
30
+ > 10 September 2024
6
31
 
7
32
  ### New Features
8
33
 
@@ -59,7 +59,7 @@ When you wish to contribute to the code base, please consider the following guid
59
59
  or
60
60
 
61
61
  ```shell
62
- tox -e py310 -e lint -e docs -e check-packaging
62
+ tox run -e py39,lint,docs,check-packaging
63
63
  ```
64
64
 
65
65
  * Commit your changes using a descriptive commit message.
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dir-content-diff
3
- Version: 1.10.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,20 +35,21 @@ 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-html<4,>=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"
52
+ Requires-Dist: pytest-html>=3.2; extra == "test"
50
53
  Provides-Extra: pandas
51
54
  Requires-Dist: pandas>=1.4; extra == "pandas"
52
55
  Requires-Dist: pyarrow>=11; 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)
@@ -2,11 +2,22 @@
2
2
 
3
3
  Simple tool to compare directory contents.
4
4
  """
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
+
5
15
  import copy
6
16
  import importlib.metadata
7
17
  import re
8
18
  from pathlib import Path
9
19
 
20
+ from dir_content_diff.base_comparators import BaseComparator
10
21
  from dir_content_diff.base_comparators import DefaultComparator
11
22
  from dir_content_diff.base_comparators import IniComparator
12
23
  from dir_content_diff.base_comparators import JsonComparator
@@ -19,7 +30,6 @@ from dir_content_diff.util import format_ext
19
30
 
20
31
  __version__ = importlib.metadata.version("dir-content-diff")
21
32
 
22
-
23
33
  _DEFAULT_COMPARATORS = {
24
34
  None: DefaultComparator(),
25
35
  ".cfg": IniComparator(), # luigi config files
@@ -105,7 +115,9 @@ def unregister_comparator(ext, quiet=False):
105
115
  return _COMPARATORS.pop(ext, None)
106
116
 
107
117
 
108
- 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
+ ):
109
121
  """Compare 2 files and return the difference.
110
122
 
111
123
  Args:
@@ -126,7 +138,9 @@ def compare_files(ref_file, comp_file, comparator, *args, return_raw_diffs=False
126
138
  LOGGER.debug("Compare: %s and %s", ref_file, comp_file)
127
139
 
128
140
  try:
129
- 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
+ )
130
144
  except Exception as exception: # pylint: disable=broad-except
131
145
  load_kwargs = kwargs.pop("load_kwargs", None)
132
146
  format_data_kwargs = kwargs.pop("format_data_kwargs", None)
@@ -138,7 +152,9 @@ def compare_files(ref_file, comp_file, comparator, *args, return_raw_diffs=False
138
152
  try:
139
153
  exception_args = "\n".join(str(i) for i in exception.args)
140
154
  except Exception: # pylint: disable=broad-exception-caught
141
- 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
+ )
142
158
  exc_type = type(exception).__name__
143
159
  return diff_msg_formatter(
144
160
  ref_file,
@@ -176,18 +192,22 @@ def export_formatted_file(file, formatted_file, comparator, **kwargs):
176
192
  file,
177
193
  **kwargs.get(
178
194
  "load_kwargs",
179
- comparator._default_load_kwargs
180
- if hasattr(comparator, "_default_load_kwargs")
181
- else {},
195
+ (
196
+ comparator._default_load_kwargs
197
+ if hasattr(comparator, "_default_load_kwargs")
198
+ else {}
199
+ ),
182
200
  ),
183
201
  )
184
202
  formatted_data = comparator.format_data(
185
203
  data,
186
204
  **kwargs.get(
187
205
  "format_data_kwargs",
188
- comparator._default_format_data_kwargs
189
- if hasattr(comparator, "_default_format_data_kwargs")
190
- else {},
206
+ (
207
+ comparator._default_format_data_kwargs
208
+ if hasattr(comparator, "_default_format_data_kwargs")
209
+ else {}
210
+ ),
191
211
  ),
192
212
  )
193
213
  Path(formatted_file).parent.mkdir(parents=True, exist_ok=True)
@@ -196,15 +216,40 @@ def export_formatted_file(file, formatted_file, comparator, **kwargs):
196
216
  formatted_file,
197
217
  **kwargs.get(
198
218
  "save_kwargs",
199
- comparator._default_save_kwargs
200
- if hasattr(comparator, "_default_save_kwargs")
201
- else {},
219
+ (
220
+ comparator._default_save_kwargs
221
+ if hasattr(comparator, "_default_save_kwargs")
222
+ else {}
223
+ ),
202
224
  ),
203
225
  )
204
226
  else:
205
- LOGGER.info(
206
- "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,
207
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)
208
253
 
209
254
 
210
255
  def compare_trees(
@@ -267,9 +312,6 @@ def compare_trees(
267
312
  difference messages. If the directories are considered as equal, an empty ``dict`` is
268
313
  returned.
269
314
  """
270
- if comparators is None:
271
- comparators = _COMPARATORS
272
-
273
315
  ref_path = Path(ref_path)
274
316
  comp_path = Path(comp_path)
275
317
  formatted_data_path = comp_path.with_name(
@@ -309,12 +351,10 @@ def compare_trees(
309
351
  break
310
352
  if specific_file_args is None:
311
353
  specific_file_args = {}
312
- comparator = specific_file_args.pop(
313
- "comparator",
314
- comparators.get(
315
- ref_file.suffix,
316
- _COMPARATORS.get(None),
317
- ),
354
+ comparator = pick_comparator(
355
+ comparator=specific_file_args.pop("comparator", None),
356
+ suffix=ref_file.suffix,
357
+ comparators=comparators,
318
358
  )
319
359
  comparator_args = specific_file_args.pop("args", [])
320
360
  res = compare_files(
@@ -369,7 +409,9 @@ def assert_equal_trees(*args, export_formatted_files=False, **kwargs):
369
409
  if export_formatted_files is True and assert_equal_trees._pytest_export_suffix:
370
410
  export_formatted_files = assert_equal_trees._pytest_export_suffix
371
411
 
372
- 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
+ )
373
415
 
374
416
  # Sort the files according to their relative paths
375
417
  sorted_items = sorted(different_files.items(), key=lambda x: x[0])
@@ -1,17 +1,29 @@
1
1
  """Module containing the base comparators."""
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
+
2
12
  import configparser
3
13
  import filecmp
4
14
  import json
5
15
  import re
6
16
  from abc import ABC
7
17
  from abc import abstractmethod
18
+ from pathlib import Path
8
19
  from xml.etree import ElementTree
9
20
 
10
21
  import dictdiffer
22
+ import diff_pdf_visually
11
23
  import jsonpath_ng
12
24
  import yaml
13
25
  from dicttoxml import dicttoxml
14
- from diff_pdf_visually import pdf_similar
26
+ from diff_pdf_visually import pdfdiff_pages
15
27
 
16
28
  from dir_content_diff.util import diff_msg_formatter
17
29
 
@@ -221,7 +233,10 @@ class BaseComparator(ABC):
221
233
  if hasattr(filtered_diffs, "items"):
222
234
  formatted_diffs = self.concatenate(
223
235
  self.sort(
224
- [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
+ ],
225
240
  **sort_kwargs,
226
241
  ),
227
242
  **concat_kwargs,
@@ -229,7 +244,10 @@ class BaseComparator(ABC):
229
244
  else:
230
245
  formatted_diffs = self.concatenate(
231
246
  self.sort(
232
- [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
+ ],
233
251
  **sort_kwargs,
234
252
  ),
235
253
  **concat_kwargs,
@@ -253,7 +271,10 @@ class BaseComparator(ABC):
253
271
 
254
272
  def __eq__(self, other):
255
273
  """Compare 2 :class:`dir_content_diff.base_comparators.BaseComparator` instances."""
256
- 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
+ ):
257
278
  return False
258
279
 
259
280
  for k, v in self.__dict__.items():
@@ -362,7 +383,8 @@ class DictComparator(BaseComparator):
362
383
  for i in path.find(data):
363
384
  if isinstance(i.value, str):
364
385
  i.full_path.update(
365
- data, re.sub(pattern, new_value, i.value, count, flags)
386
+ data,
387
+ re.sub(pattern, new_value, i.value, count, flags),
366
388
  )
367
389
  return data
368
390
 
@@ -509,7 +531,13 @@ class XmlComparator(DictComparator):
509
531
  def add_to_output(obj, child):
510
532
  """Add entry from :class:`xml.etree.ElementTree.Element` object into the given object."""
511
533
  if isinstance(obj, dict):
512
- 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
+ )
513
541
  for sub in child:
514
542
  XmlComparator.add_to_output(obj[child.tag], sub)
515
543
  elif isinstance(obj, list):
@@ -591,7 +619,8 @@ class PdfComparator(BaseComparator):
591
619
 
592
620
  Keyword Args:
593
621
  threshold (int): The threshold used to compare the images.
594
- 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.
595
624
  dpi (int): The resolution used to convert the PDF files into images.
596
625
  verbosity (int): The log verbosity.
597
626
  max_report_pagenos (int): Only this number of the different pages will be logged (only
@@ -599,4 +628,105 @@ class PdfComparator(BaseComparator):
599
628
  num_threads (int): If set to 2 (the default), the image conversion are processed in
600
629
  parallel. If set to 1 it is processed sequentially.
601
630
  """
602
- 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)