Repository: pyxem/kikuchipy (language: python)

Issue:
Errors in IO plugin tests using dask.keys()
Two tests of the NORDIF and h5ebsd IO plugins looking through `dask.array.dask.keys()` strings fail on [HyperSpy's extension integration tests](https://github.com/hyperspy/hyperspy-extensions-list/runs/5087004619?check_suite_focus=true#step:13:70):

https://github.com/pyxem/kikuchipy/blob/853371528be59cb502d438f6647df1f614971603/kikuchipy/io/plugins/tests/test_nordif.py#L345-L355

https://github.com/pyxem/kikuchipy/blob/853371528be59cb502d438f6647df1f614971603/kikuchipy/io/plugins/tests/test_h5ebsd.py#L289-L298
Updates to the data module
@harripj had some good questions in his review of a new PR to orix for a data module there (https://github.com/pyxem/orix/pull/318). We should touch up the code slightly and the documentation:
- [ ] Inform of lack of automatic deletion of old version directories in local cache when downloading data sets with newer versions of kikuchipy
- [ ] Tell `pooch` the name of the development branch (`develop`, not `master`)
- [ ] Specify licenses of each file in the function docstrings
Errors in IO plugin tests using dask.keys()
Two tests of the NORDIF and h5ebsd IO plugins looking through `dask.array.dask.keys()` strings fail on [HyperSpy's extension integration tests](https://github.com/hyperspy/hyperspy-extensions-list/runs/5087004619?check_suite_focus=true#step:13:70):

https://github.com/pyxem/kikuchipy/blob/853371528be59cb502d438f6647df1f614971603/kikuchipy/io/plugins/tests/test_nordif.py#L345-L355

https://github.com/pyxem/kikuchipy/blob/853371528be59cb502d438f6647df1f614971603/kikuchipy/io/plugins/tests/test_h5ebsd.py#L289-L298


Discussion / hints:
Key is `original-array` in latest dask versions, so we should just check for both as is done in https://github.com/hyperspy/hyperspy/pull/2888.

Key is `original-array` in latest dask versions, so we should just check for both as is done in https://github.com/hyperspy/hyperspy/pull/2888.

Fix patch:
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index fc57b21e..e3d11388 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,5 +1,5 @@
 repos:
   - repo: https://github.com/psf/black
-    rev: 21.7b0
+    rev: 22.3.0
     hooks:
       - id: black
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 81cd1cd3..caa360e7 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -21,6 +21,8 @@ Contributors
 
 Added
 -----
+- `progressbar` parameter to functions downloading external datasets in the data module.
+  (`#515 <https://github.com/pyxem/kikuchipy/pull/515>`_)
 - Support for Python 3.10. (`#504 <https://github.com/pyxem/kikuchipy/pull/504>`_)
 - `EBSD.static_background` property for easier access to the background pattern.
   (`#475 <https://github.com/pyxem/kikuchipy/pull/475>`_)
diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst
index 377a200d..f2687a2d 100644
--- a/CONTRIBUTING.rst
+++ b/CONTRIBUTING.rst
@@ -260,20 +260,22 @@ the `pooch <https://www.fatiando.org/pooch/latest/>`_ Python library. These are
 in a file registry (`kikuchipy.data._registry.py`) with their file verification string
 (hash, SHA256, obtain with e.g. `sha256sum <file>`) and location, the latter potentially
 not within the package but from the `kikuchipy-data
-<https://github.com/pyxem/kikuchipy-data>`_ repository, since some files are considered
-too large to include in the package.
+<https://github.com/pyxem/kikuchipy-data>`_ repository or elsewhere, since some files
+are considered too large to include in the package.
 
 If a required dataset isn't in the package, but is in the registry, it can be downloaded
 from the repository when the user passes `allow_download=True` to e.g.
 :func:`~kikuchipy.data.nickel_ebsd_large`. The dataset is then downloaded to a local
-cache, e.g. `/home/user/.cache/kikuchipy/`. Pooch handles downloading, caching, version
-control, file verification (against hash) etc. If we have updated the file hash, pooch
-will re-download it. If the file is available in the cache, it can be loaded as the
-other files in the data module.
-
-The desired data cache directory used by pooch can be set with a global
-`KIKUCHIPY_DATA_DIR` variable locally, e.g. by setting
-`export KIKUCHIPY_DATA_DIR=~/kikuchipy_data` in `~/.bashrc`.
+cache, in the location returned from `pooch.os_cache("kikuchipy")`. The location can be
+set with a global `KIKUCHIPY_DATA_DIR` variable locally, e.g. by setting
+`export KIKUCHIPY_DATA_DIR=~/kikuchipy_data` in `~/.bashrc`. Pooch handles downloading,
+caching, version control, file verification (against hash) etc. of files not included in
+the package. If we have updated the file hash, pooch will re-download it. If the file is
+available in the cache, it can be loaded as the other files in the data module.
+
+With every new version of kikuchipy, a new directory of datasets with the version name
+is added to the cache directory. Any old directories are not deleted automatically, and
+should then be deleted manually if desired.
 
 Improving performance
 =====================
diff --git a/kikuchipy/_rotation/__init__.py b/kikuchipy/_rotation/__init__.py
index 3e9b0533..8bb38350 100644
--- a/kikuchipy/_rotation/__init__.py
+++ b/kikuchipy/_rotation/__init__.py
@@ -109,10 +109,10 @@ def _rotate_vector(rotation: np.ndarray, vector: np.ndarray) -> np.ndarray:
     y = vector[:, 1]
     z = vector[:, 2]
     rotated_vector = np.zeros(vector.shape)
-    aa = a ** 2
-    bb = b ** 2
-    cc = c ** 2
-    dd = d ** 2
+    aa = a**2
+    bb = b**2
+    cc = c**2
+    dd = d**2
     ac = a * c
     ab = a * b
     ad = a * d
diff --git a/kikuchipy/crystallography/matrices.py b/kikuchipy/crystallography/matrices.py
index 6d3bff29..bae12099 100644
--- a/kikuchipy/crystallography/matrices.py
+++ b/kikuchipy/crystallography/matrices.py
@@ -75,16 +75,13 @@ def get_reciprocal_metric_tensor(lattice: Lattice) -> np.ndarray:
     a, b, c = lattice.abcABG()[:3]
     ca, cb, cg = lattice.ca, lattice.cb, lattice.cg
     sa, sb, sg = lattice.sa, lattice.sb, lattice.sg
-    terms_12_21 = a * b * (c ** 2) * (ca * cb - cg)
-    terms_13_31 = a * (b ** 2) * c * (cg * ca - cb)
-    terms_23_32 = (a ** 2) * b * c * (cb * cg - ca)
-    return (
-        np.array(
-            [
-                [(b * c * sa) ** 2, terms_12_21, terms_13_31],
-                [terms_12_21, (a * c * sb) ** 2, terms_23_32],
-                [terms_13_31, terms_23_32, (a * b * sg) ** 2],
-            ]
-        )
-        / np.linalg.det(lattice.metrics)
-    )
+    terms_12_21 = a * b * (c**2) * (ca * cb - cg)
+    terms_13_31 = a * (b**2) * c * (cg * ca - cb)
+    terms_23_32 = (a**2) * b * c * (cb * cg - ca)
+    return np.array(
+        [
+            [(b * c * sa) ** 2, terms_12_21, terms_13_31],
+            [terms_12_21, (a * c * sb) ** 2, terms_23_32],
+            [terms_13_31, terms_23_32, (a * b * sg) ** 2],
+        ]
+    ) / np.linalg.det(lattice.metrics)
diff --git a/kikuchipy/data/__init__.py b/kikuchipy/data/__init__.py
index 615417d1..553c2a36 100644
--- a/kikuchipy/data/__init__.py
+++ b/kikuchipy/data/__init__.py
@@ -19,18 +19,27 @@
 
 Some datasets must be downloaded from the web. For more test datasets,
 see :doc:`open datasets <open_datasets>`.
+
+Some datasets must be downloaded from the web. Datasets are placed in a
+local cache, in the location returned from `pooch.os_cache("kikuchipy")`
+by default. The location can be overwritten with a global
+`KIKUCHIPY_DATA_DIR` environment variable.
+
+With every new version of kikuchipy, a new directory of datasets with
+the version name is added to the cache directory. Any old directories
+are not deleted automatically, and should then be deleted manually if
+desired.
 """
 
 import os
 from pathlib import Path
-from typing import Union
 
-import pooch as ppooch
+import pooch
 
 from kikuchipy.signals import EBSD, EBSDMasterPattern
 from kikuchipy import load
 from kikuchipy.release import version
-from kikuchipy.data._registry import registry, registry_urls
+from kikuchipy.data._registry import registry_hashes, registry_urls
 
 
 __all__ = [
@@ -43,56 +52,39 @@
 ]
 
 
-fetcher = ppooch.create(
-    path=ppooch.os_cache("kikuchipy"),
+_fetcher = pooch.create(
+    path=pooch.os_cache("kikuchipy"),
     base_url="",
     version=version.replace(".dev", "+"),
+    version_dev="develop",
     env="KIKUCHIPY_DATA_DIR",
-    registry=registry,
+    registry=registry_hashes,
     urls=registry_urls,
 )
-cache_data_path = fetcher.path.joinpath("data")
-package_data_path = Path(os.path.abspath(os.path.dirname(__file__)))
-
-
-def _has_hash(path, expected_hash):
-    """Check if the provided path has the expected hash."""
-    if not os.path.exists(path):
-        return False
-    else:
-        return ppooch.file_hash(path) == expected_hash
 
 
-def _cautious_downloader(url, output_file, pooch):
-    if pooch.allow_download:
-        delattr(pooch, "allow_download")
-        # HTTPDownloader() requires tqdm, a HyperSpy dependency, so
-        # adding it to our dependencies doesn't cost anything
-        download = ppooch.HTTPDownloader(progressbar=True)
-        download(url, output_file, pooch)
+def _fetch(filename: str, allow_download: bool = False, progressbar=True) -> Path:
+    fname = "data/" + filename
+    expected_hash = registry_hashes[fname]
+    file_in_package = Path(os.path.dirname(__file__)) / ".." / fname
+    if file_in_package.exists() and pooch.file_hash(file_in_package) == expected_hash:
+        # Bypass pooch
+        file_path = file_in_package
     else:
-        raise ValueError(
-            "The dataset must be (re)downloaded from the kikuchipy-data "
-            "repository on GitHub (https://github.com/pyxem/kikuchipy-data) to "
-            "your local cache with the pooch Python package. Pass "
-            "`allow_download=True` to allow this download."
-        )
-
-
-def _fetch(filename: str, allow_download: bool = False):
-    resolved_path = os.path.join(package_data_path, "..", filename)
-    expected_hash = registry[filename]
-    if _has_hash(resolved_path, expected_hash):  # File already in data module
-        return resolved_path
-    else:  # Pooch must download the data to the local cache
-        fetcher.allow_download = allow_download  # Extremely ugly
-        resolved_path = fetcher.fetch(filename, downloader=_cautious_downloader)
-    return resolved_path
-
-
-def _load(filename: str, **kwargs) -> Union[EBSD, EBSDMasterPattern]:
-    allow_download = kwargs.pop("allow_download", False)
-    return load(_fetch(filename, allow_download=allow_download), **kwargs)
+        file_in_cache = Path(_fetcher.path) / fname
+        if file_in_cache.exists():
+            allow_download = True
+        if allow_download:
+            downloader = pooch.HTTPDownloader(progressbar=progressbar)
+            file_path = _fetcher.fetch(fname, downloader=downloader)
+        else:
+            raise ValueError(
+                f"Dataset {filename} must be (re)downloaded from the kikuchipy-data "
+                "repository on GitHub (https://github.com/pyxem/kikuchipy-data) to your"
+                " local cache with the pooch Python package. Pass `allow_download=True`"
+                " to allow this download."
+            )
+    return file_path
 
 
 def nickel_ebsd_small(**kwargs) -> EBSD:
@@ -100,6 +92,8 @@ def nickel_ebsd_small(**kwargs) -> EBSD:
     pixels from Nickel, acquired on a NORDIF UF-1100 detector
     :cite:`aanes2019electron`.
 
+    Carries a CC BY 4.0 license.
+
     Parameters
     ----------
     kwargs
@@ -109,8 +103,16 @@ def nickel_ebsd_small(**kwargs) -> EBSD:
     -------
     signal : EBSD
         EBSD signal.
+
+    Examples
+    --------
+    >>> import kikuchipy as kp
+    >>> s = kp.data.nickel_ebsd_small()
+    >>> s
+    <EBSD, title: patterns My awes0m4 ..., dimensions: (3, 3|60, 60)>
     """
-    return _load(filename="data/kikuchipy_h5ebsd/patterns.h5", **kwargs)
+    fname = _fetch("kikuchipy_h5ebsd/patterns.h5")
+    return load(fname, **kwargs)
 
 
 def nickel_ebsd_master_pattern_small(**kwargs) -> EBSDMasterPattern:
@@ -118,6 +120,8 @@ def nickel_ebsd_master_pattern_small(**kwargs) -> EBSDMasterPattern:
     northern and southern hemisphere of a Nickel master pattern at 20
     keV accelerating voltage.
 
+    Carries a CC BY 4.0 license.
+
     Parameters
     ----------
     kwargs
@@ -139,22 +143,44 @@ def nickel_ebsd_master_pattern_small(**kwargs) -> EBSDMasterPattern:
     :meth:`~kikuchipy.io.plugins.h5ebsd.dict2h5ebsdgroup` with
     keyword arguments `compression="gzip"` and `compression_opts=9`. All
     other HDF5 groups and datasets are the same as in the original file.
+
+    Examples
+    --------
+    >>> import kikuchipy as kp
+    >>> s = kp.data.nickel_ebsd_master_pattern_small()
+    >>> s
+    <EBSDMasterPattern, title: ni_mc_mp_20kv_uint8_gzip_opts9, dimensions: (|401, 401)>
+    >>> s.projection
+    'stereographic'
+
+    Import master pattern in the square Lambert projection
+
+    >>> s2 = kp.data.nickel_ebsd_master_pattern_small(projection="lambert")
+    >>> s2.projection
+    'lambert'
     """
-    fname = "data/emsoft_ebsd_master_pattern/ni_mc_mp_20kv_uint8_gzip_opts9.h5"
-    return _load(fname, **kwargs)
+    fname = _fetch("emsoft_ebsd_master_pattern/ni_mc_mp_20kv_uint8_gzip_opts9.h5")
+    return load(fname, **kwargs)
 
 
-def nickel_ebsd_large(allow_download: bool = False, **kwargs) -> EBSD:
+def nickel_ebsd_large(
+    allow_download: bool = False, progressbar: bool = True, **kwargs
+) -> EBSD:
     """4125 EBSD patterns in a (55, 75) navigation shape of (60, 60)
     detector pixels from Nickel, acquired on a NORDIF UF-1100 detector
     :cite:`aanes2019electron`.
 
+    Carries a CC BY 4.0 license.
+
     Parameters
     ----------
     allow_download : bool
         Whether to allow downloading the dataset from the kikuchipy-data
         GitHub repository (https://github.com/pyxem/kikuchipy-data) to
         the local cache with the pooch Python package. Default is False.
+    progressbar
+        Whether to show a progressbar when downloading. Default is
+        False.
     kwargs
         Keyword arguments passed to :func:`~kikuchipy.io._io.load`.
 
@@ -162,15 +188,21 @@ def nickel_ebsd_large(allow_download: bool = False, **kwargs) -> EBSD:
     -------
     signal : EBSD
         EBSD signal.
+
+    Examples
+    --------
+    >>> import kikuchipy as kp
+    >>> s = kp.data.nickel_ebsd_large(allow_download=True)
+    >>> s
+    <EBSD, title: patterns Scan 1, dimensions: (75, 55|60, 60)>
     """
-    return _load(
-        filename="data/nickel_ebsd_large/patterns.h5",
-        allow_download=allow_download,
-        **kwargs,
-    )
+    fname = _fetch("nickel_ebsd_large/patterns.h5", allow_download, progressbar)
+    return load(fname, **kwargs)
 
 
-def silicon_ebsd_moving_screen_in(allow_download: bool = False, **kwargs) -> EBSD:
+def silicon_ebsd_moving_screen_in(
+    allow_download: bool = False, progressbar: bool = True, **kwargs
+) -> EBSD:
     """One EBSD pattern of (480, 480) detector pixels from a single
     crystal Silicon sample, acquired on a NORDIF UF-420 detector.
 
@@ -179,12 +211,17 @@ def silicon_ebsd_moving_screen_in(allow_download: bool = False, **kwargs) -> EBS
     acquired to test the moving-screen projection center estimation
     technique :cite:`hjelen1991electron`.
 
+    Carries a CC BY 4.0 license.
+
     Parameters
     ----------
     allow_download : bool
         Whether to allow downloading the dataset from the kikuchipy-data
         GitHub repository (https://github.com/pyxem/kikuchipy-data) to
         the local cache with the pooch Python package. Default is False.
+    progressbar
+        Whether to show a progressbar when downloading. Default is
+        False.
     kwargs
         Keyword arguments passed to :func:`~kikuchipy.io._io.load`.
 
@@ -197,15 +234,21 @@ def silicon_ebsd_moving_screen_in(allow_download: bool = False, **kwargs) -> EBS
     --------
     silicon_ebsd_moving_screen_out5mm
     silicon_ebsd_moving_screen_out10mm
+
+    Examples
+    --------
+    >>> import kikuchipy as kp
+    >>> s = kp.data.silicon_ebsd_moving_screen_in(allow_download=True)
+    >>> s
+    <EBSD, title: si_in Scan 1, dimensions: (|480, 480)>
     """
-    return _load(
-        filename="data/silicon_ebsd_moving_screen/si_in.h5",
-        allow_download=allow_download,
-        **kwargs,
-    )
+    fname = _fetch("silicon_ebsd_moving_screen/si_in.h5", allow_download, progressbar)
+    return load(fname, **kwargs)
 
 
-def silicon_ebsd_moving_screen_out5mm(allow_download: bool = False, **kwargs) -> EBSD:
+def silicon_ebsd_moving_screen_out5mm(
+    allow_download: bool = False, progressbar: bool = True, **kwargs
+) -> EBSD:
     """One EBSD pattern of (480, 480) detector pixels from a single
     crystal Silicon sample, acquired on a NORDIF UF-420 detector.
 
@@ -216,12 +259,17 @@ def silicon_ebsd_moving_screen_out5mm(allow_download: bool = False, **kwargs) ->
     the moving-screen projection center estimation technique
     :cite:`hjelen1991electron`.
 
+    Carries a CC BY 4.0 license.
+
     Parameters
     ----------
     allow_download : bool
         Whether to allow downloading the dataset from the kikuchipy-data
         GitHub repository (https://github.com/pyxem/kikuchipy-data) to
         the local cache with the pooch Python package. Default is False.
+    progressbar
+        Whether to show a progressbar when downloading. Default is
+        False.
     kwargs
         Keyword arguments passed to :func:`~kikuchipy.io._io.load`.
 
@@ -234,15 +282,23 @@ def silicon_ebsd_moving_screen_out5mm(allow_download: bool = False, **kwargs) ->
     --------
     silicon_ebsd_moving_screen_in
     silicon_ebsd_moving_screen_out10mm
+
+    Examples
+    --------
+    >>> import kikuchipy as kp
+    >>> s = kp.data.silicon_ebsd_moving_screen_out5mm(allow_download=True)
+    >>> s
+    <EBSD, title: si_out5mm Scan 1, dimensions: (|480, 480)>
     """
-    return _load(
-        filename="data/silicon_ebsd_moving_screen/si_out5mm.h5",
-        allow_download=allow_download,
-        **kwargs,
+    fname = _fetch(
+        "silicon_ebsd_moving_screen/si_out5mm.h5", allow_download, progressbar
     )
+    return load(fname, **kwargs)
 
 
-def silicon_ebsd_moving_screen_out10mm(allow_download: bool = False, **kwargs) -> EBSD:
+def silicon_ebsd_moving_screen_out10mm(
+    allow_download: bool = False, progressbar: bool = True, **kwargs
+) -> EBSD:
     """One EBSD pattern of (480, 480) detector pixels from a single
     crystal Silicon sample, acquired on a NORDIF UF-420 detector.
 
@@ -253,12 +309,17 @@ def silicon_ebsd_moving_screen_out10mm(allow_download: bool = False, **kwargs) -
     the moving-screen projection center estimation technique
     :cite:`hjelen1991electron`.
 
+    Carries a CC BY 4.0 license.
+
     Parameters
     ----------
     allow_download : bool
         Whether to allow downloading the dataset from the kikuchipy-data
         GitHub repository (https://github.com/pyxem/kikuchipy-data) to
         the local cache with the pooch Python package. Default is False.
+    progressbar
+        Whether to show a progressbar when downloading. Default is
+        False.
     kwargs
         Keyword arguments passed to :func:`~kikuchipy.io._io.load`.
 
@@ -271,9 +332,15 @@ def silicon_ebsd_moving_screen_out10mm(allow_download: bool = False, **kwargs) -
     --------
     silicon_ebsd_moving_screen_in
     silicon_ebsd_moving_screen_out5mm
+
+    Examples
+    --------
+    >>> import kikuchipy as kp
+    >>> s = kp.data.silicon_ebsd_moving_screen_out10mm(allow_download=True)
+    >>> s
+    <EBSD, title: si_out10mm Scan 1, dimensions: (|480, 480)>
     """
-    return _load(
-        filename="data/silicon_ebsd_moving_screen/si_out10mm.h5",
-        allow_download=allow_download,
-        **kwargs,
+    fname = _fetch(
+        "silicon_ebsd_moving_screen/si_out10mm.h5", allow_download, progressbar
     )
+    return load(fname, **kwargs)
diff --git a/kikuchipy/data/_registry.py b/kikuchipy/data/_registry.py
index c7729610..153be44b 100644
--- a/kikuchipy/data/_registry.py
+++ b/kikuchipy/data/_registry.py
@@ -16,7 +16,7 @@
 # along with kikuchipy. If not, see <http://www.gnu.org/licenses/>.
 
 # fmt: off
-registry = {
+registry_hashes = {
     "data/kikuchipy_h5ebsd/patterns.h5": "7a99ce88174c725f5407b6fcc1eab0c4255694ca8e6029fde7f372f3ab40897f",
     "data/emsoft_ebsd_master_pattern/ni_mc_mp_20kv_uint8_gzip_opts9.h5": "8a7c1fb471d9ce750f0332a154e87cf41eed7529be508548e0c0f51ec6f92bc2",
     "data/nickel_ebsd_large/patterns.h5": "3ea6e729c3adfdea9dce461806f011c24bf70b011dcf4d90a23a6aa29f15872c",
diff --git a/kikuchipy/detectors/ebsd_detector.py b/kikuchipy/detectors/ebsd_detector.py
index f0de50bf..ae6c1d71 100644
--- a/kikuchipy/detectors/ebsd_detector.py
+++ b/kikuchipy/detectors/ebsd_detector.py
@@ -397,10 +397,10 @@ def r_max(self) -> np.ndarray:
         coordinates.
         """
         corners = np.zeros(self.navigation_shape + (4,))
-        corners[..., 0] = self.x_min ** 2 + self.y_min ** 2  # Up. left
-        corners[..., 1] = self.x_max ** 2 + self.y_min ** 2  # Up. right
-        corners[..., 2] = self.x_max ** 2 + self.y_max ** 2  # Lo. right
-        corners[..., 3] = self.x_min ** 2 + self.y_min ** 2  # Lo. left
+        corners[..., 0] = self.x_min**2 + self.y_min**2  # Up. left
+        corners[..., 1] = self.x_max**2 + self.y_min**2  # Up. right
+        corners[..., 2] = self.x_max**2 + self.y_max**2  # Lo. right
+        corners[..., 3] = self.x_min**2 + self.y_min**2  # Lo. left
         return np.atleast_2d(np.sqrt(np.max(corners, axis=-1)))
 
     def pc_emsoft(self, version: int = 5) -> np.ndarray:
diff --git a/kikuchipy/io/plugins/emsoft_ebsd.py b/kikuchipy/io/plugins/emsoft_ebsd.py
index a01bcd0f..d64e33b7 100644
--- a/kikuchipy/io/plugins/emsoft_ebsd.py
+++ b/kikuchipy/io/plugins/emsoft_ebsd.py
@@ -235,7 +235,7 @@ def _crystaldata2phase(dictionary: dict) -> Phase:
                 atype=atom_types[i],
                 xyz=atom_data[:3, i],
                 occupancy=atom_data[3, i],
-                Uisoequiv=atom_data[4, i] / (8 * np.pi ** 2) * 1e2,  # Å^-2
+                Uisoequiv=atom_data[4, i] / (8 * np.pi**2) * 1e2,  # Å^-2
             )
         )
 
diff --git a/kikuchipy/pattern/_pattern.py b/kikuchipy/pattern/_pattern.py
index 1050bce3..6fd5d9fc 100644
--- a/kikuchipy/pattern/_pattern.py
+++ b/kikuchipy/pattern/_pattern.py
@@ -204,7 +204,7 @@ def _dynamic_background_frequency_space_setup(
     # Get Gaussian filtering window
     shape = (int(truncate * std),) * 2
     window = Window("gaussian", std=std, shape=shape)
-    window = window / (2 * np.pi * std ** 2)
+    window = window / (2 * np.pi * std**2)
     window = window / np.sum(window)
 
     # FFT filter setup
@@ -495,7 +495,7 @@ def fft_spectrum(fft_pattern: np.ndarray) -> np.ndarray:
     fft_spectrum : numpy.ndarray
         2D FFT spectrum of the EBSD pattern.
     """
-    return np.sqrt(fft_pattern.real ** 2 + fft_pattern.imag ** 2)
+    return np.sqrt(fft_pattern.real**2 + fft_pattern.imag**2)
 
 
 @nb.jit(nopython=True, nogil=True, cache=True)
@@ -562,7 +562,7 @@ def fft_frequency_vectors(shape: Tuple[int, int]) -> np.ndarray:
 
     frequency_vectors = np.empty(shape=(sy, sx))
     for i in range(sy):
-        frequency_vectors[i] = liney[i] ** 2 + linex ** 2 - 1
+        frequency_vectors[i] = liney[i] ** 2 + linex**2 - 1
 
     return frequency_vectors
 
@@ -573,7 +573,7 @@ def _zero_mean(patterns: np.ndarray, axis: Union[int, tuple]) -> np.ndarray:
 
 
 def _normalize(patterns: np.ndarray, axis: Union[int, tuple]) -> np.ndarray:
-    patterns_squared = patterns ** 2
+    patterns_squared = patterns**2
     patterns_norm = np.nansum(patterns_squared, axis=axis, keepdims=True)
-    patterns_norm_squared = patterns_norm ** 0.5
+    patterns_norm_squared = patterns_norm**0.5
     return patterns / patterns_norm_squared
diff --git a/kikuchipy/projections/gnomonic_projection.py b/kikuchipy/projections/gnomonic_projection.py
index a1d061f6..d8e5c9ea 100644
--- a/kikuchipy/projections/gnomonic_projection.py
+++ b/kikuchipy/projections/gnomonic_projection.py
@@ -97,6 +97,6 @@ def xy2vector(xy: np.ndarray) -> Vector3d:
         >>> xyz = GnomonicProjection.xy2vector(xy_g)
         """
         x, y = xy[..., 0], xy[..., 1]
-        polar = np.arctan(np.sqrt(x ** 2 + y ** 2))
+        polar = np.arctan(np.sqrt(x**2 + y**2))
         azimuth = np.arctan2(y, x)
         return Vector3d.from_polar(polar=polar, azimuth=azimuth)
diff --git a/kikuchipy/projections/lambert_projection.py b/kikuchipy/projections/lambert_projection.py
index 39112d0d..3da3e30f 100644
--- a/kikuchipy/projections/lambert_projection.py
+++ b/kikuchipy/projections/lambert_projection.py
@@ -81,7 +81,7 @@ def xy2vector(xy: np.ndarray) -> Vector3d:
             abs_yx, c_x * np.sin(true_term), c_y * np.cos(false_term)
         )
         cart[..., 2] = np.where(
-            abs_yx, 1 - (2 * (X ** 2)) / np.pi, 1 - (2 * (Y ** 2)) / np.pi
+            abs_yx, 1 - (2 * (X**2)) / np.pi, 1 - (2 * (Y**2)) / np.pi
         )
 
         return Vector3d(cart)
@@ -110,7 +110,7 @@ def _eq_c(p: Union[np.ndarray, float, int]) -> Union[np.ndarray, float, int]:
     """Private function used inside LambertProjection.xy2vector to
     increase readability.
     """
-    return (2 * p / np.pi) * np.sqrt(np.pi - p ** 2)
+    return (2 * p / np.pi) * np.sqrt(np.pi - p**2)
 
 
 @nb.jit("float64[:, :](float64[:, :])", nogil=True, cache=True, nopython=True)
diff --git a/kikuchipy/projections/spherical_projection.py b/kikuchipy/projections/spherical_projection.py
index 10c415ae..965c875a 100644
--- a/kikuchipy/projections/spherical_projection.py
+++ b/kikuchipy/projections/spherical_projection.py
@@ -80,7 +80,7 @@ def _get_polar_coordinates(v: Union[Vector3d, np.ndarray]) -> np.ndarray:
     polar[..., 1] = np.where(
         np.arctan2(y, x) < 0, np.arctan2(y, x) + 2 * np.pi, np.arctan2(y, x)
     )  # Azimuth
-    polar[..., 2] = np.sqrt(x ** 2 + y ** 2 + z ** 2)  # r
+    polar[..., 2] = np.sqrt(x**2 + y**2 + z**2)  # r
     polar[..., 0] = np.arccos(z / polar[..., 2])  # Polar
 
     return polar
@@ -104,7 +104,7 @@ def get_polar(v: Union[Vector3d, np.ndarray]) -> np.ndarray:
         x, y, z = v.xyz
     else:
         x, y, z = v[..., 0], v[..., 1], v[..., 2]
-    r = np.sqrt(x ** 2 + y ** 2 + z ** 2)
+    r = np.sqrt(x**2 + y**2 + z**2)
     return np.arccos(z / r)
 
 
@@ -148,4 +148,4 @@ def get_radial(v: Union[Vector3d, np.ndarray]) -> np.ndarray:
         x, y, z = v.xyz
     else:
         x, y, z = v[..., 0], v[..., 1], v[..., 2]
-    return np.sqrt(x ** 2 + y ** 2 + z ** 2)
+    return np.sqrt(x**2 + y**2 + z**2)
diff --git a/kikuchipy/signals/util/_dask.py b/kikuchipy/signals/util/_dask.py
index e9106edf..7eb1a5d6 100644
--- a/kikuchipy/signals/util/_dask.py
+++ b/kikuchipy/signals/util/_dask.py
@@ -198,7 +198,7 @@ def _rechunk_learning_results(
     learning_results_shape = factors.shape + loadings.shape
 
     # Determine maximum number of (strictly necessary) chunks
-    suggested_size = mbytes_chunk * 2 ** 20
+    suggested_size = mbytes_chunk * 2**20
     factors_size = factors.nbytes
     loadings_size = loadings.nbytes
     total_size = factors_size + loadings_size
diff --git a/kikuchipy/signals/util/_map_helper.py b/kikuchipy/signals/util/_map_helper.py
index 5a22d4c4..521edee6 100644
--- a/kikuchipy/signals/util/_map_helper.py
+++ b/kikuchipy/signals/util/_map_helper.py
@@ -176,7 +176,7 @@ def _neighbour_dot_products(
     if output is None:
         return np.nanmean(dot_products)
     else:
-        center_value = (pattern ** 2).sum()
+        center_value = (pattern**2).sum()
         output[pat_idx][flat_window_truthy_indices[center_index]] = center_value
         output[pat_idx][flat_window_truthy_indices[neighbour_idx]] = dot_products
         # Output variable is modified in place, but `_map_helper()`
diff --git a/kikuchipy/simulations/features.py b/kikuchipy/simulations/features.py
index fb68992d..92be8e6e 100644
--- a/kikuchipy/simulations/features.py
+++ b/kikuchipy/simulations/features.py
@@ -416,7 +416,7 @@ def y_gnomonic(self) -> np.ndarray:
     @property
     def r_gnomonic(self) -> np.ndarray:
         """Gnomonic radius for all zone axes per pattern."""
-        return np.sqrt(self.x_gnomonic ** 2 + self.y_gnomonic ** 2)
+        return np.sqrt(self.x_gnomonic**2 + self.y_gnomonic**2)
 
     @property
     def within_gnomonic_radius(self) -> np.ndarray:


Test patch:
diff --git a/kikuchipy/conftest.py b/kikuchipy/conftest.py
index 3ad1e960..ef62b524 100644
--- a/kikuchipy/conftest.py
+++ b/kikuchipy/conftest.py
@@ -341,7 +341,7 @@ def nickel_zone_axes(nickel_kikuchi_band, nickel_rotations, pc1):
     navigation_axes = (1, 2)[:nav_dim]
 
     n_hkl = bands.size
-    n_hkl2 = n_hkl ** 2
+    n_hkl2 = n_hkl**2
     uvw = np.cross(hkl[:, np.newaxis, :], hkl).reshape((n_hkl2, 3))
     not000 = np.count_nonzero(uvw, axis=1) != 0
     uvw = uvw[not000]
diff --git a/kikuchipy/data/tests/test_data.py b/kikuchipy/data/tests/test_data.py
index 1f0003f8..a14e72ce 100644
--- a/kikuchipy/data/tests/test_data.py
+++ b/kikuchipy/data/tests/test_data.py
@@ -16,6 +16,7 @@
 # along with kikuchipy. If not, see <http://www.gnu.org/licenses/>.
 
 import os
+from pathlib import Path
 
 from dask.array import Array
 import numpy as np
@@ -72,15 +73,24 @@ def test_load_nickel_ebsd_master_pattern_small_kwargs(
         assert isinstance(mp_lazy, LazyEBSDMasterPattern)
         assert isinstance(mp_lazy.data, Array)
 
-    def test_load_nickel_ebsd_large_raises(self):
-        """Raises desired error message."""
-        file = data.cache_data_path.joinpath("nickel_ebsd_large/patterns.h5")
+    def test_not_allow_download_raises(self):
+        """Not passing `allow_download` raises expected error."""
+        file = Path(data._fetcher.path, "data/nickel_ebsd_large/patterns.h5")
+
+        # Rename file (dangerous!)
+        new_name = str(file) + ".bak"
+        rename = False
         if file.exists():  # pragma: no cover
-            os.remove(file)
-            os.rmdir(file.parent)
-        with pytest.raises(ValueError, match="The dataset must be"):
+            rename = True
+            os.rename(file, new_name)
+
+        with pytest.raises(ValueError, match="Dataset nickel_ebsd_large/patterns.h5"):
             _ = data.nickel_ebsd_large(allow_download=False)
 
+        # Revert rename
+        if rename:  # pragma: no cover
+            os.rename(new_name, file)
+
     def test_load_nickel_ebsd_large_allow_download(self):
         """Download from external."""
         s = data.nickel_ebsd_large(lazy=True, allow_download=True)
diff --git a/kikuchipy/filters/tests/test_window.py b/kikuchipy/filters/tests/test_window.py
index 2da207ca..e8c8f413 100644
--- a/kikuchipy/filters/tests/test_window.py
+++ b/kikuchipy/filters/tests/test_window.py
@@ -465,7 +465,7 @@ def test_distance_to_origin(self, shape, origin, answer):
     )
     def test_gaussian(self, std, shape, answer):
         w = Window("gaussian", std=std, shape=shape)
-        w = w / (2 * np.pi * std ** 2)
+        w = w / (2 * np.pi * std**2)
         w = w / np.sum(w)
 
         assert np.allclose(w, answer)
diff --git a/kikuchipy/io/plugins/tests/test_h5ebsd.py b/kikuchipy/io/plugins/tests/test_h5ebsd.py
index 2d77600d..a7905519 100644
--- a/kikuchipy/io/plugins/tests/test_h5ebsd.py
+++ b/kikuchipy/io/plugins/tests/test_h5ebsd.py
@@ -288,9 +288,10 @@ def test_load_save_lazy(self, save_path_hdf5):
 
     def test_load_readonly(self):
         s = load(KIKUCHIPY_FILE, lazy=True)
+        keys = ["array-original", "original-array"]
         k = next(
             filter(
-                lambda x: isinstance(x, str) and x.startswith("array-original"),
+                lambda x: isinstance(x, str) and any([x.startswith(j) for j in keys]),
                 s.data.dask.keys(),
             )
         )
diff --git a/kikuchipy/io/plugins/tests/test_nordif.py b/kikuchipy/io/plugins/tests/test_nordif.py
index c13e8a6e..0e0ea14f 100644
--- a/kikuchipy/io/plugins/tests/test_nordif.py
+++ b/kikuchipy/io/plugins/tests/test_nordif.py
@@ -344,9 +344,10 @@ def test_load_to_memory(self):
 
     def test_load_readonly(self):
         s = load(PATTERN_FILE, lazy=True)
+        keys = ["array-original", "original-array"]
         k = next(
             filter(
-                lambda x: isinstance(x, str) and x.startswith("array-original"),
+                lambda x: isinstance(x, str) and any([x.startswith(j) for j in keys]),
                 s.data.dask.keys(),
             )
         )
diff --git a/kikuchipy/projections/tests/test_lambert_projection.py b/kikuchipy/projections/tests/test_lambert_projection.py
index e4ff2332..967fa10d 100644
--- a/kikuchipy/projections/tests/test_lambert_projection.py
+++ b/kikuchipy/projections/tests/test_lambert_projection.py
@@ -114,7 +114,7 @@ def test_gnomonic_to_lambert(self):
     def test_shape_respect(self):
         """Check that LambertProjection.project() respects navigation axes"""
         sx = 60
-        a = np.arange(1, sx ** 2 + 1).reshape((sx, sx))
+        a = np.arange(1, sx**2 + 1).reshape((sx, sx))
         v = Vector3d(np.dstack([a, a, a]))
         assert v.shape == (sx, sx)
         assert v.data.shape == (sx, sx, 3)
diff --git a/kikuchipy/simulations/tests/test_features.py b/kikuchipy/simulations/tests/test_features.py
index 29df2e77..9c00b68d 100644
--- a/kikuchipy/simulations/tests/test_features.py
+++ b/kikuchipy/simulations/tests/test_features.py
@@ -452,7 +452,7 @@ def test_init(
         assert np.allclose(za.y_gnomonic, desired_y_gnomonic)
         assert np.allclose(
             za.r_gnomonic,
-            np.sqrt(desired_x_gnomonic ** 2 + desired_y_gnomonic ** 2),
+            np.sqrt(desired_x_gnomonic**2 + desired_y_gnomonic**2),
         )
 
     @pytest.mark.parametrize(