diff --git a/pyproject.toml b/pyproject.toml index 1d741304..e707d81e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -128,7 +128,7 @@ convention = "google" "nexus_utils.py" = ["ALL"] "fits_utils.py" = ["ALL"] "tests/*" = ["PLR2004", "ERA001"] - +"resources/*" = ["INP001"] [tool.mypy] ignore_missing_imports = true diff --git a/src/arpes/__init__.py b/src/arpes/__init__.py index 83ba33e1..aac6c17d 100644 --- a/src/arpes/__init__.py +++ b/src/arpes/__init__.py @@ -5,6 +5,8 @@ import warnings +import igor + # Use both version conventions for people's sanity. VERSION = "4.0.0 beta1" __version__ = VERSION @@ -13,6 +15,12 @@ __all__ = ["check", "__version__"] +def _check_igor_version() -> bool: + if igor.__version__ <= "0.3": + raise ValueError + return True + + def check() -> None: """Verifies certain aspects of the installation and provides guidance broken installations.""" @@ -42,9 +50,7 @@ def verify_igor_pro() -> str | None: try: import igor - if igor.__version__ <= "0.3": - msg = "Not using patched version of igorpy." - raise ValueError(msg) + _check_igor_version() except ValueError: return warning_incompatible diff --git a/src/arpes/analysis/band_analysis.py b/src/arpes/analysis/band_analysis.py index d712ba6e..cbc6113a 100644 --- a/src/arpes/analysis/band_analysis.py +++ b/src/arpes/analysis/band_analysis.py @@ -23,7 +23,7 @@ from arpes.utilities.jupyter import wrap_tqdm if TYPE_CHECKING: - from collections.abc import Generator + from collections.abc import Generator, Hashable import lmfit as lf from _typeshed import Incomplete @@ -433,10 +433,12 @@ def fit_bands( """Fits bands and determines dispersion in some region of a spectrum. Args: - arr(xr.DataArray): + arr(xr.DataArray): ARPES data for fit. band_description: A description of the bands to fit in the region - background - direction + direction: fit direction (along the enegy or momentum), + default is "mdc" (Momentum Distribution Curve). + preferred_k_direction: #TODO: NEED to consider is this is required. + step: if "Initial" is set, .... Returns: Fitted bands. @@ -543,7 +545,11 @@ def fit_bands( return band_results, unpacked_bands, residual # Memo bunt_result is xr.DataArray -def _interpolate_intersecting_fragments(coord, coord_index, points): +def _interpolate_intersecting_fragments( + coord: Incomplete, + coord_index: int, + points: Incomplete, +) -> Incomplete: """Finds all consecutive pairs of points in `points`. [TODO:description] @@ -581,8 +587,8 @@ def _interpolate_intersecting_fragments(coord, coord_index, points): def _iterate_marginals( arr: xr.DataArray, - iterate_directions: list[str] | None = None, -) -> Generator[tuple[xr.DataArray, dict[str, Any], None, None]]: + iterate_directions: list[Hashable] | None = None, +) -> Generator[tuple[xr.DataArray, dict[str, Any]], None, None]: if iterate_directions is None: iterate_directions = [str(dim) for dim in arr.dims] iterate_directions.remove("eV") diff --git a/src/arpes/analysis/mask.py b/src/arpes/analysis/mask.py index 65e77002..75e1d0b2 100644 --- a/src/arpes/analysis/mask.py +++ b/src/arpes/analysis/mask.py @@ -50,8 +50,8 @@ def raw_poly_to_mask(poly: Incomplete) -> dict[str, Incomplete]: def polys_to_mask( mask_dict: dict[str, Incomplete], - coords, - shape, + coords: Incomplete, + shape: Incomplete, radius: float = 0, *, invert: bool = False, @@ -66,9 +66,9 @@ def polys_to_mask( waypoints are given in unitful values rather than index values. Args: - mask_dict - coords - shape + mask_dict: + coords: + shape: radius (float): Additional margin on the path in coordinates of *points*. invert (bool): @@ -139,7 +139,7 @@ def apply_mask( data: xr.DataArray, mask: dict[str, Incomplete], replace: float = np.nan, - radius=None, + radius: Incomplete = None, *, invert: bool = False, ) -> xr.DataArray: diff --git a/src/arpes/corrections/fermi_edge_corrections.py b/src/arpes/corrections/fermi_edge_corrections.py index 9a6253fb..77aabd0a 100644 --- a/src/arpes/corrections/fermi_edge_corrections.py +++ b/src/arpes/corrections/fermi_edge_corrections.py @@ -165,7 +165,7 @@ def build_direct_fermi_edge_correction( others = [d for d in arr.dims if d not in exclude_axes] edge_fit = broadcast_model(GStepBModel, arr.sum(others).sel(eV=energy_range), along).results - def sieve(_, v) -> bool: + def sieve(_: Incomplete, v: Incomplete) -> bool: return v.item().params["center"].stderr < 0.001 # noqa: PLR2004 corrections = edge_fit.G.filter_coord(along, sieve).G.map( diff --git a/src/arpes/deep_learning/interpret.py b/src/arpes/deep_learning/interpret.py index 42882654..8e8e3e3e 100644 --- a/src/arpes/deep_learning/interpret.py +++ b/src/arpes/deep_learning/interpret.py @@ -137,7 +137,7 @@ def items(self) -> list[InterpretationItem]: def top_losses(self, *, ascending: bool = False) -> list[InterpretationItem]: """Orders the items by loss.""" - def key(item): + def key(item: Incomplete): return item.loss if ascending else -item.loss return sorted(self.items, key=key) diff --git a/src/arpes/endstations/__init__.py b/src/arpes/endstations/__init__.py index 84aa56f6..9cbefd71 100644 --- a/src/arpes/endstations/__init__.py +++ b/src/arpes/endstations/__init__.py @@ -939,6 +939,9 @@ def clean_key_name(k: str) -> str: try: resized_data = data_for_resize.reshape(column_shape) except Exception: + logger.exception( + "Found an error in resized_data=data_for_resize.rechape(column_shape)", + ) # sometimes for whatever reason FITS errors and cannot read the data continue diff --git a/src/arpes/load_pxt.py b/src/arpes/load_pxt.py index 3455fc98..fae16518 100644 --- a/src/arpes/load_pxt.py +++ b/src/arpes/load_pxt.py @@ -267,8 +267,8 @@ def read_single_pxt( try: loaded = igor.load(reference_path, initial_byte_order=try_byte_order) break - except Exception as err: - logger.info(f"Exception occurs. {err=}, {type(err)=}") + except Exception: + logger.exception("Exception occurs") else: loaded = igor.load(reference_path, initial_byte_order=byte_order) if raw: diff --git a/src/arpes/plotting/basic.py b/src/arpes/plotting/basic.py index f84fcdcb..ce396388 100644 --- a/src/arpes/plotting/basic.py +++ b/src/arpes/plotting/basic.py @@ -69,6 +69,5 @@ def make_reference_plots(df: pd.DataFrame, *, with_kspace: bool = False) -> None pattern="k_{}_norm_kp.png", ) - except Exception as e: - logger.debug(str(e)) - warnings.warn(f"Cannot make plots for {index}", stacklevel=2) + except Exception: + logger.exception(f"Cannot make plots for {index}") diff --git a/src/arpes/plotting/bz.py b/src/arpes/plotting/bz.py index c5f23d03..36ae7c1b 100644 --- a/src/arpes/plotting/bz.py +++ b/src/arpes/plotting/bz.py @@ -3,7 +3,6 @@ from __future__ import annotations import itertools -import warnings from logging import DEBUG, INFO, Formatter, StreamHandler, getLogger from typing import TYPE_CHECKING, TypeAlias @@ -363,12 +362,9 @@ def bz3d_plot( try: from ase.dft.bz import bz_vertices # dynamic because we do not require ase except ImportError: - warnings.warn( + logger.exception( "You will need to install ASE (Atomic Simulation Environment) to use this feature.", - stacklevel=2, ) - msg = "You will need to install ASE before using Brillouin Zone plotting" - raise ImportError(msg) class Arrow3D(FancyArrowPatch): def __init__( @@ -382,7 +378,7 @@ def __init__( FancyArrowPatch.__init__(self, (0, 0), (0, 0), *args, **kwargs) self._verts3d = xs, ys, zs - def draw(self, renderer) -> None: + def draw(self, renderer: Incomplete) -> None: xs3d, ys3d, zs3d = self._verts3d xs, ys, zs = proj3d.proj_transform(xs3d, ys3d, zs3d, renderer.M) self.set_positions((xs[0], ys[0]), (xs[1], ys[1])) @@ -537,7 +533,7 @@ def annotate_special_paths( cell: NDArray[np.float_] | Sequence[Sequence[float]] | None = None, offset: dict[str, Sequence[float]] | None = None, special_points: dict[str, NDArray[np.float_]] | None = None, - labels=None, + labels: Incomplete = None, **kwargs: Incomplete, ) -> None: """Annotates user indicated paths in k-space by plotting lines (or points) over the BZ.""" @@ -641,16 +637,16 @@ def bz2d_segments( segments_x = [] segments_y = [] - for points, _normal in twocell_to_bz1(cell)[0]: - points = apply_transformations(points, transformations) - x, y, z = np.concatenate([points, points[:1]]).T + for points, _normal in twocell_to_bz1(np.array(cell))[0]: + transformed_points = apply_transformations(points, transformations) + x, y, z = np.concatenate([transformed_points, transformed_points[:1]]).T segments_x.append(x) segments_y.append(y) return segments_x, segments_y -def twocell_to_bz1(cell: NDArray[np.float_]): +def twocell_to_bz1(cell: NDArray[np.float_]) -> Incomplete: from ase.dft.bz import bz_vertices # 2d in x-y plane diff --git a/src/arpes/plotting/bz_tool/RangeOrSingleValueWidget.py b/src/arpes/plotting/bz_tool/RangeOrSingleValueWidget.py index e2d12b74..81b7e411 100644 --- a/src/arpes/plotting/bz_tool/RangeOrSingleValueWidget.py +++ b/src/arpes/plotting/bz_tool/RangeOrSingleValueWidget.py @@ -6,6 +6,7 @@ from __future__ import annotations from functools import partial +from logging import DEBUG, INFO, Formatter, StreamHandler, getLogger from typing import TYPE_CHECKING from PySide6 import QtWidgets @@ -16,6 +17,19 @@ from . import BZTool +LOGLEVELS = (DEBUG, INFO) +LOGLEVEL = LOGLEVELS[1] +logger = getLogger(__name__) +fmt = "%(asctime)s %(levelname)s %(name)s :%(message)s" +formatter = Formatter(fmt) +handler = StreamHandler() +handler.setLevel(LOGLEVEL) +logger.setLevel(LOGLEVEL) +handler.setFormatter(formatter) +logger.addHandler(handler) +logger.propagate = False + + __all__ = ["RangeOrSingleValueWidget"] @@ -61,10 +75,10 @@ def __init__( self.recompute() - def mode_changed(self, event, source) -> None: + def mode_changed(self, event: Incomplete, source: Incomplete) -> None: """Unused, currently.""" - def value_changed(self, event, source) -> None: + def value_changed(self, event: Incomplete, source: Incomplete) -> None: """Responds to changes in the internal value.""" if self._prevent_change_events: return diff --git a/src/arpes/plotting/dynamic_tool.py b/src/arpes/plotting/dynamic_tool.py index 17aada75..d2796e5d 100644 --- a/src/arpes/plotting/dynamic_tool.py +++ b/src/arpes/plotting/dynamic_tool.py @@ -87,8 +87,8 @@ def update_data(self) -> None: try: mapped_data = self._function(self.data, **self.current_arguments) self.views["f(xy)"].setImage(mapped_data.fillna(0)) - except Exception as err: - logger.debug(f"Exception occurs. {err=}, {type(err)=}") + except Exception: + logger.exception("Exception occurs") def add_controls(self) -> None: specification = self.calculate_control_specification() diff --git a/src/arpes/plotting/utils.py b/src/arpes/plotting/utils.py index 94409cf1..129c8d26 100644 --- a/src/arpes/plotting/utils.py +++ b/src/arpes/plotting/utils.py @@ -1102,8 +1102,8 @@ def remove_colorbars(fig: Figure | None = None) -> None: ax.remove() else: remove_colorbars(plt.gcf()) - except Exception as err: - logger.debug(f"Exception occurs: {err=}, {type(err)=}") + except Exception: + logger.exception("Exception occurs") def generic_colorbarmap_for_data( @@ -1242,7 +1242,7 @@ def savefig( desired_path: str | Path, dpi: int = 400, data: list[XrTypes] | tuple[XrTypes, ...] | set[XrTypes] | None = None, - save_data=None, + save_data: Incomplete | None = None, *, paper: bool = False, **kwargs: Incomplete, @@ -1374,8 +1374,8 @@ def path_for_plot(desired_path: str | Path) -> Path: if exc.errno != errno.EEXIST: raise return filename - except Exception as e: - warnings.warn(f"Misconfigured FIGURE_PATH saving locally: {e}", stacklevel=2) + except Exception: + logger.exception("Misconfigured FIGURE_PATH saving locally") return Path.cwd() / desired_path diff --git a/src/arpes/utilities/bz.py b/src/arpes/utilities/bz.py index f6bbc6d3..df53442c 100644 --- a/src/arpes/utilities/bz.py +++ b/src/arpes/utilities/bz.py @@ -400,7 +400,7 @@ def build_2dbz_poly( return raw_poly_to_mask(points_2d) -def bz_symmetry(flat_symmetry_points) -> Literal["rect", "square", "hex"] | None: +def bz_symmetry(flat_symmetry_points: dict | None) -> Literal["rect", "square", "hex"] | None: """Determines symmetry from a list of the symmetry points. Args: @@ -701,7 +701,7 @@ def reduced_bz_selection(data: DataType) -> DataType: return data -def bz_cutter(symmetry_points, *, reduced: bool = True): +def bz_cutter(symmetry_points: Incomplete, *, reduced: bool = True): """Cuts data so that it areas outside the Brillouin zone are masked away. Args: @@ -711,7 +711,7 @@ def bz_cutter(symmetry_points, *, reduced: bool = True): TODO: UNFINISHED, Test """ - def build_bz_mask(data) -> None: + def build_bz_mask(data: Incomplete) -> None: """[TODO:summary]. Args: @@ -721,7 +721,7 @@ def build_bz_mask(data) -> None: [TODO:description] """ - def cutter(data, cut_value: float = np.nan): + def cutter(data: Incomplete, cut_value: float = np.nan) -> Incomplete: """[TODO:summary]. Args: diff --git a/src/arpes/utilities/ui.py b/src/arpes/utilities/ui.py index d41d638f..d0994a55 100644 --- a/src/arpes/utilities/ui.py +++ b/src/arpes/utilities/ui.py @@ -465,7 +465,7 @@ def _wrap_text(str_or_widget: str | QLabel) -> QLabel: return label(str_or_widget) if isinstance(str_or_widget, str) else str_or_widget -def _unwrap_subject(subject_or_widget): +def _unwrap_subject(subject_or_widget: Incomplete) -> Incomplete: try: return subject_or_widget.subject except AttributeError: @@ -495,7 +495,7 @@ def submit(gate: str, keys: list[str], ui: dict[str, QWidget]) -> rx.Observable: ) -def _try_unwrap_value(v): +def _try_unwrap_value(v: Incomplete) -> Incomplete: try: return v.value except AttributeError: @@ -590,16 +590,16 @@ def bind_dataclass(dataclass_instance: Incomplete, prefix: str, ui: dict[str, QW ) inverse_mapping = {v: k for k, v in forward_mapping.items()} - def extract_field(v): + def extract_field(v: Incomplete) -> Incomplete: try: return v.value except AttributeError: return v - def translate_to_field(x): + def translate_to_field(x: Incomplete) -> Incomplete: return forward_mapping[x] - def translate_from_field(x): + def translate_from_field(x: Incomplete) -> Incomplete: return inverse_mapping[extract_field(x)] current_value = translate_from_field(getattr(dataclass_instance, field_name)) @@ -609,8 +609,8 @@ def translate_from_field(x): w.subject.on_next(current_value) # close over the translation function - def build_setter(translate, name): - def setter(value) -> None: + def build_setter(translate: Incomplete, name: Incomplete) -> Incomplete: + def setter(value: Incomplete) -> None: try: value = translate(value) except ValueError: diff --git a/src/arpes/utilities/xarray.py b/src/arpes/utilities/xarray.py index a7cf0264..35a7d33d 100644 --- a/src/arpes/utilities/xarray.py +++ b/src/arpes/utilities/xarray.py @@ -2,6 +2,7 @@ from __future__ import annotations +from logging import DEBUG, INFO, Formatter, StreamHandler, getLogger from typing import TYPE_CHECKING, Any import xarray as xr @@ -25,6 +26,19 @@ ) +LOGLEVELS = (DEBUG, INFO) +LOGLEVEL = LOGLEVELS[1] +logger = getLogger(__name__) +fmt = "%(asctime)s %(levelname)s %(name)s :%(message)s" +formatter = Formatter(fmt) +handler = StreamHandler() +handler.setLevel(LOGLEVEL) +logger.setLevel(LOGLEVEL) +handler.setFormatter(formatter) +logger.addHandler(handler) +logger.propagate = False + + def unwrap_xarray_item(item: xr.DataArray) -> xr.DataArray | float: """Unwraps something that might or might not be an xarray like with .item() attribute. diff --git a/src/arpes/widgets.py b/src/arpes/widgets.py index 7b9e0cde..868d7653 100644 --- a/src/arpes/widgets.py +++ b/src/arpes/widgets.py @@ -74,7 +74,7 @@ from matplotlib.colors import Colormap from numpy.typing import NDArray - from ._typing import CURRENTCONTEXT, MOMENTUM, DataType, XrTypes + from ._typing import MOMENTUM, CurrentContext, DataType, XrTypes IncompleteMPL: TypeAlias = Incomplete @@ -161,8 +161,8 @@ def onselect(self, verts: NDArray[np.float_]) -> None: if self._on_select is not None: self._on_select(self.ind) - except Exception as err: - logger.debug(f"Exception occurs: {err=}, {type(err)=}") + except Exception: + logger.exception("Exception occurs") def disconnect(self) -> None: self.lasso.disconnect_events() @@ -280,7 +280,7 @@ def handle_select(self, event_click: MouseEvent, event_release: MouseEvent) -> N self._inner_on_select(region) - def attach_selector(self, on_select) -> None: + def attach_selector(self, on_select: Incomplete) -> None: # data should already have been set """[TODO:summary]. @@ -404,7 +404,7 @@ def mask(self): # noqa: ANN202 return self._mask @mask.setter - def mask(self, new_mask) -> None: + def mask(self, new_mask: Incomplete) -> None: """[TODO:summary]. Args: @@ -510,7 +510,7 @@ def compute_parameters() -> dict: ] return dict(itertools.chain(*[list(d.items()) for d in renamed])) - def on_add_new_peak(selection) -> None: + def on_add_new_peak(selection: Incomplete) -> None: """[TODO:summary]. Args: @@ -587,7 +587,7 @@ def pca_explorer( initial_values: list[float] | None = None, *, transpose_mask: bool = False, -) -> CURRENTCONTEXT: +) -> CurrentContext: """A tool providing PCA (Principal component analysis) decomposition exploration of a dataset. Args: @@ -609,7 +609,7 @@ def pca_explorer( pca_dims.remove(component_dim) other_dims = [d for d in data.dims if d not in pca_dims] - context: CURRENTCONTEXT = { + context: CurrentContext = { "selected_components": initial_values, "selected_indices": [], "sum_data": None, @@ -727,15 +727,15 @@ def clamp(x: int, low: int, high: int) -> int: assert val_x != val_y set_axes(val_x, val_y) - except Exception as err: - logger.debug(f"Exception occurs: {err=}, {type(err)=}") + except Exception: + logger.exception("Exception occurs") context["axis_button"] = Button(ax_widget_1, "Change Decomp Axes") context["axis_button"].on_clicked(on_change_axes) context["axis_X_input"] = TextBox(ax_widget_2, "Axis X:", initial=str(initial_values[0])) context["axis_Y_input"] = TextBox(ax_widget_3, "Axis Y:", initial=str(initial_values[1])) - def on_select_summed(region) -> None: + def on_select_summed(region: Incomplete) -> None: """[TODO:summary]. Args: @@ -759,7 +759,7 @@ def kspace_tool( resolution: dict | None = None, coords: dict[str, NDArray[np.float_] | xr.DataArray] | None = None, **kwargs: Incomplete, -) -> CURRENTCONTEXT: +) -> CurrentContext: """A utility for assigning coordinate offsets using a live momentum conversion. Args: @@ -788,7 +788,7 @@ def kspace_tool( data_array.S.transpose_to_front("eV") data_array = data_array.copy(deep=True) - ctx: CURRENTCONTEXT = {"original_data": original_data, "data": data_array, "widgets": []} + ctx: CurrentContext = {"original_data": original_data, "data": data_array, "widgets": []} arpes.config.CONFIG["CURRENT_CONTEXT"] = ctx gs = gridspec.GridSpec(4, 3) ax_initial = plt.subplot(gs[0:2, 0:2]) @@ -929,7 +929,7 @@ def pick_rectangles( Returns: [TODO:description] """ - ctx: CURRENTCONTEXT = {"points": [], "rect_next": False} + ctx: CurrentContext = {"points": [], "rect_next": False} arpes.config.CONFIG["CURRENT_CONTEXT"] = ctx rects = [] @@ -1034,7 +1034,7 @@ def pick_points( """ using_image_data = isinstance(data_or_str, str | pathlib.Path) - ctx: CURRENTCONTEXT = {"points": []} + ctx: CurrentContext = {"points": []} arpes.config.CONFIG["CURRENT_CONTEXT"] = ctx fig = plt.figure()