diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 32e3642c..6562351a 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -18,8 +18,8 @@ is available to guide the process: https://www.colour-science.org/contributing/. - [ ] Pyright static checking has been run and passed. - [ ] Pre-commit hooks have been run and passed. - - + + **Documentation** diff --git a/.github/workflows/continuous-integration-documentation.yml b/.github/workflows/continuous-integration-documentation.yml index 6fbdda26..b3188f94 100644 --- a/.github/workflows/continuous-integration-documentation.yml +++ b/.github/workflows/continuous-integration-documentation.yml @@ -7,12 +7,12 @@ jobs: name: ${{ matrix.os }} - Python ${{ matrix.python-version }} strategy: matrix: - os: [ubuntu-22.04] - python-version: [3.12] + os: [ubuntu-latest] + python-version: [3.13] fail-fast: false runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v4 - name: Environment Variables run: | echo "CI_PYTHON_VERSION=${{ matrix.python-version }}" >> $GITHUB_ENV @@ -22,27 +22,23 @@ jobs: echo "COLOUR_SCIENCE__DOCUMENTATION_BUILD=True" >> $GITHUB_ENV shell: bash - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Install Dependencies run: | sudo apt-get update sudo apt-get --yes install latexmk texlive-full - - name: Install Poetry - env: - POETRY_VERSION: 1.4.0 + - name: Install uv run: | - curl -sSL https://install.python-poetry.org | POETRY_HOME=$HOME/.poetry python3 - - echo "$HOME/.poetry/bin" >> $GITHUB_PATH + pip install uv shell: bash - name: Install Package Dependencies run: | - poetry run python -m pip install --upgrade pip - poetry install - poetry run python -c "import imageio;imageio.plugins.freeimage.download()" + uv sync --all-extras --no-dev + uv run python -c "import imageio;imageio.plugins.freeimage.download()" shell: bash - name: Build Documentation run: | - poetry run invoke docs + uv run invoke docs shell: bash diff --git a/.github/workflows/continuous-integration-quality-unit-tests.yml b/.github/workflows/continuous-integration-quality-unit-tests.yml index 580ee23f..fdf5c471 100644 --- a/.github/workflows/continuous-integration-quality-unit-tests.yml +++ b/.github/workflows/continuous-integration-quality-unit-tests.yml @@ -7,12 +7,12 @@ jobs: name: ${{ matrix.os }} - Python ${{ matrix.python-version }} strategy: matrix: - os: [macOS-latest, ubuntu-22.04, windows-latest] - python-version: [3.9, "3.10", 3.11, 3.12] + os: [macOS-latest, ubuntu-latest, windows-latest] + python-version: ["3.10", 3.11, 3.12, 3.13] fail-fast: false runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v4 with: submodules: true - name: Environment Variables @@ -23,12 +23,12 @@ jobs: echo "COVERALLS_REPO_TOKEN=${{ secrets.COVERALLS_REPO_TOKEN }}" >> $GITHUB_ENV echo "MPLBACKEND=AGG" >> $GITHUB_ENV shell: bash - - name: Set up Python 3.9 for Pre-Commit - uses: actions/setup-python@v4 + - name: Set up Python 3.10 for Pre-Commit + uses: actions/setup-python@v5 with: - python-version: 3.9 + python-version: "3.10" - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Install Dependencies (macOS) @@ -36,20 +36,21 @@ jobs: run: | brew install dcraw exiftool brew install --cask adobe-dng-converter - shell: bash + brew install freeimage + # TODO: Drop when https://github.com/imageio/imageio/issues/628 is addressed + echo "IMAGEIO_FREEIMAGE_LIB=/opt/homebrew/Cellar/freeimage/3.18.0/lib/libfreeimage.3.18.0.dylib" >> $GITHUB_ENV - name: Install Dependencies (Ubuntu) - if: matrix.os == 'ubuntu-22.04' + if: matrix.os == 'ubuntu-latest' run: | sudo apt-get update sudo apt-get --yes install dcraw exiftool - shell: bash - name: Install Dependencies (Windows) if: matrix.os == 'windows-latest' run: | - curl -L https://exiftool.org/exiftool-12.51.zip -o exiftool-12.51.zip - unzip -d exiftool exiftool-12.51.zip - cp exiftool/exiftool\(-k\).exe exiftool/exiftool.exe - echo "$PWD/exiftool" | sed -e 's/^\///' -e 's/\//\\/g' -e 's/^./\0:/' >> $GITHUB_PATH + curl -L https://exiftool.org/exiftool-12.98_64.zip -o exiftool-12.98_64.zip + unzip -d exiftool exiftool-12.98_64.zip + cp exiftool/exiftool-12.98_64/exiftool\(-k\).exe exiftool/exiftool-12.98_64/exiftool.exe + echo "$PWD/exiftool/exiftool-12.98_64" | sed -e 's/^\///' -e 's/\//\\/g' -e 's/^./\0:/' >> $GITHUB_PATH curl -L https://cdn.fastpictureviewer.com/bin/dcraw.zip?v=201605100 -o dcraw.zip unzip -d dcraw dcraw.zip echo "$PWD/dcraw" | sed -e 's/^\///' -e 's/\//\\/g' -e 's/^./\0:/' >> $GITHUB_PATH @@ -65,32 +66,29 @@ jobs: run: | echo "C:\Program Files\Adobe\Adobe DNG Converter" >> $GITHUB_PATH shell: bash - - name: Install Poetry - env: - POETRY_VERSION: 1.4.0 + - name: Install uv run: | - curl -sSL https://install.python-poetry.org | POETRY_HOME=$HOME/.poetry python3 - - echo "$HOME/.poetry/bin" >> $GITHUB_PATH + pip install uv shell: bash - name: Install Package Dependencies run: | - poetry run python -m pip install --upgrade pip - poetry install - poetry run python -c "import imageio;imageio.plugins.freeimage.download()" + uv sync --all-extras --no-dev + uv run python -c "import imageio;imageio.plugins.freeimage.download()" shell: bash - name: Pre-Commit (All Files) run: | - poetry run pre-commit run --all-files + uv run pre-commit run --all-files shell: bash - name: Test Optimised Python Execution run: | - poetry run python -OO -c "import $CI_PACKAGE" + uv run python -OO -c "import $CI_PACKAGE" shell: bash - name: Test with Pytest run: | - poetry run python -W ignore -m pytest --doctest-modules --ignore=$CI_PACKAGE/examples --cov=$CI_PACKAGE $CI_PACKAGE + uv run python -W ignore -m pytest --doctest-modules --ignore=$CI_PACKAGE/examples --cov=$CI_PACKAGE $CI_PACKAGE shell: bash - name: Upload Coverage to coveralls.io + if: matrix.os == 'macOS-latest' && matrix.python-version == '3.12' run: | - if [ -z "$COVERALLS_REPO_TOKEN" ]; then echo \"COVERALLS_REPO_TOKEN\" secret is undefined!; else poetry run coveralls; fi + if [ -z "$COVERALLS_REPO_TOKEN" ]; then echo \"COVERALLS_REPO_TOKEN\" secret is undefined!; else uv run coveralls; fi shell: bash diff --git a/.github/workflows/continuous-integration-static-type-checking.yml b/.github/workflows/continuous-integration-static-type-checking.yml index 1df15e06..ec193273 100644 --- a/.github/workflows/continuous-integration-static-type-checking.yml +++ b/.github/workflows/continuous-integration-static-type-checking.yml @@ -8,22 +8,22 @@ jobs: strategy: matrix: os: [macOS-latest] - python-version: [3.12] + python-version: [3.13] fail-fast: false runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v4 - name: Environment Variables run: | echo "CI_PACKAGE=colour_hdri" >> $GITHUB_ENV shell: bash - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Install Package Dependencies run: | - pip install -r requirements.txt + cat requirements.txt | grep -Eo '(^[^#]+)' | xargs -n 1 pip install || true - name: Static Type Checking run: | - pyright --skipunannotated + pyright --threads --skipunannotated diff --git a/.gitignore b/.gitignore index 485f5e68..5df5afbb 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ .fleet .idea .ipynb_checkpoints +.python-version .sandbox .vs .vscode @@ -17,4 +18,4 @@ colour_hdri.egg-info dist docs/_build docs/generated -poetry.lock +uv.lock diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 054a788c..50a4e22d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -25,28 +25,23 @@ repos: - id: flynt args: [--verbose] - repo: https://github.com/PyCQA/isort - rev: "5.12.0" + rev: "5.13.2" hooks: - id: isort - repo: https://github.com/astral-sh/ruff-pre-commit - rev: "v0.1.6" + rev: "v0.1.14" hooks: + - id: ruff-format - id: ruff - - repo: https://github.com/psf/black-pre-commit-mirror - rev: 23.11.0 - hooks: - - id: black - language_version: python3.9 - repo: https://github.com/adamchainz/blacken-docs rev: 1.16.0 hooks: - id: blacken-docs - language_version: python3.9 + language_version: python3.10 - repo: https://github.com/pre-commit/mirrors-prettier rev: "v3.1.0" hooks: - id: prettier - exclude: config-aces-reference.ocio.yaml - repo: https://github.com/pre-commit/pygrep-hooks rev: "v1.10.0" hooks: diff --git a/CONTRIBUTORS.rst b/CONTRIBUTORS.rst index 552cb2e8..1e848a70 100644 --- a/CONTRIBUTORS.rst +++ b/CONTRIBUTORS.rst @@ -4,7 +4,7 @@ Contributors Development & Technical Support ------------------------------- -- **Thomas Mansencal**, *Technology Supervisor @ Wētā FX* +- **Thomas Mansencal**, *Principal Pipeline Programmer @ Epic Games* Project coordination, overall development. diff --git a/README.rst b/README.rst index 7e064410..e9dd7461 100644 --- a/README.rst +++ b/README.rst @@ -12,7 +12,7 @@ Colour - HDRI :target: https://coveralls.io/r/colour-science/colour-hdri :alt: Coverage Status .. |codacy| image:: https://img.shields.io/codacy/grade/f422dc0703dd4653b2b766217c745813/develop.svg?style=flat-square - :target: https://www.codacy.com/app/colour-science/colour-hdri + :target: https://app.codacy.com/gh/colour-science/colour-hdri :alt: Code Grade .. |version| image:: https://img.shields.io/pypi/v/colour-hdri.svg?style=flat-square :target: https://pypi.org/project/colour-hdri @@ -74,18 +74,18 @@ Primary Dependencies **Colour - HDRI** requires various dependencies in order to run: -- `python >= 3.9, < 4 `__ -- `colour-science >= 4.3 `__ +- `python >= 3.10, < 3.14 `__ +- `colour-science >= 4.4 `__ - `imageio >= 2, < 3 `__ -- `numpy >= 1.22, < 2 `__ -- `scipy >= 1.8, < 2 `__ +- `numpy >= 1.24, < 3 `__ +- `scipy >= 1.10, < 2 `__ Optional Features Dependencies ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - `colour-demosaicing `__ -- `Adobe DNG Converter `__ -- `dcraw `__ +- `Adobe DNG Converter `__ +- `dcraw `__ - `ExifTool `__ - `rawpy `__ diff --git a/TODO.rst b/TODO.rst index 3be677fb..9a819146 100644 --- a/TODO.rst +++ b/TODO.rst @@ -6,22 +6,22 @@ TODO - colour_hdri/__init__.py - - Line 287 : # TODO: Remove legacy printing support when deemed appropriate. + - Line 281 : # TODO: Remove legacy printing support when deemed appropriate. - colour_hdri/tonemapping/global_operators/operators.py - - Line 584 : # TODO: Implement automatic *p* and *non-uniform* computations support. + - Line 582 : # TODO: Implement automatic *p* and *non-uniform* computations support. - colour_hdri/utilities/exif.py - - Line 318 : # TODO: Find a better name. + - Line 317 : # TODO: Find a better name. - colour_hdri/utilities/image.py - - Line 443 : # TODO: Revise then "MixinDataclassArray" is improved. + - Line 438 : # TODO: Revise then "MixinDataclassArray" is improved. About ----- diff --git a/colour_hdri/__init__.py b/colour_hdri/__init__.py index 5d03f318..def6c0f0 100644 --- a/colour_hdri/__init__.py +++ b/colour_hdri/__init__.py @@ -252,18 +252,14 @@ def __getattr__(self, attribute) -> Any: ROOT_RESOURCES_EXAMPLES: str = os.path.join( ROOT_RESOURCES, "colour-hdri-examples-datasets" ) -ROOT_RESOURCES_TESTS: str = os.path.join( - ROOT_RESOURCES, "colour-hdri-tests-datasets" -) +ROOT_RESOURCES_TESTS: str = os.path.join(ROOT_RESOURCES, "colour-hdri-tests-datasets") __application_name__ = "Colour - HDRI" __major_version__ = "0" __minor_version__ = "2" -__change_version__ = "3" -__version__ = ".".join( - (__major_version__, __minor_version__, __change_version__) -) +__change_version__ = "4" +__version__ = ".".join((__major_version__, __minor_version__, __change_version__)) try: _version: str = ( @@ -278,9 +274,7 @@ def __getattr__(self, attribute) -> Any: except Exception: _version: str = __version__ -colour.utilities.ANCILLARY_COLOUR_SCIENCE_PACKAGES[ # pyright: ignore - "colour-hdri" -] = _version +colour.utilities.ANCILLARY_COLOUR_SCIENCE_PACKAGES["colour-hdri"] = _version # pyright: ignore del _version diff --git a/colour_hdri/calibration/absolute_luminance.py b/colour_hdri/calibration/absolute_luminance.py index 5281a574..bcb9f7e5 100644 --- a/colour_hdri/calibration/absolute_luminance.py +++ b/colour_hdri/calibration/absolute_luminance.py @@ -2,7 +2,7 @@ Absolute Luminance Calibration - Lagarde (2016) =============================================== -Defines the *Lagarde (2016)* panoramic images absolute *Luminance* calibration +Define the *Lagarde (2016)* panoramic images absolute *Luminance* calibration objects: - :func:`colour_hdri.absolute_luminance_calibration_Lagarde2016` @@ -91,7 +91,7 @@ def upper_hemisphere_illuminance_weights_Lagarde2016( ) -> NDArrayFloat: """ Compute upper hemisphere illuminance weights for use with applications - unable to perform the computation directly, i.e. *Adobe Photoshop*. + unable to perform the computation directly, i.e., *Adobe Photoshop*. Parameters ---------- diff --git a/colour_hdri/calibration/debevec1997.py b/colour_hdri/calibration/debevec1997.py index abfe8f86..5b5342f9 100644 --- a/colour_hdri/calibration/debevec1997.py +++ b/colour_hdri/calibration/debevec1997.py @@ -2,7 +2,7 @@ Debevec (1997) Camera Response Function Computation =================================================== -Defines the *Debevec (1997)* camera responses computation objects: +Define the *Debevec (1997)* camera responses computation objects: - :func:`colour_hdri.g_solve` - :func:`colour_hdri.camera_response_functions_Debevec1997` @@ -139,7 +139,7 @@ def extrapolating_function_polynomial( given camera response functions. The extrapolation occurs where the weighting function masks fully the - camera response functions, e.g. at both ends for *Debevec (1997)*. + camera response functions, e.g., at both ends for *Debevec (1997)*. Parameters ---------- @@ -246,9 +246,7 @@ def camera_response_functions_Debevec1997( w = partial(weighting_function, **weighting_function_kwargs) - g_c = [ - g_solve(s_o[..., x], L_l, l_s, w, n)[0] for x in range(s_o.shape[-1]) - ] + g_c = [g_solve(s_o[..., x], L_l, l_s, w, n)[0] for x in range(s_o.shape[-1])] crfs = np.exp(tstack(np.array(g_c))) if extrapolating_function is not None: diff --git a/colour_hdri/calibration/tests/test_absolute_luminance.py b/colour_hdri/calibration/tests/test_absolute_luminance.py index e0e53a33..4ec20c09 100644 --- a/colour_hdri/calibration/tests/test_absolute_luminance.py +++ b/colour_hdri/calibration/tests/test_absolute_luminance.py @@ -1,4 +1,3 @@ -# !/usr/bin/env python """ Define the unit tests for the :mod:`colour_hdri.calibration.absolute_luminance` module. @@ -7,7 +6,6 @@ from __future__ import annotations import os -import unittest import numpy as np from colour import read_image @@ -42,7 +40,7 @@ ) -class TestUpperHemisphereIlluminanceLagarde2016(unittest.TestCase): +class TestUpperHemisphereIlluminanceLagarde2016: """ Define :func:`colour_hdri.calibration.absolute_luminance.\ upper_hemisphere_illuminance_Lagarde2016` definition unit tests methods. @@ -61,23 +59,19 @@ def test_upper_hemisphere_illuminance_Lagarde2016(self): ) np.testing.assert_allclose( - upper_hemisphere_illuminance_Lagarde2016( - np.ones((16, 32, 3)) * 10 - ), + upper_hemisphere_illuminance_Lagarde2016(np.ones((16, 32, 3)) * 10), 29.344691653426061, atol=TOLERANCE_ABSOLUTE_TESTS, ) np.testing.assert_allclose( - upper_hemisphere_illuminance_Lagarde2016( - np.ones((16, 32, 3)) * 0.1 - ), + upper_hemisphere_illuminance_Lagarde2016(np.ones((16, 32, 3)) * 0.1), 0.293446916534261, atol=TOLERANCE_ABSOLUTE_TESTS, ) -class TestUpperHemisphereIlluminanceWeightsLagarde2016(unittest.TestCase): +class TestUpperHemisphereIlluminanceWeightsLagarde2016: """ Define :func:`colour_hdri.calibration.absolute_luminance.\ upper_hemisphere_illuminance_weights_Lagarde2016` definition unit tests @@ -134,7 +128,7 @@ def test_upper_hemisphere_illuminance_weights_Lagarde2016(self): ) -class TestAbsoluteLuminanceCalibrationLagarde2016(unittest.TestCase): +class TestAbsoluteLuminanceCalibrationLagarde2016: """ Define :func:`colour_hdri.calibration.absolute_luminance.\ absolute_luminance_calibration_Lagarde2016` definition unit tests methods. @@ -170,14 +164,7 @@ def test_absolute_luminance_calibration_Lagarde2016(self): ) np.testing.assert_allclose( - absolute_luminance_calibration_Lagarde2016( - reference_exr_file, 51000 - ), + absolute_luminance_calibration_Lagarde2016(reference_exr_file, 51000), test_exr_file, - rtol=0.0000001, atol=0.0000001, ) - - -if __name__ == "__main__": - unittest.main() diff --git a/colour_hdri/calibration/tests/test_debevec1997.py b/colour_hdri/calibration/tests/test_debevec1997.py index be1cf98f..3e381874 100644 --- a/colour_hdri/calibration/tests/test_debevec1997.py +++ b/colour_hdri/calibration/tests/test_debevec1997.py @@ -1,4 +1,3 @@ -# !/usr/bin/env python """ Define the unit tests for the :mod:`colour_hdri.calibration.debevec1997` module. @@ -7,7 +6,6 @@ from __future__ import annotations import os -import unittest import numpy as np from colour.hints import List @@ -36,9 +34,7 @@ "TestCameraResponseFunctionsDebevec1997", ] -ROOT_RESOURCES_FROBISHER_001: str = os.path.join( - ROOT_RESOURCES_TESTS, "frobisher_001" -) +ROOT_RESOURCES_FROBISHER_001: str = os.path.join(ROOT_RESOURCES_TESTS, "frobisher_001") ROOT_RESOURCES_CALIBRATION: str = os.path.join( ROOT_RESOURCES_TESTS, "colour_hdri", "calibration" @@ -47,7 +43,7 @@ IMAGES_JPG: List[str] = filter_files(ROOT_RESOURCES_FROBISHER_001, ("jpg",)) -class TestGSolve(unittest.TestCase): +class TestGSolve: """ Define :func:`colour_hdri.calibration.debevec1997.g_solve` definition unit tests methods. @@ -74,9 +70,7 @@ def test_g_solve(self): np.testing.assert_allclose( g, np.load( - os.path.join( - ROOT_RESOURCES_CALIBRATION, f"test_g_solve_g_{i}.npy" - ) + os.path.join(ROOT_RESOURCES_CALIBRATION, f"test_g_solve_g_{i}.npy") ), atol=0.001, ) @@ -85,15 +79,13 @@ def test_g_solve(self): np.testing.assert_allclose( lE, np.load( - os.path.join( - ROOT_RESOURCES_CALIBRATION, f"test_g_solve_lE_{i}.npy" - ) + os.path.join(ROOT_RESOURCES_CALIBRATION, f"test_g_solve_lE_{i}.npy") ), atol=0.001, ) -class TestCameraResponseFunctionsDebevec1997(unittest.TestCase): +class TestCameraResponseFunctionsDebevec1997: """ Define :func:`colour_hdri.calibration.debevec1997.\ camera_response_functions_Debevec1997` definition unit tests methods. @@ -107,9 +99,7 @@ def test_camera_response_function_Debevec1997(self): # Lower precision for unit tests under *Github Actions*. np.testing.assert_allclose( - camera_response_functions_Debevec1997( - ImageStack.from_files(IMAGES_JPG) - ), + camera_response_functions_Debevec1997(ImageStack.from_files(IMAGES_JPG)), np.load( os.path.join( ROOT_RESOURCES_CALIBRATION, @@ -118,7 +108,3 @@ def test_camera_response_function_Debevec1997(self): ), atol=0.00001, ) - - -if __name__ == "__main__": - unittest.main() diff --git a/colour_hdri/distortion/tests/test_vignette.py b/colour_hdri/distortion/tests/test_vignette.py index 32fea8c0..3c7bbc93 100644 --- a/colour_hdri/distortion/tests/test_vignette.py +++ b/colour_hdri/distortion/tests/test_vignette.py @@ -1,4 +1,3 @@ -# !/usr/bin/env python """ Define the unit tests for the :mod:`colour_hdri.distortion.vignette` module. """ @@ -6,7 +5,6 @@ from __future__ import annotations import os -import unittest import numpy as np from colour.constants import TOLERANCE_ABSOLUTE_TESTS @@ -55,7 +53,7 @@ ) -class TestApplyRadialGradient(unittest.TestCase): +class TestApplyRadialGradient: """ Define :func:`colour_hdri.distortion.vignette.apply_radial_gradient` definition unit tests methods. @@ -122,7 +120,7 @@ def test_apply_radial_gradient(self): ) -class TestParabolic2DFunction(unittest.TestCase): +class TestParabolic2DFunction: """ Define :func:`colour_hdri.distortion.vignette.parabolic_2D_function` definition unit tests methods. @@ -194,7 +192,7 @@ def test_parabolic_2D_function(self): ) -class TestHyperbolicCosine2DFunction(unittest.TestCase): +class TestHyperbolicCosine2DFunction: """ Define :func:`colour_hdri.distortion.vignette.hyperbolic_cosine_2D_function` definition unit tests methods. @@ -266,7 +264,7 @@ def test_hyperbolic_cosine_2D_function(self): ) -class TestVignettePrincipalPoint(unittest.TestCase): +class TestVignettePrincipalPoint: """ Define :func:`colour_hdri.distortion.vignette.vignette_principal_point` definition unit tests methods. @@ -279,15 +277,13 @@ def test_vignette_principal_point(self): """ np.testing.assert_allclose( - vignette_principal_point( - apply_radial_gradient(np.ones([50, 70, 3])) - ), + vignette_principal_point(apply_radial_gradient(np.ones([50, 70, 3]))), np.array([0.49000000, 0.49285714]), atol=TOLERANCE_ABSOLUTE_TESTS, ) -class TestCharacteriseVignette2DFunction(unittest.TestCase): +class TestCharacteriseVignette2DFunction: """ Define :func:`colour_hdri.distortion.vignette.\ characterise_vignette_2D_function` definition unit tests methods. @@ -380,7 +376,7 @@ def test_characterise_vignette_2D_function(self): ) -class TestCorrectVignette2DFunction(unittest.TestCase): +class TestCorrectVignette2DFunction: """ Define :func:`colour_hdri.distortion.vignette.correct_vignette_2D_function` definition unit tests methods. @@ -510,7 +506,7 @@ def test_correct_vignette_2D_function(self): ) -class TestCharacteriseVignetteBivariateSpline(unittest.TestCase): +class TestCharacteriseVignetteBivariateSpline: """ Define :func:`colour_hdri.distortion.vignette.\ characterise_vignette_bivariate_spline` definition unit tests methods. @@ -543,7 +539,7 @@ def test_characterise_vignette_bivariate_spline(self): ) -class TestCorrectVignetteBivariateSpline(unittest.TestCase): +class TestCorrectVignetteBivariateSpline: """ Define :func:`colour_hdri.distortion.vignette.\ correct_vignette_bivariate_spline` definition unit tests methods. @@ -613,7 +609,7 @@ def test_correct_vignette_bivariate_spline(self): ) -class TestRadialSamplingFunction(unittest.TestCase): +class TestRadialSamplingFunction: """ Define :func:`colour_hdri.distortion.vignette.radial_sampling_function` definition unit tests methods. @@ -824,7 +820,7 @@ def test_radial_sampling_function(self): ) -class TestVignetteSamplingCoordinates(unittest.TestCase): +class TestVignetteSamplingCoordinates: """ Define :func:`colour_hdri.distortion.vignette.vignette_sampling_coordinates` definition unit tests methods. @@ -1011,7 +1007,7 @@ def test_vignette_sampling_coordinates(self): ) -class TestCharacteriseVignetteRBF(unittest.TestCase): +class TestCharacteriseVignetteRBF: """ Define :func:`colour_hdri.distortion.vignette.characterise_vignette_RBF` definition unit tests methods. @@ -1213,7 +1209,7 @@ def test_characterise_vignette_RBF(self): ) -class TestCorrectVignetteRBF(unittest.TestCase): +class TestCorrectVignetteRBF: """ Define :func:`colour_hdri.distortion.vignette.correct_vignette_RBF` definition unit tests methods. @@ -1281,7 +1277,3 @@ def test_correct_vignette_RBF(self): ), atol=TOLERANCE_ABSOLUTE_TESTS, ) - - -if __name__ == "__main__": - unittest.main() diff --git a/colour_hdri/distortion/vignette.py b/colour_hdri/distortion/vignette.py index 07672d68..7c966d67 100644 --- a/colour_hdri/distortion/vignette.py +++ b/colour_hdri/distortion/vignette.py @@ -2,7 +2,7 @@ Lens Vignette Characterisation & Correction =========================================== -Defines various objects to correct camera lens vignette: +Define various objects to correct camera lens vignette: - :func:`colour_hdri.distortion.apply_radial_gradient` - :func:`colour_hdri.distortion.parabolic_2D_function` @@ -164,9 +164,7 @@ def apply_radial_gradient( return np.squeeze(np.nan_to_num(np.clip(image, 0, 1))) -def vignette_principal_point( - image: ArrayLike, threshold: float = 0.99 -) -> NDArrayFloat: +def vignette_principal_point(image: ArrayLike, threshold: float = 0.99) -> NDArrayFloat: """ Return the vignette principal point for given image. @@ -471,9 +469,7 @@ def characterise_vignette_2D_function( )[0] ) - return DataVignetteCharacterisation( - as_float_array(parameters), principal_point - ) + return DataVignetteCharacterisation(as_float_array(parameters), principal_point) def correct_vignette_2D_function( @@ -503,9 +499,7 @@ def correct_vignette_2D_function( -------- >>> image = apply_radial_gradient(np.ones([5, 7])) >>> characterisation_data = characterise_vignette_2D_function(image) - >>> np.around( - ... correct_vignette_2D_function(image, characterisation_data), 3 - ... ) + >>> np.around(correct_vignette_2D_function(image, characterisation_data), 3) array([[-0. , 0.122, 0.597, 0.747, 0.781, 1.08 , -0. ], [ 0. , 0.413, 0.676, 0.82 , 0.76 , 0.576, 0. ], [ 0. , 0.468, 0.759, 1.103, 0.838, 0.611, 0. ], @@ -521,9 +515,9 @@ def correct_vignette_2D_function( '"{0}" function is invalid, it must be one of {1}!', ) - vignette_characterisation_function = ( - VIGNETTE_CHARACTERISATION_2D_FUNCTIONS[function] - ) + vignette_characterisation_function = VIGNETTE_CHARACTERISATION_2D_FUNCTIONS[ + function + ] parameters, principal_point = characterisation_data.values @@ -564,7 +558,7 @@ def characterise_vignette_bivariate_spline( Standard deviation of the gaussian filtering kernel applied on the resampled image at given ``samples`` count. samples - Samples count of the resampled image on the long edge. + Sample count of the resampled image on the long edge. degree Degree of the bivariate spline. @@ -596,7 +590,7 @@ def characterise_vignette_bivariate_spline( x_1_n, y_1_n = np.linspace(0, 1, height_n), np.linspace(0, 1, width_n) # NOTE: Here "parameters" represent a lower resolution version of the - # image, i.e. the "I_v" function directly. + # image, i.e., the "I_v" function directly. parameters = zeros((height_n, width_n, channels)) for i in range(channels): @@ -650,9 +644,7 @@ def correct_vignette_bivariate_spline( -------- >>> image = apply_radial_gradient(np.ones([5, 7])) >>> characterisation_data = characterise_vignette_bivariate_spline(image) - >>> np.around( - ... correct_vignette_bivariate_spline(image, characterisation_data), 3 - ... ) + >>> np.around(correct_vignette_bivariate_spline(image, characterisation_data), 3) array([[ 0. , 0.345, 3.059, 4.072, 3.059, 0.345, 0. ], [ 0. , 3.624, 7.304, 9.058, 7.304, 3.624, 0. ], [ 0. , 4.936, 9.481, 14.032, 9.481, 4.936, 0. ], @@ -698,7 +690,7 @@ def radial_sampling_function( radius Sample distribution radius. radial_bias - Sample distribution bias, i.e. an exponent affecting the radial + Sample distribution bias, i.e., an exponent affecting the radial distribution. Returns @@ -757,7 +749,7 @@ def vignette_sampling_coordinates( radius Sample distribution radius. radial_bias - Sample distribution bias, i.e. an exponent affecting the radial + Sample distribution bias, i.e., an exponent affecting the radial distribution. Returns @@ -790,12 +782,12 @@ def vignette_sampling_coordinates( coordinates = np.vstack(samples) - coordinates[..., 0] = LinearInterpolator( - [0, 0.5, 1], [0, principal_point[0], 1] - )(coordinates[..., 0]) - coordinates[..., 1] = LinearInterpolator( - [0, 0.5, 1], [0, principal_point[1], 1] - )(coordinates[..., 1]) + coordinates[..., 0] = LinearInterpolator([0, 0.5, 1], [0, principal_point[0], 1])( + coordinates[..., 0] + ) + coordinates[..., 1] = LinearInterpolator([0, 0.5, 1], [0, principal_point[1], 1])( + coordinates[..., 1] + ) radial_samples = radial_sampling_function( samples_rho, @@ -871,14 +863,10 @@ def characterise_vignette_RBF( parameters = [] for i in range(channels): - filtered = gaussian_filter( - image[..., i], denoise_sigma, truncate=denoise_sigma - ) + filtered = gaussian_filter(image[..., i], denoise_sigma, truncate=denoise_sigma) parameters.append(filtered[x_indices, y_indices]) - return DataVignetteCharacterisation( - np.transpose(parameters), principal_point - ) + return DataVignetteCharacterisation(np.transpose(parameters), principal_point) def correct_vignette_RBF( @@ -956,8 +944,8 @@ def correct_vignette_RBF( epsilon=epsilon, ) - I_v = interpolator(tstack([y_1, x_1]).reshape([-1, 2])).reshape( - height, width + I_v = np.reshape( + interpolator(np.reshape(tstack([y_1, x_1]), (-1, 2))), (height, width) ) image[..., i] /= I_v @@ -1007,7 +995,7 @@ def characterise_vignette( resampled image at given ``samples`` count. samples {:func:`colour_hdri.distortion.characterise_vignette_bivariate_spline`}, - Samples count of the resampled image on the long edge. + Sample count of the resampled image on the long edge. degree {:func:`colour_hdri.distortion.characterise_vignette_bivariate_spline`}, Degree of the bivariate spline. @@ -1029,9 +1017,7 @@ def characterise_vignette( (180, 1) >>> principal_point # doctest: +ELLIPSIS array([ 0.4983333..., 0.49875 ]) - >>> parameters, principal_point = characterise_vignette( - ... image, method="RBF" - ... ).values + >>> parameters, principal_point = characterise_vignette(image, method="RBF").values >>> parameters.shape (180, 1) >>> principal_point # doctest: +ELLIPSIS @@ -1052,9 +1038,7 @@ def characterise_vignette( array([ 0.4983333..., 0.49875 ]) """ - method = validate_method( - method, tuple(VIGNETTE_CHARACTERISATION_METHODS.keys()) - ) + method = validate_method(method, tuple(VIGNETTE_CHARACTERISATION_METHODS.keys())) return VIGNETTE_CHARACTERISATION_METHODS[method](image, **kwargs) @@ -1125,21 +1109,15 @@ def correct_vignette( [ 0. , 0.967, 2.03 , 2.552, 2.03 , 0.967, 0. ], [ 0. , 0.091, 0.841, 1.134, 0.841, 0.091, 0. ]]) >>> characterisation_data = characterise_vignette(image, method="RBF") - >>> np.around( - ... correct_vignette(image, characterisation_data, method="RBF"), 3 - ... ) + >>> np.around(correct_vignette(image, characterisation_data, method="RBF"), 3) array([[ 0. , 0.091, 0.841, 1.134, 0.841, 0.091, 0. ], [ 0. , 0.967, 2.03 , 2.552, 2.03 , 0.967, 0. ], [ 0. , 1.323, 2.647, 3.97 , 2.647, 1.323, 0. ], [ 0. , 0.967, 2.03 , 2.552, 2.03 , 0.967, 0. ], [ 0. , 0.091, 0.841, 1.134, 0.841, 0.091, 0. ]]) - >>> characterisation_data = characterise_vignette( - ... image, method="2D Function" - ... ) + >>> characterisation_data = characterise_vignette(image, method="2D Function") >>> np.around( - ... correct_vignette( - ... image, characterisation_data, method="2D Function" - ... ), + ... correct_vignette(image, characterisation_data, method="2D Function"), ... 3, ... ) array([[-0. , 0.122, 0.597, 0.747, 0.781, 1.08 , -0. ], @@ -1147,13 +1125,9 @@ def correct_vignette( [ 0. , 0.468, 0.759, 1.103, 0.838, 0.611, 0. ], [ 0. , 0.439, 0.709, 0.858, 0.801, 0.628, -0. ], [-0. , 0.193, 0.742, 0.913, 1.049, -0.477, -0. ]]) - >>> characterisation_data = characterise_vignette( - ... image, method="Bivariate Spline" - ... ) + >>> characterisation_data = characterise_vignette(image, method="Bivariate Spline") >>> np.around( - ... correct_vignette( - ... image, characterisation_data, method="Bivariate Spline" - ... ), + ... correct_vignette(image, characterisation_data, method="Bivariate Spline"), ... 3, ... ) array([[ 0. , 0.345, 3.059, 4.072, 3.059, 0.345, 0. ], @@ -1165,6 +1139,4 @@ def correct_vignette( method = validate_method(method, tuple(VIGNETTE_CORRECTION_METHODS.keys())) - return VIGNETTE_CORRECTION_METHODS[method]( - image, characterisation_data, **kwargs - ) + return VIGNETTE_CORRECTION_METHODS[method](image, characterisation_data, **kwargs) diff --git a/colour_hdri/exposure/common.py b/colour_hdri/exposure/common.py index 2abfe1bb..80ef0e28 100644 --- a/colour_hdri/exposure/common.py +++ b/colour_hdri/exposure/common.py @@ -2,7 +2,7 @@ Exposure Value Computation ========================== -Defines the exposure value computation objects: +Define the exposure value computation objects: - :func:`colour_hdri.average_luminance` - :func:`colour_hdri.average_illuminance` @@ -177,7 +177,7 @@ def luminance_to_exposure_value( Notes ----- - The exposure value :math:`EV` indicates a combination of camera - settings rather than the focal plane exposure, i.e. luminous exposure, + settings rather than the focal plane exposure, i.e., luminous exposure, photometric exposure, :math:`H`. The focal plane exposure is time-integrated illuminance. @@ -233,7 +233,7 @@ def illuminance_to_exposure_value( Notes ----- - The exposure value :math:`EV` indicates a combination of camera - settings rather than the focal plane exposure, i.e. luminous exposure, + settings rather than the focal plane exposure, i.e., luminous exposure, photometric exposure, :math:`H`. The focal plane exposure is time-integrated illuminance. diff --git a/colour_hdri/exposure/dsc.py b/colour_hdri/exposure/dsc.py index 04abd124..39345ee0 100644 --- a/colour_hdri/exposure/dsc.py +++ b/colour_hdri/exposure/dsc.py @@ -2,7 +2,7 @@ Digital Still Camera Exposure ============================= -Defines various objects for modeling Digital Still Camera (DSC) exposure: +Define various objects for modeling Digital Still Camera (DSC) exposure: - :func:`colour_hdri.focal_plane_exposure` - :func:`colour_hdri.arithmetic_mean_focal_plane_exposure` @@ -337,9 +337,7 @@ def exposure_index_values(H_a: ArrayLike) -> NDArrayFloat: return as_float(10 / as_float_array(H_a)) -def exposure_value_100( - N: ArrayLike, t: ArrayLike, S: ArrayLike -) -> NDArrayFloat: +def exposure_value_100(N: ArrayLike, t: ArrayLike, S: ArrayLike) -> NDArrayFloat: """ Compute the exposure value :math:`EV100` from given relative aperture *F-Number* :math:`N`, *Exposure Time* :math:`t` and *ISO* arithmetic diff --git a/colour_hdri/exposure/tests/test_common.py b/colour_hdri/exposure/tests/test_common.py index 6ca6fc8c..0abd8029 100644 --- a/colour_hdri/exposure/tests/test_common.py +++ b/colour_hdri/exposure/tests/test_common.py @@ -1,7 +1,5 @@ -# !/usr/bin/env python """Define the unit tests for the :mod:`colour_hdri.exposure.common` module.""" -import unittest import numpy as np from colour.constants import TOLERANCE_ABSOLUTE_TESTS @@ -29,7 +27,7 @@ ] -class TestAverageLuminance(unittest.TestCase): +class TestAverageLuminance: """ Define :func:`colour_hdri.exposure.common.average_luminance` definition unit tests methods. @@ -49,7 +47,7 @@ def test_average_luminance(self): ) -class TestAverageIlluminance(unittest.TestCase): +class TestAverageIlluminance: """ Define :func:`colour_hdri.exposure.common.average_illuminance` definition unit tests methods. @@ -72,7 +70,7 @@ def test_average_illuminance(self): ) -class TestLuminanceToExposureValue(unittest.TestCase): +class TestLuminanceToExposureValue: """ Define :func:`colour_hdri.exposure.common.luminance_to_exposure_value` definition unit tests methods. @@ -95,7 +93,7 @@ def test_luminance_to_exposure_value(self): ) -class TestIlluminanceToExposureValue(unittest.TestCase): +class TestIlluminanceToExposureValue: """ Define :func:`colour_hdri.exposure.common.illuminance_to_exposure_value` definition unit tests methods. @@ -118,7 +116,7 @@ def test_illuminance_to_exposure_value(self): ) -class TestAdjustExposure(unittest.TestCase): +class TestAdjustExposure: """ Define :func:`colour_hdri.exposure.common.adjust_exposure` definition unit tests methods. @@ -132,7 +130,3 @@ def test_adjust_exposure(self): np.array([0.5, 1.0, 1.5, 2.0]), atol=TOLERANCE_ABSOLUTE_TESTS, ) - - -if __name__ == "__main__": - unittest.main() diff --git a/colour_hdri/exposure/tests/test_dsc.py b/colour_hdri/exposure/tests/test_dsc.py index a124687a..3917d664 100644 --- a/colour_hdri/exposure/tests/test_dsc.py +++ b/colour_hdri/exposure/tests/test_dsc.py @@ -1,7 +1,5 @@ -# !/usr/bin/env python """Define the unit tests for the :mod:`colour_hdri.exposure.dsc` module.""" -import unittest import numpy as np from colour.constants import TOLERANCE_ABSOLUTE_TESTS @@ -34,7 +32,7 @@ ] -class TestQFactor(unittest.TestCase): +class TestQFactor: """ Define :func:`colour_hdri.exposure.dsc.q_factor` definition unit tests methods. @@ -54,7 +52,7 @@ def test_q_factor(self): ) -class TestFocalPlaneExposure(unittest.TestCase): +class TestFocalPlaneExposure: """ Define :func:`colour_hdri.exposure.dsc.focal_plane_exposure` definition unit tests methods. @@ -80,7 +78,7 @@ def test_focal_plane_exposure(self): ) -class TestArithmeticMeanFocalPlaneExposure(unittest.TestCase): +class TestArithmeticMeanFocalPlaneExposure: """ Define :func:`colour_hdri.exposure.dsc.\ arithmetic_mean_focal_plane_exposure` definition unit tests methods. @@ -103,7 +101,7 @@ def test_arithmetic_mean_focal_plane_exposure(self): ) -class TestSaturationBasedSpeedFocalPlaneExposure(unittest.TestCase): +class TestSaturationBasedSpeedFocalPlaneExposure: """ Define :func:`colour_hdri.exposure.dsc.\ saturation_based_speed_focal_plane_exposure` definition unit tests methods. @@ -133,7 +131,7 @@ def test_saturation_based_speed_focal_plane_exposure(self): ) -class TestExposureIndexValues(unittest.TestCase): +class TestExposureIndexValues: """ Define :func:`colour_hdri.exposure.dsc.exposure_index_values` definition unit tests methods. @@ -146,15 +144,13 @@ def test_exposure_index_values(self): """ np.testing.assert_allclose( - exposure_index_values( - np.array([0.16439371, 0.08810904, 0.09310904]) - ), + exposure_index_values(np.array([0.16439371, 0.08810904, 0.09310904])), np.array([60.82957797, 113.49573211, 107.40095699]), atol=TOLERANCE_ABSOLUTE_TESTS, ) -class TestExposureValue100(unittest.TestCase): +class TestExposureValue100: """ Define :func:`colour_hdri.exposure.dsc.exposure_value_100` definition unit tests methods. @@ -177,7 +173,7 @@ def test_exposure_value_100(self): ) -class TestPhotometricExposureScaleFactorLagarde2014(unittest.TestCase): +class TestPhotometricExposureScaleFactorLagarde2014: """ Define :func:`colour_hdri.exposure.dsc.\ photometric_exposure_scale_factor_Lagarde2014` definition unit tests @@ -200,7 +196,3 @@ def test_photometric_exposure_scale_factor_Lagarde2014(self): np.array([0.00005221, 0.00037884, 0.00135554]), atol=TOLERANCE_ABSOLUTE_TESTS, ) - - -if __name__ == "__main__": - unittest.main() diff --git a/colour_hdri/generation/hdri.py b/colour_hdri/generation/hdri.py index 8b1e8098..01c74d6c 100644 --- a/colour_hdri/generation/hdri.py +++ b/colour_hdri/generation/hdri.py @@ -2,7 +2,7 @@ HDRI Generation =============== -Defines the HDRI generation objects: +Define the HDRI generation objects: - :func:`colour_hdri.image_stack_to_HDRI` @@ -109,9 +109,7 @@ def image_stack_to_HDRI( image_data = image.data if camera_response_functions is not None: - camera_response_functions = as_float_array( - camera_response_functions - ) + camera_response_functions = as_float_array(camera_response_functions) samples = np.linspace(0, 1, camera_response_functions.shape[0]) R, G, B = tsplit(image.data) diff --git a/colour_hdri/generation/tests/test_hdri.py b/colour_hdri/generation/tests/test_hdri.py index 4e6a9514..850ffaec 100644 --- a/colour_hdri/generation/tests/test_hdri.py +++ b/colour_hdri/generation/tests/test_hdri.py @@ -1,10 +1,8 @@ -# !/usr/bin/env python """Define the unit tests for the :mod:`colour_hdri.generation.radiance` module.""" from __future__ import annotations import os -import unittest import numpy as np from colour import RGB_COLOURSPACES @@ -29,9 +27,7 @@ "TestImageStackToHDRI", ] -ROOT_RESOURCES_FROBISHER_001: str = os.path.join( - ROOT_RESOURCES_TESTS, "frobisher_001" -) +ROOT_RESOURCES_FROBISHER_001: str = os.path.join(ROOT_RESOURCES_TESTS, "frobisher_001") ROOT_RESOURCES_GENERATION: str = os.path.join( ROOT_RESOURCES_TESTS, "colour_hdri", "generation" @@ -40,7 +36,7 @@ IMAGES_JPG: List[str] = filter_files(ROOT_RESOURCES_FROBISHER_001, ("jpg",)) -class TestImageStackToHDRI(unittest.TestCase): +class TestImageStackToHDRI: """ Define :func:`colour_hdri.generation.radiance.image_stack_to_HDRI` definition unit tests methods. @@ -53,9 +49,7 @@ def test_image_stack_to_HDRI(self): """ image_stack = ImageStack.from_files(IMAGES_JPG) - image_stack.data = RGB_COLOURSPACES["sRGB"].cctf_decoding( - image_stack.data - ) + image_stack.data = RGB_COLOURSPACES["sRGB"].cctf_decoding(image_stack.data) # Lower precision for unit tests under *travis-ci*. np.testing.assert_allclose( @@ -66,7 +60,6 @@ def test_image_stack_to_HDRI(self): "test_image_stack_to_hdri_linear.npy", ) ), - rtol=0.0001, atol=0.0001, ) @@ -85,10 +78,5 @@ def test_image_stack_to_HDRI(self): "test_image_stack_to_hdri_crfs.npy", ) ), - rtol=0.0001, atol=0.0001, ) - - -if __name__ == "__main__": - unittest.main() diff --git a/colour_hdri/generation/tests/test_weighting_functions.py b/colour_hdri/generation/tests/test_weighting_functions.py index b150ad36..d095622b 100644 --- a/colour_hdri/generation/tests/test_weighting_functions.py +++ b/colour_hdri/generation/tests/test_weighting_functions.py @@ -1,10 +1,8 @@ -# !/usr/bin/env python """ Define the unit tests for the :mod:`colour_hdri.generation.weighting_functions` module. """ -import unittest import numpy as np from colour.constants import TOLERANCE_ABSOLUTE_TESTS @@ -29,7 +27,7 @@ ] -class TestNormalDistributionFunction(unittest.TestCase): +class TestNormalDistributionFunction: """ Define :func:`colour_hdri.generation.weighting_functions.\ normal_distribution_function` definition unit tests methods. @@ -99,7 +97,7 @@ def test_normal_distribution_function(self): ) -class TestHatFunction(unittest.TestCase): +class TestHatFunction: """ Define :func:`colour_hdri.generation.weighting_functions.hat_function` definition unit tests methods. @@ -131,7 +129,7 @@ def test_hat_function(self): ) -class TestWeightingFunctionDebevec1997(unittest.TestCase): +class TestWeightingFunctionDebevec1997: """ Define :func:`colour_hdri.generation.weighting_functions.\ weighting_function_Debevec1997` definition unit tests methods. @@ -199,7 +197,3 @@ def test_weighting_function_Debevec1997(self): ), atol=TOLERANCE_ABSOLUTE_TESTS, ) - - -if __name__ == "__main__": - unittest.main() diff --git a/colour_hdri/generation/weighting_functions.py b/colour_hdri/generation/weighting_functions.py index 479e416a..6f9d64a8 100644 --- a/colour_hdri/generation/weighting_functions.py +++ b/colour_hdri/generation/weighting_functions.py @@ -2,7 +2,7 @@ Weighting Functions =================== -Defines the weighting function objects used when generating HDRIs: +Define the weighting function objects used when generating HDRIs: - :func:`colour_hdri.normal_distribution_function` - :func:`colour_hdri.hat_function` diff --git a/colour_hdri/models/datasets/dng.py b/colour_hdri/models/datasets/dng.py index 436e0b4f..05a2deeb 100644 --- a/colour_hdri/models/datasets/dng.py +++ b/colour_hdri/models/datasets/dng.py @@ -2,7 +2,7 @@ Adobe DNG SDK Dataset ===================== -Defines various datasets objects for *Adobe DNG SDK*: +Define various datasets objects for *Adobe DNG SDK*: - :attr:`colour_hdri.models.datasets.dng.CCS_ILLUMINANT_ADOBEDNG` - :attr:`colour_hdri.models.datasets.dng.\ diff --git a/colour_hdri/models/dng.py b/colour_hdri/models/dng.py index b1f62f49..1d3cc749 100644 --- a/colour_hdri/models/dng.py +++ b/colour_hdri/models/dng.py @@ -2,7 +2,7 @@ Adobe DNG SDK Colour Processing =============================== -Defines various objects implementing *Adobe DNG SDK* colour processing: +Define various objects implementing *Adobe DNG SDK* colour processing: - :func:`colour_hdri.xy_to_camera_neutral` - :func:`colour_hdri.camera_neutral_to_xy` @@ -115,8 +115,7 @@ from colour.algebra import ( is_identity, linear_conversion, - matrix_dot, - vector_dot, + vecmul, ) from colour.constants import EPSILON from colour.hints import ArrayLike, Literal, NDArrayFloat @@ -302,7 +301,7 @@ def xy_to_camera_neutral( analog_balance, ) - camera_neutral = vector_dot(M_XYZ_to_camera, xy_to_XYZ(xy)) + camera_neutral = vecmul(M_XYZ_to_camera, xy_to_XYZ(xy)) camera_neutral /= camera_neutral[1] return camera_neutral @@ -408,7 +407,7 @@ def camera_neutral_to_xy( analog_balance, ) - XYZ = vector_dot(np.linalg.inv(M_XYZ_to_camera), camera_neutral) + XYZ = vecmul(np.linalg.inv(M_XYZ_to_camera), camera_neutral) xy = XYZ_to_xy(XYZ) if np.abs(np.sum(xy_p - xy)) <= epsilon: @@ -508,11 +507,7 @@ def matrix_XYZ_to_camera_space( CCT, _D_uv = uv_to_CCT_Robertson1968(uv) if is_identity(M_color_matrix_1) or is_identity(M_color_matrix_2): - M_CM = ( - M_color_matrix_1 - if is_identity(M_color_matrix_2) - else M_color_matrix_2 - ) + M_CM = M_color_matrix_1 if is_identity(M_color_matrix_2) else M_color_matrix_2 else: M_CM = matrix_interpolated( CCT, @@ -530,7 +525,7 @@ def matrix_XYZ_to_camera_space( M_camera_calibration_2, ) - M_XYZ_to_camera_space = matrix_dot(matrix_dot(M_AB, M_CC), M_CM) + M_XYZ_to_camera_space = np.matmul(np.matmul(M_AB, M_CC), M_CM) return M_XYZ_to_camera_space @@ -546,21 +541,23 @@ def matrix_camera_space_to_XYZ( analog_balance: ArrayLike, M_forward_matrix_1: ArrayLike, M_forward_matrix_2: ArrayLike, - chromatic_adaptation_transform: Literal[ - "Bianco 2010", - "Bianco PC 2010", - "Bradford", - "CAT02 Brill 2008", - "CAT02", - "CAT16", - "CMCCAT2000", - "CMCCAT97", - "Fairchild", - "Sharp", - "Von Kries", - "XYZ Scaling", - ] - | str = "Bradford", + chromatic_adaptation_transform: ( + Literal[ + "Bianco 2010", + "Bianco PC 2010", + "Bradford", + "CAT02 Brill 2008", + "CAT02", + "CAT16", + "CMCCAT2000", + "CMCCAT97", + "Fairchild", + "Sharp", + "Von Kries", + "XYZ Scaling", + ] + | str + ) = "Bradford", ) -> NDArrayFloat: """ Return the *Camera Space* to *CIE XYZ* matrix for given *xy* white @@ -677,7 +674,7 @@ def matrix_camera_space_to_XYZ( xy_to_XYZ(CCS_ILLUMINANT_ADOBEDNG), chromatic_adaptation_transform, ) - M_camera_space_to_XYZ = matrix_dot(M_CAT, M_camera_to_XYZ) + M_camera_space_to_XYZ = np.matmul(M_CAT, M_camera_to_XYZ) else: uv = UCS_to_uv(XYZ_to_UCS(xy_to_XYZ(xy))) CCT, _D_uv = uv_to_CCT_Robertson1968(uv) @@ -712,8 +709,8 @@ def matrix_camera_space_to_XYZ( M_AB = np.diagflat(analog_balance) - M_reference_neutral = vector_dot( - np.linalg.inv(matrix_dot(M_AB, M_CC)), camera_neutral + M_reference_neutral = vecmul( + np.linalg.inv(np.matmul(M_AB, M_CC)), camera_neutral ) M_D = np.linalg.inv(np.diagflat(M_reference_neutral)) M_FM = matrix_interpolated( @@ -723,8 +720,8 @@ def matrix_camera_space_to_XYZ( M_forward_matrix_1, M_forward_matrix_2, ) - M_camera_space_to_XYZ = matrix_dot( - matrix_dot(M_FM, M_D), np.linalg.inv(matrix_dot(M_AB, M_CC)) + M_camera_space_to_XYZ = np.matmul( + np.matmul(M_FM, M_D), np.linalg.inv(np.matmul(M_AB, M_CC)) ) return M_camera_space_to_XYZ diff --git a/colour_hdri/models/rgb.py b/colour_hdri/models/rgb.py index 9bfe1807..45b4b600 100644 --- a/colour_hdri/models/rgb.py +++ b/colour_hdri/models/rgb.py @@ -2,7 +2,7 @@ RGB Colourspace & Transformations ================================= -Defines the following *RGB* colourspace transformations: +Define the following *RGB* colourspace transformations: - :func:`colour_hdri.camera_space_to_RGB` - :func:`colour_hdri.camera_space_to_sRGB` @@ -11,7 +11,7 @@ from __future__ import annotations import numpy as np -from colour.algebra import matrix_dot, vector_dot +from colour.algebra import vecmul from colour.hints import ArrayLike, NDArrayFloat from colour.models import RGB_COLOURSPACES @@ -74,11 +74,11 @@ def camera_space_to_RGB( array([ 0.7564180..., 0.8683192..., 0.6044589...]) """ - M_RGB_camera = matrix_dot(M_XYZ_to_camera_space, matrix_RGB_to_XYZ) + M_RGB_camera = np.matmul(M_XYZ_to_camera_space, matrix_RGB_to_XYZ) M_RGB_camera /= np.transpose(np.sum(M_RGB_camera, axis=1)[None]) - RGB_f = vector_dot(np.linalg.inv(M_RGB_camera), RGB) + RGB_f = vecmul(np.linalg.inv(M_RGB_camera), RGB) return RGB_f diff --git a/colour_hdri/models/tests/test_adobe_dng.py b/colour_hdri/models/tests/test_adobe_dng.py index 2b4bdb27..44c433d7 100644 --- a/colour_hdri/models/tests/test_adobe_dng.py +++ b/colour_hdri/models/tests/test_adobe_dng.py @@ -1,4 +1,3 @@ -# !/usr/bin/env python """ Define the unit tests for the :mod:`colour_hdri.models.dng` module. @@ -10,8 +9,6 @@ from __future__ import annotations -import unittest - import numpy as np from colour.constants import TOLERANCE_ABSOLUTE_TESTS from colour.hints import NDArrayFloat @@ -99,7 +96,7 @@ ) -class TestMatrixInterpolated(unittest.TestCase): +class TestMatrixInterpolated: """ Define :func:`colour_hdri.models.adobe_dng.matrix_interpolated` definition unit tests methods. @@ -119,47 +116,37 @@ def test_matrix_interpolated(self): ] ) np.testing.assert_allclose( - matrix_interpolated( - 5000, 2850, 6500, M_COLOR_MATRIX_1, M_COLOR_MATRIX_2 - ), + matrix_interpolated(5000, 2850, 6500, M_COLOR_MATRIX_1, M_COLOR_MATRIX_2), M_reference, atol=TOLERANCE_ABSOLUTE_TESTS, ) np.testing.assert_allclose( - matrix_interpolated( - 2850, 2850, 6500, M_COLOR_MATRIX_1, M_COLOR_MATRIX_2 - ), + matrix_interpolated(2850, 2850, 6500, M_COLOR_MATRIX_1, M_COLOR_MATRIX_2), M_COLOR_MATRIX_1, atol=TOLERANCE_ABSOLUTE_TESTS, ) np.testing.assert_allclose( - matrix_interpolated( - 1000, 2850, 6500, M_COLOR_MATRIX_1, M_COLOR_MATRIX_2 - ), + matrix_interpolated(1000, 2850, 6500, M_COLOR_MATRIX_1, M_COLOR_MATRIX_2), M_COLOR_MATRIX_1, atol=TOLERANCE_ABSOLUTE_TESTS, ) np.testing.assert_allclose( - matrix_interpolated( - 6500, 2850, 6500, M_COLOR_MATRIX_1, M_COLOR_MATRIX_2 - ), + matrix_interpolated(6500, 2850, 6500, M_COLOR_MATRIX_1, M_COLOR_MATRIX_2), M_COLOR_MATRIX_2, atol=TOLERANCE_ABSOLUTE_TESTS, ) np.testing.assert_allclose( - matrix_interpolated( - 10000, 2850, 6500, M_COLOR_MATRIX_1, M_COLOR_MATRIX_2 - ), + matrix_interpolated(10000, 2850, 6500, M_COLOR_MATRIX_1, M_COLOR_MATRIX_2), M_COLOR_MATRIX_2, atol=TOLERANCE_ABSOLUTE_TESTS, ) -class TestXy_to_camera_neutral(unittest.TestCase): +class TestXy_to_camera_neutral: """ Define :func:`colour_hdri.models.adobe_dng.\ xy_to_camera_neutral` definition unit tests methods. @@ -217,7 +204,7 @@ def test_xy_to_camera_neutral(self): ) -class TestCamera_neutral_to_xy(unittest.TestCase): +class TestCamera_neutral_to_xy: """ Define :func:`colour_hdri.models.adobe_dng.\ camera_neutral_to_xy` definition unit tests methods. @@ -275,7 +262,7 @@ def test_camera_neutral_to_xy(self): ) -class TestMatrix_XYZ_to_camera_space(unittest.TestCase): +class TestMatrix_XYZ_to_camera_space: """ Define :func:`colour_hdri.models.adobe_dng.\ matrix_XYZ_to_camera_space` definition unit tests methods. @@ -353,7 +340,7 @@ def test_matrix_XYZ_to_camera_space(self): ) -class TestMatrix_Camera_space_to_XYZ(unittest.TestCase): +class TestMatrix_Camera_space_to_XYZ: """ Define :func:`colour_hdri.models.adobe_dng.\ matrix_camera_space_to_XYZ` definition unit tests methods. @@ -460,7 +447,3 @@ def test_matrix_camera_space_to_XYZ(self): M_reference, atol=TOLERANCE_ABSOLUTE_TESTS, ) - - -if __name__ == "__main__": - unittest.main() diff --git a/colour_hdri/models/tests/test_rgb.py b/colour_hdri/models/tests/test_rgb.py index b90ef594..605524aa 100644 --- a/colour_hdri/models/tests/test_rgb.py +++ b/colour_hdri/models/tests/test_rgb.py @@ -1,7 +1,5 @@ -# !/usr/bin/env python """Define the unit tests for the :mod:`colour_hdri.models.rgb` module.""" -import unittest import numpy as np from colour.constants import TOLERANCE_ABSOLUTE_TESTS @@ -21,7 +19,7 @@ ] -class TestCameraSpaceToRGB(unittest.TestCase): +class TestCameraSpaceToRGB: """ Define :func:`colour_hdri.models.rgb.camera_space_to_RGB` definition unit tests methods. @@ -53,7 +51,7 @@ def test_camera_space_to_RGB(self): ) -class TestCameraSpaceTosRGB(unittest.TestCase): +class TestCameraSpaceTosRGB: """ Define :func:`colour_hdri.models.rgb.camera_space_to_sRGB` definition unit tests methods. @@ -76,7 +74,3 @@ def test_camera_space_to_sRGB(self): np.array([0.75643502, 0.86831555, 0.60447061]), atol=TOLERANCE_ABSOLUTE_TESTS, ) - - -if __name__ == "__main__": - unittest.main() diff --git a/colour_hdri/plotting/hdri.py b/colour_hdri/plotting/hdri.py index 71a8e718..c7d8c4e1 100644 --- a/colour_hdri/plotting/hdri.py +++ b/colour_hdri/plotting/hdri.py @@ -2,7 +2,7 @@ HDRI Plotting ============= -Defines the HDRI plotting objects: +Define the HDRI plotting objects: - :func:`colour_hdri.plotting.plot_HDRI_strip` """ @@ -77,9 +77,7 @@ def plot_HDRI_strip( ev = i * ev_steps axis = plt.subplot(grid[i]) axis.imshow(np.clip(cctf_encoding(adjust_exposure(image, ev)), 0, 1)) - axis.text( - width * 0.05, height - height * 0.05, f"EV {ev}", color=(1, 1, 1) - ) + axis.text(width * 0.05, height - height * 0.05, f"EV {ev}", color=(1, 1, 1)) axis.set_xticks([]) axis.set_yticks([]) axis.set_aspect("equal") diff --git a/colour_hdri/plotting/tonemapping.py b/colour_hdri/plotting/tonemapping.py index b7fd4b04..de36fd3e 100644 --- a/colour_hdri/plotting/tonemapping.py +++ b/colour_hdri/plotting/tonemapping.py @@ -2,7 +2,7 @@ Tonemapping Operators Plotting ============================== -Defines the tonemapping operators plotting objects: +Define the tonemapping operators plotting objects: - :func:`colour_hdri.plotting.plot_tonemapping_operator_image` """ @@ -115,8 +115,6 @@ def plot_tonemapping_operator_image( } ) plt.gca().set_xscale("log", basex=2) - plt.gca().xaxis.set_major_formatter( - matplotlib.ticker.ScalarFormatter() - ) + plt.gca().xaxis.set_major_formatter(matplotlib.ticker.ScalarFormatter()) return render(**settings) diff --git a/colour_hdri/process/dng.py b/colour_hdri/process/dng.py index ec80d36c..5fd1e066 100644 --- a/colour_hdri/process/dng.py +++ b/colour_hdri/process/dng.py @@ -2,7 +2,7 @@ Adobe DNG SDK Conversion Process ================================ -Defines various objects implementing raw conversion based on *Adobe DNG SDK* +Define various objects implementing raw conversion based on *Adobe DNG SDK* and *dcraw*: - :func:`colour_hdri.convert_raw_files_to_dng_files` @@ -55,6 +55,8 @@ "read_dng_files_exif_tags", ] +LOGGER = logging.getLogger(__name__) + _IS_MACOS_PLATFORM: bool = platform.system() == "Darwin" """Whether the current platform is *macOS*.""" @@ -70,13 +72,11 @@ RAW_CONVERTER_ARGUMENTS_BAYER_CFA: str = '-t 0 -D -W -4 -T "{raw_file}"' if _IS_WINDOWS_PLATFORM: - RAW_CONVERTER_ARGUMENTS_BAYER_CFA = ( - RAW_CONVERTER_ARGUMENTS_BAYER_CFA.replace('"', "") + RAW_CONVERTER_ARGUMENTS_BAYER_CFA = RAW_CONVERTER_ARGUMENTS_BAYER_CFA.replace( + '"', "" ) if is_documentation_building(): # pragma: no cover - RAW_CONVERTER_ARGUMENTS_BAYER_CFA = DocstringText( - RAW_CONVERTER_ARGUMENTS_BAYER_CFA - ) + RAW_CONVERTER_ARGUMENTS_BAYER_CFA = DocstringText(RAW_CONVERTER_ARGUMENTS_BAYER_CFA) RAW_CONVERTER_ARGUMENTS_BAYER_CFA.__doc__ = """ Arguments for the command line raw conversion application for non demosaiced linear *tiff* file format output. @@ -86,8 +86,8 @@ '-t 0 -H 1 -r 1 1 1 1 -4 -q 3 -o 0 -T "{raw_file}"' ) if _IS_WINDOWS_PLATFORM: - RAW_CONVERTER_ARGUMENTS_DEMOSAICING = ( - RAW_CONVERTER_ARGUMENTS_DEMOSAICING.replace('"', "") + RAW_CONVERTER_ARGUMENTS_DEMOSAICING = RAW_CONVERTER_ARGUMENTS_DEMOSAICING.replace( + '"', "" ) if is_documentation_building(): # pragma: no cover RAW_CONVERTER_ARGUMENTS_DEMOSAICING = DocstringText( @@ -100,8 +100,7 @@ if _IS_MACOS_PLATFORM: DNG_CONVERTER: str = ( - "/Applications/Adobe DNG Converter.app/Contents/" - "MacOS/Adobe DNG Converter" + "/Applications/Adobe DNG Converter.app/Contents/MacOS/Adobe DNG Converter" ) elif _IS_WINDOWS_PLATFORM: DNG_CONVERTER: str = "Adobe DNG Converter" @@ -138,29 +137,29 @@ "F Number": (parse_exif_number, None), "ISO": (parse_exif_number, None), "CFA Pattern 2": ( - lambda x: parse_exif_array(x, np.int_), + lambda x: parse_exif_array(x, np.int64), None, ), "CFA Plane Color": ( - lambda x: parse_exif_array(x, np.int_), + lambda x: parse_exif_array(x, np.int64), None, ), "Black Level Repeat Dim": ( - lambda x: parse_exif_array(x, np.int_), + lambda x: parse_exif_array(x, np.int64), None, ), - "Black Level": (lambda x: parse_exif_array(x, np.int_), None), - "White Level": (lambda x: parse_exif_array(x, np.int_), None), + "Black Level": (lambda x: parse_exif_array(x, np.int64), None), + "White Level": (lambda x: parse_exif_array(x, np.int64), None), "Samples Per Pixel": ( - lambda x: parse_exif_number(x, np.int_), + lambda x: parse_exif_number(x, np.int64), None, ), - "Active Area": (lambda x: parse_exif_array(x, np.int_), None), - "Orientation": (lambda x: parse_exif_number(x, np.int_), None), + "Active Area": (lambda x: parse_exif_array(x, np.int64), None), + "Orientation": (lambda x: parse_exif_number(x, np.int64), None), "Camera Calibration Sig": (parse_exif_string, None), "Profile Calibration Sig": (parse_exif_string, None), "Calibration Illuminant 1": ( - lambda x: parse_exif_number(x, np.int_), + lambda x: parse_exif_number(x, np.int64), 17, ), "Calibration Illuminant 2": ( @@ -168,51 +167,51 @@ 21, ), "Color Matrix 1": ( - lambda x: parse_exif_array(x, np.float_, (3, 3)), + lambda x: parse_exif_array(x, np.float64, (3, 3)), "1 0 0 0 1 0 0 0 1", ), "Color Matrix 2": ( - lambda x: parse_exif_array(x, np.float_, (3, 3)), + lambda x: parse_exif_array(x, np.float64, (3, 3)), "1 0 0 0 1 0 0 0 1", ), "Camera Calibration 1": ( - lambda x: parse_exif_array(x, np.float_, (3, 3)), + lambda x: parse_exif_array(x, np.float64, (3, 3)), "1 0 0 0 1 0 0 0 1", ), "Camera Calibration 2": ( - lambda x: parse_exif_array(x, np.float_, (3, 3)), + lambda x: parse_exif_array(x, np.float64, (3, 3)), "1 0 0 0 1 0 0 0 1", ), "Analog Balance": ( - lambda x: parse_exif_array(x, np.float_), + lambda x: parse_exif_array(x, np.float64), "1 1 1", ), "Reduction Matrix 1": ( - lambda x: parse_exif_array(x, np.float_, (3, 3)), + lambda x: parse_exif_array(x, np.float64, (3, 3)), "1 0 0 0 1 0 0 0 1", ), "Reduction Matrix 2": ( - lambda x: parse_exif_array(x, np.float_, (3, 3)), + lambda x: parse_exif_array(x, np.float64, (3, 3)), "1 0 0 0 1 0 0 0 1", ), "Forward Matrix 1": ( - lambda x: parse_exif_array(x, np.float_, (3, 3)), + lambda x: parse_exif_array(x, np.float64, (3, 3)), "1 0 0 0 1 0 0 0 1", ), "Forward Matrix 2": ( - lambda x: parse_exif_array(x, np.float_, (3, 3)), + lambda x: parse_exif_array(x, np.float64, (3, 3)), "1 0 0 0 1 0 0 0 1", ), "As Shot Neutral": ( - lambda x: parse_exif_array(x, np.float_), + lambda x: parse_exif_array(x, np.float64), "1 1 1", ), "Baseline Exposure": ( - lambda x: parse_exif_number(x, np.float_), + lambda x: parse_exif_number(x, np.float64), None, ), "Baseline Noise": ( - lambda x: parse_exif_number(x, np.float_), + lambda x: parse_exif_number(x, np.float64), None, ), } @@ -257,26 +256,23 @@ def convert_raw_files_to_dng_files( """ dng_converter = optional(dng_converter, DNG_CONVERTER) - dng_converter_arguments = optional( - dng_converter_arguments, DNG_CONVERTER_ARGUMENTS - ) + dng_converter_arguments = optional(dng_converter_arguments, DNG_CONVERTER_ARGUMENTS) dng_files = [] for raw_file in raw_files: raw_file_extension = os.path.splitext(raw_file)[1] dng_file = os.path.join( output_directory, - os.path.basename( - re.sub(f"{raw_file_extension}$", ".dng", raw_file) - ), + os.path.basename(re.sub(f"{raw_file_extension}$", ".dng", raw_file)), ) if path_exists(dng_file): os.remove(dng_file) - logging.info( - 'Converting "{raw_file}" file to "{dng_file}" file.', - extra={"raw_file": raw_file, "dng_file": dng_file}, + LOGGER.info( + 'Converting "%s" file to "%s" file.', + raw_file, + dng_file, ) command = [ @@ -336,12 +332,10 @@ def convert_dng_files_to_intermediate_files( if path_exists(intermediate_file): os.remove(intermediate_file) - logging.info( - 'Converting "{dng_file}" file to "{intermediate_file}" file.', - extra={ - "dng_file": dng_file, - "intermediate_file": intermediate_file, - }, + LOGGER.info( + 'Converting "%s" file to "%s" file.', + dng_file, + intermediate_file, ) command = [ @@ -356,9 +350,7 @@ def convert_dng_files_to_intermediate_files( subprocess.call(command, shell=_IS_WINDOWS_PLATFORM) # noqa: S603 - tiff_file = os.path.join( - output_directory, os.path.basename(intermediate_file) - ) + tiff_file = os.path.join(output_directory, os.path.basename(intermediate_file)) if tiff_file != intermediate_file: if path_exists(tiff_file): os.remove(tiff_file) @@ -402,9 +394,7 @@ def read_dng_files_exif_tags( exif_tag = exif_tags[group].get(tag) if exif_tag is None: binding[group][tag] = ( - default - if default is None - else parser(EXIFTag(value=default)) + default if default is None else parser(EXIFTag(value=default)) ) else: binding[group][tag] = parser(exif_tag[0]) diff --git a/colour_hdri/process/tests/test_dng.py b/colour_hdri/process/tests/test_dng.py index 80b87744..f67afa19 100644 --- a/colour_hdri/process/tests/test_dng.py +++ b/colour_hdri/process/tests/test_dng.py @@ -1,4 +1,3 @@ -# !/usr/bin/env python """Define the unit tests for the :mod:`colour_hdri.process.adobe_dng` module.""" from __future__ import annotations @@ -7,7 +6,6 @@ import platform import shutil import tempfile -import unittest import zipfile import numpy as np @@ -38,29 +36,25 @@ "TestConvertDngFilesToIntermediateFiles", ] -ROOT_RESOURCES_FROBISHER_001: str = os.path.join( - ROOT_RESOURCES_TESTS, "frobisher_001" -) +ROOT_RESOURCES_FROBISHER_001: str = os.path.join(ROOT_RESOURCES_TESTS, "frobisher_001") -ROOT_PROCESS: str = os.path.join( - ROOT_RESOURCES_TESTS, "colour_hdri", "process" -) +ROOT_PROCESS: str = os.path.join(ROOT_RESOURCES_TESTS, "colour_hdri", "process") IMAGES_RAW: List[str] = filter_files(ROOT_RESOURCES_FROBISHER_001, ("CR2",)) -class TestConvertRawFilesToDngFiles(unittest.TestCase): +class TestConvertRawFilesToDngFiles: """ Define :func:`colour_hdri.process.adobe_dng.\ convert_raw_files_to_dng_files` definition unit tests methods. """ - def setUp(self): + def setup_method(self): """Initialise the common tests attributes.""" self._temporary_directory = tempfile.mkdtemp() - def tearDown(self): + def teardown_method(self): """After tests actions.""" shutil.rmtree(self._temporary_directory) @@ -78,9 +72,7 @@ def test_convert_raw_files_to_dng_files(self): reference_dng_files = sorted(filter_files(ROOT_PROCESS, ("dng",))) test_dng_files = sorted( - convert_raw_files_to_dng_files( - IMAGES_RAW, self._temporary_directory - ) + convert_raw_files_to_dng_files(IMAGES_RAW, self._temporary_directory) ) for test_dng_file, reference_dng_file in zip( @@ -93,18 +85,18 @@ def test_convert_raw_files_to_dng_files(self): ) -class TestConvertDngFilesToIntermediateFiles(unittest.TestCase): +class TestConvertDngFilesToIntermediateFiles: """ Define :func:`colour_hdri.process.adobe_dng.\ convert_dng_files_to_intermediate_files` definition unit tests methods. """ - def setUp(self): + def setup_method(self): """Initialise the common tests attributes.""" self._temporary_directory = tempfile.mkdtemp() - def tearDown(self): + def teardown_method(self): """After tests actions.""" shutil.rmtree(self._temporary_directory) @@ -170,7 +162,7 @@ def test_convert_dng_files_to_intermediate_files(self): ) -class TestReadDngFilesExifTags(unittest.TestCase): +class TestReadDngFilesExifTags: """ Define :func:`colour_hdri.process.adobe_dng.\ read_dng_files_exif_tags` definition unit tests methods. @@ -184,9 +176,9 @@ def test_read_dng_files_exif_tags(self): reference_dng_files = sorted(filter_files(ROOT_PROCESS, ("dng",))) exif_tags = read_dng_files_exif_tags(reference_dng_files) - self.assertEqual(len(exif_tags), 3) - self.assertIn("EXIF", exif_tags[0]) - self.assertIn("Make", exif_tags[0]["EXIF"]) + assert len(exif_tags) == 3 + assert "EXIF" in exif_tags[0] + assert "Make" in exif_tags[0]["EXIF"] np.testing.assert_allclose( exif_tags[0]["EXIF"]["Exposure Time"], @@ -197,7 +189,3 @@ def test_read_dng_files_exif_tags(self): np.testing.assert_array_equal( exif_tags[0]["EXIF"]["Reduction Matrix 1"], np.identity(3) ) - - -if __name__ == "__main__": - unittest.main() diff --git a/colour_hdri/recovery/highlights.py b/colour_hdri/recovery/highlights.py index b24bd9ea..5eb7e01d 100644 --- a/colour_hdri/recovery/highlights.py +++ b/colour_hdri/recovery/highlights.py @@ -2,7 +2,7 @@ Clipped Highlights Recovery =========================== -Defines the clipped highlights recovery objects: +Define the clipped highlights recovery objects: - :func:`colour_hdri.highlights_recovery_blend` - :func:`colour_hdri.highlights_recovery_LCHab` @@ -22,12 +22,12 @@ from __future__ import annotations import numpy as np -from colour.algebra import vector_dot +from colour.algebra import vecmul from colour.hints import ArrayLike, NDArrayFloat +from colour.models import Lab_to_LCHab # pyright: ignore +from colour.models import LCHab_to_Lab # pyright: ignore from colour.models import ( - Lab_to_LCHab, Lab_to_XYZ, - LCHab_to_Lab, RGB_Colourspace, RGB_COLOURSPACE_sRGB, RGB_to_XYZ, @@ -84,9 +84,9 @@ def highlights_recovery_blend( clipping_level = np.min(multipliers) * threshold - Lab = vector_dot(M, RGB) + Lab = vecmul(M, RGB) - Lab_c = vector_dot(M, np.minimum(RGB, clipping_level)) + Lab_c = vecmul(M, np.minimum(RGB, clipping_level)) s = np.sum((Lab * Lab)[..., 1:3], axis=2) s_c = np.sum((Lab_c * Lab_c)[..., 1:3], axis=2) @@ -96,7 +96,7 @@ def highlights_recovery_blend( Lab[:, :, 1:3] *= np.rollaxis(ratio[None], 0, 3) - RGB_o = vector_dot(np.linalg.inv(M), Lab) + RGB_o = vecmul(np.linalg.inv(M), Lab) return RGB_o @@ -147,8 +147,6 @@ def highlights_recovery_LCHab( ) return XYZ_to_RGB( - Lab_to_XYZ( - LCHab_to_Lab(tstack([L, C_c, H])), RGB_colourspace.whitepoint - ), + Lab_to_XYZ(LCHab_to_Lab(tstack([L, C_c, H])), RGB_colourspace.whitepoint), RGB_colourspace, ) diff --git a/colour_hdri/recovery/tests/test_recovery.py b/colour_hdri/recovery/tests/test_recovery.py index 6eb60cd0..01ce85dc 100644 --- a/colour_hdri/recovery/tests/test_recovery.py +++ b/colour_hdri/recovery/tests/test_recovery.py @@ -1,4 +1,3 @@ -# !/usr/bin/env python """Define the unit tests for the :mod:`colour_hdri.recovery.highlights` module.""" from __future__ import annotations @@ -10,7 +9,6 @@ import shutil import subprocess import tempfile -import unittest import numpy as np from colour import read_image @@ -47,9 +45,7 @@ _IS_WINDOWS_PLATFORM: bool = platform.system() in ("Windows", "Microsoft") """Whether the current platform is *Windows*.""" -ROOT_RESOURCES_FROBISHER_001: str = os.path.join( - ROOT_RESOURCES_TESTS, "frobisher_001" -) +ROOT_RESOURCES_FROBISHER_001: str = os.path.join(ROOT_RESOURCES_TESTS, "frobisher_001") ROOT_RESOURCES_RECOVERY: str = os.path.join( ROOT_RESOURCES_TESTS, "colour_hdri", "recovery" @@ -66,18 +62,18 @@ ) -class TestHighlightsRecoveryBlend(unittest.TestCase): +class TestHighlightsRecoveryBlend: """ - Define :func:`colour_hdri.recovery.highlights.\ -highlights_recovery_blend` definition unit tests methods. + Define :func:`colour_hdri.recovery.highlights.highlights_recovery_blend` + definition unit tests methods. """ - def setUp(self): + def setup_method(self): """Initialise the common tests attributes.""" self._temporary_directory = tempfile.mkdtemp() - def tearDown(self): + def teardown_method(self): """After tests actions.""" shutil.rmtree(self._temporary_directory) @@ -99,18 +95,16 @@ def test_highlights_recovery_blend(self): command = [ RAW_CONVERTER, *shlex.split( - RAW_CONVERTER_ARGUMENTS_DEMOSAICING.format( - raw_file=test_raw_file - ), + RAW_CONVERTER_ARGUMENTS_DEMOSAICING.format(raw_file=test_raw_file), posix=not _IS_WINDOWS_PLATFORM, ), ] subprocess.call(command) # noqa: S603 - test_tiff_file = read_image( - str(re.sub("\\.CR2$", ".tiff", test_raw_file)) - )[::10, ::10, :] + test_tiff_file = read_image(str(re.sub("\\.CR2$", ".tiff", test_raw_file)))[ + ::10, ::10, : + ] test_tiff_file *= multipliers test_tiff_file = highlights_recovery_blend(test_tiff_file, multipliers) @@ -123,23 +117,21 @@ def test_highlights_recovery_blend(self): ) reference_exr_file = read_image(str(reference_exr_path)) - np.testing.assert_allclose( - test_tiff_file, reference_exr_file, rtol=0.0001, atol=0.0001 - ) + np.testing.assert_allclose(test_tiff_file, reference_exr_file, atol=0.0025) -class TestHighlightsRecoveryLCHab(unittest.TestCase): +class TestHighlightsRecoveryLCHab: """ - Define :func:`colour_hdri.recovery.highlights.\ -highlights_recovery_LCHab` definition unit tests methods. + Define :func:`colour_hdri.recovery.highlights.highlights_recovery_LCHab` + definition unit tests methods. """ - def setUp(self): + def setup_method(self): """Initialise the common tests attributes.""" self._temporary_directory = tempfile.mkdtemp() - def tearDown(self): + def teardown_method(self): """After tests actions.""" shutil.rmtree(self._temporary_directory) @@ -161,23 +153,19 @@ def test_highlights_recovery_LCHab(self): command = [ RAW_CONVERTER, *shlex.split( - RAW_CONVERTER_ARGUMENTS_DEMOSAICING.format( - raw_file=test_raw_file - ), + RAW_CONVERTER_ARGUMENTS_DEMOSAICING.format(raw_file=test_raw_file), posix=not _IS_WINDOWS_PLATFORM, ), ] subprocess.call(command) # noqa: S603 - test_tiff_file = read_image( - str(re.sub("\\.CR2$", ".tiff", test_raw_file)) - )[::10, ::10, :] + test_tiff_file = read_image(str(re.sub("\\.CR2$", ".tiff", test_raw_file)))[ + ::10, ::10, : + ] test_tiff_file *= multipliers - test_tiff_file = highlights_recovery_LCHab( - test_tiff_file, min(multipliers) - ) + test_tiff_file = highlights_recovery_LCHab(test_tiff_file, min(multipliers)) test_tiff_file = camera_space_to_sRGB( test_tiff_file, matrix_XYZ_to_camera_space ) @@ -188,10 +176,4 @@ def test_highlights_recovery_LCHab(self): ) reference_exr_file = read_image(str(reference_exr_path)) - np.testing.assert_allclose( - test_tiff_file, reference_exr_file, rtol=0.0001, atol=0.0001 - ) - - -if __name__ == "__main__": - unittest.main() + np.testing.assert_allclose(test_tiff_file, reference_exr_file, atol=0.0025) diff --git a/colour_hdri/sampling/grossberg2003.py b/colour_hdri/sampling/grossberg2003.py index d6be622b..64969219 100644 --- a/colour_hdri/sampling/grossberg2003.py +++ b/colour_hdri/sampling/grossberg2003.py @@ -2,7 +2,7 @@ Grossberg (2003) Histogram Based Image Sampling =============================================== -Defines the *Grossberg (2003)* histogram based image sampling objects: +Define the *Grossberg (2003)* histogram based image sampling objects: - :func:`colour_hdri.samples_Grossberg2003` @@ -46,7 +46,7 @@ def samples_Grossberg2003( image_stack Stack of single channel or multi-channel floating point images. samples - Samples count. + Sample count. n Histograms bins count. @@ -73,15 +73,13 @@ def samples_Grossberg2003( ] ) cdf = np.cumsum(histograms, axis=0) - cdf_i.append(cdf.astype(np.float_) / np.max(cdf, axis=0)) + cdf_i.append(cdf.astype(np.float64) / np.max(cdf, axis=0)) samples_cdf_i = np.zeros((samples, len(cdf_i), channels_c)) samples_u = np.linspace(0, 1, samples) for i in np.arange(samples): for j in np.arange(channels_c): for k, cdf in enumerate(cdf_i): - samples_cdf_i[i, k, j] = np.argmin( - np.abs(cdf[:, j] - samples_u[i]) - ) + samples_cdf_i[i, k, j] = np.argmin(np.abs(cdf[:, j] - samples_u[i])) return samples_cdf_i diff --git a/colour_hdri/sampling/tests/test_grossberg2003.py b/colour_hdri/sampling/tests/test_grossberg2003.py index 6ee4fdbd..fa9f3eb9 100644 --- a/colour_hdri/sampling/tests/test_grossberg2003.py +++ b/colour_hdri/sampling/tests/test_grossberg2003.py @@ -1,4 +1,3 @@ -# !/usr/bin/env python """ Define the unit tests for the :mod:`colour_hdri.sampling.grossberg2003` module. @@ -7,7 +6,6 @@ from __future__ import annotations import os -import unittest import numpy as np from colour.constants import TOLERANCE_ABSOLUTE_TESTS @@ -31,9 +29,7 @@ "TestSamplesGrossberg2003", ] -ROOT_RESOURCES_FROBISHER_001: str = os.path.join( - ROOT_RESOURCES_TESTS, "frobisher_001" -) +ROOT_RESOURCES_FROBISHER_001: str = os.path.join(ROOT_RESOURCES_TESTS, "frobisher_001") ROOT_RESOURCES_SAMPLING: str = os.path.join( ROOT_RESOURCES_TESTS, "colour_hdri", "sampling" @@ -42,7 +38,7 @@ IMAGES_JPG: List[str] = filter_files(ROOT_RESOURCES_FROBISHER_001, ("jpg",)) -class TestSamplesGrossberg2003(unittest.TestCase): +class TestSamplesGrossberg2003: """ Define :func:`colour_hdri.sampling.grossberg2003.\ samples_Grossberg2003` definition unit tests methods. @@ -57,13 +53,7 @@ def test_samples_Grossberg2003(self): np.testing.assert_allclose( samples_Grossberg2003(ImageStack.from_files(IMAGES_JPG).data), np.load( - os.path.join( - ROOT_RESOURCES_SAMPLING, "test_samples_Grossberg2003.npy" - ) + os.path.join(ROOT_RESOURCES_SAMPLING, "test_samples_Grossberg2003.npy") ), atol=TOLERANCE_ABSOLUTE_TESTS, ) - - -if __name__ == "__main__": - unittest.main() diff --git a/colour_hdri/sampling/tests/test_variance_minimization.py b/colour_hdri/sampling/tests/test_variance_minimization.py index 15f15d6b..b6d6b106 100644 --- a/colour_hdri/sampling/tests/test_variance_minimization.py +++ b/colour_hdri/sampling/tests/test_variance_minimization.py @@ -1,4 +1,3 @@ -# !/usr/bin/env python """ Define the unit tests for the :mod:`colour_hdri.sampling.variance_minimization` module. @@ -7,7 +6,6 @@ from __future__ import annotations import os -import unittest import numpy as np from colour import RGB_COLOURSPACES, RGB_luminance, read_image @@ -42,7 +40,7 @@ ) -class TestLuminanceVariance(unittest.TestCase): +class TestLuminanceVariance: """ Define :func:`colour_hdri.sampling.variance_minimization.\ luminance_variance` definition unit tests methods. @@ -61,7 +59,7 @@ def test_luminance_variance(self): ) -class TestFindRegionsVarianceMinimizationViriyothai2009(unittest.TestCase): +class TestFindRegionsVarianceMinimizationViriyothai2009: """ Define :func:`colour_hdri.sampling.variance_minimization.\ find_regions_variance_minimization_Viriyothai2009` definition unit tests @@ -89,44 +87,38 @@ def test_find_regions_variance_minimization_Viriyothai2009(self): Y = RGB_luminance(image, colourspace.primaries, colourspace.whitepoint) regions = find_regions_variance_minimization_Viriyothai2009(Y, n=1) - self.assertListEqual(regions, [(0, 256, 0, 156), (0, 256, 156, 256)]) + assert regions == [(0, 256, 0, 156), (0, 256, 156, 256)] regions = find_regions_variance_minimization_Viriyothai2009(Y, n=2) - self.assertListEqual( - regions, - [ - (0, 97, 0, 156), - (97, 256, 0, 156), - (0, 100, 156, 256), - (100, 256, 156, 256), - ], - ) + assert regions == [ + (0, 97, 0, 156), + (97, 256, 0, 156), + (0, 100, 156, 256), + (100, 256, 156, 256), + ] regions = find_regions_variance_minimization_Viriyothai2009(Y, n=4) - self.assertListEqual( - regions, - [ - (0, 39, 0, 91), - (39, 97, 0, 91), - (0, 39, 91, 156), - (39, 97, 91, 156), - (97, 159, 0, 92), - (97, 159, 92, 156), - (159, 256, 0, 93), - (159, 256, 93, 156), - (0, 42, 156, 216), - (42, 100, 156, 216), - (0, 44, 216, 256), - (44, 100, 216, 256), - (100, 163, 156, 215), - (100, 163, 215, 256), - (163, 256, 156, 216), - (163, 256, 216, 256), - ], - ) - - -class TestHighlightRegionsVarianceMinimization(unittest.TestCase): + assert regions == [ + (0, 39, 0, 91), + (39, 97, 0, 91), + (0, 39, 91, 156), + (39, 97, 91, 156), + (97, 159, 0, 92), + (97, 159, 92, 156), + (159, 256, 0, 93), + (159, 256, 93, 156), + (0, 42, 156, 216), + (42, 100, 156, 216), + (0, 44, 216, 256), + (44, 100, 216, 256), + (100, 163, 156, 215), + (100, 163, 215, 256), + (163, 256, 156, 216), + (163, 256, 216, 256), + ] + + +class TestHighlightRegionsVarianceMinimization: """ Define :func:`colour_hdri.sampling.variance_minimization.\ highlight_regions_variance_minimization` definition unit tests methods. @@ -166,9 +158,7 @@ def test_highlight_regions_variance_minimization(self): ) -class TestLightProbeSamplingVarianceMinimizationViriyothai2009( - unittest.TestCase -): +class TestLightProbeSamplingVarianceMinimizationViriyothai2009: """ Define :func:`colour_hdri.sampling.variance_minimization.\ light_probe_sampling_variance_minimization_Viriyothai2009` definition unit @@ -191,9 +181,7 @@ def test_light_probe_sampling_variance_minimization_Viriyothai2009(self): ) ) - lights = light_probe_sampling_variance_minimization_Viriyothai2009( - image - ) + lights = light_probe_sampling_variance_minimization_Viriyothai2009(image) uvs = np.array([light[0] for light in lights]) colours = np.array([light[1] for light in lights]) indexes = np.array([light[2] for light in lights]) @@ -271,7 +259,3 @@ def test_light_probe_sampling_variance_minimization_Viriyothai2009(self): ] ), ) - - -if __name__ == "__main__": - unittest.main() diff --git a/colour_hdri/sampling/variance_minimization.py b/colour_hdri/sampling/variance_minimization.py index dda05be6..8f2f20de 100644 --- a/colour_hdri/sampling/variance_minimization.py +++ b/colour_hdri/sampling/variance_minimization.py @@ -2,7 +2,7 @@ Viriyothai (2009) Variance Minimization Light Probe Sampling ============================================================ -Defines the *Viriyothai (2009)* variance minimization light probe sampling +Define the *Viriyothai (2009)* variance minimization light probe sampling objects: - :func:`colour_hdri.\ @@ -38,9 +38,7 @@ ] -class Light_Specification( - namedtuple("Light_Specification", ("uv", "colour", "index")) -): +class Light_Specification(namedtuple("Light_Specification", ("uv", "colour", "index"))): """ Define a light probe sampling resulting light specification. @@ -80,9 +78,7 @@ def luminance_variance(a: ArrayLike) -> float: x_centroid, y_centroid = centroid(a) - variance = np.sqrt( - np.sum(a * ((y - y_centroid) ** 2 + (x - x_centroid) ** 2)) - ) + variance = np.sqrt(np.sum(a * ((y - y_centroid) ** 2 + (x - x_centroid) ** 2))) return as_float_scalar(variance) @@ -152,7 +148,7 @@ def find_regions_variance_minimization_Viriyothai2009( regions = sub_regions - return regions # pyright: ignore + return regions def highlight_regions_variance_minimization( @@ -231,9 +227,7 @@ def light_probe_sampling_variance_minimization_Viriyothai2009( f"effectively computed!" ) - Y = RGB_luminance( - light_probe, colourspace.primaries, colourspace.whitepoint - ) + Y = RGB_luminance(light_probe, colourspace.primaries, colourspace.whitepoint) regions = find_regions_variance_minimization_Viriyothai2009(Y, iterations) lights = [] diff --git a/colour_hdri/tonemapping/global_operators/operators.py b/colour_hdri/tonemapping/global_operators/operators.py index 122ee847..433d892e 100644 --- a/colour_hdri/tonemapping/global_operators/operators.py +++ b/colour_hdri/tonemapping/global_operators/operators.py @@ -2,7 +2,7 @@ Global Tonemapping Operators ============================ -Defines the global tonemapping operators objects: +Define the global tonemapping operators objects: - :func:`colour_hdri.tonemapping_operator_simple` - :func:`colour_hdri.tonemapping_operator_normalisation` @@ -461,9 +461,7 @@ def tonemapping_operator_logarithmic_mapping( RGB_luminance(RGB, colourspace.primaries, colourspace.whitepoint) ) L_max = np.max(L) - L_d = as_float_array( - (np.log(1 + p * L) / np.log(1 + p * L_max)) ** (1 / q) - ) + L_d = as_float_array((np.log(1 + p * L) / np.log(1 + p * L_max)) ** (1 / q)) return RGB * L_d[..., None] / L[..., None] @@ -657,9 +655,7 @@ def tonemapping_operator_Tumblin1999( ) def f(x: float | NDArrayFloat) -> NDArrayFloat: - return np.where( - x > 100, 2.655, 1.855 + 0.4 * np.log10(x + 2.3 * 10**-5) - ) + return np.where(x > 100, 2.655, 1.855 + 0.4 * np.log10(x + 2.3 * 10**-5)) L_wa = np.exp(np.mean(np.log(L_w + 2.3 * 10**-5))) g_d = f(L_da) @@ -757,11 +753,7 @@ def tonemapping_operator_Reinhard2004( if m > 0 else ( 0.3 - + 0.7 - * ( - (np.log(L_max) - L_lav) - / (np.log(L_max) - np.log(L_min)) ** 1.4 - ) + + 0.7 * ((np.log(L_max) - L_lav) / (np.log(L_max) - np.log(L_min)) ** 1.4) ) ) @@ -857,12 +849,8 @@ def f( E: float, F: float, ) -> float | NDArrayFloat: - return ( - (x * (A * x + C * B) + D * E) / (x * (A * x + B) + D * F) - ) - E / F + return ((x * (A * x + C * B) + D * E) / (x * (A * x + B) + D * F)) - E / F RGB = f(RGB * exposure_bias, A, B, C, D, E, F) - return cast( - NDArrayFloat, RGB * (1 / f(linear_whitepoint, A, B, C, D, E, F)) - ) + return cast(NDArrayFloat, RGB * (1 / f(linear_whitepoint, A, B, C, D, E, F))) diff --git a/colour_hdri/tonemapping/global_operators/tests/test_operators.py b/colour_hdri/tonemapping/global_operators/tests/test_operators.py index 9e068ed3..aa4c16b1 100644 --- a/colour_hdri/tonemapping/global_operators/tests/test_operators.py +++ b/colour_hdri/tonemapping/global_operators/tests/test_operators.py @@ -1,10 +1,8 @@ -# !/usr/bin/env python """ Define the unit tests for the :mod:`colour_hdri.tonemapping.global_operators.operators` module. """ -import unittest import numpy as np from colour.constants import TOLERANCE_ABSOLUTE_TESTS @@ -47,7 +45,7 @@ ] -class TestLogAverage(unittest.TestCase): +class TestLogAverage: """ Define :func:`colour_hdri.utilities.common.log_average` definition unit tests methods. @@ -59,12 +57,11 @@ def test_log_average(self): np.testing.assert_allclose( log_average(np.linspace(0, 10, 10)), np.array(0.125071409675722), - rtol=0.025, atol=0.025, ) -class TestTonemappingOperatorSimple(unittest.TestCase): +class TestTonemappingOperatorSimple: """ Define :func:`colour_hdri.tonemapping.global_operators.operators.\ tonemapping_operator_simple` definition unit tests methods. @@ -107,7 +104,7 @@ def test_tonemapping_operator_simple(self): ) -class TestTonemappingOperatorNormalisation(unittest.TestCase): +class TestTonemappingOperatorNormalisation: """ Define :func:`colour_hdri.tonemapping.global_operators.operators.\ tonemapping_operator_normalisation` definition unit tests methods. @@ -150,7 +147,7 @@ def test_tonemapping_operator_normalisation(self): ) -class TestTonemappingOperatorGamma(unittest.TestCase): +class TestTonemappingOperatorGamma: """ Define :func:`colour_hdri.tonemapping.global_operators.operators.\ tonemapping_operator_gamma` definition unit tests methods. @@ -195,7 +192,7 @@ def test_tonemapping_operator_gamma(self): ) -class TestTonemappingOperatorLogarithmic(unittest.TestCase): +class TestTonemappingOperatorLogarithmic: """ Define :func:`colour_hdri.tonemapping.global_operators.operators.\ tonemapping_operator_logarithmic` definition unit tests methods. @@ -240,7 +237,7 @@ def test_tonemapping_operator_logarithmic(self): ) -class TestTonemappingOperatorExponential(unittest.TestCase): +class TestTonemappingOperatorExponential: """ Define :func:`colour_hdri.tonemapping.global_operators.operators.\ tonemapping_operator_exponential` definition unit tests methods. @@ -285,7 +282,7 @@ def test_tonemapping_operator_exponential(self): ) -class TestTonemappingOperatorLogarithmicMapping(unittest.TestCase): +class TestTonemappingOperatorLogarithmicMapping: """ Define :func:`colour_hdri.tonemapping.global_operators.operators.\ tonemapping_operator_logarithmic_mapping` definition unit tests methods. @@ -330,7 +327,7 @@ def test_tonemapping_operator_logarithmic_mapping(self): ) -class TestTonemappingOperatorExponentiationMapping(unittest.TestCase): +class TestTonemappingOperatorExponentiationMapping: """ Define :func:`colour_hdri.tonemapping.global_operators.operators.\ tonemapping_operator_exponentiation_mapping` definition unit tests methods. @@ -375,7 +372,7 @@ def test_tonemapping_operator_exponentiation_mapping(self): ) -class TestTonemappingOperatorSchlick1994(unittest.TestCase): +class TestTonemappingOperatorSchlick1994: """ Define :func:`colour_hdri.tonemapping.global_operators.operators.\ tonemapping_operator_Schlick1994` definition unit tests methods. @@ -419,7 +416,7 @@ def test_tonemapping_operator_Schlick1994(self): ) -class TestTonemappingOperatorTumblin1999(unittest.TestCase): +class TestTonemappingOperatorTumblin1999: """ Define :func:`colour_hdri.tonemapping.global_operators.operators.\ tonemapping_operator_Tumblin1999` definition unit tests methods. @@ -465,7 +462,7 @@ def test_tonemapping_operator_Tumblin1999(self): ) -class TestTonemappingOperatorReinhard2004(unittest.TestCase): +class TestTonemappingOperatorReinhard2004: """ Define :func:`colour_hdri.tonemapping.global_operators.operators.\ tonemapping_operator_Reinhard2004` definition unit tests methods. @@ -512,7 +509,7 @@ def test_tonemapping_operator_Reinhard2004(self): ) -class TestTonemappingOperatorFilmic(unittest.TestCase): +class TestTonemappingOperatorFilmic: """ Define :func:`colour_hdri.tonemapping.global_operators.operators.\ tonemapping_operator_filmic` definition unit tests methods. @@ -561,7 +558,3 @@ def test_tonemapping_operator_filmic(self): ), atol=TOLERANCE_ABSOLUTE_TESTS, ) - - -if __name__ == "__main__": - unittest.main() diff --git a/colour_hdri/utilities/common.py b/colour_hdri/utilities/common.py index a8bd0f78..b2d9a0ec 100644 --- a/colour_hdri/utilities/common.py +++ b/colour_hdri/utilities/common.py @@ -2,7 +2,7 @@ Common Utilities ================ -Defines the common utilities objects that don't fall in any specific category. +Define the common utilities objects that don't fall in any specific category. """ from __future__ import annotations @@ -72,9 +72,7 @@ def vivified_to_dict(vivified: Dict | defaultdict) -> Dict: """ if isinstance(vivified, defaultdict): - vivified = { - key: vivified_to_dict(value) for key, value in vivified.items() - } + vivified = {key: vivified_to_dict(value) for key, value in vivified.items()} return vivified diff --git a/colour_hdri/utilities/exif.py b/colour_hdri/utilities/exif.py index 7c142e27..2a5214f8 100644 --- a/colour_hdri/utilities/exif.py +++ b/colour_hdri/utilities/exif.py @@ -66,6 +66,8 @@ "write_exif_tag", ] +LOGGER = logging.getLogger(__name__) + _IS_WINDOWS_PLATFORM: bool = platform.system() in ("Windows", "Microsoft") """Whether the current platform is *Windows*.""" @@ -118,9 +120,7 @@ def parse_exif_string(exif_tag: EXIFTag) -> str: return str(exif_tag.value) -def parse_exif_number( - exif_tag: EXIFTag, dtype: Type[DTypeReal] | None = None -) -> Real: +def parse_exif_number(exif_tag: EXIFTag, dtype: Type[DTypeReal] | None = None) -> Real: """ Parse given EXIF tag assuming it is a number type and return its value. @@ -164,9 +164,7 @@ def parse_exif_fraction( dtype = optional(dtype, DTYPE_FLOAT_DEFAULT) value = ( - exif_tag.value - if exif_tag.value is None - else float(Fraction(exif_tag.value)) + exif_tag.value if exif_tag.value is None else float(Fraction(exif_tag.value)) ) return as_float_scalar(value, dtype) # pyright: ignore @@ -197,11 +195,14 @@ def parse_exif_array( dtype = optional(dtype, DTYPE_FLOAT_DEFAULT) - value = ( - exif_tag.value if exif_tag.value is None else exif_tag.value.split() - ) + value = exif_tag.value if exif_tag.value is None else exif_tag.value.split() + + array = as_array(value, dtype) # pyright: ignore - return np.reshape(as_array(value, dtype), shape) # pyright: ignore + if shape is not None: + array = np.reshape(array, shape) + + return array def parse_exif_data(data: str) -> List: @@ -258,7 +259,7 @@ def read_exif_tags(image: str) -> defaultdict: EXIF tags. """ - logging.info("Reading '{image}' image EXIF data.", extra={"image": image}) + LOGGER.info('Reading "%s" image EXIF data.', image) exif_tags = vivification() lines = str( @@ -301,15 +302,13 @@ def copy_exif_tags(source: str, target: str) -> bool: Definition success. """ - logging.info( - "Copying '{source}' file EXIF data to '{target}' file.", - extra={"source": source, "target": target}, - ) + LOGGER.info('Copying "%s" file EXIF data to "%s" file.', source, target) arguments = [EXIF_EXECUTABLE, "-overwrite_original", "-TagsFromFile"] arguments += [source, target] subprocess.check_output( - arguments, shell=_IS_WINDOWS_PLATFORM # noqa: S603 + arguments, + shell=_IS_WINDOWS_PLATFORM, # noqa: S603 ) return True @@ -353,7 +352,7 @@ def delete_exif_tags(image: str) -> bool: Definition success. """ - logging.info("Deleting '{image}' image EXIF tags.", extra={"image": image}) + LOGGER.info('Deleting "%s" image EXIF tags.', image) subprocess.check_output( [EXIF_EXECUTABLE, "-overwrite_original", "-all=", image], @@ -394,9 +393,11 @@ def read_exif_tag(image: str, tag: str) -> str: .strip() ) - logging.info( - "Reading '{image}' image '{tag}' EXIF tag value: '{value}'", - extra={"image": image, "tag": tag, "value": value}, + LOGGER.info( + 'Reading "%s" image "%s" EXIF tag value: "%s"', + image, + tag, + value, ) return value @@ -421,15 +422,18 @@ def write_exif_tag(image: str, tag: str, value: str) -> bool: Definition success. """ - logging.info( - "Writing '{image}' image '{tag}' EXIF tag with '{value}' value.", - extra={"image": image, "tag": tag, "value": value}, + LOGGER.info( + 'Writing "%s" image "%s" EXIF tag with "%s" value.', + image, + tag, + value, ) arguments = [EXIF_EXECUTABLE, "-overwrite_original"] arguments += [f"-{tag}={value}", image] subprocess.check_output( - arguments, shell=_IS_WINDOWS_PLATFORM # noqa: S603 + arguments, + shell=_IS_WINDOWS_PLATFORM, # noqa: S603 ) return True diff --git a/colour_hdri/utilities/image.py b/colour_hdri/utilities/image.py index 03ec45ab..30c2e174 100644 --- a/colour_hdri/utilities/image.py +++ b/colour_hdri/utilities/image.py @@ -2,7 +2,7 @@ Image Data & Metadata Utilities =============================== -Defines various image data and metadata utilities classes: +Define various image data and metadata utilities classes: - :class:`colour_hdri.Metadata` - :class:`colour_hdri.Image` @@ -31,7 +31,6 @@ MixinDataclassArray, as_float_array, attest, - is_string, tsplit, tstack, warning, @@ -58,6 +57,8 @@ "ImageStack", ] +LOGGER = logging.getLogger(__name__) + @dataclass class Metadata(MixinDataclassArray): @@ -86,9 +87,7 @@ class Metadata(MixinDataclassArray): iso: Real | None = field(default_factory=lambda: None) black_level: NDArrayFloat | None = field(default_factory=lambda: None) white_level: NDArrayFloat | None = field(default_factory=lambda: None) - white_balance_multipliers: NDArrayFloat | None = field( - default_factory=lambda: None - ) + white_balance_multipliers: NDArrayFloat | None = field(default_factory=lambda: None) class Image: @@ -155,7 +154,7 @@ def path(self, value: str | None): if value is not None: attest( - is_string(value), + isinstance(value, str), f'"path" property: "{value}" type is not "str"!', ) @@ -248,7 +247,7 @@ def read_data(self, cctf_decoding: Callable | None = None) -> NDArrayFloat: """ if self._path is not None: - logging.info('Reading "{path}" image.', extra={"path": self._path}) + LOGGER.info('Reading "%s" image.', self._path) data = read_image(str(self._path)) if cctf_decoding is not None: @@ -276,9 +275,7 @@ def read_metadata(self) -> Metadata: """ if self._path is not None: - logging.info( - 'Reading "{path}" image metadata.', extra={"path": self._path} - ) + LOGGER.info('Reading "%s" image metadata.', self._path) exif_data = read_exif_tags(self._path) @@ -312,9 +309,7 @@ def read_metadata(self) -> Metadata: white_level = parse_exif_array(white_level[0]) white_level = as_float_array(white_level) / 65535 - white_balance_multipliers = exif_data["EXIF"].get( - "As Shot Neutral" - ) + white_balance_multipliers = exif_data["EXIF"].get("As Shot Neutral") if white_balance_multipliers is not None: white_balance_multipliers = parse_exif_array( white_balance_multipliers[0] diff --git a/colour_hdri/utilities/tests/test_common.py b/colour_hdri/utilities/tests/test_common.py index a359d9b9..4a562c26 100644 --- a/colour_hdri/utilities/tests/test_common.py +++ b/colour_hdri/utilities/tests/test_common.py @@ -1,10 +1,8 @@ -# !/usr/bin/env python """Define the unit tests for the :mod:`colour_hdri.utilities.common` module.""" from __future__ import annotations import os -import unittest from colour_hdri import ROOT_RESOURCES_TESTS from colour_hdri.utilities import ( @@ -29,12 +27,10 @@ "TestFilterFiles", ] -ROOT_RESOURCES_FROBISHER_001: str = os.path.join( - ROOT_RESOURCES_TESTS, "frobisher_001" -) +ROOT_RESOURCES_FROBISHER_001: str = os.path.join(ROOT_RESOURCES_TESTS, "frobisher_001") -class TestVivification(unittest.TestCase): +class TestVivification: """ Define :func:`colour_hdri.utilities.common.vivification` definition unit tests methods. @@ -45,11 +41,11 @@ def test_vivification(self): vivified = vivification() vivified["my"]["attribute"] = 1 - self.assertIn("attribute", vivified["my"].keys()) - self.assertEqual(vivified["my"]["attribute"], 1) + assert "attribute" in vivified["my"] + assert vivified["my"]["attribute"] == 1 -class TestVivifiedToDict(unittest.TestCase): +class TestVivifiedToDict: """ Define :func:`colour_hdri.utilities.common.vivified_to_dict` definition unit tests methods. @@ -61,12 +57,12 @@ def test_vivified_to_dict(self): vivified = vivification() vivified["my"]["attribute"] = 1 vivified_as_dict = vivified_to_dict(vivified) - self.assertIsInstance({}, type(vivified_as_dict)) - self.assertIn("attribute", vivified_as_dict["my"].keys()) - self.assertEqual(vivified_as_dict["my"]["attribute"], 1) + assert isinstance({}, type(vivified_as_dict)) + assert "attribute" in vivified_as_dict["my"] + assert vivified_as_dict["my"]["attribute"] == 1 -class TestPathExists(unittest.TestCase): +class TestPathExists: """ Define :func:`colour_hdri.utilities.common.path_exists` definition unit tests methods. @@ -75,11 +71,11 @@ class TestPathExists(unittest.TestCase): def test_path_exists(self): """Test :func:`colour_hdri.utilities.common.path_exists` definition.""" - self.assertTrue(path_exists(__file__)) - self.assertFalse(path_exists("")) + assert path_exists(__file__) + assert not path_exists("") -class TestFilterFiles(unittest.TestCase): +class TestFilterFiles: """ Define :func:`colour_hdri.utilities.common.filter_files` definition unit tests methods. @@ -89,18 +85,11 @@ def test_filter_files(self): """Test :func:`colour_hdri.utilities.common.filter_files` definition.""" raw_files = filter_files(ROOT_RESOURCES_FROBISHER_001, ("CR2", "jpg")) - self.assertListEqual( - sorted(map(os.path.basename, raw_files)), - [ - "IMG_2600.CR2", - "IMG_2600.jpg", - "IMG_2601.CR2", - "IMG_2601.jpg", - "IMG_2602.CR2", - "IMG_2602.jpg", - ], - ) - - -if __name__ == "__main__": - unittest.main() + assert sorted(map(os.path.basename, raw_files)) == [ + "IMG_2600.CR2", + "IMG_2600.jpg", + "IMG_2601.CR2", + "IMG_2601.jpg", + "IMG_2602.CR2", + "IMG_2602.jpg", + ] diff --git a/colour_hdri/utilities/tests/test_exif.py b/colour_hdri/utilities/tests/test_exif.py index c3fc4a70..a027a1b4 100644 --- a/colour_hdri/utilities/tests/test_exif.py +++ b/colour_hdri/utilities/tests/test_exif.py @@ -1,4 +1,3 @@ -# !/usr/bin/env python """Define the unit tests for the :mod:`colour_hdri.utilities.exif` module.""" from __future__ import annotations @@ -6,7 +5,6 @@ import os import shutil import tempfile -import unittest import numpy as np from colour.constants import TOLERANCE_ABSOLUTE_TESTS @@ -51,12 +49,10 @@ "TestWriteExifTag", ] -ROOT_RESOURCES_FROBISHER_001: str = os.path.join( - ROOT_RESOURCES_TESTS, "frobisher_001" -) +ROOT_RESOURCES_FROBISHER_001: str = os.path.join(ROOT_RESOURCES_TESTS, "frobisher_001") -class TestParseExifString(unittest.TestCase): +class TestParseExifString: """ Define :func:`colour_hdri.utilities.exif.parse_exif_string` definition unit tests methods. @@ -66,10 +62,10 @@ def test_parse_exif_string(self): """Test :func:`colour_hdri.utilities.exif.parse_exif_string` definition.""" exif_tag = EXIFTag("EXIF", "Make", "Canon", "271") - self.assertEqual(parse_exif_string(exif_tag), "Canon") + assert parse_exif_string(exif_tag) == "Canon" -class TestParseExifNumber(unittest.TestCase): +class TestParseExifNumber: """ Define :func:`colour_hdri.utilities.exif.parse_exif_number` definition unit tests methods. @@ -79,13 +75,13 @@ def test_parse_exif_number(self): """Test :func:`colour_hdri.utilities.exif.parse_exif_number` definition.""" exif_tag = EXIFTag("EXIF", "Focal Length", "16", "37386") - self.assertEqual(parse_exif_number(exif_tag), 16) + assert parse_exif_number(exif_tag) == 16 exif_tag = EXIFTag("EXIF", "Focal Length", "16", "37386") - self.assertIsInstance(parse_exif_number(exif_tag, np.int_), np.int_) + assert isinstance(parse_exif_number(exif_tag, np.int_), np.int_) -class TestParseExifFraction(unittest.TestCase): +class TestParseExifFraction: """ Define :func:`colour_hdri.utilities.exif.parse_exif_fraction` definition unit tests methods. @@ -112,7 +108,7 @@ def test_parse_exif_fraction(self): ) -class TestParseExifArray(unittest.TestCase): +class TestParseExifArray: """ Define :func:`colour_hdri.utilities.exif.parse_exif_array` definition unit tests methods. @@ -160,7 +156,7 @@ def test_parse_exif_array(self): ) -class TestParseExifData(unittest.TestCase): +class TestParseExifData: """ Define :func:`colour_hdri.utilities.exif.parse_exif_data` definition unit tests methods. @@ -169,29 +165,20 @@ class TestParseExifData(unittest.TestCase): def test_parse_exif_data(self): """Test :func:`colour_hdri.utilities.exif.parse_exif_data` definition.""" - self.assertListEqual( - parse_exif_data( - "[XMP] - Description :" - ), - ["XMP", "-", "Description", ""], - ) + assert parse_exif_data( + "[XMP] - Description :" + ) == ["XMP", "-", "Description", ""] - self.assertListEqual( - parse_exif_data( - "[EXIF] 296 Resolution Unit : 2" - ), - ["EXIF", "296", "Resolution Unit", "2"], - ) + assert parse_exif_data( + "[EXIF] 296 Resolution Unit : 2" + ) == ["EXIF", "296", "Resolution Unit", "2"] - self.assertListEqual( - parse_exif_data( - "[ICC_Profile] 8 Profile Version : 528" - ), - ["ICC_Profile", "8", "Profile Version", "528"], - ) + assert parse_exif_data( + "[ICC_Profile] 8 Profile Version : 528" + ) == ["ICC_Profile", "8", "Profile Version", "528"] -class TestReadExifTags(unittest.TestCase): +class TestReadExifTags: """ Define :func:`colour_hdri.utilities.exif.read_exif_tags` definition unit tests methods. @@ -200,78 +187,62 @@ class TestReadExifTags(unittest.TestCase): def test_read_exif_tags(self): """Test :func:`colour_hdri.utilities.exif.read_exif_tags` definition.""" - test_jpg_image = filter_files(ROOT_RESOURCES_FROBISHER_001, ("jpg",))[ - 0 - ] + test_jpg_image = filter_files(ROOT_RESOURCES_FROBISHER_001, ("jpg",))[0] exif_data = vivified_to_dict(read_exif_tags(test_jpg_image)) - self.assertIsInstance(exif_data, type({})) + assert isinstance(exif_data, type({})) - self.assertListEqual( - sorted(exif_data.keys()), - [ - "Composite", - "EXIF", - "ExifTool", - "File", - "ICC_Profile", - "JFIF", - "Photoshop", - "XMP", - ], - ) + assert sorted(exif_data.keys()) == [ + "Composite", + "EXIF", + "ExifTool", + "File", + "ICC_Profile", + "JFIF", + "Photoshop", + "XMP", + ] - self.assertListEqual( - sorted(exif_data["EXIF"].values(), key=lambda x: x[0].name), + assert sorted(exif_data["EXIF"].values(), key=lambda x: x[0].name) == [ + [EXIFTag("EXIF", "Camera Model Name", "EOS 5D Mark II", "272")], + [EXIFTag("EXIF", "Create Date", "2015:09:19 03:39:20", "36868")], [ - [ - EXIFTag( - "EXIF", "Camera Model Name", "EOS 5D Mark II", "272" - ) - ], - [ - EXIFTag( - "EXIF", "Create Date", "2015:09:19 03:39:20", "36868" - ) - ], - [ - EXIFTag( - "EXIF", - "Date/Time Original", - "2015:09:19 03:39:20", - "36867", - ) - ], - [EXIFTag("EXIF", "Exif Image Height", "426", "40963")], - [EXIFTag("EXIF", "Exif Image Width", "640", "40962")], - [EXIFTag("EXIF", "Exposure Time", "0.125", "33434")], - [EXIFTag("EXIF", "F Number", "8", "33437")], - [EXIFTag("EXIF", "Focal Length", "16", "37386")], - [EXIFTag("EXIF", "ISO", "100", "34855")], - [EXIFTag("EXIF", "Make", "Canon", "271")], - [EXIFTag("EXIF", "Modify Date", "2015:09:19 03:39:20", "306")], - [EXIFTag("EXIF", "Orientation", "1", "274")], - [EXIFTag("EXIF", "Photometric Interpretation", "2", "262")], - [EXIFTag("EXIF", "Resolution Unit", "2", "296")], - [EXIFTag("EXIF", "Software", "Photos 1.0.1", "305")], - [EXIFTag("EXIF", "X Resolution", "72", "282")], - [EXIFTag("EXIF", "Y Resolution", "72", "283")], + EXIFTag( + "EXIF", + "Date/Time Original", + "2015:09:19 03:39:20", + "36867", + ) ], - ) + [EXIFTag("EXIF", "Exif Image Height", "426", "40963")], + [EXIFTag("EXIF", "Exif Image Width", "640", "40962")], + [EXIFTag("EXIF", "Exposure Time", "0.125", "33434")], + [EXIFTag("EXIF", "F Number", "8", "33437")], + [EXIFTag("EXIF", "Focal Length", "16", "37386")], + [EXIFTag("EXIF", "ISO", "100", "34855")], + [EXIFTag("EXIF", "Make", "Canon", "271")], + [EXIFTag("EXIF", "Modify Date", "2015:09:19 03:39:20", "306")], + [EXIFTag("EXIF", "Orientation", "1", "274")], + [EXIFTag("EXIF", "Photometric Interpretation", "2", "262")], + [EXIFTag("EXIF", "Resolution Unit", "2", "296")], + [EXIFTag("EXIF", "Software", "Photos 1.0.1", "305")], + [EXIFTag("EXIF", "X Resolution", "72", "282")], + [EXIFTag("EXIF", "Y Resolution", "72", "283")], + ] -class TestCopyExifTags(unittest.TestCase): +class TestCopyExifTags: """ Define :func:`colour_hdri.utilities.exif.copy_exif_tags` definition unit tests methods. """ - def setUp(self): + def setup_method(self): """Initialise the common tests attributes.""" self._temporary_directory = tempfile.mkdtemp() - def tearDown(self): + def teardown_method(self): """After tests actions.""" shutil.rmtree(self._temporary_directory) @@ -279,33 +250,31 @@ def tearDown(self): def test_copy_exif_tags(self): """Test :func:`colour_hdri.utilities.exif.copy_exif_tags` definition.""" - reference_jpg_image = filter_files( - ROOT_RESOURCES_FROBISHER_001, ("jpg",) - )[0] + reference_jpg_image = filter_files(ROOT_RESOURCES_FROBISHER_001, ("jpg",))[0] test_jpg_image = os.path.join( self._temporary_directory, os.path.basename(reference_jpg_image) ) shutil.copyfile(reference_jpg_image, test_jpg_image) - self.assertEqual(read_exif_tag(test_jpg_image, "Aperture"), "8.0") + assert read_exif_tag(test_jpg_image, "Aperture") == "8.0" delete_exif_tags(test_jpg_image) - self.assertEqual(read_exif_tag(test_jpg_image, "Aperture"), "") + assert read_exif_tag(test_jpg_image, "Aperture") == "" copy_exif_tags(reference_jpg_image, test_jpg_image) - self.assertEqual(read_exif_tag(test_jpg_image, "Aperture"), "8.0") + assert read_exif_tag(test_jpg_image, "Aperture") == "8.0" -class TestUpdateExifTags(unittest.TestCase): +class TestUpdateExifTags: """ Define :func:`colour_hdri.utilities.exif.update_exif_tags` definition unit tests methods. """ - def setUp(self): + def setup_method(self): """Initialise the common tests attributes.""" self._temporary_directory = tempfile.mkdtemp() - def tearDown(self): + def teardown_method(self): """After tests actions.""" shutil.rmtree(self._temporary_directory) @@ -313,9 +282,7 @@ def tearDown(self): def test_update_exif_tags(self): """Test :func:`colour_hdri.utilities.exif.update_exif_tags` definition.""" - reference_jpg_images = filter_files( - ROOT_RESOURCES_FROBISHER_001, ("jpg",) - ) + reference_jpg_images = filter_files(ROOT_RESOURCES_FROBISHER_001, ("jpg",)) test_jpg_images = [] for reference_jpg_image in reference_jpg_images: test_jpg_image = os.path.join( @@ -324,26 +291,26 @@ def test_update_exif_tags(self): ) shutil.copyfile(reference_jpg_image, test_jpg_image) delete_exif_tags(test_jpg_image) - self.assertEqual(read_exif_tag(test_jpg_image, "Aperture"), "") + assert read_exif_tag(test_jpg_image, "Aperture") == "" test_jpg_images.append(test_jpg_image) update_exif_tags(zip(reference_jpg_images, test_jpg_images)) for test_jpg_image in test_jpg_images: - self.assertEqual(read_exif_tag(test_jpg_image, "Aperture"), "8.0") + assert read_exif_tag(test_jpg_image, "Aperture") == "8.0" -class TestDeleteExifTags(unittest.TestCase): +class TestDeleteExifTags: """ Define :func:`colour_hdri.utilities.exif.delete_exif_tags` definition unit tests methods. """ - def setUp(self): + def setup_method(self): """Initialise the common tests attributes.""" self._temporary_directory = tempfile.mkdtemp() - def tearDown(self): + def teardown_method(self): """After tests actions.""" shutil.rmtree(self._temporary_directory) @@ -351,20 +318,18 @@ def tearDown(self): def test_delete_exif_tags(self): """Test :func:`colour_hdri.utilities.exif.delete_exif_tags` definition.""" - reference_jpg_image = filter_files( - ROOT_RESOURCES_FROBISHER_001, ("jpg",) - )[0] + reference_jpg_image = filter_files(ROOT_RESOURCES_FROBISHER_001, ("jpg",))[0] test_jpg_image = os.path.join( self._temporary_directory, os.path.basename(reference_jpg_image) ) shutil.copyfile(reference_jpg_image, test_jpg_image) - self.assertEqual(read_exif_tag(test_jpg_image, "Aperture"), "8.0") + assert read_exif_tag(test_jpg_image, "Aperture") == "8.0" delete_exif_tags(test_jpg_image) - self.assertEqual(read_exif_tag(test_jpg_image, "Aperture"), "") + assert read_exif_tag(test_jpg_image, "Aperture") == "" -class TestReadExifTag(unittest.TestCase): +class TestReadExifTag: """ Define :func:`colour_hdri.utilities.exif.read_exif_tag` definition unit tests methods. @@ -373,27 +338,25 @@ class TestReadExifTag(unittest.TestCase): def test_read_exif_tag(self): """Test :func:`colour_hdri.utilities.exif.read_exif_tag` definition.""" - test_jpg_image = filter_files(ROOT_RESOURCES_FROBISHER_001, ("jpg",))[ - 0 - ] + test_jpg_image = filter_files(ROOT_RESOURCES_FROBISHER_001, ("jpg",))[0] - self.assertEqual(read_exif_tag(test_jpg_image, "Aperture"), "8.0") - self.assertEqual(read_exif_tag(test_jpg_image, "ExposureTime"), "1/8") - self.assertEqual(read_exif_tag(test_jpg_image, "ISO"), "100") + assert read_exif_tag(test_jpg_image, "Aperture") == "8.0" + assert read_exif_tag(test_jpg_image, "ExposureTime") == "1/8" + assert read_exif_tag(test_jpg_image, "ISO") == "100" -class TestWriteExifTag(unittest.TestCase): +class TestWriteExifTag: """ Define :func:`colour_hdri.utilities.exif.write_exif_tag` definition unit tests methods. """ - def setUp(self): + def setup_method(self): """Initialise the common tests attributes.""" self._temporary_directory = tempfile.mkdtemp() - def tearDown(self): + def teardown_method(self): """After tests actions.""" shutil.rmtree(self._temporary_directory) @@ -401,19 +364,13 @@ def tearDown(self): def test_write_exif_tag(self): """Test :func:`colour_hdri.utilities.exif.write_exif_tag` definition.""" - reference_jpg_image = filter_files( - ROOT_RESOURCES_FROBISHER_001, ("jpg",) - )[0] + reference_jpg_image = filter_files(ROOT_RESOURCES_FROBISHER_001, ("jpg",))[0] test_jpg_image = os.path.join( self._temporary_directory, os.path.basename(reference_jpg_image) ) shutil.copyfile(reference_jpg_image, test_jpg_image) # *Aperture* exif tag is not writeable, changing for *FNumber*. - self.assertEqual(read_exif_tag(test_jpg_image, "FNumber"), "8.0") + assert read_exif_tag(test_jpg_image, "FNumber") == "8.0" write_exif_tag(test_jpg_image, "FNumber", "16.0") - self.assertEqual(read_exif_tag(test_jpg_image, "FNumber"), "16.0") - - -if __name__ == "__main__": - unittest.main() + assert read_exif_tag(test_jpg_image, "FNumber") == "16.0" diff --git a/colour_hdri/utilities/tests/test_image.py b/colour_hdri/utilities/tests/test_image.py index 0051394c..e55e97bf 100644 --- a/colour_hdri/utilities/tests/test_image.py +++ b/colour_hdri/utilities/tests/test_image.py @@ -1,10 +1,8 @@ -# !/usr/bin/env python """Define the unit tests for the :mod:`colour_hdri.utilities.image` module.""" from __future__ import annotations import os -import unittest import numpy as np from colour.constants import TOLERANCE_ABSOLUTE_TESTS @@ -24,23 +22,19 @@ "TestImageStack", ] -ROOT_RESOURCES_FROBISHER_001: str = os.path.join( - ROOT_RESOURCES_TESTS, "frobisher_001" -) +ROOT_RESOURCES_FROBISHER_001: str = os.path.join(ROOT_RESOURCES_TESTS, "frobisher_001") -class TestImage(unittest.TestCase): +class TestImage: """ Define :class:`colour_hdri.utilities.image.Image` class unit tests methods. """ - def setUp(self): + def setup_method(self): """Initialise the common tests attributes.""" - self._test_jpg_image = filter_files( - ROOT_RESOURCES_FROBISHER_001, ("jpg",) - )[0] + self._test_jpg_image = filter_files(ROOT_RESOURCES_FROBISHER_001, ("jpg",))[0] def test_required_attributes(self): """Test the presence of required attributes.""" @@ -48,7 +42,7 @@ def test_required_attributes(self): required_attributes = ("path", "data", "metadata") for attribute in required_attributes: - self.assertIn(attribute, dir(Image)) + assert attribute in dir(Image) def test_required_methods(self): """Test the presence of required methods.""" @@ -56,40 +50,38 @@ def test_required_methods(self): required_methods = ("__init__", "read_data", "read_metadata") for method in required_methods: - self.assertIn(method, dir(Image)) + assert method in dir(Image) def test_read_data(self): """Test :attr:`colour_hdri.utilities.image.Image.read_data` method.""" image = Image(self._test_jpg_image) - self.assertIsNone(image.data) - self.assertTupleEqual(image.read_data().shape, (426, 640, 3)) + assert image.data is None + assert image.read_data().shape == (426, 640, 3) def test_read_metadata(self): """Test :attr:`colour_hdri.utilities.image.Image.end` method.""" image = Image(self._test_jpg_image) - self.assertEqual(image.metadata, None) + assert image.metadata is None np.testing.assert_array_equal( np.array(image.read_metadata()), np.array([8.0, 0.125, 100.0, np.nan, np.nan, np.nan]), ) -class TestImageStack(unittest.TestCase): +class TestImageStack: """ Define :class:`colour_hdri.utilities.image.ImageStack` class unit tests methods. """ - def setUp(self): + def setup_method(self): """Initialise the common tests attributes.""" - self._test_jpg_images = filter_files( - ROOT_RESOURCES_FROBISHER_001, ("jpg",) - ) + self._test_jpg_images = filter_files(ROOT_RESOURCES_FROBISHER_001, ("jpg",)) self._image_stack = ImageStack().from_files(self._test_jpg_images) @@ -109,7 +101,7 @@ def test_required_methods(self): ) for method in required_methods: - self.assertIn(method, dir(ImageStack)) + assert method in dir(ImageStack) def test__getitem__(self): """ @@ -118,7 +110,7 @@ def test__getitem__(self): """ for image in self._image_stack: - self.assertIsInstance(image, Image) + assert isinstance(image, Image) def test__setitem__(self): """ @@ -132,7 +124,7 @@ def test__setitem__(self): image.read_metadata() image_stack.insert(0, image) - self.assertEqual(image_stack[0], image) + assert image_stack[0] == image def test__delitem__(self): """ @@ -144,12 +136,12 @@ def test__delitem__(self): del image_stack[0] - self.assertEqual(len(image_stack), 2) + assert len(image_stack) == 2 def test__len__(self): """Test :attr:`colour_hdri.utilities.image.ImageStack.__len__` method.""" - self.assertEqual(len(self._image_stack), 3) + assert len(self._image_stack) == 3 def test__getattr__(self): """ @@ -157,7 +149,7 @@ def test__getattr__(self): method. """ - self.assertTupleEqual(self._image_stack.data.shape, (426, 640, 3, 3)) + assert self._image_stack.data.shape == (426, 640, 3, 3) np.testing.assert_allclose( self._image_stack.f_number, @@ -165,7 +157,7 @@ def test__getattr__(self): atol=TOLERANCE_ABSOLUTE_TESTS, ) - self.assertEqual(self._image_stack[0].metadata.f_number, 8) + assert self._image_stack[0].metadata.f_number == 8 np.testing.assert_allclose( self._image_stack.exposure_time, @@ -173,13 +165,13 @@ def test__getattr__(self): atol=TOLERANCE_ABSOLUTE_TESTS, ) - self.assertEqual(self._image_stack[0].metadata.exposure_time, 0.125) + assert self._image_stack[0].metadata.exposure_time == 0.125 np.testing.assert_array_equal( self._image_stack.black_level, np.array([np.nan, np.nan, np.nan]) ) - self.assertEqual(self._image_stack[0].metadata.black_level, None) + assert self._image_stack[0].metadata.black_level is None def test__setattr__(self): """ @@ -189,11 +181,11 @@ def test__setattr__(self): image_stack = ImageStack().from_files(self._test_jpg_images) - self.assertTupleEqual(image_stack.data.shape, (426, 640, 3, 3)) + assert image_stack.data.shape == (426, 640, 3, 3) image_stack.data = np.random.random((20, 10, 3, 3)) - self.assertTupleEqual(image_stack.data.shape, (20, 10, 3, 3)) + assert image_stack.data.shape == (20, 10, 3, 3) np.testing.assert_allclose( image_stack.f_number, @@ -209,7 +201,7 @@ def test__setattr__(self): atol=TOLERANCE_ABSOLUTE_TESTS, ) - self.assertEqual(image_stack[0].metadata.f_number, 1) + assert image_stack[0].metadata.f_number == 1 np.testing.assert_array_equal( image_stack.black_level, np.array([np.nan, np.nan, np.nan]) @@ -223,7 +215,7 @@ def test__setattr__(self): atol=TOLERANCE_ABSOLUTE_TESTS, ) - self.assertEqual(image_stack[0].metadata.black_level, 2048) + assert image_stack[0].metadata.black_level == 2048 def test_from_files(self): """ @@ -232,8 +224,4 @@ def test_from_files(self): """ image_stack = ImageStack().from_files(reversed(self._test_jpg_images)) - self.assertListEqual(list(image_stack.path), self._test_jpg_images) - - -if __name__ == "__main__": - unittest.main() + assert list(image_stack.path) == self._test_jpg_images diff --git a/docs/installation.rst b/docs/installation.rst index 5a830402..cd260add 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -13,18 +13,18 @@ Primary Dependencies **Colour - HDRI** requires various dependencies in order to run: -- `python >= 3.9, < 4 `__ -- `colour-science >= 4.3 `__ +- `python >= 3.10, < 3.14 `__ +- `colour-science >= 4.4 `__ - `imageio >= 2, < 3 `__ -- `numpy >= 1.22, < 2 `__ -- `scipy >= 1.8, < 2 `__ +- `numpy >= 1.24, < 3 `__ +- `scipy >= 1.10, < 2 `__ Optional Features Dependencies ------------------------------ - `colour-demosaicing `__ -- `Adobe DNG Converter `__ -- `dcraw `__ +- `Adobe DNG Converter `__ +- `dcraw `__ - `ExifTool `__ - `rawpy `__ @@ -41,9 +41,6 @@ The optional features dependencies are installed as follows:: pip install --user 'colour-hdri[optional]' -The figures plotting dependencies are installed as follows:: - - pip install --user 'colour-hdri[plotting]' The overall development dependencies are installed as follows:: diff --git a/docs/requirements.txt b/docs/requirements.txt index 3a8fc4b7..a18f2ffb 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,51 +1,52 @@ -accessible-pygments==0.0.4 ; python_version >= "3.9" and python_version < "3.13" -alabaster==0.7.13 ; python_version >= "3.9" and python_version < "3.13" -babel==2.14.0 ; python_version >= "3.9" and python_version < "3.13" -beautifulsoup4==4.12.2 ; python_version >= "3.9" and python_version < "3.13" -biblib-simple==0.1.2 ; python_version >= "3.9" and python_version < "3.13" -certifi==2023.11.17 ; python_version >= "3.9" and python_version < "3.13" -charset-normalizer==3.3.2 ; python_version >= "3.9" and python_version < "3.13" -colorama==0.4.6 ; python_version >= "3.9" and python_version < "3.13" and sys_platform == "win32" -colour-demosaicing==0.2.5 ; python_version >= "3.9" and python_version < "3.13" -colour-science==0.4.4 ; python_version >= "3.9" and python_version < "3.13" -contourpy==1.2.0 ; python_version >= "3.9" and python_version < "3.13" -cycler==0.12.1 ; python_version >= "3.9" and python_version < "3.13" -docutils==0.20.1 ; python_version >= "3.9" and python_version < "3.13" -fonttools==4.47.0 ; python_version >= "3.9" and python_version < "3.13" -idna==3.6 ; python_version >= "3.9" and python_version < "3.13" -imageio==2.33.1 ; python_version >= "3.9" and python_version < "3.13" -imagesize==1.4.1 ; python_version >= "3.9" and python_version < "3.13" -importlib-metadata==7.0.0 ; python_version >= "3.9" and python_version < "3.10" -importlib-resources==6.1.1 ; python_version >= "3.9" and python_version < "3.10" -jinja2==3.1.2 ; python_version >= "3.9" and python_version < "3.13" -kiwisolver==1.4.5 ; python_version >= "3.9" and python_version < "3.13" -latexcodec==2.0.1 ; python_version >= "3.9" and python_version < "3.13" -markupsafe==2.1.3 ; python_version >= "3.9" and python_version < "3.13" -matplotlib==3.8.2 ; python_version >= "3.9" and python_version < "3.13" -numpy==1.26.2 ; python_version >= "3.9" and python_version < "3.13" -packaging==23.2 ; python_version >= "3.9" and python_version < "3.13" -pillow==10.1.0 ; python_version >= "3.9" and python_version < "3.13" -pybtex==0.24.0 ; python_version >= "3.9" and python_version < "3.13" -pybtex-docutils==1.0.3 ; python_version >= "3.9" and python_version < "3.13" -pydata-sphinx-theme==0.14.4 ; python_version >= "3.9" and python_version < "3.13" -pygments==2.17.2 ; python_version >= "3.9" and python_version < "3.13" -pyparsing==3.1.1 ; python_version >= "3.9" and python_version < "3.13" -python-dateutil==2.8.2 ; python_version >= "3.9" and python_version < "3.13" -pyyaml==6.0.1 ; python_version >= "3.9" and python_version < "3.13" -requests==2.31.0 ; python_version >= "3.9" and python_version < "3.13" -restructuredtext-lint==1.4.0 ; python_version >= "3.9" and python_version < "3.13" -scipy==1.11.4 ; python_version >= "3.9" and python_version < "3.13" -six==1.16.0 ; python_version >= "3.9" and python_version < "3.13" -snowballstemmer==2.2.0 ; python_version >= "3.9" and python_version < "3.13" -soupsieve==2.5 ; python_version >= "3.9" and python_version < "3.13" -sphinx==7.2.6 ; python_version >= "3.9" and python_version < "3.13" -sphinxcontrib-applehelp==1.0.7 ; python_version >= "3.9" and python_version < "3.13" -sphinxcontrib-bibtex==2.6.1 ; python_version >= "3.9" and python_version < "3.13" -sphinxcontrib-devhelp==1.0.5 ; python_version >= "3.9" and python_version < "3.13" -sphinxcontrib-htmlhelp==2.0.4 ; python_version >= "3.9" and python_version < "3.13" -sphinxcontrib-jsmath==1.0.1 ; python_version >= "3.9" and python_version < "3.13" -sphinxcontrib-qthelp==1.0.6 ; python_version >= "3.9" and python_version < "3.13" -sphinxcontrib-serializinghtml==1.1.9 ; python_version >= "3.9" and python_version < "3.13" -typing-extensions==4.9.0 ; python_version >= "3.9" and python_version < "3.13" -urllib3==2.1.0 ; python_version >= "3.9" and python_version < "3.13" -zipp==3.17.0 ; python_version >= "3.9" and python_version < "3.10" +# This file was autogenerated by uv via the following command: +# uv export --no-hashes --all-extras --no-dev +accessible-pygments==0.0.5 +alabaster==1.0.0 +babel==2.16.0 +beautifulsoup4==4.12.3 +biblib-simple==0.1.2 +certifi==2024.8.30 +charset-normalizer==3.4.0 +colorama==0.4.6 ; sys_platform == 'win32' +colour-demosaicing==0.2.6 +colour-science==0.4.6 +contourpy==1.3.0 +cycler==0.12.1 +docutils==0.21.2 +fonttools==4.54.1 +idna==3.10 +imageio==2.35.1 +imagesize==1.4.1 +jinja2==3.1.4 +kiwisolver==1.4.7 +latexcodec==3.0.0 +markupsafe==3.0.1 +matplotlib==3.9.2 +numpy==2.1.2 +packaging==24.1 +pillow==10.4.0 +pybtex==0.24.0 +pybtex-docutils==1.0.3 +pydata-sphinx-theme==0.15.4 +pygments==2.18.0 +pyparsing==3.1.4 +python-dateutil==2.9.0.post0 +pyyaml==6.0.2 +requests==2.32.3 +restructuredtext-lint==1.4.0 +scipy==1.14.1 +setuptools==75.1.0 ; python_full_version >= '3.12' +six==1.16.0 +snowballstemmer==2.2.0 +soupsieve==2.6 +sphinx==8.1.2 +sphinxcontrib-applehelp==2.0.0 +sphinxcontrib-bibtex==2.6.3 +sphinxcontrib-devhelp==2.0.0 +sphinxcontrib-htmlhelp==2.1.0 +sphinxcontrib-jsmath==1.0.1 +sphinxcontrib-qthelp==2.0.0 +sphinxcontrib-serializinghtml==2.0.0 +tomli==2.0.2 ; python_full_version < '3.11' +typing-extensions==4.12.2 +urllib3==2.2.3 diff --git a/pyproject.toml b/pyproject.toml index c7527b4d..fd1c52e3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,13 +1,16 @@ -[tool.poetry] +[project] name = "colour-hdri" -version = "0.2.3" +version = "0.2.4" description = "HDRI processing algorithms for Python" -license = "BSD-3-Clause" -authors = [ "Colour Developers " ] -maintainers = [ "Colour Developers " ] -readme = 'README.rst' -repository = "https://github.com/colour-science/colour-hdri" -homepage = "https://www.colour-science.org/" +readme = "README.rst" +requires-python = ">=3.10,<3.14" +authors = [ + { name = "Colour Developers", email = "colour-developers@colour-science.org" }, +] +maintainers = [ + { name = "Colour Developers", email = "colour-developers@colour-science.org" } +] +license = { text = "BSD-3-Clause" } keywords = [ "color", "color-science", @@ -42,6 +45,59 @@ classifiers = [ "Topic :: Scientific/Engineering", "Topic :: Software Development" ] +dependencies = [ + "colour-science>=0.4.4", + "imageio>=2,<3", + "numpy>=1.24,<3", + "scipy>=1.10,<2", + "typing-extensions>=4,<5", +] + +[project.optional-dependencies] +optional = [ + "colour-demosaicing>=0.2.4", + "matplotlib>=3.7", +] +docs = [ + "biblib-simple", + "pydata-sphinx-theme", + "restructuredtext-lint", + "sphinx", + "sphinxcontrib-bibtex", +] + +[project.urls] +Homepage = "https://www.colour-science.org" +Documentation = "https://colour-hdri.readthedocs.org" +Repository = "https://github.com/colour-science/colour-hdri" +Issues = "https://github.com/colour-science/colour-hdri/issues" +Changelog = "https://github.com/colour-science/colour-hdri/releases" + +[tool.uv] +package = true +dev-dependencies = [ + "coverage", + "coveralls", + "hatch", + "invoke", + "jupyter", + "pre-commit", + "pyright", + "pytest", + "pytest-cov", + "pytest-xdist", + "toml", + "twine", +] + +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[tool.hatch.build.targets.wheel] +packages = [ "colour_demosaicing" ] + +[tool.hatch.build.targets.sdist] exclude = [ "colour_hdri/resources/colour-hdri-examples-datasets/*", "colour_hdri/resources/colour-hdri-examples-datasets/frobisher_001/*", @@ -57,47 +113,8 @@ exclude = [ "colour_hdri/resources/colour-hdri-tests-datasets/unity_001/*", ] -[tool.poetry.dependencies] -python = ">= 3.9, < 3.13" -colour-science = ">= 0.4.4" -imageio = ">= 2, < 3" -numpy = ">= 1.22, < 2" -scipy = ">= 1.8, < 2" -typing-extensions = ">= 4, < 5" - -[tool.poetry.group.optional.dependencies] -colour-demosaicing = ">= 0.2.4" -matplotlib = ">= 3.5, != 3.5.0, != 3.5.1" - -[tool.poetry.group.dev.dependencies] -coverage = "!= 6.3" -coveralls = "*" -invoke = "*" -jupyter = "*" -pre-commit = ">= 3.5" -pyright = "*" -pytest = "*" -pytest-cov = "*" -pytest-xdist = "*" -toml = "*" -twine = "*" - -[tool.poetry.group.docs.dependencies] -biblib-simple = "*" -pydata-sphinx-theme = "*" -restructuredtext-lint = "*" -sphinx = "*" -sphinxcontrib-bibtex = "*" - -[tool.black] -line-length = 79 -exclude = ''' -/( - \.git - | build - | dist -)/ -''' +[tool.codespell] +skip = "BIBLIOGRAPHY.bib,CONTRIBUTORS.rst,*.ipynb" [tool.flynt] line_length=999 @@ -213,9 +230,9 @@ convention = "numpy" "colour_hdri/examples/*" = ["INP", "T201", "T203"] "docs/*" = ["INP"] "tasks.py" = ["INP"] +"test_*" = ["S101"] "utilities/*" = ["EXE001", "INP"] "utilities/unicode_to_ascii.py" = ["RUF001"] -[build-system] -requires = [ "poetry_core>=1.0.0" ] -build-backend = "poetry.core.masonry.api" +[tool.ruff.format] +docstring-code-format = true diff --git a/requirements.txt b/requirements.txt index 37b28e2d..e59ab867 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,172 +1,187 @@ -accessible-pygments==0.0.4 ; python_version >= "3.9" and python_version < "3.13" -alabaster==0.7.13 ; python_version >= "3.9" and python_version < "3.13" -anyio==4.2.0 ; python_version >= "3.9" and python_version < "3.13" -appnope==0.1.3 ; python_version >= "3.9" and python_version < "3.13" and platform_system == "Darwin" -argon2-cffi==23.1.0 ; python_version >= "3.9" and python_version < "3.13" -argon2-cffi-bindings==21.2.0 ; python_version >= "3.9" and python_version < "3.13" -arrow==1.3.0 ; python_version >= "3.9" and python_version < "3.13" -asttokens==2.4.1 ; python_version >= "3.9" and python_version < "3.13" -async-lru==2.0.4 ; python_version >= "3.9" and python_version < "3.13" -attrs==23.1.0 ; python_version >= "3.9" and python_version < "3.13" -babel==2.14.0 ; python_version >= "3.9" and python_version < "3.13" -beautifulsoup4==4.12.2 ; python_version >= "3.9" and python_version < "3.13" -biblib-simple==0.1.2 ; python_version >= "3.9" and python_version < "3.13" -bleach==6.1.0 ; python_version >= "3.9" and python_version < "3.13" -certifi==2023.11.17 ; python_version >= "3.9" and python_version < "3.13" -cffi==1.16.0 ; python_version >= "3.9" and python_version < "3.13" -cfgv==3.4.0 ; python_version >= "3.9" and python_version < "3.13" -charset-normalizer==3.3.2 ; python_version >= "3.9" and python_version < "3.13" -colorama==0.4.6 ; python_version >= "3.9" and python_version < "3.13" and sys_platform == "win32" -colour-demosaicing==0.2.5 ; python_version >= "3.9" and python_version < "3.13" -colour-science==0.4.4 ; python_version >= "3.9" and python_version < "3.13" -comm==0.2.0 ; python_version >= "3.9" and python_version < "3.13" -contourpy==1.2.0 ; python_version >= "3.9" and python_version < "3.13" -coverage==7.3.3 ; python_version >= "3.9" and python_version < "3.13" -coverage[toml]==7.3.3 ; python_version >= "3.9" and python_version < "3.13" -coveralls==1.8.0 ; python_version >= "3.9" and python_version < "3.13" -cryptography==41.0.7 ; python_version >= "3.9" and python_version < "3.13" and sys_platform == "linux" -cycler==0.12.1 ; python_version >= "3.9" and python_version < "3.13" -debugpy==1.8.0 ; python_version >= "3.9" and python_version < "3.13" -decorator==5.1.1 ; python_version >= "3.9" and python_version < "3.13" -defusedxml==0.7.1 ; python_version >= "3.9" and python_version < "3.13" -distlib==0.3.8 ; python_version >= "3.9" and python_version < "3.13" -docopt==0.6.2 ; python_version >= "3.9" and python_version < "3.13" -docutils==0.20.1 ; python_version >= "3.9" and python_version < "3.13" -exceptiongroup==1.2.0 ; python_version >= "3.9" and python_version < "3.11" -execnet==2.0.2 ; python_version >= "3.9" and python_version < "3.13" -executing==2.0.1 ; python_version >= "3.9" and python_version < "3.13" -fastjsonschema==2.19.0 ; python_version >= "3.9" and python_version < "3.13" -filelock==3.13.1 ; python_version >= "3.9" and python_version < "3.13" -fonttools==4.47.0 ; python_version >= "3.9" and python_version < "3.13" -fqdn==1.5.1 ; python_version >= "3.9" and python_version < "3.13" -identify==2.5.33 ; python_version >= "3.9" and python_version < "3.13" -idna==3.6 ; python_version >= "3.9" and python_version < "3.13" -imageio==2.33.1 ; python_version >= "3.9" and python_version < "3.13" -imagesize==1.4.1 ; python_version >= "3.9" and python_version < "3.13" -importlib-metadata==7.0.0 ; python_version >= "3.9" and python_version < "3.13" -importlib-resources==6.1.1 ; python_version >= "3.9" and python_version < "3.10" -iniconfig==2.0.0 ; python_version >= "3.9" and python_version < "3.13" -invoke==2.2.0 ; python_version >= "3.9" and python_version < "3.13" -ipykernel==6.27.1 ; python_version >= "3.9" and python_version < "3.13" -ipython==8.18.1 ; python_version >= "3.9" and python_version < "3.13" -ipywidgets==8.1.1 ; python_version >= "3.9" and python_version < "3.13" -isoduration==20.11.0 ; python_version >= "3.9" and python_version < "3.13" -jaraco-classes==3.3.0 ; python_version >= "3.9" and python_version < "3.13" -jedi==0.19.1 ; python_version >= "3.9" and python_version < "3.13" -jeepney==0.8.0 ; python_version >= "3.9" and python_version < "3.13" and sys_platform == "linux" -jinja2==3.1.2 ; python_version >= "3.9" and python_version < "3.13" -json5==0.9.14 ; python_version >= "3.9" and python_version < "3.13" -jsonpointer==2.4 ; python_version >= "3.9" and python_version < "3.13" -jsonschema==4.20.0 ; python_version >= "3.9" and python_version < "3.13" -jsonschema-specifications==2023.11.2 ; python_version >= "3.9" and python_version < "3.13" -jsonschema[format-nongpl]==4.20.0 ; python_version >= "3.9" and python_version < "3.13" -jupyter==1.0.0 ; python_version >= "3.9" and python_version < "3.13" -jupyter-client==8.6.0 ; python_version >= "3.9" and python_version < "3.13" -jupyter-console==6.6.3 ; python_version >= "3.9" and python_version < "3.13" -jupyter-core==5.5.1 ; python_version >= "3.9" and python_version < "3.13" -jupyter-events==0.9.0 ; python_version >= "3.9" and python_version < "3.13" -jupyter-lsp==2.2.1 ; python_version >= "3.9" and python_version < "3.13" -jupyter-server==2.12.1 ; python_version >= "3.9" and python_version < "3.13" -jupyter-server-terminals==0.5.0 ; python_version >= "3.9" and python_version < "3.13" -jupyterlab==4.0.9 ; python_version >= "3.9" and python_version < "3.13" -jupyterlab-pygments==0.3.0 ; python_version >= "3.9" and python_version < "3.13" -jupyterlab-server==2.25.2 ; python_version >= "3.9" and python_version < "3.13" -jupyterlab-widgets==3.0.9 ; python_version >= "3.9" and python_version < "3.13" -keyring==24.3.0 ; python_version >= "3.9" and python_version < "3.13" -kiwisolver==1.4.5 ; python_version >= "3.9" and python_version < "3.13" -latexcodec==2.0.1 ; python_version >= "3.9" and python_version < "3.13" -markdown-it-py==3.0.0 ; python_version >= "3.9" and python_version < "3.13" -markupsafe==2.1.3 ; python_version >= "3.9" and python_version < "3.13" -matplotlib==3.8.2 ; python_version >= "3.9" and python_version < "3.13" -matplotlib-inline==0.1.6 ; python_version >= "3.9" and python_version < "3.13" -mdurl==0.1.2 ; python_version >= "3.9" and python_version < "3.13" -mistune==3.0.2 ; python_version >= "3.9" and python_version < "3.13" -more-itertools==10.1.0 ; python_version >= "3.9" and python_version < "3.13" -nbclient==0.9.0 ; python_version >= "3.9" and python_version < "3.13" -nbconvert==7.13.0 ; python_version >= "3.9" and python_version < "3.13" -nbformat==5.9.2 ; python_version >= "3.9" and python_version < "3.13" -nest-asyncio==1.5.8 ; python_version >= "3.9" and python_version < "3.13" -nh3==0.2.15 ; python_version >= "3.9" and python_version < "3.13" -nodeenv==1.8.0 ; python_version >= "3.9" and python_version < "3.13" -notebook==7.0.6 ; python_version >= "3.9" and python_version < "3.13" -notebook-shim==0.2.3 ; python_version >= "3.9" and python_version < "3.13" -numpy==1.26.2 ; python_version >= "3.9" and python_version < "3.13" -overrides==7.4.0 ; python_version >= "3.9" and python_version < "3.13" -packaging==23.2 ; python_version >= "3.9" and python_version < "3.13" -pandocfilters==1.5.0 ; python_version >= "3.9" and python_version < "3.13" -parso==0.8.3 ; python_version >= "3.9" and python_version < "3.13" -pexpect==4.9.0 ; python_version >= "3.9" and python_version < "3.13" and sys_platform != "win32" -pillow==10.1.0 ; python_version >= "3.9" and python_version < "3.13" -pkginfo==1.9.6 ; python_version >= "3.9" and python_version < "3.13" -platformdirs==4.1.0 ; python_version >= "3.9" and python_version < "3.13" -pluggy==1.3.0 ; python_version >= "3.9" and python_version < "3.13" -pre-commit==3.6.0 ; python_version >= "3.9" and python_version < "3.13" -prometheus-client==0.19.0 ; python_version >= "3.9" and python_version < "3.13" -prompt-toolkit==3.0.43 ; python_version >= "3.9" and python_version < "3.13" -psutil==5.9.7 ; python_version >= "3.9" and python_version < "3.13" -ptyprocess==0.7.0 ; python_version >= "3.9" and python_version < "3.13" and (sys_platform != "win32" or os_name != "nt") -pure-eval==0.2.2 ; python_version >= "3.9" and python_version < "3.13" -pybtex==0.24.0 ; python_version >= "3.9" and python_version < "3.13" -pybtex-docutils==1.0.3 ; python_version >= "3.9" and python_version < "3.13" -pycparser==2.21 ; python_version >= "3.9" and python_version < "3.13" -pydata-sphinx-theme==0.14.4 ; python_version >= "3.9" and python_version < "3.13" -pygments==2.17.2 ; python_version >= "3.9" and python_version < "3.13" -pyparsing==3.1.1 ; python_version >= "3.9" and python_version < "3.13" -pyright==1.1.341 ; python_version >= "3.9" and python_version < "3.13" -pytest==7.4.3 ; python_version >= "3.9" and python_version < "3.13" -pytest-cov==4.1.0 ; python_version >= "3.9" and python_version < "3.13" -pytest-xdist==3.5.0 ; python_version >= "3.9" and python_version < "3.13" -python-dateutil==2.8.2 ; python_version >= "3.9" and python_version < "3.13" -python-json-logger==2.0.7 ; python_version >= "3.9" and python_version < "3.13" -pywin32==306 ; sys_platform == "win32" and platform_python_implementation != "PyPy" and python_version >= "3.9" and python_version < "3.13" -pywin32-ctypes==0.2.2 ; python_version >= "3.9" and python_version < "3.13" and sys_platform == "win32" -pywinpty==2.0.12 ; python_version >= "3.9" and python_version < "3.13" and os_name == "nt" -pyyaml==6.0.1 ; python_version >= "3.9" and python_version < "3.13" -pyzmq==25.1.2 ; python_version >= "3.9" and python_version < "3.13" -qtconsole==5.5.1 ; python_version >= "3.9" and python_version < "3.13" -qtpy==2.4.1 ; python_version >= "3.9" and python_version < "3.13" -readme-renderer==42.0 ; python_version >= "3.9" and python_version < "3.13" -referencing==0.32.0 ; python_version >= "3.9" and python_version < "3.13" -requests==2.31.0 ; python_version >= "3.9" and python_version < "3.13" -requests-toolbelt==1.0.0 ; python_version >= "3.9" and python_version < "3.13" -restructuredtext-lint==1.4.0 ; python_version >= "3.9" and python_version < "3.13" -rfc3339-validator==0.1.4 ; python_version >= "3.9" and python_version < "3.13" -rfc3986==2.0.0 ; python_version >= "3.9" and python_version < "3.13" -rfc3986-validator==0.1.1 ; python_version >= "3.9" and python_version < "3.13" -rich==13.7.0 ; python_version >= "3.9" and python_version < "3.13" -rpds-py==0.15.2 ; python_version >= "3.9" and python_version < "3.13" -scipy==1.11.4 ; python_version >= "3.9" and python_version < "3.13" -secretstorage==3.3.3 ; python_version >= "3.9" and python_version < "3.13" and sys_platform == "linux" -send2trash==1.8.2 ; python_version >= "3.9" and python_version < "3.13" -setuptools==69.0.2 ; python_version >= "3.9" and python_version < "3.13" -six==1.16.0 ; python_version >= "3.9" and python_version < "3.13" -sniffio==1.3.0 ; python_version >= "3.9" and python_version < "3.13" -snowballstemmer==2.2.0 ; python_version >= "3.9" and python_version < "3.13" -soupsieve==2.5 ; python_version >= "3.9" and python_version < "3.13" -sphinx==7.2.6 ; python_version >= "3.9" and python_version < "3.13" -sphinxcontrib-applehelp==1.0.7 ; python_version >= "3.9" and python_version < "3.13" -sphinxcontrib-bibtex==2.6.1 ; python_version >= "3.9" and python_version < "3.13" -sphinxcontrib-devhelp==1.0.5 ; python_version >= "3.9" and python_version < "3.13" -sphinxcontrib-htmlhelp==2.0.4 ; python_version >= "3.9" and python_version < "3.13" -sphinxcontrib-jsmath==1.0.1 ; python_version >= "3.9" and python_version < "3.13" -sphinxcontrib-qthelp==1.0.6 ; python_version >= "3.9" and python_version < "3.13" -sphinxcontrib-serializinghtml==1.1.9 ; python_version >= "3.9" and python_version < "3.13" -stack-data==0.6.3 ; python_version >= "3.9" and python_version < "3.13" -terminado==0.18.0 ; python_version >= "3.9" and python_version < "3.13" -tinycss2==1.2.1 ; python_version >= "3.9" and python_version < "3.13" -toml==0.10.2 ; python_version >= "3.9" and python_version < "3.13" -tomli==2.0.1 ; python_version >= "3.9" and python_full_version <= "3.11.0a6" -tornado==6.4 ; python_version >= "3.9" and python_version < "3.13" -traitlets==5.14.0 ; python_version >= "3.9" and python_version < "3.13" -twine==4.0.2 ; python_version >= "3.9" and python_version < "3.13" -types-python-dateutil==2.8.19.14 ; python_version >= "3.9" and python_version < "3.13" -typing-extensions==4.9.0 ; python_version >= "3.9" and python_version < "3.13" -uri-template==1.3.0 ; python_version >= "3.9" and python_version < "3.13" -urllib3==2.1.0 ; python_version >= "3.9" and python_version < "3.13" -virtualenv==20.25.0 ; python_version >= "3.9" and python_version < "3.13" -wcwidth==0.2.12 ; python_version >= "3.9" and python_version < "3.13" -webcolors==1.13 ; python_version >= "3.9" and python_version < "3.13" -webencodings==0.5.1 ; python_version >= "3.9" and python_version < "3.13" -websocket-client==1.7.0 ; python_version >= "3.9" and python_version < "3.13" -widgetsnbextension==4.0.9 ; python_version >= "3.9" and python_version < "3.13" -zipp==3.17.0 ; python_version >= "3.9" and python_version < "3.13" +# This file was autogenerated by uv via the following command: +# uv export --no-hashes --all-extras +accessible-pygments==0.0.5 +alabaster==1.0.0 +anyio==4.6.0 +appnope==0.1.4 ; platform_system == 'Darwin' +argon2-cffi==23.1.0 +argon2-cffi-bindings==21.2.0 +arrow==1.3.0 +asttokens==2.4.1 +async-lru==2.0.4 +attrs==24.2.0 +babel==2.16.0 +backports-tarfile==1.2.0 ; python_full_version < '3.12' +beautifulsoup4==4.12.3 +biblib-simple==0.1.2 +bleach==6.1.0 +certifi==2024.8.30 +cffi==1.17.1 +cfgv==3.4.0 +charset-normalizer==3.4.0 +click==8.1.7 +colorama==0.4.6 ; sys_platform == 'win32' or platform_system == 'Windows' +colour-demosaicing==0.2.6 +colour-science==0.4.6 +comm==0.2.2 +contourpy==1.3.0 +coverage==7.6.2 +coveralls==4.0.1 +cryptography==43.0.1 ; sys_platform == 'linux' +cycler==0.12.1 +debugpy==1.8.7 +decorator==5.1.1 +defusedxml==0.7.1 +distlib==0.3.9 +docopt==0.6.2 +docutils==0.21.2 +exceptiongroup==1.2.2 ; python_full_version < '3.11' +execnet==2.1.1 +executing==2.1.0 +fastjsonschema==2.20.0 +filelock==3.16.1 +fonttools==4.54.1 +fqdn==1.5.1 +h11==0.14.0 +hatch==1.12.0 +hatchling==1.25.0 +httpcore==1.0.6 +httpx==0.27.2 +hyperlink==21.0.0 +identify==2.6.1 +idna==3.10 +imageio==2.35.1 +imagesize==1.4.1 +importlib-metadata==8.5.0 +iniconfig==2.0.0 +invoke==2.2.0 +ipykernel==6.29.5 +ipython==8.28.0 +ipywidgets==8.1.5 +isoduration==20.11.0 +jaraco-classes==3.4.0 +jaraco-context==6.0.1 +jaraco-functools==4.1.0 +jedi==0.19.1 +jeepney==0.8.0 ; sys_platform == 'linux' +jinja2==3.1.4 +json5==0.9.25 +jsonpointer==3.0.0 +jsonschema==4.23.0 +jsonschema-specifications==2024.10.1 +jupyter==1.1.1 +jupyter-client==8.6.3 +jupyter-console==6.6.3 +jupyter-core==5.7.2 +jupyter-events==0.10.0 +jupyter-lsp==2.2.5 +jupyter-server==2.14.2 +jupyter-server-terminals==0.5.3 +jupyterlab==4.2.5 +jupyterlab-pygments==0.3.0 +jupyterlab-server==2.27.3 +jupyterlab-widgets==3.0.13 +keyring==25.4.1 +kiwisolver==1.4.7 +latexcodec==3.0.0 +markdown-it-py==3.0.0 +markupsafe==3.0.1 +matplotlib==3.9.2 +matplotlib-inline==0.1.7 +mdurl==0.1.2 +mistune==3.0.2 +more-itertools==10.5.0 +nbclient==0.10.0 +nbconvert==7.16.4 +nbformat==5.10.4 +nest-asyncio==1.6.0 +nh3==0.2.18 +nodeenv==1.9.1 +notebook==7.2.2 +notebook-shim==0.2.4 +numpy==2.1.2 +overrides==7.7.0 +packaging==24.1 +pandocfilters==1.5.1 +parso==0.8.4 +pathspec==0.12.1 +pexpect==4.9.0 +pillow==10.4.0 +pkginfo==1.10.0 +platformdirs==4.3.6 +pluggy==1.5.0 +pre-commit==4.0.1 +prometheus-client==0.21.0 +prompt-toolkit==3.0.48 +psutil==6.0.0 +ptyprocess==0.7.0 +pure-eval==0.2.3 +pybtex==0.24.0 +pybtex-docutils==1.0.3 +pycparser==2.22 +pydata-sphinx-theme==0.15.4 +pygments==2.18.0 +pyparsing==3.1.4 +pyright==1.1.384 +pytest==8.3.3 +pytest-cov==5.0.0 +pytest-xdist==3.6.1 +python-dateutil==2.9.0.post0 +python-json-logger==2.0.7 +pywin32==308 ; platform_python_implementation != 'PyPy' and sys_platform == 'win32' +pywin32-ctypes==0.2.3 ; sys_platform == 'win32' +pywinpty==2.0.13 ; os_name == 'nt' +pyyaml==6.0.2 +pyzmq==26.2.0 +readme-renderer==44.0 +referencing==0.35.1 +requests==2.32.3 +requests-toolbelt==1.0.0 +restructuredtext-lint==1.4.0 +rfc3339-validator==0.1.4 +rfc3986==2.0.0 +rfc3986-validator==0.1.1 +rich==13.9.2 +rpds-py==0.20.0 +scipy==1.14.1 +secretstorage==3.3.3 ; sys_platform == 'linux' +send2trash==1.8.3 +setuptools==75.1.0 +shellingham==1.5.4 +six==1.16.0 +sniffio==1.3.1 +snowballstemmer==2.2.0 +soupsieve==2.6 +sphinx==8.1.2 +sphinxcontrib-applehelp==2.0.0 +sphinxcontrib-bibtex==2.6.3 +sphinxcontrib-devhelp==2.0.0 +sphinxcontrib-htmlhelp==2.1.0 +sphinxcontrib-jsmath==1.0.1 +sphinxcontrib-qthelp==2.0.0 +sphinxcontrib-serializinghtml==2.0.0 +stack-data==0.6.3 +terminado==0.18.1 +tinycss2==1.3.0 +toml==0.10.2 +tomli==2.0.2 ; python_full_version <= '3.11' +tomli-w==1.1.0 +tomlkit==0.13.2 +tornado==6.4.1 +traitlets==5.14.3 +trove-classifiers==2024.10.12 +twine==5.1.1 +types-python-dateutil==2.9.0.20241003 +typing-extensions==4.12.2 +uri-template==1.3.0 +urllib3==2.2.3 +userpath==1.9.2 +uv==0.4.20 +virtualenv==20.26.6 +wcwidth==0.2.13 +webcolors==24.8.0 +webencodings==0.5.1 +websocket-client==1.8.0 +widgetsnbextension==4.0.13 +zipp==3.20.2 +zstandard==0.23.0 diff --git a/tasks.py b/tasks.py index 8471daf1..c3329d25 100644 --- a/tasks.py +++ b/tasks.py @@ -83,7 +83,7 @@ def clean( docs Whether to clean the *docs* directory. bytecode - Whether to clean the bytecode files, e.g. *.pyc* files. + Whether to clean the bytecode files, e.g., *.pyc* files. pytest Whether to clean the *Pytest* cache directory. """ @@ -135,9 +135,7 @@ def formatting( message_box('Cleaning up "BibTeX" file...') bibtex_path = BIBLIOGRAPHY_NAME with open(bibtex_path) as bibtex_file: - entries = ( - biblib.bib.Parser().parse(bibtex_file.read()).get_entries() - ) + entries = biblib.bib.Parser().parse(bibtex_file.read()).get_entries() for entry in sorted(entries.values(), key=lambda x: x.key): with contextlib.suppress(KeyError): @@ -174,7 +172,7 @@ def quality( if pyright: message_box('Checking codebase with "Pyright"...') - ctx.run("pyright --skipunannotated --level warning") + ctx.run("pyright --threads --skipunannotated --level warning") if rstlint: message_box('Linting "README.rst" file...') @@ -240,7 +238,7 @@ def examples(ctx: Context): @task(formatting, quality, precommit, tests, examples) def preflight(ctx: Context): # noqa: ARG001 """ - Perform the preflight tasks, i.e. *formatting*, *tests*, *quality*, and + Perform the preflight tasks, i.e., *formatting*, *tests*, *quality*, and *examples*. Parameters @@ -267,9 +265,7 @@ def docs(ctx: Context, html: bool = True, pdf: bool = True): Whether to build the *PDF* documentation. """ - with ctx.prefix("export COLOUR_SCIENCE__DOCUMENTATION_BUILD=True"), ctx.cd( - "docs" - ): + with ctx.prefix("export COLOUR_SCIENCE__DOCUMENTATION_BUILD=True"), ctx.cd("docs"): if html: message_box('Building "HTML" documentation...') ctx.run("make html") @@ -308,26 +304,19 @@ def requirements(ctx: Context): """ message_box('Exporting "requirements.txt" file...') - ctx.run( - "poetry export -f requirements.txt " - "--without-hashes " - "--with dev,docs,optional " - "--output requirements.txt" - ) + ctx.run('uv export --no-hashes --all-extras | grep -v "-e \\." > requirements.txt') message_box('Exporting "docs/requirements.txt" file...') ctx.run( - "poetry export -f requirements.txt " - "--without-hashes " - "--with docs,optional " - "--output docs/requirements.txt" + 'uv export --no-hashes --all-extras --no-dev | grep -v "-e \\." > ' + "docs/requirements.txt" ) @task(clean, preflight, docs, todo, requirements) def build(ctx: Context): """ - Build the project and runs dependency tasks, i.e. *docs*, *todo*, and + Build the project and runs dependency tasks, i.e., *docs*, *todo*, and *preflight*. Parameters @@ -337,7 +326,7 @@ def build(ctx: Context): """ message_box("Building...") - ctx.run("poetry build") + ctx.run("uv build") ctx.run("twine check dist/*") @@ -366,18 +355,18 @@ def virtualise(ctx: Context, tests: bool = True): ) with ctx.cd(unique_name): - ctx.run("poetry install") - ctx.run("source $(poetry env info -p)/bin/activate") + ctx.run("uv sync --all-extras --no-dev") ctx.run( - 'python -c "import imageio;' - 'imageio.plugins.freeimage.download()"' + 'uv run python -c "import imageio;imageio.plugins.freeimage.download()"' ) if tests: ctx.run( - "poetry run pytest " + "source .venv/bin/activate && " + "uv run pytest " "--doctest-modules " f"--ignore={PYTHON_PACKAGE_NAME}/examples " f"{PYTHON_PACKAGE_NAME}", + env={"MPLBACKEND": "AGG"}, ) @@ -422,9 +411,7 @@ def tag(ctx: Context): remote_tags = result.stdout.strip().split("\n") # pyright: ignore tags = set() for remote_tag in remote_tags: - tags.add( - remote_tag.split("refs/tags/")[1].replace("refs/tags/", "^{}") - ) + tags.add(remote_tag.split("refs/tags/")[1].replace("refs/tags/", "^{}")) version_tags = sorted(tags) if f"v{version}" in version_tags: raise RuntimeError( diff --git a/utilities/export_todo.py b/utilities/export_todo.py index 901bd305..69f3c5e2 100755 --- a/utilities/export_todo.py +++ b/utilities/export_todo.py @@ -40,9 +40,7 @@ https://opensource.org/licenses/BSD-3-Clause | `https://github.com/colour-science/colour-hdri \ `__ -"""[ - 1: -] +"""[1:] def extract_todo_items(root_directory: str) -> dict: