diff --git a/.coveragerc b/.coveragerc index 171cfe5..c339195 100644 --- a/.coveragerc +++ b/.coveragerc @@ -5,4 +5,5 @@ sigterm = True exclude_lines = pragma: no cover if __name__ == .__main__.: + if TYPE_CHECKING: pass diff --git a/colour_datasets/__init__.py b/colour_datasets/__init__.py index 4099509..c06086b 100644 --- a/colour_datasets/__init__.py +++ b/colour_datasets/__init__.py @@ -56,7 +56,7 @@ __major_version__ = "0" __minor_version__ = "2" __change_version__ = "6" -__version__ = ".".join((__major_version__, __minor_version__, __change_version__)) +__version__ = f"{__major_version__}.{__minor_version__}.{__change_version__}" try: _version = ( @@ -68,7 +68,7 @@ .strip() .decode("utf-8") ) -except Exception: +except Exception: # noqa: BLE001 _version = __version__ colour.utilities.ANCILLARY_COLOUR_SCIENCE_PACKAGES["colour-datasets"] = _version # pyright: ignore diff --git a/colour_datasets/loaders/__init__.py b/colour_datasets/loaders/__init__.py index 5aaf654..76ecf2d 100644 --- a/colour_datasets/loaders/__init__.py +++ b/colour_datasets/loaders/__init__.py @@ -3,8 +3,11 @@ from __future__ import annotations import sys +import typing + +if typing.TYPE_CHECKING: + from colour.hints import Any -from colour.hints import Any from colour.utilities import CanonicalMapping, warning from colour_datasets.records import datasets diff --git a/colour_datasets/loaders/abstract.py b/colour_datasets/loaders/abstract.py index 433b195..b5538c1 100644 --- a/colour_datasets/loaders/abstract.py +++ b/colour_datasets/loaders/abstract.py @@ -10,10 +10,12 @@ from __future__ import annotations from abc import ABC, abstractmethod +from typing import TYPE_CHECKING -from colour.hints import Any +if TYPE_CHECKING: + from colour.hints import Any -from colour_datasets.records import Record + from colour_datasets.records import Record __author__ = "Colour Developers" __copyright__ = "Copyright 2019 Colour Developers" @@ -122,7 +124,7 @@ def load(self) -> Any: when they implement it, e.g., ``super().sync()``. """ - def sync(self): + def sync(self) -> None: """ Sync the dataset content, i.e., checks whether it is synced and pulls it if required. diff --git a/colour_datasets/loaders/asano2015.py b/colour_datasets/loaders/asano2015.py index a6d2720..cfd829a 100644 --- a/colour_datasets/loaders/asano2015.py +++ b/colour_datasets/loaders/asano2015.py @@ -17,7 +17,8 @@ from __future__ import annotations import os -from collections import namedtuple +from dataclasses import dataclass, field +from typing import TYPE_CHECKING import numpy as np import xlrd @@ -26,7 +27,10 @@ LMS_ConeFundamentals, XYZ_ColourMatchingFunctions, ) -from colour.hints import Dict, NDArrayFloat + +if TYPE_CHECKING: + from colour.hints import Dict + from colour.utilities import as_float_array, tstack from colour_datasets.loaders import AbstractDatasetLoader @@ -47,12 +51,8 @@ ] -class Specification_Asano2015( - namedtuple( - "Specification_Asano2015", - ("XYZ_2", "XYZ_10", "LMS_2", "LMS_10", "parameters", "others"), - ) -): +@dataclass(frozen=True) +class Specification_Asano2015: """ Define the *Asano (2015)* specification for an observer. @@ -76,22 +76,12 @@ class Specification_Asano2015( :cite:`Asano2015` """ - def __new__( - cls, - XYZ_2: XYZ_ColourMatchingFunctions, - XYZ_10: XYZ_ColourMatchingFunctions, - LMS_2: LMS_ConeFundamentals, - LMS_10: LMS_ConeFundamentals, - parameters: NDArrayFloat, - others: Dict | None = None, - ): - """ - Return a new instance of the - :class:`colour_datasets.loaders.asano2015.Specification_Asano2015` - class. - """ - - return super().__new__(cls, XYZ_2, XYZ_10, LMS_2, LMS_10, parameters, others) + XYZ_2: XYZ_ColourMatchingFunctions + XYZ_10: XYZ_ColourMatchingFunctions + LMS_2: LMS_ConeFundamentals + LMS_10: LMS_ConeFundamentals + parameters: Dict + others: Dict = field(default_factory=dict) class DatasetLoader_Asano2015(AbstractDatasetLoader): @@ -199,7 +189,7 @@ def load(self) -> Dict[str, Dict[int, Specification_Asano2015]]: observer["LMS_2"], observer["LMS_10"], observer["parameters"], - dict(zip(header, values[i])), + dict(zip(header, values[i], strict=False)), ) return self._content @@ -284,7 +274,9 @@ def parse_workbook_Asano2015( for i in range(observers[1]): observer = i + 1 - data[observer]["parameters"] = dict(zip(header, as_float_array(values[i]))) + data[observer]["parameters"] = dict( + zip(header, as_float_array(values[i]), strict=False) + ) return data diff --git a/colour_datasets/loaders/brendel2020.py b/colour_datasets/loaders/brendel2020.py index 343b636..5a9141c 100644 --- a/colour_datasets/loaders/brendel2020.py +++ b/colour_datasets/loaders/brendel2020.py @@ -18,10 +18,14 @@ from __future__ import annotations import os +from typing import TYPE_CHECKING import numpy as np from colour import LinearInterpolator, SpectralDistribution, SpectralShape -from colour.hints import Dict + +if TYPE_CHECKING: + from colour.hints import Dict + from colour.utilities import as_int from colour_datasets.loaders import AbstractDatasetLoader diff --git a/colour_datasets/loaders/dyer2017.py b/colour_datasets/loaders/dyer2017.py index 5be60f8..677b6b2 100644 --- a/colour_datasets/loaders/dyer2017.py +++ b/colour_datasets/loaders/dyer2017.py @@ -19,10 +19,14 @@ import glob import json import os +from typing import TYPE_CHECKING from colour import MultiSpectralDistributions, SpectralDistribution from colour.continuous import MultiSignals, Signal -from colour.hints import Any, Dict, Literal + +if TYPE_CHECKING: + from colour.hints import Any, Dict, Literal + from colour.utilities import attest, is_numeric, optional from colour_datasets.loaders import AbstractDatasetLoader @@ -163,7 +167,7 @@ def schema_version(self) -> str | None: return self._schema_version @schema_version.setter - def schema_version(self, value: str | None): + def schema_version(self, value: str | None) -> None: """Setter for the **self.schema_version** property.""" if value is not None: @@ -193,7 +197,7 @@ def catalog_number(self) -> str | None: return self._catalog_number @catalog_number.setter - def catalog_number(self, value: str | None): + def catalog_number(self, value: str | None) -> None: """Setter for the **self.catalog_number** property.""" if value is not None: @@ -223,7 +227,7 @@ def description(self) -> str | None: return self._description @description.setter - def description(self, value: str | None): + def description(self, value: str | None) -> None: """Setter for the **self.description** property.""" if value is not None: @@ -253,7 +257,7 @@ def document_creator(self) -> str | None: return self._document_creator @document_creator.setter - def document_creator(self, value: str | None): + def document_creator(self, value: str | None) -> None: """Setter for the **self.document_creator** property.""" if value is not None: @@ -283,7 +287,7 @@ def unique_identifier(self) -> str | None: return self._unique_identifier @unique_identifier.setter - def unique_identifier(self, value: str | None): + def unique_identifier(self, value: str | None) -> None: """Setter for the **self.unique_identifier** property.""" if value is not None: @@ -313,7 +317,7 @@ def measurement_equipment(self) -> str | None: return self._measurement_equipment @measurement_equipment.setter - def measurement_equipment(self, value: str | None): + def measurement_equipment(self, value: str | None) -> None: """Setter for the **self.measurement_equipment** property.""" if value is not None: @@ -343,7 +347,7 @@ def laboratory(self) -> str | None: return self._laboratory @laboratory.setter - def laboratory(self, value: str | None): + def laboratory(self, value: str | None) -> None: """Setter for the **self.measurement_equipment** property.""" if value is not None: @@ -373,7 +377,7 @@ def document_creation_date(self) -> str | None: return self._document_creation_date @document_creation_date.setter - def document_creation_date(self, value: str | None): + def document_creation_date(self, value: str | None) -> None: """Setter for the **self.document_creation_date** property.""" if value is not None: @@ -403,7 +407,7 @@ def comments(self) -> str | None: return self._comments @comments.setter - def comments(self, value: str | None): + def comments(self, value: str | None) -> None: """Setter for the **self.comments** property.""" if value is not None: @@ -433,7 +437,7 @@ def license(self) -> str | None: return self._license @license.setter - def license(self, value: str | None): + def license(self, value: str | None) -> None: """Setter for the **self.license** property.""" if value is not None: @@ -628,7 +632,7 @@ def path(self) -> str | None: return self._path @path.setter - def path(self, value: str | None): + def path(self, value: str | None) -> None: """Setter for the **self.path** property.""" if value is not None: @@ -657,7 +661,7 @@ def header(self) -> SpectralDataHeader_AMPAS: return self._header @header.setter - def header(self, value: SpectralDataHeader_AMPAS): + def header(self, value: SpectralDataHeader_AMPAS) -> None: """Setter for the **self.header** property.""" attest( @@ -720,7 +724,7 @@ def units( "other", ] | None, - ): + ) -> None: """Setter for the **self.units** property.""" if value is not None: @@ -785,7 +789,7 @@ def reflection_geometry( "other", ] | None, - ): + ) -> None: """Setter for the **self.reflection_geometry** property.""" if value is not None: @@ -820,7 +824,7 @@ def transmission_geometry( def transmission_geometry( self, value: Literal["0:0", "di:0", "de:0", "0:di", "0:de", "d:d", "other"] | None, - ): + ) -> None: """Setter for the **self.transmission_geometry** property.""" if value is not None: @@ -850,7 +854,7 @@ def bandwidth_FWHM(self) -> float | None: return self._bandwidth_FWHM @bandwidth_FWHM.setter - def bandwidth_FWHM(self, value: float | None): + def bandwidth_FWHM(self, value: float | None) -> None: """Setter for the **self.bandwidth_FWHM** property.""" if value is not None: @@ -881,7 +885,7 @@ def bandwidth_corrected(self) -> bool | None: return self._bandwidth_corrected @bandwidth_corrected.setter - def bandwidth_corrected(self, value: bool | None): + def bandwidth_corrected(self, value: bool | None) -> None: """Setter for the **self.bandwidth_corrected** property.""" if value is not None: @@ -930,23 +934,23 @@ def read(self) -> SpectralDistribution: # attributes according to outcome of # https://github.com/ampas/rawtoaces/issues/114. if ( - "manufacturer" in self._header._kwargs - and "model" in self._header._kwargs + "manufacturer" in self._header._kwargs # noqa: SLF001 + and "model" in self._header._kwargs # noqa: SLF001 ): self.name = ( - f"{self._header._kwargs['manufacturer']} " - f"{self._header._kwargs['model']}" + f"{self._header._kwargs['manufacturer']} " # noqa: SLF001 + f"{self._header._kwargs['model']}" # noqa: SLF001 ) - elif "illuminant" in self._header._kwargs: - self.name = self._header._kwargs["illuminant"] - elif "type" in self._header._kwargs: - self.name = self._header._kwargs["type"] + elif "illuminant" in self._header._kwargs: # noqa: SLF001 + self.name = self._header._kwargs["illuminant"] # noqa: SLF001 + elif "type" in self._header._kwargs: # noqa: SLF001 + self.name = self._header._kwargs["type"] # noqa: SLF001 self.display_name = self.name return self - else: - raise ValueError("The spectral distribution path is undefined!") + msg = "The spectral distribution path is undefined!" + raise ValueError(msg) class MultiSpectralDistributions_AMPAS(MultiSpectralDistributions): @@ -1132,7 +1136,7 @@ def path(self) -> str | None: return self._path @path.setter - def path(self, value: str | None): + def path(self, value: str | None) -> None: """Setter for the **self.path** property.""" if value is not None: @@ -1161,7 +1165,7 @@ def header(self) -> SpectralDataHeader_AMPAS: return self._header @header.setter - def header(self, value: SpectralDataHeader_AMPAS): + def header(self, value: SpectralDataHeader_AMPAS) -> None: """Setter for the **self.header** property.""" attest( @@ -1224,7 +1228,7 @@ def units( "other", ] | None, - ): + ) -> None: """Setter for the **self.units** property.""" if value is not None: @@ -1289,7 +1293,7 @@ def reflection_geometry( "other", ] | None, - ): + ) -> None: """Setter for the **self.reflection_geometry** property.""" if value is not None: @@ -1324,7 +1328,7 @@ def transmission_geometry( def transmission_geometry( self, value: Literal["0:0", "di:0", "de:0", "0:di", "0:de", "d:d", "other"] | None, - ): + ) -> None: """Setter for the **self.transmission_geometry** property.""" if value is not None: @@ -1354,7 +1358,7 @@ def bandwidth_FWHM(self) -> float | None: return self._bandwidth_FWHM @bandwidth_FWHM.setter - def bandwidth_FWHM(self, value: float | None): + def bandwidth_FWHM(self, value: float | None) -> None: """Setter for the **self.bandwidth_FWHM** property.""" if value is not None: @@ -1385,7 +1389,7 @@ def bandwidth_corrected(self) -> bool | None: return self._bandwidth_corrected @bandwidth_corrected.setter - def bandwidth_corrected(self, value: bool | None): + def bandwidth_corrected(self, value: bool | None) -> None: """Setter for the **self.bandwidth_corrected** property.""" if value is not None: @@ -1433,24 +1437,24 @@ def read(self) -> MultiSpectralDistributions: # attributes according to outcome of # https://github.com/ampas/rawtoaces/issues/114. if ( - "manufacturer" in self._header._kwargs - and "model" in self._header._kwargs + "manufacturer" in self._header._kwargs # noqa: SLF001 + and "model" in self._header._kwargs # noqa: SLF001 ): self.name = ( - f"{self._header._kwargs['manufacturer']} " - f"{self._header._kwargs['model']}" + f"{self._header._kwargs['manufacturer']} " # noqa: SLF001 + f"{self._header._kwargs['model']}" # noqa: SLF001 ) - elif "illuminant" in self._header._kwargs: - self.name = self._header._kwargs["illuminant"] - elif "type" in self._header._kwargs: - self.name = self._header._kwargs["type"] + elif "illuminant" in self._header._kwargs: # noqa: SLF001 + self.name = self._header._kwargs["illuminant"] # noqa: SLF001 + elif "type" in self._header._kwargs: # noqa: SLF001 + self.name = self._header._kwargs["type"] # noqa: SLF001 self.display_name = self.name self.display_labels = self.labels return self - else: - raise ValueError("The multi-spectral distributions path is undefined!") + msg = "The multi-spectral distributions path is undefined!" + raise ValueError(msg) class DatasetLoader_Dyer2017(AbstractDatasetLoader): diff --git a/colour_datasets/loaders/ebner1998.py b/colour_datasets/loaders/ebner1998.py index a52d906..1b4c4db 100644 --- a/colour_datasets/loaders/ebner1998.py +++ b/colour_datasets/loaders/ebner1998.py @@ -20,10 +20,14 @@ import codecs import os -from collections import namedtuple +from dataclasses import dataclass +from typing import TYPE_CHECKING import numpy as np -from colour.hints import Dict, NDArrayFloat + +if TYPE_CHECKING: + from colour.hints import Dict, NDArrayFloat + from colour.utilities import as_float_array from colour_datasets.loaders import AbstractDatasetLoader @@ -43,12 +47,8 @@ ] -class ConstantPerceivedHueColourMatches_Ebner1998( - namedtuple( - "ConstantPerceivedHueColourMatches_Ebner1998", - ("name", "XYZ_r", "XYZ_cr", "XYZ_ct", "metadata"), - ) -): +@dataclass(frozen=True) +class ConstantPerceivedHueColourMatches_Ebner1998: """ Define *Ebner and Fairchild (1998)* *Constant Perceived-Hue Data* colour matches data for a given hue angle. @@ -70,6 +70,19 @@ class ConstantPerceivedHueColourMatches_Ebner1998( Dataset metadata. """ + name: str + XYZ_r: NDArrayFloat + XYZ_cr: NDArrayFloat + XYZ_ct: NDArrayFloat + metadata: Dict + + def __post_init__(self) -> None: + """Post-initialise the class.""" + + object.__setattr__(self, "XYZ_r", as_float_array(self.XYZ_r)) + object.__setattr__(self, "XYZ_cr", as_float_array(self.XYZ_cr)) + object.__setattr__(self, "XYZ_ct", as_float_array(self.XYZ_ct)) + class DatasetLoader_Ebner1998(AbstractDatasetLoader): """ diff --git a/colour_datasets/loaders/hung1995.py b/colour_datasets/loaders/hung1995.py index 27a7bea..9079abc 100644 --- a/colour_datasets/loaders/hung1995.py +++ b/colour_datasets/loaders/hung1995.py @@ -19,11 +19,16 @@ from __future__ import annotations import os -from collections import namedtuple +from dataclasses import dataclass +from typing import TYPE_CHECKING import numpy as np from colour import CCS_ILLUMINANTS, xy_to_XYZ, xyY_to_XYZ -from colour.hints import Dict + +if TYPE_CHECKING: + from colour.hints import Dict, NDArrayFloat + +from colour.utilities import as_float_array from colour_datasets.loaders import AbstractDatasetLoader from colour_datasets.records import datasets @@ -42,12 +47,8 @@ ] -class ConstantPerceivedHueColourMatches_Hung1995( - namedtuple( - "ConstantPerceivedHueColourMatches_Hung1995", - ("name", "XYZ_r", "XYZ_cr", "XYZ_ct", "metadata"), - ) -): +@dataclass(frozen=True) +class ConstantPerceivedHueColourMatches_Hung1995: """ Define *Hung and Berns (1995)* *Constant Hue Loci Data* colour matches data for a given hue angle. @@ -69,6 +70,19 @@ class ConstantPerceivedHueColourMatches_Hung1995( Dataset metadata. """ + name: str + XYZ_r: NDArrayFloat + XYZ_cr: NDArrayFloat + XYZ_ct: NDArrayFloat + metadata: Dict + + def __post_init__(self) -> None: + """Post-initialise the class.""" + + object.__setattr__(self, "XYZ_r", as_float_array(self.XYZ_r)) + object.__setattr__(self, "XYZ_cr", as_float_array(self.XYZ_cr)) + object.__setattr__(self, "XYZ_ct", as_float_array(self.XYZ_ct)) + class DatasetLoader_Hung1995(AbstractDatasetLoader): """ diff --git a/colour_datasets/loaders/jakob2019.py b/colour_datasets/loaders/jakob2019.py index 3d6155c..63478b8 100644 --- a/colour_datasets/loaders/jakob2019.py +++ b/colour_datasets/loaders/jakob2019.py @@ -19,8 +19,11 @@ import glob import os +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from colour.hints import Dict -from colour.hints import Dict from colour.recovery import LUT3D_Jakob2019 from colour_datasets.loaders import AbstractDatasetLoader diff --git a/colour_datasets/loaders/jiang2013.py b/colour_datasets/loaders/jiang2013.py index 8f7f157..f0c0b9a 100644 --- a/colour_datasets/loaders/jiang2013.py +++ b/colour_datasets/loaders/jiang2013.py @@ -21,11 +21,15 @@ import codecs import os import re +from typing import TYPE_CHECKING import numpy as np from colour import SpectralShape + +if TYPE_CHECKING: + from colour.hints import Dict + from colour.characterisation import RGB_CameraSensitivities -from colour.hints import Dict from colour.utilities import as_float_array from colour_datasets.loaders import AbstractDatasetLoader diff --git a/colour_datasets/loaders/karge2015.py b/colour_datasets/loaders/karge2015.py index 5e5526a..4458271 100644 --- a/colour_datasets/loaders/karge2015.py +++ b/colour_datasets/loaders/karge2015.py @@ -21,9 +21,13 @@ import os import re from collections import defaultdict +from typing import TYPE_CHECKING from colour.algebra import LinearInterpolator -from colour.hints import Dict + +if TYPE_CHECKING: + from colour.hints import Dict + from colour.io import read_sds_from_csv_file from colour_datasets.loaders import AbstractDatasetLoader diff --git a/colour_datasets/loaders/kuopio.py b/colour_datasets/loaders/kuopio.py index 75113db..c85dc89 100644 --- a/colour_datasets/loaders/kuopio.py +++ b/colour_datasets/loaders/kuopio.py @@ -40,13 +40,18 @@ import os import re import sys -from collections import namedtuple +import typing +from dataclasses import dataclass from typing import ClassVar import numpy as np import scipy.io from colour import SpectralDistribution, SpectralShape -from colour.hints import Any, Dict, Tuple, Type, cast + +if typing.TYPE_CHECKING: + from colour.hints import Any, Dict, Tuple, Type + +from colour.hints import cast from colour_datasets.loaders import AbstractDatasetLoader from colour_datasets.records import datasets @@ -68,12 +73,8 @@ ] -class MatFileMetadata_KuopioUniversity( - namedtuple( - "MatFileMetadata_KuopioUniversity", - ("key", "shape", "transpose", "identifiers"), - ) -): +@dataclass(frozen=True) +class MatFileMetadata_KuopioUniversity: """ Metadata storage for an *University of Kuopio* dataset spectral distributions. @@ -90,6 +91,11 @@ class MatFileMetadata_KuopioUniversity( Identifiers for the spectral distributions. """ + key: str + shape: SpectralShape + transpose: bool + identifiers: str | None + def read_sds_from_mat_file_KuopioUniversity( mat_file: str, metadata: MatFileMetadata_KuopioUniversity @@ -132,7 +138,7 @@ def read_sds_from_mat_file_KuopioUniversity( identifier = f"{identifier} ({i})" sds[identifier] = SpectralDistribution( - dict(zip(wavelengths, data)), name=identifier + dict(zip(wavelengths, data, strict=False)), name=identifier ) return sds diff --git a/colour_datasets/loaders/labsphere2019.py b/colour_datasets/loaders/labsphere2019.py index c31eac9..a6da5eb 100644 --- a/colour_datasets/loaders/labsphere2019.py +++ b/colour_datasets/loaders/labsphere2019.py @@ -17,10 +17,14 @@ from __future__ import annotations import os +from typing import TYPE_CHECKING import numpy as np from colour import SpectralDistribution -from colour.hints import Dict + +if TYPE_CHECKING: + from colour.hints import Dict + from colour.utilities import tsplit from colour_datasets.loaders import AbstractDatasetLoader diff --git a/colour_datasets/loaders/luo1997.py b/colour_datasets/loaders/luo1997.py index 31d1a17..0c4a9f7 100644 --- a/colour_datasets/loaders/luo1997.py +++ b/colour_datasets/loaders/luo1997.py @@ -32,10 +32,14 @@ from __future__ import annotations import os -from collections import namedtuple +from dataclasses import dataclass +from typing import TYPE_CHECKING import numpy as np -from colour.hints import Dict, Tuple + +if TYPE_CHECKING: + from colour.hints import Dict, NDArrayFloat, Tuple + from colour.utilities import as_float_array, usage_warning from colour_datasets.loaders import AbstractDatasetLoader @@ -56,9 +60,8 @@ ] -class ExperimentalGroupLuo1997( - namedtuple("ExperimentalGroupLuo1997", ("name", "phases", "metadata")) -): +@dataclass(frozen=True) +class ExperimentalGroupLuo1997: """ Define a *Luo and Rhodes (1997)* *LUTCHI Colour Appearance Data* experimental group, i.e., a group of experimental phases. @@ -74,22 +77,13 @@ class ExperimentalGroupLuo1997( Experimental group metadata. """ + name: str + phases: Dict + metadata: Dict -class ExperimentalPhaseLuo1997( - namedtuple( - "ExperimentalPhaseLuo1997", - ( - "name", - "JQCH_v", - "xyY_c", - "S_Y_c", - "Y_b", - "Y_r", - "XYZ_o", - "metadata", - ), - ) -): + +@dataclass(frozen=True) +class ExperimentalPhaseLuo1997: """ Define a *Luo and Rhodes (1997)* *LUTCHI Colour Appearance Data* experimental phase. @@ -123,6 +117,15 @@ class ExperimentalPhaseLuo1997( Experimental phase metadata. """ + name: str + JQCH_v: NDArrayFloat + xyY_c: NDArrayFloat + S_Y_c: NDArrayFloat + Y_b: float + Y_r: float + XYZ_o: NDArrayFloat + metadata: Dict + class DatasetLoader_Luo1997(AbstractDatasetLoader): """ @@ -1032,6 +1035,7 @@ def load(self) -> Dict[str, ExperimentalGroupLuo1997]: zip( phase_metadata_headers, [samples_count, (neutrals_start, neutrals_end)], + strict=False, ) ), ) @@ -1043,6 +1047,7 @@ def load(self) -> Dict[str, ExperimentalGroupLuo1997]: zip( group_metadata_headers, experimental_groups_summary[group], + strict=False, ) ), ) diff --git a/colour_datasets/loaders/luo1999.py b/colour_datasets/loaders/luo1999.py index eba8365..01815fa 100644 --- a/colour_datasets/loaders/luo1999.py +++ b/colour_datasets/loaders/luo1999.py @@ -27,10 +27,15 @@ import codecs import os -from collections import namedtuple +import typing +from dataclasses import dataclass import numpy as np -from colour.hints import Dict, Tuple, cast + +if typing.TYPE_CHECKING: + from colour.hints import Dict, NDArrayFloat, Tuple + +from colour.hints import cast from colour.utilities import as_float_array from colour_datasets.loaders import AbstractDatasetLoader @@ -50,23 +55,8 @@ ] -class CorrespondingColourDataset_Luo1999( - namedtuple( - "CorrespondingColourDataset_Luo1999", - ( - "name", - "XYZ_r", - "XYZ_t", - "XYZ_cr", - "XYZ_ct", - "Y_r", - "Y_t", - "B_r", - "B_t", - "metadata", - ), - ) -): +@dataclass(frozen=True) +class CorrespondingColourDataset_Luo1999: """ Define a *Luo and Rhodes (1999)* *Corresponding-Colour Datasets* dataset. @@ -97,6 +87,17 @@ class CorrespondingColourDataset_Luo1999( Dataset metadata. """ + name: str + XYZ_r: NDArrayFloat + XYZ_t: NDArrayFloat + XYZ_cr: NDArrayFloat + XYZ_ct: NDArrayFloat + Y_r: float + Y_t: float + B_r: float + B_t: float + metadata: Dict + class DatasetLoader_Luo1999(AbstractDatasetLoader): """ @@ -449,7 +450,7 @@ def load(self) -> Dict[str, CorrespondingColourDataset_Luo1999]: XYZ_ct.append(list(map(float, values[3:]))) name = f"{key} - {filename.split('.')[1]}" - dataset_metadata = dict(zip(metadata_headers, metadata)) + dataset_metadata = dict(zip(metadata_headers, metadata, strict=False)) Y_r = dataset_metadata["Illuminance (lux)"][i][0] Y_t = dataset_metadata["Illuminance (lux)"][i][1] diff --git a/colour_datasets/loaders/solomotav2023.py b/colour_datasets/loaders/solomotav2023.py index e33a89f..165d187 100644 --- a/colour_datasets/loaders/solomotav2023.py +++ b/colour_datasets/loaders/solomotav2023.py @@ -19,9 +19,13 @@ import glob import os +from typing import TYPE_CHECKING from colour.characterisation import RGB_CameraSensitivities -from colour.hints import Dict + +if TYPE_CHECKING: + from colour.hints import Dict + from colour.io import read_sds_from_csv_file from colour_datasets.loaders import AbstractDatasetLoader diff --git a/colour_datasets/loaders/tests/test_abstract.py b/colour_datasets/loaders/tests/test_abstract.py index af59abb..22c0d6a 100644 --- a/colour_datasets/loaders/tests/test_abstract.py +++ b/colour_datasets/loaders/tests/test_abstract.py @@ -20,7 +20,7 @@ class TestAbstractDatasetLoader: class unit tests methods. """ - def test_required_attributes(self): + def test_required_attributes(self) -> None: """Test the presence of required attributes.""" required_attributes = ("ID", "record", "id", "content") @@ -28,7 +28,7 @@ def test_required_attributes(self): for attribute in required_attributes: assert attribute in dir(AbstractDatasetLoader) - def test_required_methods(self): + def test_required_methods(self) -> None: """Test the presence of required methods.""" required_methods = ("__init__", "load", "sync") diff --git a/colour_datasets/loaders/tests/test_asano2015.py b/colour_datasets/loaders/tests/test_asano2015.py index 8f3ff22..dfa57fd 100644 --- a/colour_datasets/loaders/tests/test_asano2015.py +++ b/colour_datasets/loaders/tests/test_asano2015.py @@ -25,7 +25,7 @@ class TestDatasetLoader_Asano2015: class unit tests methods. """ - def test_required_attributes(self): + def test_required_attributes(self) -> None: """Test the presence of required attributes.""" required_attributes = ("ID",) @@ -33,7 +33,7 @@ def test_required_attributes(self): for attribute in required_attributes: assert attribute in dir(DatasetLoader_Asano2015) - def test_required_methods(self): + def test_required_methods(self) -> None: """Test the presence of required methods.""" required_methods = ("__init__", "load", "parse_workbook_Asano2015") @@ -41,7 +41,7 @@ def test_required_methods(self): for method in required_methods: assert method in dir(DatasetLoader_Asano2015) - def test_load(self): + def test_load(self) -> None: """ Test :func:`colour_datasets.loaders.asano2015.\ DatasetLoader_Asano2015.load` method. @@ -133,7 +133,7 @@ class TestBuildAsano2015: definition unit tests methods. """ - def test_build_Asano2015(self): + def test_build_Asano2015(self) -> None: """ Test :func:`colour_datasets.loaders.asano2015.build_Asano2015` definition. diff --git a/colour_datasets/loaders/tests/test_brendel2020.py b/colour_datasets/loaders/tests/test_brendel2020.py index d8ae053..045803c 100644 --- a/colour_datasets/loaders/tests/test_brendel2020.py +++ b/colour_datasets/loaders/tests/test_brendel2020.py @@ -29,7 +29,7 @@ class TestDatasetLoader_Brendel2020: DatasetLoader_Brendel2020` class unit tests methods. """ - def test_required_attributes(self): + def test_required_attributes(self) -> None: """Test the presence of required attributes.""" required_attributes = ("ID",) @@ -37,7 +37,7 @@ def test_required_attributes(self): for attribute in required_attributes: assert attribute in dir(DatasetLoader_Brendel2020) - def test_required_methods(self): + def test_required_methods(self) -> None: """Test the presence of required methods.""" required_methods = ("__init__", "load") @@ -45,7 +45,7 @@ def test_required_methods(self): for method in required_methods: assert method in dir(DatasetLoader_Brendel2020) - def test_load(self): + def test_load(self) -> None: """ Test :func:`colour_datasets.loaders.brendel2020.\ DatasetLoader_Brendel2020.load` method. @@ -66,7 +66,7 @@ class TestBuildBrendel2020: definition unit tests methods. """ - def test_build_Brendel2020(self): + def test_build_Brendel2020(self) -> None: """ Test :func:`colour_datasets.loaders.brendel2020.build_Brendel2020` definition. diff --git a/colour_datasets/loaders/tests/test_dyer2017.py b/colour_datasets/loaders/tests/test_dyer2017.py index e1d8761..40d462e 100644 --- a/colour_datasets/loaders/tests/test_dyer2017.py +++ b/colour_datasets/loaders/tests/test_dyer2017.py @@ -24,7 +24,7 @@ class TestDatasetLoader_Dyer2017: class unit tests methods. """ - def test_required_attributes(self): + def test_required_attributes(self) -> None: """Test the presence of required attributes.""" required_attributes = ("ID",) @@ -32,7 +32,7 @@ def test_required_attributes(self): for attribute in required_attributes: assert attribute in dir(DatasetLoader_Dyer2017) - def test_required_methods(self): + def test_required_methods(self) -> None: """Test the presence of required methods.""" required_methods = ("__init__", "load") @@ -40,7 +40,7 @@ def test_required_methods(self): for method in required_methods: assert method in dir(DatasetLoader_Dyer2017) - def test_load(self): + def test_load(self) -> None: """ Test :func:`colour_datasets.loaders.dyer2017.DatasetLoader_Dyer2017.\ load` method. @@ -287,7 +287,7 @@ class TestBuildDyer2017: definition unit tests methods. """ - def test_build_Dyer2017(self): + def test_build_Dyer2017(self) -> None: """ Test :func:`colour_datasets.loaders.dyer2017.build_Dyer2017` definition. diff --git a/colour_datasets/loaders/tests/test_ebner1998.py b/colour_datasets/loaders/tests/test_ebner1998.py index 7ce9655..9153f75 100644 --- a/colour_datasets/loaders/tests/test_ebner1998.py +++ b/colour_datasets/loaders/tests/test_ebner1998.py @@ -24,7 +24,7 @@ class TestDatasetLoader_Ebner1998: class unit tests methods. """ - def test_required_attributes(self): + def test_required_attributes(self) -> None: """Test the presence of required attributes.""" required_attributes = ("ID",) @@ -32,7 +32,7 @@ def test_required_attributes(self): for attribute in required_attributes: assert attribute in dir(DatasetLoader_Ebner1998) - def test_required_methods(self): + def test_required_methods(self) -> None: """Test the presence of required methods.""" required_methods = ("__init__", "load") @@ -40,7 +40,7 @@ def test_required_methods(self): for method in required_methods: assert method in dir(DatasetLoader_Ebner1998) - def test_load(self): + def test_load(self) -> None: """ Test :func:`colour_datasets.loaders.ebner1998.\ DatasetLoader_Ebner1998.load` method. @@ -125,7 +125,7 @@ class TestBuildEbner1998: definition unit tests methods. """ - def test_build_Ebner1998(self): + def test_build_Ebner1998(self) -> None: """ Test :func:`colour_datasets.loaders.ebner1998.build_Ebner1998` definition. diff --git a/colour_datasets/loaders/tests/test_hung1995.py b/colour_datasets/loaders/tests/test_hung1995.py index 850f9e6..c73fbbc 100644 --- a/colour_datasets/loaders/tests/test_hung1995.py +++ b/colour_datasets/loaders/tests/test_hung1995.py @@ -24,7 +24,7 @@ class TestDatasetLoader_Hung1995: class unit tests methods. """ - def test_required_attributes(self): + def test_required_attributes(self) -> None: """Test the presence of required attributes.""" required_attributes = ("ID",) @@ -32,7 +32,7 @@ def test_required_attributes(self): for attribute in required_attributes: assert attribute in dir(DatasetLoader_Hung1995) - def test_required_methods(self): + def test_required_methods(self) -> None: """Test the presence of required methods.""" required_methods = ("__init__", "load") @@ -40,7 +40,7 @@ def test_required_methods(self): for method in required_methods: assert method in dir(DatasetLoader_Hung1995) - def test_load(self): + def test_load(self) -> None: """ Test :func:`colour_datasets.loaders.hung1995.DatasetLoader_Hung1995.\ load` method. @@ -112,7 +112,7 @@ class TestBuildHung1995: definition unit tests methods. """ - def test_build_Hung1995(self): + def test_build_Hung1995(self) -> None: """ Test :func:`colour_datasets.loaders.hung1995.build_Hung1995` definition. diff --git a/colour_datasets/loaders/tests/test_jakob2019.py b/colour_datasets/loaders/tests/test_jakob2019.py index 7fa1900..5ce3f33 100644 --- a/colour_datasets/loaders/tests/test_jakob2019.py +++ b/colour_datasets/loaders/tests/test_jakob2019.py @@ -21,7 +21,7 @@ class TestDatasetLoader_Jakob2019: class unit tests methods. """ - def test_required_attributes(self): + def test_required_attributes(self) -> None: """Test the presence of required attributes.""" required_attributes = ("ID",) @@ -29,7 +29,7 @@ def test_required_attributes(self): for attribute in required_attributes: assert attribute in dir(DatasetLoader_Jakob2019) - def test_required_methods(self): + def test_required_methods(self) -> None: """Test the presence of required methods.""" required_methods = ("__init__", "load") @@ -37,7 +37,7 @@ def test_required_methods(self): for method in required_methods: assert method in dir(DatasetLoader_Jakob2019) - def test_load(self): + def test_load(self) -> None: """ Test :func:`colour_datasets.loaders.jakob2019.\ DatasetLoader_Jakob2019.load` method. @@ -58,7 +58,7 @@ class TestBuildJakob2019: definition unit tests methods. """ - def test_build_Jakob2019(self): + def test_build_Jakob2019(self) -> None: """ Test :func:`colour_datasets.loaders.jakob2019.build_Jakob2019` definition. diff --git a/colour_datasets/loaders/tests/test_jiang2013.py b/colour_datasets/loaders/tests/test_jiang2013.py index f3a632c..4143b46 100644 --- a/colour_datasets/loaders/tests/test_jiang2013.py +++ b/colour_datasets/loaders/tests/test_jiang2013.py @@ -23,7 +23,7 @@ class TestDatasetLoader_Jiang2013: class unit tests methods. """ - def test_required_attributes(self): + def test_required_attributes(self) -> None: """Test the presence of required attributes.""" required_attributes = ("ID",) @@ -31,7 +31,7 @@ def test_required_attributes(self): for attribute in required_attributes: assert attribute in dir(DatasetLoader_Jiang2013) - def test_required_methods(self): + def test_required_methods(self) -> None: """Test the presence of required methods.""" required_methods = ("__init__", "load") @@ -39,7 +39,7 @@ def test_required_methods(self): for method in required_methods: assert method in dir(DatasetLoader_Jiang2013) - def test_load(self): + def test_load(self) -> None: """ Test :func:`colour_datasets.loaders.jiang2013.\ DatasetLoader_Jiang2013.load` method. @@ -85,7 +85,7 @@ class TestBuildJiang2013: definition unit tests methods. """ - def test_build_Jiang2013(self): + def test_build_Jiang2013(self) -> None: """ Test :func:`colour_datasets.loaders.jiang2013.build_Jiang2013` definition. diff --git a/colour_datasets/loaders/tests/test_karge2015.py b/colour_datasets/loaders/tests/test_karge2015.py index 07669fa..079df02 100644 --- a/colour_datasets/loaders/tests/test_karge2015.py +++ b/colour_datasets/loaders/tests/test_karge2015.py @@ -23,7 +23,7 @@ class TestDatasetLoader_Karge2015: class unit tests methods. """ - def test_required_attributes(self): + def test_required_attributes(self) -> None: """Test the presence of required attributes.""" required_attributes = ("ID",) @@ -31,7 +31,7 @@ def test_required_attributes(self): for attribute in required_attributes: assert attribute in dir(DatasetLoader_Karge2015) - def test_required_methods(self): + def test_required_methods(self) -> None: """Test the presence of required methods.""" required_methods = ("__init__", "load") @@ -39,7 +39,7 @@ def test_required_methods(self): for method in required_methods: assert method in dir(DatasetLoader_Karge2015) - def test_load(self): + def test_load(self) -> None: """ Test :func:`colour_datasets.loaders.karge2015.\ DatasetLoader_Karge2015.load` method. @@ -66,7 +66,7 @@ class TestBuildKarge2015: definition unit tests methods. """ - def test_build_Karge2015(self): + def test_build_Karge2015(self) -> None: """ Test :func:`colour_datasets.loaders.karge2015.build_Karge2015` definition. diff --git a/colour_datasets/loaders/tests/test_kuopio.py b/colour_datasets/loaders/tests/test_kuopio.py index 57bc5bf..3f88b78 100644 --- a/colour_datasets/loaders/tests/test_kuopio.py +++ b/colour_datasets/loaders/tests/test_kuopio.py @@ -42,7 +42,7 @@ class TestReadSdsFromMatFileKuopioUniversity: read_sds_from_mat_file_KuopioUniversity` definition unit tests methods. """ - def test_read_sds_from_mat_file_KuopioUniversity(self): + def test_read_sds_from_mat_file_KuopioUniversity(self) -> None: """ Test :func:`colour_datasets.loaders.kuopio.\ read_sds_from_mat_file_KuopioUniversity` definition. @@ -105,7 +105,7 @@ class TestDatasetLoader_KuopioUniversity: DatasetLoader_KuopioUniversity` class unit tests methods. """ - def test_required_attributes(self): + def test_required_attributes(self) -> None: """Test the presence of required attributes.""" required_attributes = ("ID", "METADATA") @@ -123,7 +123,7 @@ def test_required_attributes(self): for attribute in required_attributes: assert attribute in dir(dataset_loader) - def test_required_methods(self): + def test_required_methods(self) -> None: """Test the presence of required methods.""" required_methods = ("__init__", "load") @@ -141,7 +141,7 @@ def test_required_methods(self): for method in required_methods: assert method in dir(dataset_loader) - def test_load(self): + def test_load(self) -> None: """ Test :func:`colour_datasets.loaders.kuopio.\ DatasetLoader_KuopioUniversity.load` method. diff --git a/colour_datasets/loaders/tests/test_labsphere2019.py b/colour_datasets/loaders/tests/test_labsphere2019.py index 0fbf313..ef2c95d 100644 --- a/colour_datasets/loaders/tests/test_labsphere2019.py +++ b/colour_datasets/loaders/tests/test_labsphere2019.py @@ -29,7 +29,7 @@ class TestDatasetLoader_Labsphere2019: DatasetLoader_Labsphere2019` class unit tests methods. """ - def test_required_attributes(self): + def test_required_attributes(self) -> None: """Test the presence of required attributes.""" required_attributes = ("ID",) @@ -37,7 +37,7 @@ def test_required_attributes(self): for attribute in required_attributes: assert attribute in dir(DatasetLoader_Labsphere2019) - def test_required_methods(self): + def test_required_methods(self) -> None: """Test the presence of required methods.""" required_methods = ("__init__", "load") @@ -45,7 +45,7 @@ def test_required_methods(self): for method in required_methods: assert method in dir(DatasetLoader_Labsphere2019) - def test_load(self): + def test_load(self) -> None: """ Test :func:`colour_datasets.loaders.labsphere2019.\ DatasetLoader_Labsphere2019.load` method. @@ -64,7 +64,7 @@ class TestBuildLabsphere2019: definition unit tests methods. """ - def test_build_Labsphere2019(self): + def test_build_Labsphere2019(self) -> None: """ Test :func:`colour_datasets.loaders.labsphere2019.build_Labsphere2019` definition. diff --git a/colour_datasets/loaders/tests/test_luo1997.py b/colour_datasets/loaders/tests/test_luo1997.py index c6ba504..251250b 100644 --- a/colour_datasets/loaders/tests/test_luo1997.py +++ b/colour_datasets/loaders/tests/test_luo1997.py @@ -24,7 +24,7 @@ class TestDatasetLoader_Luo1997: class unit tests methods. """ - def test_required_attributes(self): + def test_required_attributes(self) -> None: """Test the presence of required attributes.""" required_attributes = ("ID",) @@ -32,7 +32,7 @@ def test_required_attributes(self): for attribute in required_attributes: assert attribute in dir(DatasetLoader_Luo1997) - def test_required_methods(self): + def test_required_methods(self) -> None: """Test the presence of required methods.""" required_methods = ("__init__", "load") @@ -40,7 +40,7 @@ def test_required_methods(self): for method in required_methods: assert method in dir(DatasetLoader_Luo1997) - def test_load(self): + def test_load(self) -> None: """ Test :func:`colour_datasets.loaders.luo1997.DatasetLoader_Luo1997.\ load` method. @@ -175,7 +175,7 @@ class TestBuildLuo1997: definition unit tests methods. """ - def test_build_Luo1997(self): + def test_build_Luo1997(self) -> None: """ Test :func:`colour_datasets.loaders.luo1997.build_Luo1997` definition. diff --git a/colour_datasets/loaders/tests/test_luo1999.py b/colour_datasets/loaders/tests/test_luo1999.py index 80135ea..d71734e 100644 --- a/colour_datasets/loaders/tests/test_luo1999.py +++ b/colour_datasets/loaders/tests/test_luo1999.py @@ -24,7 +24,7 @@ class TestDatasetLoader_Luo1999: class unit tests methods. """ - def test_required_attributes(self): + def test_required_attributes(self) -> None: """Test the presence of required attributes.""" required_attributes = ("ID",) @@ -32,7 +32,7 @@ def test_required_attributes(self): for attribute in required_attributes: assert attribute in dir(DatasetLoader_Luo1999) - def test_required_methods(self): + def test_required_methods(self) -> None: """Test the presence of required methods.""" required_methods = ("__init__", "load") @@ -40,7 +40,7 @@ def test_required_methods(self): for method in required_methods: assert method in dir(DatasetLoader_Luo1999) - def test_load(self): + def test_load(self) -> None: """ Test :func:`colour_datasets.loaders.luo1999.DatasetLoader_Luo1999.\ load` method. @@ -158,7 +158,7 @@ class TestBuildLuo1999: definition unit tests methods. """ - def test_build_Luo1999(self): + def test_build_Luo1999(self) -> None: """ Test :func:`colour_datasets.loaders.luo1999.build_Luo1999` definition. diff --git a/colour_datasets/loaders/tests/test_solomotav2023.py b/colour_datasets/loaders/tests/test_solomotav2023.py index 0aba835..9080f1e 100644 --- a/colour_datasets/loaders/tests/test_solomotav2023.py +++ b/colour_datasets/loaders/tests/test_solomotav2023.py @@ -26,7 +26,7 @@ class TestDatasetLoader_Solomotav2023: class unit tests methods. """ - def test_required_attributes(self): + def test_required_attributes(self) -> None: """Test the presence of required attributes.""" required_attributes = ("ID",) @@ -34,7 +34,7 @@ def test_required_attributes(self): for attribute in required_attributes: assert attribute in dir(DatasetLoader_Solomotav2023) - def test_required_methods(self): + def test_required_methods(self) -> None: """Test the presence of required methods.""" required_methods = ("__init__", "load") @@ -42,7 +42,7 @@ def test_required_methods(self): for method in required_methods: assert method in dir(DatasetLoader_Solomotav2023) - def test_load(self): + def test_load(self) -> None: """ Test :func:`colour_datasets.loaders.solomotav2023.\ DatasetLoader_Solomotav2023.load` method. @@ -62,7 +62,7 @@ class TestBuildSolomotav2023: definition unit tests methods. """ - def test_build_Solomotav2023(self): + def test_build_Solomotav2023(self) -> None: """ Test :func:`colour_datasets.loaders.solomotav2023.build_Solomotav2023` definition. diff --git a/colour_datasets/loaders/tests/test_winquist2022.py b/colour_datasets/loaders/tests/test_winquist2022.py index 5c05aab..1181981 100644 --- a/colour_datasets/loaders/tests/test_winquist2022.py +++ b/colour_datasets/loaders/tests/test_winquist2022.py @@ -31,7 +31,7 @@ class TestDatasetLoader_Winquist2022: class unit tests methods. """ - def test_required_attributes(self): + def test_required_attributes(self) -> None: """Test the presence of required attributes.""" required_attributes = ("ID",) @@ -39,7 +39,7 @@ def test_required_attributes(self): for attribute in required_attributes: assert attribute in dir(DatasetLoader_Winquist2022) - def test_required_methods(self): + def test_required_methods(self) -> None: """Test the presence of required methods.""" required_methods = ("__init__", "load") @@ -47,7 +47,7 @@ def test_required_methods(self): for method in required_methods: assert method in dir(DatasetLoader_Winquist2022) - def test_load(self): + def test_load(self) -> None: """ Test :func:`colour_datasets.loaders.winquist2022.DatasetLoader_Winquist2022.\ @@ -70,7 +70,7 @@ class TestBuildWinquist2022: definition unit tests methods. """ - def test_build_Winquist2022(self): + def test_build_Winquist2022(self) -> None: """ Test :func:`colour_datasets.loaders.winquist2022.build_Winquist2022` definition. diff --git a/colour_datasets/loaders/tests/test_xrite2016.py b/colour_datasets/loaders/tests/test_xrite2016.py index 01afa35..7e68b8b 100644 --- a/colour_datasets/loaders/tests/test_xrite2016.py +++ b/colour_datasets/loaders/tests/test_xrite2016.py @@ -23,7 +23,7 @@ class TestDatasetLoader_XRite2016: class unit tests methods. """ - def test_required_attributes(self): + def test_required_attributes(self) -> None: """Test the presence of required attributes.""" required_attributes = ("ID",) @@ -31,7 +31,7 @@ def test_required_attributes(self): for attribute in required_attributes: assert attribute in dir(DatasetLoader_XRite2016) - def test_required_methods(self): + def test_required_methods(self) -> None: """Test the presence of required methods.""" required_methods = ("__init__", "load") @@ -39,7 +39,7 @@ def test_required_methods(self): for method in required_methods: assert method in dir(DatasetLoader_XRite2016) - def test_load(self): + def test_load(self) -> None: """ Test :func:`colour_datasets.loaders.xrite2016.\ DatasetLoader_XRite2016.load` method. @@ -66,7 +66,7 @@ class TestBuildXRite2016: definition unit tests methods. """ - def test_build_XRite2016(self): + def test_build_XRite2016(self) -> None: """ Test :func:`colour_datasets.loaders.xrite2016.build_XRite2016` definition. diff --git a/colour_datasets/loaders/tests/test_zhao2009.py b/colour_datasets/loaders/tests/test_zhao2009.py index fa0b045..5b5ee11 100644 --- a/colour_datasets/loaders/tests/test_zhao2009.py +++ b/colour_datasets/loaders/tests/test_zhao2009.py @@ -23,7 +23,7 @@ class TestDatasetLoader_Zhao2009: class unit tests methods. """ - def test_required_attributes(self): + def test_required_attributes(self) -> None: """Test the presence of required attributes.""" required_attributes = ("ID",) @@ -31,7 +31,7 @@ def test_required_attributes(self): for attribute in required_attributes: assert attribute in dir(DatasetLoader_Zhao2009) - def test_required_methods(self): + def test_required_methods(self) -> None: """Test the presence of required methods.""" required_methods = ("__init__", "load") @@ -39,7 +39,7 @@ def test_required_methods(self): for method in required_methods: assert method in dir(DatasetLoader_Zhao2009) - def test_load(self): + def test_load(self) -> None: """ Test :func:`colour_datasets.loaders.zhao2009.\ DatasetLoader_Zhao2009.load` method. @@ -71,7 +71,7 @@ class TestBuildZhao2009: definition unit tests methods. """ - def test_build_Zhao2009(self): + def test_build_Zhao2009(self) -> None: """ Test :func:`colour_datasets.loaders.zhao2009.build_Zhao2009` definition. diff --git a/colour_datasets/loaders/winquist2022.py b/colour_datasets/loaders/winquist2022.py index c92f202..aa6b0cf 100644 --- a/colour_datasets/loaders/winquist2022.py +++ b/colour_datasets/loaders/winquist2022.py @@ -20,8 +20,10 @@ import glob import os +from typing import TYPE_CHECKING -from colour.hints import Dict +if TYPE_CHECKING: + from colour.hints import Dict from colour_datasets.loaders import AbstractDatasetLoader from colour_datasets.loaders.dyer2017 import MultiSpectralDistributions_AMPAS diff --git a/colour_datasets/loaders/xrite2016.py b/colour_datasets/loaders/xrite2016.py index fa63f6e..cdfaf8f 100644 --- a/colour_datasets/loaders/xrite2016.py +++ b/colour_datasets/loaders/xrite2016.py @@ -20,11 +20,14 @@ import codecs import os +from typing import TYPE_CHECKING import numpy as np from colour import CCS_ILLUMINANTS, Lab_to_XYZ, XYZ_to_xyY from colour.characterisation import ColourChecker -from colour.hints import Dict + +if TYPE_CHECKING: + from colour.hints import Dict from colour_datasets.loaders import AbstractDatasetLoader from colour_datasets.records import datasets @@ -110,7 +113,7 @@ def load(self) -> Dict[str, ColourChecker]: illuminant = CCS_ILLUMINANTS["CIE 1931 2 Degree Standard Observer"]["ICC D50"] self._content = {} - for key, filename in zip(keys, filenames): + for key, filename in zip(keys, filenames, strict=False): directory = os.path.splitext(filename)[0] path = os.path.join(self.record.repository, "dataset", directory, filename) @@ -142,10 +145,10 @@ def load(self) -> Dict[str, ColourChecker]: np.reshape(np.array(samples_data, dtype=object), (i, j, 2)), [1, 0, 2], ) - keys, values = zip(*np.reshape(samples, (-1, 2))) + keys, values = zip(*np.reshape(samples, (-1, 2)), strict=False) values = XYZ_to_xyY(Lab_to_XYZ(values, illuminant)) self._content[key] = ColourChecker( - key, dict(zip(keys, values)), illuminant, j, i + key, dict(zip(keys, values, strict=False)), illuminant, j, i ) return self._content diff --git a/colour_datasets/loaders/zhao2009.py b/colour_datasets/loaders/zhao2009.py index faf1d01..3d15ba4 100644 --- a/colour_datasets/loaders/zhao2009.py +++ b/colour_datasets/loaders/zhao2009.py @@ -18,10 +18,13 @@ from __future__ import annotations import os +from typing import TYPE_CHECKING import numpy as np from colour.characterisation import RGB_CameraSensitivities -from colour.hints import Dict + +if TYPE_CHECKING: + from colour.hints import Dict from colour_datasets.loaders import AbstractDatasetLoader from colour_datasets.records import datasets diff --git a/colour_datasets/records/configuration.py b/colour_datasets/records/configuration.py index 30a6032..db886d3 100644 --- a/colour_datasets/records/configuration.py +++ b/colour_datasets/records/configuration.py @@ -9,13 +9,17 @@ import functools import os +from typing import TYPE_CHECKING -from colour.hints import Any, Callable, Dict from colour.utilities import Structure from colour.utilities.documentation import ( DocstringDict, is_documentation_building, ) +from typing_extensions import Self + +if TYPE_CHECKING: + from colour.hints import Any, Callable, Dict __author__ = "Colour Developers" __copyright__ = "Copyright 2019 Colour Developers" @@ -75,7 +79,7 @@ def use_sandbox( state: bool = True, api_url: str = "https://sandbox.zenodo.org/api", community: str = "colour-science-datasets", -): +) -> None: """ Modify the *Colour - Datasets* configuration to use *Zenodo* sandbox. @@ -120,7 +124,7 @@ def __init__( self._api_url = api_url self._community = community - def __enter__(self) -> sandbox: + def __enter__(self) -> Self: """ Set the configuration to the *Zenodo* sandbox upon entering the context manager. @@ -130,7 +134,7 @@ def __enter__(self) -> sandbox: return self - def __exit__(self, *args: Any): + def __exit__(self, *args: Any) -> None: """Restore the configuration upon exiting the context manager.""" use_sandbox(False) diff --git a/colour_datasets/records/tests/test_configuration.py b/colour_datasets/records/tests/test_configuration.py index 53d160c..a950710 100644 --- a/colour_datasets/records/tests/test_configuration.py +++ b/colour_datasets/records/tests/test_configuration.py @@ -24,12 +24,12 @@ class TestUseSandbox: definition unit tests methods. """ - def teardown_method(self): + def teardown_method(self) -> None: """After tests actions.""" use_sandbox(False) - def test_use_sandbox(self): + def test_use_sandbox(self) -> None: """ Test :func:`colour_datasets.records.configuration.use_sandbox` definition. @@ -47,7 +47,7 @@ class TestSandbox: definition unit tests methods. """ - def test_sandbox(self): + def test_sandbox(self) -> None: """ Test :func:`colour_datasets.records.configuration.sandbox` definition. diff --git a/colour_datasets/records/tests/test_zenodo.py b/colour_datasets/records/tests/test_zenodo.py index 200a328..b7e74e3 100644 --- a/colour_datasets/records/tests/test_zenodo.py +++ b/colour_datasets/records/tests/test_zenodo.py @@ -29,7 +29,7 @@ class TestRecord(unittest.TestCase): methods. """ - def setUp(self): + def setUp(self) -> None: """Initialise the common tests attributes.""" self._data = json_open("https://zenodo.org/api/records/3245883") @@ -37,7 +37,7 @@ def setUp(self): self._record = Record(self._data, self._configuration) - def test_required_attributes(self): + def test_required_attributes(self) -> None: """Test the presence of required attributes.""" required_attributes = ( @@ -51,7 +51,7 @@ def test_required_attributes(self): for attribute in required_attributes: self.assertIn(attribute, dir(Record)) - def test_required_methods(self): + def test_required_methods(self) -> None: """Test the presence of required methods.""" required_methods = ( @@ -67,7 +67,7 @@ def test_required_methods(self): for method in required_methods: self.assertIn(method, dir(Record)) - def test_configuration(self): + def test_configuration(self) -> None: """ Test :func:colour_datasets.records.zenodo.Record.configuration` property. @@ -75,12 +75,12 @@ def test_configuration(self): self.assertEqual(self._record.configuration, self._configuration) - def test_data(self): + def test_data(self) -> None: """Test :func:colour_datasets.records.zenodo.Record.data` property.""" self.assertEqual(self._record.data, self._data) - def test_repository(self): + def test_repository(self) -> None: """ Test :func:colour_datasets.records.zenodo.Record.repository` property. @@ -91,12 +91,12 @@ def test_repository(self): os.path.join(self._configuration.repository, "3245883"), ) - def test_id(self): + def test_id(self) -> None: """Test :func:colour_datasets.records.zenodo.Record.id` property.""" self.assertEqual(self._record.id, "3245883") - def test_title(self): + def test_title(self) -> None: """ Test :func:colour_datasets.records.zenodo.Record.title` property. @@ -107,7 +107,7 @@ def test_title(self): "Camera Spectral Sensitivity Database - Jiang et al. (2013)", ) - def test__init__(self): + def test__init__(self) -> None: """ Test :func:`colour_datasets.records.zenodo.Record.__init__` method. """ @@ -119,7 +119,7 @@ def test__init__(self): "Camera Spectral Sensitivity Database - Jiang et al. (2013)", ) - def test__str__(self): + def test__str__(self) -> None: """ Test :func:`colour_datasets.records.zenodo.Record.__str__` method. """ @@ -166,7 +166,7 @@ def test__str__(self): )[1:], ) - def test__repr__(self): + def test__repr__(self) -> None: """ Test :func:`colour_datasets.records.zenodo.Record.__repr__` method. """ @@ -180,7 +180,7 @@ def test__repr__(self): Record, ) - def test_from_id(self): + def test_from_id(self) -> None: """Test :func:`colour_datasets.records.zenodo.Record.from_id` method.""" record = Record.from_id("3245883") @@ -191,7 +191,7 @@ def test_from_id(self): "Camera Spectral Sensitivity Database - Jiang et al. (2013)", ) - def test_synced(self): + def test_synced(self) -> None: """Test :func:`colour_datasets.records.zenodo.Record.synced` method.""" self._record.pull() @@ -199,14 +199,14 @@ def test_synced(self): self._record.remove() self.assertFalse(self._record.synced()) - def test_pull(self): + def test_pull(self) -> None: """Test :func:`colour_datasets.records.zenodo.Record.pull` method.""" self._record.remove() self._record.pull() self.assertTrue(self._record.synced()) - def test_remove(self): + def test_remove(self) -> None: """Test :func:`colour_datasets.records.zenodo.Record.remove` method.""" self._record.pull() @@ -220,7 +220,7 @@ class TestCommunity(unittest.TestCase): methods. """ - def setUp(self): + def setUp(self) -> None: """Initialise the common tests attributes.""" community_data = json_open( @@ -236,7 +236,7 @@ def setUp(self): self._community = Community(self._data, self._configuration) - def test_required_attributes(self): + def test_required_attributes(self) -> None: """Test the presence of required attributes.""" required_attributes = ( @@ -249,7 +249,7 @@ def test_required_attributes(self): for attribute in required_attributes: self.assertIn(attribute, dir(Community)) - def test_required_methods(self): + def test_required_methods(self) -> None: """Test the presence of required methods.""" required_methods = ( @@ -268,7 +268,7 @@ def test_required_methods(self): for method in required_methods: self.assertIn(method, dir(Community)) - def test_configuration(self): + def test_configuration(self) -> None: """ Test :func:colour_datasets.records.zenodo.Community.configuration` property. @@ -276,14 +276,14 @@ def test_configuration(self): self.assertEqual(self._community.configuration, self._configuration) - def test_data(self): + def test_data(self) -> None: """ Test :func:colour_datasets.records.zenodo.Community.data` property. """ self.assertEqual(self._community.data, self._data) - def test_repository(self): + def test_repository(self) -> None: """ Test :func:colour_datasets.records.zenodo.Community.repository` property. @@ -291,14 +291,14 @@ def test_repository(self): self.assertEqual(self._community.repository, self._configuration.repository) - def test_records(self): + def test_records(self) -> None: """ Test :func:colour_datasets.records.zenodo.Community.records` property. """ self.assertIn("3245883", list(self._community.records)) - def test__init__(self): + def test__init__(self) -> None: """ Test :func:`colour_datasets.records.zenodo.Community.__init__` method. """ @@ -310,7 +310,7 @@ def test__init__(self): "Camera Spectral Sensitivity Database - Jiang et al. (2013)", ) - def test__str__(self): + def test__str__(self) -> None: """ Test :func:`colour_datasets.records.zenodo.Community.__str__` method. """ @@ -339,7 +339,7 @@ def test__str__(self): )[1:], ) - def test__repr__(self): + def test__repr__(self) -> None: """ Test :func:`colour_datasets.records.zenodo.Community.__repr__` method. """ @@ -353,7 +353,7 @@ def test__repr__(self): Community, ) - def test__getitem__(self): + def test__getitem__(self) -> None: """ Test :func:`colour_datasets.records.zenodo.Community.__getitem__` method. @@ -361,7 +361,7 @@ def test__getitem__(self): self.assertIs(self._community["3245883"], self._community.records["3245883"]) - def test__iter__(self): + def test__iter__(self) -> None: """ Test :func:`colour_datasets.records.zenodo.Community.__iter__` method. @@ -369,7 +369,7 @@ def test__iter__(self): self.assertListEqual(list(self._community), list(self._community.records)) - def test__len__(self): + def test__len__(self) -> None: """ Test :func:`colour_datasets.records.zenodo.Community.__getitem__` method. @@ -377,7 +377,7 @@ def test__len__(self): self.assertEqual(len(self._community), len(self._community.records)) - def test_from_id(self): + def test_from_id(self) -> None: """ Test :func:`colour_datasets.records.zenodo.Community.from_id` method. """ @@ -390,7 +390,7 @@ def test_from_id(self): "Camera Spectral Sensitivity Database - Jiang et al. (2013)", ) - def test_synced(self): + def test_synced(self) -> None: """ Test :func:`colour_datasets.records.zenodo.Community.synced` method. """ @@ -400,7 +400,7 @@ def test_synced(self): self._community.remove() self.assertFalse(self._community.synced()) - def test_pull(self): + def test_pull(self) -> None: """ Test :func:`colour_datasets.records.zenodo.Community.pull` method. """ @@ -409,7 +409,7 @@ def test_pull(self): self._community.pull() self.assertTrue(self._community.synced()) - def test_remove(self): + def test_remove(self) -> None: """ Test :func:`colour_datasets.records.zenodo.Community.remove` method. """ diff --git a/colour_datasets/records/zenodo.py b/colour_datasets/records/zenodo.py index 87a616f..c081f3a 100644 --- a/colour_datasets/records/zenodo.py +++ b/colour_datasets/records/zenodo.py @@ -23,20 +23,23 @@ from collections.abc import Mapping from html.parser import HTMLParser from pprint import pformat +from typing import TYPE_CHECKING import setuptools.archive_util -from colour.hints import ( - Any, - Callable, - Dict, - Generator, - List, -) from colour.utilities import optional, warning from colour_datasets.records import Configuration from colour_datasets.utilities import json_open, url_download +if TYPE_CHECKING: + from colour.hints import ( + Any, + Callable, + Dict, + Generator, + List, + ) + __author__ = "Colour Developers" __copyright__ = "Copyright 2019 Colour Developers" __license__ = "BSD-3-Clause - https://opensource.org/licenses/BSD-3-Clause" @@ -202,7 +205,7 @@ def strip_html(text: str) -> str: ] ) - representation = "\n".join( + return "\n".join( [ f'{metadata["title"]} - {metadata["version"]}', f'{"=" * (len(self.title) + 3 + len(metadata["version"]))}', @@ -225,8 +228,6 @@ def strip_html(text: str) -> str: ] ) - return representation - def __repr__(self) -> str: """ Return an evaluable string representation of the *Zenodo* record. @@ -331,7 +332,7 @@ def synced(self) -> bool: ] ) - def pull(self, use_urls_txt_file: bool = True, retries: int = 3): + def pull(self, use_urls_txt_file: bool = True, retries: int = 3) -> None: """ Pull the *Zenodo* record data to the local repository. @@ -414,10 +415,13 @@ def urls_download(urls: Dict) -> None: urls_download(urls) else: - raise ValueError( # noqa: TRY301 + msg = ( f'"{self._configuration.urls_txt_file}" file was not ' f"found in record data!" ) + raise ValueError( # noqa: TRY301 + msg + ) except (urllib.error.URLError, ValueError) as error: warning( f"An error occurred using urls from " @@ -472,7 +476,7 @@ def urls_download(urls: Dict) -> None: with open(os.path.join(self.repository, "record.json"), "w") as record_json: json.dump(self.data, record_json, indent=4, sort_keys=True) - def remove(self): + def remove(self) -> None: """ Remove the *Zenodo* record data local repository. @@ -634,7 +638,7 @@ def __str__(self) -> str: synced = len([dataset for dataset in self.values() if dataset.synced()]) - representation = "\n".join( + return "\n".join( [ f"{self._configuration.community}", f'{"=" * len(self._configuration.community)}', @@ -650,8 +654,6 @@ def __str__(self) -> str: ] ) - return representation - def __repr__(self) -> str: """ Return an evaluable string representation of the *Zenodo* community. @@ -809,7 +811,8 @@ def from_id( os.path.exists(records_json_filename), ] ): - raise RuntimeError("Local files were not found, aborting!") from error + msg = "Local files were not found, aborting!" + raise RuntimeError(msg) from error with open(community_json_filename) as json_file: community_data = json.loads(json_file.read()) @@ -850,7 +853,7 @@ def synced(self) -> bool: return all(record.synced() for record in self._records.values()) - def pull(self, use_urls_txt_file: bool = True, retries: int = 3): + def pull(self, use_urls_txt_file: bool = True, retries: int = 3) -> None: """ Pull the *Zenodo* community data to the local repository. @@ -882,7 +885,7 @@ def pull(self, use_urls_txt_file: bool = True, retries: int = 3): for record in self._records.values(): record.pull(use_urls_txt_file, retries) - def remove(self): + def remove(self) -> None: """ Remove the *Zenodo* community data local repository. @@ -905,7 +908,7 @@ def _remove_readonly( function: Callable, path: str, excinfo: Any, # noqa: ARG001 -): +) -> None: """ Error handler for :func:`shutil.rmtree` definition that removes read-only files. diff --git a/colour_datasets/utilities/common.py b/colour_datasets/utilities/common.py index 3c0782a..2920667 100644 --- a/colour_datasets/utilities/common.py +++ b/colour_datasets/utilities/common.py @@ -17,11 +17,15 @@ import sys import urllib.error import urllib.request +from typing import TYPE_CHECKING import setuptools.archive_util from cachetools import TTLCache, cached -from colour.hints import Any, Callable, Dict from tqdm import tqdm +from typing_extensions import Self + +if TYPE_CHECKING: + from colour.hints import Any, Callable, Dict __author__ = "Colour Developers" __copyright__ = "Copyright 2019 Colour Developers" @@ -44,7 +48,7 @@ class suppress_stdout: """A context manager and decorator temporarily suppressing standard output.""" - def __enter__(self) -> suppress_stdout: + def __enter__(self) -> Self: """Redirect the standard output upon entering the context manager.""" self._stdout = sys.stdout @@ -52,7 +56,7 @@ def __enter__(self) -> suppress_stdout: return self - def __exit__(self, *args: Any): + def __exit__(self, *args: Any) -> None: """Restore the standard output upon exiting the context manager.""" sys.stdout.close() @@ -77,7 +81,7 @@ def update_to( chunks_count: int = 1, chunk_size: int = 1, total_size: int | None = None, - ): + ) -> None: """ Report the progress of an action. @@ -127,7 +131,9 @@ def hash_md5(filename: str, chunk_size: int = 2**16) -> str: return md5.hexdigest() -def url_download(url: str, filename: str, md5: str | None = None, retries: int = 3): +def url_download( + url: str, filename: str, md5: str | None = None, retries: int = 3 +) -> None: """ Download given url and saves its content at given file. @@ -172,13 +178,16 @@ def url_download(url: str, filename: str, md5: str | None = None, retries: int = socket.setdefaulttimeout(timeout) if md5 is not None and md5.lower() != hash_md5(filename): - raise ValueError( # noqa: TRY301 + msg = ( f'"MD5" hash of "{filename}" file does not match the ' f"expected hash!" ) + raise ValueError( # noqa: TRY301 + msg + ) attempt = retries - except (urllib.error.URLError, OSError, ValueError): + except (urllib.error.URLError, OSError, ValueError): # noqa: PERF203 attempt += 1 print( # noqa: T201 f'An error occurred while downloading "{filename}" file ' @@ -229,7 +238,7 @@ def json_open(url: str, retries: int = 3) -> Dict: request = urllib.request.Request(url) # noqa: S310 with urllib.request.urlopen(request) as response: # noqa: S310 return json.loads(response.read()) - except (urllib.error.URLError, ValueError): + except (urllib.error.URLError, ValueError): # noqa: PERF203 attempt += 1 print( # noqa: T201 f'An error occurred while opening "{url}" url during attempt ' @@ -287,9 +296,8 @@ def unpack_gzipfile( shutil.copyfileobj(gzip_file, output_file) except Exception as error: print(error) # noqa: T201 - raise setuptools.archive_util.UnrecognizedFormat( - f'{filename} is not a "GZIP" file!' - ) from error + msg = f'{filename} is not a "GZIP" file!' + raise setuptools.archive_util.UnrecognizedFormat(msg) from error return True diff --git a/colour_datasets/utilities/spreadsheet.py b/colour_datasets/utilities/spreadsheet.py index a5c87fd..a20446b 100644 --- a/colour_datasets/utilities/spreadsheet.py +++ b/colour_datasets/utilities/spreadsheet.py @@ -13,11 +13,14 @@ from __future__ import annotations import re +from typing import TYPE_CHECKING import xlrd -from colour.hints import Dict, List from colour.utilities import CanonicalMapping, attest +if TYPE_CHECKING: + from colour.hints import Dict, List + __author__ = "Colour Developers, Openpyxl Developers" __copyright__ = "Copyright 2019 Colour Developers" __copyright__ += ", " @@ -234,7 +237,7 @@ def cell_range_values(sheet: xlrd.sheet.Sheet, cell_range: str) -> List[str]: row_out = row_to_index(groups["row_out"]) for row in range(row_in, row_out + 1, 1): - table.append( + table.append( # noqa: PERF401 sheet.row_values(row, start_colx=column_in, end_colx=column_out + 1) ) diff --git a/colour_datasets/utilities/tests/test_common.py b/colour_datasets/utilities/tests/test_common.py index 5cef05e..98dfaf0 100644 --- a/colour_datasets/utilities/tests/test_common.py +++ b/colour_datasets/utilities/tests/test_common.py @@ -35,7 +35,7 @@ class TestHashMd5: tests methods. """ - def test_hash_md5(self): + def test_hash_md5(self) -> None: """Test :func:`colour_datasets.utilities.common.hash_md5` definition.""" dataset = build_Labsphere2019() @@ -63,17 +63,17 @@ class TestUrlDownload: unit tests methods. """ - def setup_method(self): + def setup_method(self) -> None: """Initialise the common tests attributes.""" self._temporary_file = tempfile.NamedTemporaryFile(delete=False).name # noqa: SIM115 - def teardown_method(self): + def teardown_method(self) -> None: """After tests actions.""" os.remove(self._temporary_file) - def test_url_download(self): + def test_url_download(self) -> None: """Test :func:`colour_datasets.utilities.common.url_download` definition.""" dataset = build_Labsphere2019() @@ -118,7 +118,7 @@ class TestJsonOpen: unit tests methods. """ - def test_json_open(self): + def test_json_open(self) -> None: """Test :func:`colour_datasets.utilities.common.json_open` definition.""" data = json_open("https://zenodo.org/api/records/3245883") @@ -134,17 +134,17 @@ class TestUnpackGzipfile: unit tests methods. """ - def setup_method(self): + def setup_method(self) -> None: """Initialise the common tests attributes.""" self._temporary_directory = tempfile.mkdtemp() - def teardown_method(self): + def teardown_method(self) -> None: """After tests actions.""" shutil.rmtree(self._temporary_directory) - def test_unpack_gzipfile(self): + def test_unpack_gzipfile(self) -> None: """ Test :func:`colour_datasets.utilities.common.unpack_gzipfile` definition. diff --git a/colour_datasets/utilities/tests/test_spreadsheet.py b/colour_datasets/utilities/tests/test_spreadsheet.py index b13ae38..0145e1c 100644 --- a/colour_datasets/utilities/tests/test_spreadsheet.py +++ b/colour_datasets/utilities/tests/test_spreadsheet.py @@ -38,7 +38,7 @@ class TestRowToIndex: definition unit tests methods. """ - def test_row_to_index(self): + def test_row_to_index(self) -> None: """ Test :func:`colour_datasets.utilities.spreadsheet.row_to_index` definition. @@ -59,7 +59,7 @@ class TestIndexToRow: definition unit tests methods. """ - def test_index_to_row(self): + def test_index_to_row(self) -> None: """ Test :func:`colour_datasets.utilities.spreadsheet.index_to_row` definition. @@ -78,7 +78,7 @@ class TestColumnToIndex: definition unit tests methods. """ - def test_column_to_index(self): + def test_column_to_index(self) -> None: """ Test :func:`colour_datasets.utilities.spreadsheet.column_to_index` definition. @@ -99,7 +99,7 @@ class TestIndexToColumn: definition unit tests methods. """ - def test_index_to_column(self): + def test_index_to_column(self) -> None: """ Test :func:`colour_datasets.utilities.spreadsheet.index_to_column` definition. @@ -118,7 +118,7 @@ class TestCellRangeValues: definition unit tests methods. """ - def test_cell_range_values(self): + def test_cell_range_values(self) -> None: """ Test :func:`colour_datasets.utilities.spreadsheet.cell_range_values` definition. diff --git a/pyproject.toml b/pyproject.toml index a99dbf7..a6a0bde 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -127,91 +127,51 @@ addopts = "--durations=5" [tool.ruff] target-version = "py310" line-length = 88 -select = [ - "A", # flake8-builtins - "ARG", # flake8-unused-arguments - # "ANN", # flake8-annotations - "B", # flake8-bugbear - # "BLE", # flake8-blind-except - "C4", # flake8-comprehensions - # "C90", # mccabe - # "COM", # flake8-commas - "DTZ", # flake8-datetimez - "D", # pydocstyle - "E", # pydocstyle - # "ERA", # eradicate - # "EM", # flake8-errmsg - "EXE", # flake8-executable - "F", # flake8 - # "FBT", # flake8-boolean-trap - "G", # flake8-logging-format - "I", # isort - "ICN", # flake8-import-conventions - "INP", # flake8-no-pep420 - "ISC", # flake8-implicit-str-concat - "N", # pep8-naming - # "PD", # pandas-vet - "PIE", # flake8-pie - "PGH", # pygrep-hooks - "PL", # pylint - # "PT", # flake8-pytest-style - # "PTH", # flake8-use-pathlib [Enable] - "Q", # flake8-quotes - "RET", # flake8-return - "RUF", # Ruff - "S", # flake8-bandit - "SIM", # flake8-simplify - "T10", # flake8-debugger - "T20", # flake8-print - # "TCH", # flake8-type-checking - "TID", # flake8-tidy-imports - "TRY", # tryceratops - "UP", # pyupgrade - "W", # pydocstyle - "YTT" # flake8-2020 -] +select = ["ALL"] ignore = [ - "B008", - "B905", - "D104", - "D200", - "D202", - "D205", - "D301", - "D400", - "I001", - "N801", - "N802", - "N803", - "N806", - "N813", - "N815", - "N816", - "PGH003", - "PIE804", - "PLE0605", - "PLR0911", - "PLR0912", - "PLR0913", - "PLR0915", - "PLR2004", - "RET504", - "RET505", - "RET506", - "RET507", - "RET508", - "RUF022", - "TRY003", - "TRY300", - "UP038", + "C", # Pylint - Convention + "C90", # mccabe + "COM", # flake8-commas + "ERA", # eradicate + "FBT", # flake8-boolean-trap + "FIX", # flake8-fixme + "PT", # flake8-pytest-style + "PTH", # flake8-use-pathlib [Enable] + "TD", # flake8-todos + "ANN401", # Dynamically typed expressions (typing.Any) are disallowed in `**kwargs` + "D200", # One-line docstring should fit on one line + "D202", # No blank lines allowed after function docstring + "D205", # 1 blank line required between summary line and description + "D301", # Use `r"""` if any backslashes in a docstring + "D400", # First line should end with a period + "I001", # Import block is un-sorted or un-formatted + "N801", # Class name `.*` should use CapWords convention + "N802", # Function name `.*` should be lowercase + "N803", # Argument name `.*` should be lowercase + "N806", # Variable `.*` in function should be lowercase + "N813", # Camelcase `.*` imported as lowercase `.*` + "N815", # Variable `.*` in class scope should not be mixedCase + "N816", # Variable `.*` in global scope should not be mixedCase + "NPY002", # Replace legacy `np.random.random` call with `np.random.Generator` + "PGH003", # Use specific rule codes when ignoring type issues + "PLR0912", # Too many branches + "PLR0913", # Too many arguments in function definition + "PLR0915", # Too many statements + "PLR2004", # Magic value used in comparison, consider replacing `.*` with a constant variable + "PYI036", # Star-args in `.*` should be annotated with `object` + "PYI051", # `Literal[".*"]` is redundant in a union with `str` + "PYI056", # Calling `.append()` on `__all__` may not be supported by all type checkers (use `+=` instead) + "RUF022", # [*] `__all__` is not sorted + "TRY003", # Avoid specifying long messages outside the exception class + "UP038", # Use `X | Y` in `isinstance` call instead of `(X, Y)` ] typing-modules = ["colour.hints"] -fixable = ["B", "C", "E", "F", "PIE", "RUF", "SIM", "UP", "W"] [tool.ruff.pydocstyle] convention = "numpy" [tool.ruff.per-file-ignores] +"__init__.py" = ["D104"] "colour_datasets/examples/*" = ["INP", "T201", "T203"] "docs/*" = ["INP"] "tasks.py" = ["INP"] diff --git a/tasks.py b/tasks.py index c1875e0..cdc6e44 100644 --- a/tasks.py +++ b/tasks.py @@ -20,9 +20,13 @@ if not hasattr(inspect, "getargspec"): inspect.getargspec = inspect.getfullargspec # pyright: ignore -from invoke.context import Context +from typing import TYPE_CHECKING + from invoke.tasks import task +if TYPE_CHECKING: + from invoke.context import Context + __author__ = "Colour Developers" __copyright__ = "Copyright 2019 Colour Developers" __license__ = "BSD-3-Clause - https://opensource.org/licenses/BSD-3-Clause" @@ -72,7 +76,7 @@ def clean( docs: bool = True, bytecode: bool = False, pytest: bool = True, -): +) -> None: """ Clean the project. @@ -112,7 +116,7 @@ def formatting( ctx: Context, asciify: bool = True, bibtex: bool = True, -): +) -> None: """ Convert unicode characters to ASCII and cleanup the *BibTeX* file. @@ -155,7 +159,7 @@ def quality( ctx: Context, pyright: bool = True, rstlint: bool = True, -): +) -> None: """ Check the codebase with *Pyright* and lints various *restructuredText* files with *rst-lint*. @@ -180,7 +184,7 @@ def quality( @task -def precommit(ctx: Context): +def precommit(ctx: Context) -> None: """ Run the "pre-commit" hooks on the codebase. @@ -195,7 +199,7 @@ def precommit(ctx: Context): @task -def tests(ctx: Context): +def tests(ctx: Context) -> None: """ Run the unit tests with *Pytest*. @@ -216,7 +220,7 @@ def tests(ctx: Context): @task -def examples(ctx: Context): +def examples(ctx: Context) -> None: """ Run the examples. @@ -236,7 +240,7 @@ def examples(ctx: Context): @task(formatting, quality, precommit, tests, examples) -def preflight(ctx: Context): # noqa: ARG001 +def preflight(ctx: Context) -> None: # noqa: ARG001 """ Perform the preflight tasks, i.e., *formatting*, *tests*, *quality*, and *examples*. @@ -251,7 +255,7 @@ def preflight(ctx: Context): # noqa: ARG001 @task -def docs(ctx: Context, html: bool = True, pdf: bool = True): +def docs(ctx: Context, html: bool = True, pdf: bool = True) -> None: """ Build the documentation. @@ -276,7 +280,7 @@ def docs(ctx: Context, html: bool = True, pdf: bool = True): @task -def todo(ctx: Context): +def todo(ctx: Context) -> None: """ Export the TODO items. @@ -293,7 +297,7 @@ def todo(ctx: Context): @task -def requirements(ctx: Context): +def requirements(ctx: Context) -> None: """ Export the *requirements.txt* file. @@ -314,7 +318,7 @@ def requirements(ctx: Context): @task(clean, preflight, docs, todo, requirements) -def build(ctx: Context): +def build(ctx: Context) -> None: """ Build the project and runs dependency tasks, i.e., *docs*, *todo*, and *preflight*. @@ -331,7 +335,7 @@ def build(ctx: Context): @task -def virtualise(ctx: Context, tests: bool = True): +def virtualise(ctx: Context, tests: bool = True) -> None: """ Create a virtual environment for the project build. @@ -369,7 +373,7 @@ def virtualise(ctx: Context, tests: bool = True): @task -def tag(ctx: Context): +def tag(ctx: Context) -> None: """ Tag the repository according to defined version using *git-flow*. @@ -383,7 +387,8 @@ def tag(ctx: Context): result = ctx.run("git rev-parse --abbrev-ref HEAD", hide="both") if result.stdout.strip() != "develop": # pyright: ignore - raise RuntimeError("Are you still on a feature or master branch?") + msg = "Are you still on a feature or master branch?" + raise RuntimeError(msg) with open(os.path.join(PYTHON_PACKAGE_NAME, "__init__.py")) as file_handle: file_content = file_handle.read() @@ -403,7 +408,7 @@ def tag(ctx: Context): 1 ) - version = ".".join((major_version, minor_version, change_version)) + version = f"{major_version}.{minor_version}.{change_version}" result = ctx.run("git ls-remote --tags upstream", hide="both") remote_tags = result.stdout.strip().split("\n") # pyright: ignore @@ -412,17 +417,18 @@ def tag(ctx: Context): tags.add(remote_tag.split("refs/tags/")[1].replace("refs/tags/", "^{}")) version_tags = sorted(tags) if f"v{version}" in version_tags: - raise RuntimeError( + msg = ( f'A "{PYTHON_PACKAGE_NAME}" "v{version}" tag already exists in ' f"remote repository!" ) + raise RuntimeError(msg) ctx.run(f"git flow release start v{version}") ctx.run(f"git flow release finish v{version}") @task(build) -def release(ctx: Context): +def release(ctx: Context) -> None: """ Release the project to *Pypi* with *Twine*. @@ -439,7 +445,7 @@ def release(ctx: Context): @task -def sha256(ctx: Context): +def sha256(ctx: Context) -> None: """ Compute the project *Pypi* package *sha256* with *OpenSSL*. diff --git a/utilities/export_todo.py b/utilities/export_todo.py index acc86e0..e24b4de 100755 --- a/utilities/export_todo.py +++ b/utilities/export_todo.py @@ -93,7 +93,7 @@ def extract_todo_items(root_directory: str) -> dict: return todo_items -def export_todo_items(todo_items: dict, file_path: str): +def export_todo_items(todo_items: dict, file_path: str) -> None: """ Export TODO items to given file. diff --git a/utilities/unicode_to_ascii.py b/utilities/unicode_to_ascii.py index 0fb9fea..d5c5e11 100755 --- a/utilities/unicode_to_ascii.py +++ b/utilities/unicode_to_ascii.py @@ -28,7 +28,7 @@ } -def unicode_to_ascii(root_directory: str): +def unicode_to_ascii(root_directory: str) -> None: """ Recursively convert from unicode to ASCII *.py*, *.bib* and *.rst* files in given directory.