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.
- dir_content_diff-1.12.0/.codespellrc +2 -0
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/.copier-answers.yml +2 -2
- dir_content_diff-1.12.0/.copyright.tmpl +6 -0
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/.github/workflows/commitlint.yml +3 -1
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/.github/workflows/run-tox.yml +12 -2
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/.pre-commit-config.yaml +21 -11
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/.pylintrc +1 -0
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/.readthedocs.yml +2 -2
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/CHANGELOG.md +26 -1
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/CONTRIBUTING.md +1 -1
- {dir_content_diff-1.10.0/dir_content_diff.egg-info → dir_content_diff-1.12.0}/PKG-INFO +13 -9
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/dir_content_diff/__init__.py +67 -25
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/dir_content_diff/base_comparators.py +138 -8
- dir_content_diff-1.12.0/dir_content_diff/cli/__init__.py +188 -0
- dir_content_diff-1.12.0/dir_content_diff/comparators/__init__.py +10 -0
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/dir_content_diff/comparators/dependencies.json +1 -1
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/dir_content_diff/comparators/morphio.py +10 -0
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/dir_content_diff/comparators/pandas.py +10 -0
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/dir_content_diff/comparators/voxcell.py +28 -4
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/dir_content_diff/pytest_plugin.py +10 -0
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/dir_content_diff/util.py +49 -13
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0/dir_content_diff.egg-info}/PKG-INFO +13 -9
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/dir_content_diff.egg-info/SOURCES.txt +3 -1
- dir_content_diff-1.12.0/dir_content_diff.egg-info/entry_points.txt +5 -0
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/dir_content_diff.egg-info/requires.txt +9 -5
- dir_content_diff-1.12.0/docs/source/changelog.rst +2 -0
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/docs/source/conf.py +27 -7
- dir_content_diff-1.12.0/docs/source/contributing.rst +2 -0
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/docs/source/index.rst +2 -1
- dir_content_diff-1.12.0/pyproject.toml +94 -0
- dir_content_diff-1.12.0/setup.py +49 -0
- dir_content_diff-1.12.0/tests/__init__.py +10 -0
- dir_content_diff-1.12.0/tests/comparators/__init__.py +10 -0
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/tests/comparators/test_morphio.py +11 -1
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/tests/comparators/test_pandas.py +54 -10
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/tests/comparators/test_voxcell.py +19 -3
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/tests/conftest.py +18 -2
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/tests/generate_test_files.py +10 -0
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/tests/test_base.py +198 -33
- dir_content_diff-1.12.0/tests/test_cli.py +276 -0
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/tests/test_missing_deps.py +10 -0
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/tests/test_pytest_plugin.py +10 -0
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/tests/test_util.py +10 -0
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/tests/test_version.py +10 -0
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/tox.ini +13 -3
- dir_content_diff-1.10.0/.codespellrc +0 -2
- dir_content_diff-1.10.0/.flake8 +0 -7
- dir_content_diff-1.10.0/dir_content_diff/comparators/__init__.py +0 -1
- dir_content_diff-1.10.0/dir_content_diff.egg-info/entry_points.txt +0 -2
- dir_content_diff-1.10.0/docs/source/changelog.rst +0 -1
- dir_content_diff-1.10.0/docs/source/contributing.rst +0 -1
- dir_content_diff-1.10.0/pyproject.toml +0 -38
- dir_content_diff-1.10.0/setup.py +0 -80
- dir_content_diff-1.10.0/tests/__init__.py +0 -1
- dir_content_diff-1.10.0/tests/comparators/__init__.py +0 -1
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/.auto-changelog +0 -0
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/.auto-changelog-template.hbs +0 -0
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/.codespellignorelines +0 -0
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/.coveragerc +0 -0
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/.coveragerc_min_versions +0 -0
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/.gitattributes +0 -0
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/.github/ISSUE_TEMPLATE/bug_report.yaml +0 -0
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/.github/ISSUE_TEMPLATE/feature_request.yaml +0 -0
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/.github/ISSUE_TEMPLATE/how_to_use.yaml +0 -0
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/.github/dependabot.yml +0 -0
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/.github/pull_request_template.md +0 -0
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/.github/workflows/publish-sdist.yml +0 -0
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/.gitignore +0 -0
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/.gitreview +0 -0
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/AUTHORS.md +0 -0
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/LICENSE.txt +0 -0
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/MANIFEST.in +0 -0
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/README.md +0 -0
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/codecov.yml +0 -0
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/commitlint.config.js +0 -0
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/dir_content_diff.egg-info/dependency_links.txt +0 -0
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/dir_content_diff.egg-info/top_level.txt +0 -0
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/docs/Makefile +0 -0
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/docs/source/.gitignore +0 -0
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/docs/source/api_ref.rst +0 -0
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/package.json +0 -0
- {dir_content_diff-1.10.0 → dir_content_diff-1.12.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Changes here will be overwritten by Copier
|
|
2
2
|
|
|
3
|
-
_commit: 0.1.
|
|
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:
|
|
24
|
+
use_pyproject_toml: true
|
|
25
25
|
version: 1.1.0
|
|
26
26
|
|
|
27
27
|
# End of Copier answers
|
|
@@ -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 "$
|
|
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@
|
|
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@
|
|
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:
|
|
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.
|
|
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.
|
|
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.
|
|
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:
|
|
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$
|
|
@@ -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
|
-
>
|
|
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
|
|
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.
|
|
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 ::
|
|
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:
|
|
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-
|
|
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
|
[](https://github.com/BlueBrain/dir-content-diff/releases)
|
|
61
65
|
[](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(
|
|
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(
|
|
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 =
|
|
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
|
-
|
|
180
|
-
|
|
181
|
-
|
|
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
|
-
|
|
189
|
-
|
|
190
|
-
|
|
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
|
-
|
|
200
|
-
|
|
201
|
-
|
|
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.
|
|
206
|
-
"Skip formatting for '%s' because the comparator has no saving capability.",
|
|
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 =
|
|
313
|
-
"comparator",
|
|
314
|
-
|
|
315
|
-
|
|
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(
|
|
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
|
|
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
|
-
[
|
|
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
|
-
[
|
|
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
|
|
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,
|
|
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(
|
|
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):
|
|
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
|
-
|
|
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)
|