diff --git a/Stoner/HDF5.py b/Stoner/HDF5.py index d7fa25628..1587d8729 100755 --- a/Stoner/HDF5.py +++ b/Stoner/HDF5.py @@ -37,7 +37,7 @@ def get_hdf_loader(f, default_loader=lambda *args, **kargs: None): Callable function that can produce an object of an appropriate class. """ if "type" not in f.attrs: - StonerLoadError("HDF5 Group does not specify the type attribute used to check we can load it.") + raise StonerLoadError("HDF5 Group does not specify the type attribute used to check we can load it.") typ = bytes2str(f.attrs.get("type", "")) if (typ not in globals() or not isinstance(globals()[typ], type)) and "module" not in f.attrs: raise StonerLoadError( @@ -84,8 +84,8 @@ def __init__(self, filename, mode="r"): if not mode.startswith("w"): with h5py.File(filename, "r"): pass - except (IOError, OSError): - raise StonerLoadError(f"{filename} not at HDF5 File") + except (IOError, OSError) as err: + raise StonerLoadError(f"{filename} not at HDF5 File") from err self.filename = filename def __enter__(self): @@ -108,7 +108,7 @@ def __enter__(self): raise StonerLoadError("Note a resource that can be handled with HDF") return self.handle - def __exit__(self, type, value, traceback): + def __exit__(self, _type, _value, _traceback): """Ensure we close the hdf file no matter what.""" if self.file is not None and self.close: self.file.close() diff --git a/Stoner/Image/core.py b/Stoner/Image/core.py index 87c90209c..0babdc206 100755 --- a/Stoner/Image/core.py +++ b/Stoner/Image/core.py @@ -251,7 +251,6 @@ def __new__(cls, *args, **kargs): We're using __new__ rather than __init__ to imitate a numpy array as close as possible. """ - array_arg_keys = ["dtype", "copy", "order", "subok", "ndmin", "mask"] # kwargs for array setup array_args = {k: kargs.pop(k) for k in array_arg_keys if k in kargs.keys()} user_metadata = kargs.get("metadata", {}) @@ -671,6 +670,10 @@ def __delitem__(self, index): else: super().__delitem__(index) + def save(self, filename=None, **kargs): + """Stub method for a save function.""" + raise NotImplementedError(f"Save is not implemented in {self.__class__}") + @class_modifier( [ diff --git a/Stoner/Image/folders.py b/Stoner/Image/folders.py index 3dd24f757..e23631ed4 100755 --- a/Stoner/Image/folders.py +++ b/Stoner/Image/folders.py @@ -249,7 +249,7 @@ def from_tiff(cls, filename, **kargs): except (TypeError, ValueError, IOError): metadata = [] else: - raise TypeError(f"Cannot load as an ImageFolder due to lack of description tag") + raise TypeError("Cannot load as an ImageFolder due to lack of description tag") imglist = [] for ix, md in enumerate(metadata): img.seek(ix) diff --git a/Stoner/Image/kerr.py b/Stoner/Image/kerr.py index 2df2aacc8..8bc52689a 100755 --- a/Stoner/Image/kerr.py +++ b/Stoner/Image/kerr.py @@ -83,6 +83,10 @@ def tesseractable(self): """Do a test call to tesseract to see if it is there and cache the result.""" return _tesseractable + def save(self, filename=None, **kargs): + """Stub method for a save function.""" + raise NotImplementedError(f"Save is not implemented in {self.__class__}") + @class_modifier(kerrfuncs, adaptor=image_file_adaptor) class KerrImageFile(ImageFile): @@ -99,7 +103,7 @@ def __init__(self, *args, **kargs): self._image = self.image.view(KerrArray) @ImageFile.image.getter - def image(self): + def image(self): # pylint disable=invalid-overridden-method """Access the image data.""" return self._image.view(KerrArray) diff --git a/Stoner/analysis/fitting/mixins.py b/Stoner/analysis/fitting/mixins.py index bf445fbd3..80965a7bc 100755 --- a/Stoner/analysis/fitting/mixins.py +++ b/Stoner/analysis/fitting/mixins.py @@ -172,7 +172,9 @@ def wrapper(beta, x, y, sigma, *args): class _curve_fit_result: - """Represent a result from fitting using :py:func:`scipy.optimize.curve_fit` as a class to make handling easier.""" + """Represent a result from fitting using :py:func:`scipy.optimize.curve_fit` + as a class to make handling easier. + """ def __init__(self, popt, pcov, infodict, mesg, ier): """Store the results of the curve fit full_output fit. @@ -1140,7 +1142,7 @@ def _func(x, *beta): raise TypeError( "".join( [ - f"curve_fit parameter 1 must be either a Model class from", + "curve_fit parameter 1 must be either a Model class from", f" lmfit or scipy.odr, or a callable, not a {type(func)}", ] ) diff --git a/Stoner/compat.py b/Stoner/compat.py index 2a246f788..3e787cd66 100755 --- a/Stoner/compat.py +++ b/Stoner/compat.py @@ -21,14 +21,15 @@ "_dummy", ] -from sys import version_info as __vi__ +from sys import version_info as __vi__, modules from os import walk, makedirs from os.path import join, commonpath import fnmatch -from inspect import signature, getfullargspec from shutil import which from pathlib import PurePath from packaging.version import parse as version_parse +from inspect import signature +import re import numpy as np import scipy as sp @@ -39,6 +40,11 @@ sp_version = version_parse(sp.__version__) mpl_version = version_parse(matplotlib.__version__) +modules["sre_parse"] = re._parser +modules["sre_constants"] = re._constants +modules["sre_compile"] = re._compiler + + try: import hyperspy as hs # Workaround an issue in hs 1.5.2 conda packages diff --git a/Stoner/folders/core.py b/Stoner/folders/core.py index 3e6253cbe..93fd35c6f 100755 --- a/Stoner/folders/core.py +++ b/Stoner/folders/core.py @@ -346,7 +346,8 @@ def depth(self): def each(self): """Return a :py:class:`Stoner.folders.each.item` proxy object. - This is for calling attributes of the member type of the folder.""" + This is for calling attributes of the member type of the folder. + """ return EachItem(self) @property @@ -441,7 +442,8 @@ def lsgrp(self): def metadata(self): """Return a :py:class:`Stoner.folders.metadata.MetadataProxy` object. - This allows for operations on combined metadata.""" + This allows for operations on combined metadata. + """ return MetadataProxy(self) @property @@ -948,15 +950,15 @@ def __repr__(self): cls = type(self).__name__ pth = self.key pattern = getattr(self, "pattern", "") - s = f"{cls}({pth}) with pattern {pattern} has {len(self)} files and {len(self.groups)} groups\n" + string = f"{cls}({pth}) with pattern {pattern} has {len(self)} files and {len(self.groups)} groups\n" if not short: - for r in self.ls: - s += "\t" + r + "\n" + for row in self.ls: + string += "\t" + row + "\n" for g in self.groups: # iterate over groups r = self.groups[g].__repr__() - for l in r.split("\n"): # indent each line by one tab - s += "\t" + l + "\n" - return s.strip() + for line in r.split("\n"): # indent each line by one tab + string += "\t" + line + "\n" + return string.strip() def __reversed__(self): """Create an iterator function that runs backwards through the stored objects.""" @@ -1348,8 +1350,8 @@ def group(self, key): Args: key (string or callable or list): - Either a simple string or callable function or a list. If a string then it is interpreted as an item of - metadata in each file. If a callable function then takes a single argument x which should be an + Either a simple string or callable function or a list. If a string then it is interpreted as an item + of metadata in each file. If a callable function then takes a single argument x which should be an instance of a metadataObject and returns some vale. If key is a list then the grouping is done recursely for each element in key. @@ -1473,7 +1475,7 @@ def make_name(self, value=None): name = f"Untitled-{self._last_name}" return name - def pop(self, name=-1, default=None): # pylint: disable=arguments-differ + def pop(self, name=-1, default=None): # pylint: disable=arguments-differ,arguments-renamed """Return and remove either a subgroup or named object from this folder.""" try: ret = self[name] diff --git a/Stoner/folders/each.py b/Stoner/folders/each.py index a7c158262..e97dc9fdf 100755 --- a/Stoner/folders/each.py +++ b/Stoner/folders/each.py @@ -76,6 +76,7 @@ def __setitem__(self, index, value): """ if len(value) < len(self._folder): value = value + value[-1] * (len(self._folder) - len(value)) + v = "." for v, data in zip(value, self._folder): data.setas[index] = v setas = self._folder._object_attrs.get("setas", self.collapse()) diff --git a/Stoner/plot/core.py b/Stoner/plot/core.py index 6fb23ce6a..8367a6782 100755 --- a/Stoner/plot/core.py +++ b/Stoner/plot/core.py @@ -21,7 +21,7 @@ from matplotlib import figure as mplfig from matplotlib import cm, colors, colormaps -from Stoner.compat import string_types, index_types, int_types, get_func_params +from Stoner.compat import string_types, index_types, int_types from Stoner.tools import AttributeStore, isnone, isanynone, all_type, isiterable, typedList, get_option, fix_signature from .formats import DefaultPlotStyle from .utils import errorfill @@ -230,7 +230,8 @@ def labels(self, value): def showfig(self): """Return either the current figure or self or None. - The return value depends on whether the attribute is True or False or None.""" + The return value depends on whether the attribute is True or False or None. + """ if self._showfig is None or get_option("no_figs"): return None if self._showfig: @@ -324,11 +325,14 @@ def _surface_plotter(self, x_coord, y_coord, z_coord, **kargs): ReturnsL A matplotib Figure - This function attempts to work the same as the 2D surface plotter pcolor, but draws a 3D axes set""" + This function attempts to work the same as the 2D surface plotter pcolor, but draws a 3D axes set + """ if not _3D: raise RuntimeError("3D plotting Not available. Install matplotlib toolkits") - if not isinstance(ax := self.__figure.gca(), Axes3D): + if not isinstance(self.__figure.gca(), Axes3D): ax = plt.axes(projection="3d") + else: + ax = self.__figure.gca() z_coord = np.nan_to_num(z_coord) surf = ax.plot_surface(x_coord, y_coord, z_coord, **kargs) self.fig.colorbar(surf, shrink=0.5, aspect=5, extend="both") @@ -1531,7 +1535,7 @@ def plot_xy(self, xcol=None, ycol=None, fmt=None, xerr=None, yerr=None, **kargs) if ix > 0: # Hooks for multiple subplots if multiple == "panels": loc, lab = plt.yticks() - lab = [l.get_text() for l in lab] + lab = [label.get_text() for label in lab] plt.yticks(loc[:-1], lab[:-1]) return self.showfig