From b72885ec8ff979efc92ed373757411a0cc562150 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Robert?= Date: Sun, 5 Sep 2021 20:04:32 +0200 Subject: [PATCH] ENH: inline yt.funcs.is_sequence --- doc/source/reference/api/api.rst | 1 - .../construction_data_containers.py | 13 ++++++------ yt/data_objects/data_containers.py | 5 +++-- .../index_subobjects/grid_patch.py | 4 ++-- yt/data_objects/profiles.py | 12 ++++++----- .../data_selection_objects.py | 13 ++++++------ yt/data_objects/selection_objects/slices.py | 9 ++++---- yt/data_objects/static_output.py | 7 ++++--- yt/data_objects/time_series.py | 5 +++-- yt/fields/local_fields.py | 5 +++-- yt/fields/vector_operations.py | 6 ++++-- yt/frontends/stream/definitions.py | 4 ++-- yt/funcs.py | 20 ++++++++++++------ yt/geometry/coordinates/coordinate_handler.py | 13 ++++++------ yt/testing.py | 8 +++---- yt/utilities/amr_kdtree/amr_kdtree.py | 5 +++-- yt/utilities/minimal_representation.py | 5 +++-- .../parallel_analysis_interface.py | 4 ++-- yt/visualization/base_plot_types.py | 13 ++++-------- yt/visualization/fits_image.py | 13 ++++++------ yt/visualization/line_plot.py | 7 ++++--- yt/visualization/plot_container.py | 11 +++++++--- yt/visualization/plot_modifications.py | 9 ++++---- yt/visualization/plot_window.py | 17 ++++++++------- yt/visualization/profile_plotter.py | 5 +++-- yt/visualization/volume_rendering/camera.py | 13 ++++++------ .../volume_rendering/off_axis_projection.py | 8 ++++--- .../volume_rendering/old_camera.py | 21 ++++++++++--------- .../volume_rendering/render_source.py | 5 +++-- 29 files changed, 146 insertions(+), 115 deletions(-) diff --git a/doc/source/reference/api/api.rst b/doc/source/reference/api/api.rst index e0f4a692ab8..05d0c8fd3f8 100644 --- a/doc/source/reference/api/api.rst +++ b/doc/source/reference/api/api.rst @@ -729,7 +729,6 @@ Function List ~yt.funcs.humanize_time ~yt.funcs.insert_ipython ~yt.funcs.is_root - ~yt.funcs.is_sequence ~yt.funcs.iter_fields ~yt.funcs.just_one ~yt.funcs.only_on_root diff --git a/yt/data_objects/construction_data_containers.py b/yt/data_objects/construction_data_containers.py index ca5f8f53895..ade940b8036 100644 --- a/yt/data_objects/construction_data_containers.py +++ b/yt/data_objects/construction_data_containers.py @@ -3,6 +3,7 @@ import os import warnings import zipfile +from collections.abc import Sized from functools import wraps from re import finditer from tempfile import NamedTemporaryFile, TemporaryFile @@ -20,7 +21,7 @@ ) from yt.fields.field_exceptions import NeedsGridType, NeedsOriginalGrid from yt.frontends.sph.data_structures import ParticleDataset -from yt.funcs import get_memory_usage, is_sequence, iter_fields, mylog, only_on_root +from yt.funcs import get_memory_usage, iter_fields, mylog, only_on_root from yt.geometry import particle_deposit as particle_deposit from yt.geometry.coordinates.cartesian_coordinates import all_data from yt.loaders import load_uniform_grid @@ -752,7 +753,7 @@ def set_field_parameter(self, name, val): self._data_source.set_field_parameter(name, val) def _sanitize_dims(self, dims): - if not is_sequence(dims): + if not isinstance(dims, Sized): dims = [dims] * len(self.ds.domain_left_edge) if len(dims) != len(self.ds.domain_left_edge): raise RuntimeError( @@ -761,7 +762,7 @@ def _sanitize_dims(self, dims): return np.array(dims, dtype="int32") def _sanitize_edge(self, edge): - if not is_sequence(edge): + if not isinstance(edge, Sized): edge = [edge] * len(self.ds.domain_left_edge) if len(edge) != len(self.ds.domain_left_edge): raise RuntimeError( @@ -990,7 +991,7 @@ def _fill_fields(self, fields): "int64" ) * self.ds.relative_refinement(0, self.level) refine_by = self.ds.refine_by - if not is_sequence(self.ds.refine_by): + if not isinstance(self.ds.refine_by, Sized): refine_by = [refine_by, refine_by, refine_by] refine_by = np.array(refine_by, dtype="i8") for chunk in parallel_objects(self._data_source.chunks(fields, "io")): @@ -1376,7 +1377,7 @@ def _fill_fields(self, fields): # NOTE: This usage of "refine_by" is actually *okay*, because it's # being used with respect to iref, which is *already* scaled! refine_by = self.ds.refine_by - if not is_sequence(self.ds.refine_by): + if not isinstance(self.ds.refine_by, Sized): refine_by = [refine_by, refine_by, refine_by] refine_by = np.array(refine_by, dtype="i8") @@ -2800,7 +2801,7 @@ def _setup_data_source(self): def _sanitize_edge(self, edge, default): if edge is None: return default.copy() - if not is_sequence(edge): + if not isinstance(edge, edge): edge = [edge] * len(self.ds.domain_left_edge) if len(edge) != len(self.ds.domain_left_edge): raise RuntimeError( diff --git a/yt/data_objects/data_containers.py b/yt/data_objects/data_containers.py index 4dfe2e5b912..a7c3fa339ff 100644 --- a/yt/data_objects/data_containers.py +++ b/yt/data_objects/data_containers.py @@ -1,5 +1,6 @@ import weakref from collections import defaultdict +from collections.abc import Sized from contextlib import contextmanager import numpy as np @@ -8,7 +9,7 @@ from yt.data_objects.profiles import create_profile from yt.fields.field_exceptions import NeedsGridType from yt.frontends.ytdata.utilities import save_as_dataset -from yt.funcs import get_output_filename, is_sequence, iter_fields, mylog +from yt.funcs import get_output_filename, iter_fields, mylog from yt.units.yt_array import YTArray, YTQuantity, uconcatenate from yt.utilities.amr_kdtree.api import AMRKDTree from yt.utilities.exceptions import ( @@ -1390,7 +1391,7 @@ def _tupleize_field(self, field): except AttributeError: pass - if is_sequence(field) and not isinstance(field, str): + if isinstance(field, Sized) and not isinstance(field, str): try: ftype, fname = field if not all(isinstance(_, str) for _ in field): diff --git a/yt/data_objects/index_subobjects/grid_patch.py b/yt/data_objects/index_subobjects/grid_patch.py index 8e7ed4ae3e0..efbea1b0270 100644 --- a/yt/data_objects/index_subobjects/grid_patch.py +++ b/yt/data_objects/index_subobjects/grid_patch.py @@ -1,5 +1,6 @@ import warnings import weakref +from collections.abc import Sized from typing import List, Tuple import numpy as np @@ -9,7 +10,6 @@ from yt.data_objects.selection_objects.data_selection_objects import ( YTSelectionContainer, ) -from yt.funcs import is_sequence from yt.geometry.selection_routines import convert_mask_to_indices from yt.units.yt_array import YTArray from yt.utilities.exceptions import ( @@ -171,7 +171,7 @@ def _prepare_grid(self): # This can be expensive so we allow people to disable this behavior # via a config option if RECONSTRUCT_INDEX: - if is_sequence(self.Parent) and len(self.Parent) > 0: + if isinstance(self.Parent, Sized) and len(self.Parent) > 0: p = self.Parent[0] else: p = self.Parent diff --git a/yt/data_objects/profiles.py b/yt/data_objects/profiles.py index ee1f9de757d..3ce720cb49c 100644 --- a/yt/data_objects/profiles.py +++ b/yt/data_objects/profiles.py @@ -1,10 +1,12 @@ +from collections.abc import Sized + import numpy as np from more_itertools import collapse from yt.data_objects.field_data import YTFieldData from yt.fields.derived_field import DerivedField from yt.frontends.ytdata.utilities import save_as_dataset -from yt.funcs import get_output_filename, is_sequence, iter_fields, mylog +from yt.funcs import get_output_filename, iter_fields, mylog from yt.units.unit_object import Unit from yt.units.yt_array import YTQuantity, array_like_field from yt.utilities.exceptions import ( @@ -1335,9 +1337,9 @@ def create_profile( wf = data_source.ds._get_field_info(weight_field) if not wf.sampling_type == "particle": weight_field = None - if not is_sequence(n_bins): + if not isinstance(n_bins, Sized): n_bins = [n_bins] * len(bin_fields) - if not is_sequence(accumulation): + if not isinstance(accumulation, Sized): accumulation = [accumulation] * len(bin_fields) if logs is None: logs = {} @@ -1405,10 +1407,10 @@ def create_profile( fe = data_source.ds.arr(field_ex, bf_units) fe.convert_to_units(bf_units) field_ex = [fe[0].v, fe[1].v] - if is_sequence(field_ex[0]): + if isinstance(field_ex[0], Sized): field_ex[0] = data_source.ds.quan(field_ex[0][0], field_ex[0][1]) field_ex[0] = field_ex[0].in_units(bf_units) - if is_sequence(field_ex[1]): + if isinstance(field_ex[1], Sized): field_ex[1] = data_source.ds.quan(field_ex[1][0], field_ex[1][1]) field_ex[1] = field_ex[1].in_units(bf_units) ex.append(field_ex) diff --git a/yt/data_objects/selection_objects/data_selection_objects.py b/yt/data_objects/selection_objects/data_selection_objects.py index 4b7fa7571f8..aab70c92a49 100644 --- a/yt/data_objects/selection_objects/data_selection_objects.py +++ b/yt/data_objects/selection_objects/data_selection_objects.py @@ -1,6 +1,7 @@ import itertools import uuid from collections import defaultdict +from collections.abc import Iterable, Sized from contextlib import contextmanager import numpy as np @@ -12,7 +13,7 @@ from yt.data_objects.derived_quantities import DerivedQuantityCollection from yt.data_objects.field_data import YTFieldData from yt.fields.field_exceptions import NeedsGridType -from yt.funcs import fix_axis, is_sequence, iter_fields, validate_width_tuple +from yt.funcs import fix_axis, iter_fields, validate_width_tuple from yt.geometry.selection_routines import compose_selector from yt.units import YTArray, dimensions as ytdims from yt.utilities.exceptions import ( @@ -594,7 +595,7 @@ def to_frb(self, width, resolution, center=None, height=None, periodic=False): ) validate_width_tuple(width) - if is_sequence(resolution): + if isinstance(resolution, Iterable): resolution = max(resolution) frb = CylindricalFixedResolutionBuffer(self, width, resolution) return frb @@ -603,9 +604,9 @@ def to_frb(self, width, resolution, center=None, height=None, periodic=False): center = self.center if center is None: center = (self.ds.domain_right_edge + self.ds.domain_left_edge) / 2.0 - elif is_sequence(center) and not isinstance(center, YTArray): + elif isinstance(center, Sized) and not isinstance(center, YTArray): center = self.ds.arr(center, "code_length") - if is_sequence(width): + if isinstance(width, Sized): w, u = width if isinstance(w, tuple) and isinstance(u, tuple): height = u @@ -615,12 +616,12 @@ def to_frb(self, width, resolution, center=None, height=None, periodic=False): width = self.ds.quan(width, "code_length") if height is None: height = width - elif is_sequence(height): + elif isinstance(height, Sized): h, u = height height = self.ds.quan(h, units=u) elif not isinstance(height, YTArray): height = self.ds.quan(height, "code_length") - if not is_sequence(resolution): + if not isinstance(resolution, Sized): resolution = (resolution, resolution) from yt.visualization.fixed_resolution import FixedResolutionBuffer diff --git a/yt/data_objects/selection_objects/slices.py b/yt/data_objects/selection_objects/slices.py index bc0d4e3d99b..0d62ef1ee40 100644 --- a/yt/data_objects/selection_objects/slices.py +++ b/yt/data_objects/selection_objects/slices.py @@ -1,3 +1,5 @@ +from collections.abc import Sized + import numpy as np from yt.data_objects.selection_objects.data_selection_objects import ( @@ -6,7 +8,6 @@ ) from yt.data_objects.static_output import Dataset from yt.funcs import ( - is_sequence, iter_fields, validate_3d_array, validate_axis, @@ -353,15 +354,15 @@ def to_frb(self, width, resolution, height=None, periodic=False): >>> frb = cutting.to_frb((1.0, "pc"), 1024) >>> write_image(np.log10(frb[("gas", "density")]), "density_1pc.png") """ - if is_sequence(width): + if isinstance(width, Sized): validate_width_tuple(width) width = self.ds.quan(width[0], width[1]) if height is None: height = width - elif is_sequence(height): + elif isinstance(height, Sized): validate_width_tuple(height) height = self.ds.quan(height[0], height[1]) - if not is_sequence(resolution): + if not isinstance(resolution, Sized): resolution = (resolution, resolution) from yt.visualization.fixed_resolution import FixedResolutionBuffer diff --git a/yt/data_objects/static_output.py b/yt/data_objects/static_output.py index 3b1c255f207..f0de63f8128 100644 --- a/yt/data_objects/static_output.py +++ b/yt/data_objects/static_output.py @@ -6,6 +6,7 @@ import time import weakref from collections import defaultdict +from collections.abc import Sized from stat import ST_CTIME import numpy as np @@ -19,7 +20,7 @@ from yt.fields.derived_field import ValidateSpatial from yt.fields.field_type_container import FieldTypeContainer from yt.fields.fluid_fields import setup_gradient_fields -from yt.funcs import is_sequence, iter_fields, mylog, set_intersection, setdefaultattr +from yt.funcs import iter_fields, mylog, set_intersection, setdefaultattr from yt.geometry.coordinates.api import ( CartesianCoordinateHandler, CoordinateHandler, @@ -276,7 +277,7 @@ def periodicity(self, val): removal="4.1.0", ) err_msg = f"Expected a 3-element boolean tuple, received `{val}`." - if not is_sequence(val): + if not isinstance(val, Sized): raise TypeError(err_msg) if len(val) != 3: raise ValueError(err_msg) @@ -1941,7 +1942,7 @@ def __init__( def validate_index_order(index_order): if index_order is None: index_order = (6, 2) - elif not is_sequence(index_order): + elif not isinstance(index_order, Sized): index_order = (int(index_order), 1) else: if len(index_order) != 2: diff --git a/yt/data_objects/time_series.py b/yt/data_objects/time_series.py index 747bf28a7dd..51f3e3cc83f 100644 --- a/yt/data_objects/time_series.py +++ b/yt/data_objects/time_series.py @@ -3,6 +3,7 @@ import inspect import os import weakref +from collections.abc import Sequence from functools import wraps import numpy as np @@ -12,7 +13,7 @@ from yt.config import ytcfg from yt.data_objects.analyzer_objects import AnalysisTask, create_quantity_proxy from yt.data_objects.particle_trajectories import ParticleTrajectories -from yt.funcs import is_sequence, mylog +from yt.funcs import mylog from yt.units.yt_array import YTArray, YTQuantity from yt.utilities.exceptions import YTException from yt.utilities.object_registries import ( @@ -169,7 +170,7 @@ def __init__( ): # This is needed to properly set _pre_outputs for Simulation subclasses. self._mixed_dataset_types = mixed_dataset_types - if is_sequence(outputs) and not isinstance(outputs, str): + if isinstance(outputs, Sequence) and not isinstance(outputs, str): self._pre_outputs = outputs[:] self.tasks = AnalysisTaskProxy(self) self.params = TimeSeriesParametersContainer(self) diff --git a/yt/fields/local_fields.py b/yt/fields/local_fields.py index eb59b96f807..7292276548c 100644 --- a/yt/fields/local_fields.py +++ b/yt/fields/local_fields.py @@ -1,4 +1,5 @@ -from yt.funcs import is_sequence +from collections.abc import Sized + from yt.utilities.logger import ytLogger as mylog from .field_info_container import FieldInfoContainer @@ -12,7 +13,7 @@ def add_field(self, name, function, sampling_type, **kwargs): sampling_type, kwargs.get("particle_type") ) - if isinstance(name, str) or not is_sequence(name): + if isinstance(name, str) or not isinstance(name, Sized): if sampling_type == "particle": ftype = "all" else: diff --git a/yt/fields/vector_operations.py b/yt/fields/vector_operations.py index f9887b39ccb..1d035756514 100644 --- a/yt/fields/vector_operations.py +++ b/yt/fields/vector_operations.py @@ -1,6 +1,8 @@ +from collections.abc import Sized + import numpy as np -from yt.funcs import is_sequence, just_one +from yt.funcs import just_one from yt.geometry.geometry_handler import is_curvilinear from yt.utilities.lib.misc_utilities import obtain_relative_velocity_vector from yt.utilities.math_utils import ( @@ -105,7 +107,7 @@ def _los_field(field, data): else: fns = field_comps ax = data.get_field_parameter("axis") - if is_sequence(ax): + if isinstance(ax, Sized): # Make sure this is a unit vector ax /= np.sqrt(np.dot(ax, ax)) ret = data[fns[0]] * ax[0] + data[fns[1]] * ax[1] + data[fns[2]] * ax[2] diff --git a/yt/frontends/stream/definitions.py b/yt/frontends/stream/definitions.py index d3fad42b826..c76d4906b71 100644 --- a/yt/frontends/stream/definitions.py +++ b/yt/frontends/stream/definitions.py @@ -1,8 +1,8 @@ from collections import defaultdict +from collections.abc import Sized import numpy as np -from yt.funcs import is_sequence from yt.geometry.grid_container import GridTree, MatchPointsToGrids from yt.utilities.exceptions import ( YTInconsistentGridFieldShape, @@ -161,7 +161,7 @@ def process_data(data, grid_dims=None): raise RuntimeError("The data dict appears to be invalid.\n" + str(e)) # val is a list of data to be turned into an array - elif is_sequence(val): + elif isinstance(val, Sized): field_units[field] = "" new_data[field] = np.asarray(val) diff --git a/yt/funcs.py b/yt/funcs.py index dbd89d40578..3fddc27a24d 100644 --- a/yt/funcs.py +++ b/yt/funcs.py @@ -793,7 +793,7 @@ def ensure_dir(path): def validate_width_tuple(width): - if not is_sequence(width) or len(width) != 2: + if not isinstance(width, Sized) or len(width) != 2: raise YTInvalidWidthError(f"width ({width}) is not a two element tuple") is_numeric = isinstance(width[0], numeric_type) length_has_units = isinstance(width[0], YTArray) @@ -1096,7 +1096,7 @@ def parse_h5_attr(f, attr): def obj_length(v): - if is_sequence(v): + if isinstance(v, Sized): return len(v) else: # If something isn't iterable, we return 0 @@ -1125,7 +1125,7 @@ def array_like_field(data, x, field): def validate_3d_array(obj): - if not is_sequence(obj) or len(obj) != 3: + if not isinstance(obj, Sized) or len(obj) != 3: raise TypeError( "Expected an array of size (3,), received '%s' of " "length %s" % (str(type(obj)).split("'")[1], len(obj)) @@ -1177,7 +1177,9 @@ def validate_float(obj): ) else: return - if is_sequence(obj) and (len(obj) != 1 or not isinstance(obj[0], numeric_type)): + if isinstance(obj, Sized) and ( + len(obj) != 1 or not isinstance(obj[0], numeric_type) + ): raise TypeError( "Expected a numeric value (or size-1 array), " "received '%s' of length %s" % (str(type(obj)).split("'")[1], len(obj)) @@ -1185,7 +1187,11 @@ def validate_float(obj): def validate_sequence(obj): - if obj is not None and not is_sequence(obj): + # NOTE: there is a lot of confusion between the name of the function, + # the actual check perfomed, and the error message. Sized object are a subset of sequences, + # and sequences are a subset of iterables. I'll leave the implementation alone but it should probably + # be discouraged and avoided internally + if not isinstance(obj, Sized): raise TypeError( "Expected an iterable object," " received '%s'" % str(type(obj)).split("'")[1] @@ -1225,7 +1231,9 @@ def validate_center(center): "'m', 'max', 'min'] or the prefix to be " "'max_'/'min_', received '%s'." % center ) - elif not isinstance(center, (numeric_type, YTQuantity)) and not is_sequence(center): + elif not isinstance(center, (numeric_type, YTQuantity)) and not isinstance( + center, Sized + ): raise TypeError( "Expected 'center' to be a numeric object of type " "list/tuple/np.ndarray/YTArray/YTQuantity, " diff --git a/yt/geometry/coordinates/coordinate_handler.py b/yt/geometry/coordinates/coordinate_handler.py index f5e9e522eb9..f517e406bae 100644 --- a/yt/geometry/coordinates/coordinate_handler.py +++ b/yt/geometry/coordinates/coordinate_handler.py @@ -1,10 +1,11 @@ import abc import weakref +from collections.abc import Sized from numbers import Number import numpy as np -from yt.funcs import fix_unitary, is_sequence, validate_width_tuple +from yt.funcs import fix_unitary, validate_width_tuple from yt.units.yt_array import YTArray, YTQuantity from yt.utilities.exceptions import YTCoordinateNotImplemented, YTInvalidWidthError @@ -209,7 +210,7 @@ def period(self): pass def sanitize_depth(self, depth): - if is_sequence(depth): + if isinstance(depth, Sized): validate_width_tuple(depth) depth = (self.ds.quan(depth[0], fix_unitary(depth[1])),) elif isinstance(depth, Number): @@ -227,7 +228,7 @@ def sanitize_width(self, axis, width, depth): # initialize the index if it is not already initialized self.ds.index # Default to code units - if not is_sequence(axis): + if not isinstance(axis, Sized): xax = self.x_axis[axis] yax = self.y_axis[axis] w = self.ds.domain_width[np.array([xax, yax])] @@ -237,7 +238,7 @@ def sanitize_width(self, axis, width, depth): mi = np.argmin(self.ds.domain_width) w = self.ds.domain_width[np.array((mi, mi))] width = (w[0], w[1]) - elif is_sequence(width): + elif isinstance(width, Sized): width = validate_sequence_width(width, self.ds) elif isinstance(width, YTQuantity): width = (width, width) @@ -267,7 +268,7 @@ def sanitize_center(self, center, axis): raise RuntimeError(f'center keyword "{center}" not recognized') elif isinstance(center, YTArray): return self.ds.arr(center), self.convert_to_cartesian(center) - elif is_sequence(center): + elif isinstance(center, Sized): if isinstance(center[0], str) and isinstance(center[1], str): if center[0].lower() == "min": v, center = self.ds.find_min(center[1]) @@ -276,7 +277,7 @@ def sanitize_center(self, center, axis): else: raise RuntimeError(f'center keyword "{center}" not recognized') center = self.ds.arr(center, "code_length") - elif is_sequence(center[0]) and isinstance(center[1], str): + elif isinstance(center[0], Sized) and isinstance(center[1], str): center = self.ds.arr(center[0], center[1]) else: center = self.ds.arr(center, "code_length") diff --git a/yt/testing.py b/yt/testing.py index 09832f9eca0..a9f012a9514 100644 --- a/yt/testing.py +++ b/yt/testing.py @@ -7,6 +7,7 @@ import shutil import tempfile import unittest +from collections.abc import Sized import matplotlib import numpy as np @@ -15,7 +16,6 @@ from unyt.exceptions import UnitOperationError from yt.config import ytcfg -from yt.funcs import is_sequence from yt.loaders import load from yt.units.yt_array import YTArray, YTQuantity @@ -226,11 +226,11 @@ def fake_random_ds( from yt.loaders import load_uniform_grid prng = RandomState(0x4D3D3D3) - if not is_sequence(ndims): + if not isinstance(ndims, Sized): ndims = [ndims, ndims, ndims] else: assert len(ndims) == 3 - if not is_sequence(negative): + if not isinstance(negative, Sized): if fields: negative = [negative for f in fields] else: @@ -371,7 +371,7 @@ def fake_particle_ds( from yt.loaders import load_particles prng = RandomState(0x4D3D3D3) - if negative is not None and not is_sequence(negative): + if negative is not None and not isinstance(negative, Sized): negative = [negative for f in fields] fields, units, negative = _check_field_unit_args_helper( diff --git a/yt/utilities/amr_kdtree/amr_kdtree.py b/yt/utilities/amr_kdtree/amr_kdtree.py index d5b7f3c601a..e8c50a608ec 100644 --- a/yt/utilities/amr_kdtree/amr_kdtree.py +++ b/yt/utilities/amr_kdtree/amr_kdtree.py @@ -1,8 +1,9 @@ import operator +from collections.abc import Sized import numpy as np -from yt.funcs import is_sequence, mylog +from yt.funcs import mylog from yt.geometry.grid_geometry_handler import GridIndex from yt.utilities.amr_kdtree.amr_kdtools import ( receive_and_reduce, @@ -214,7 +215,7 @@ def set_fields(self, fields, log_fields, no_ghost, force=False): or self.fields != new_fields or force ) - if not is_sequence(log_fields): + if not isinstance(log_fields, Sized): log_fields = [log_fields] new_log_fields = list(log_fields) self.tree.trunk.set_dirty(regenerate_data) diff --git a/yt/utilities/minimal_representation.py b/yt/utilities/minimal_representation.py index 58b8f8211ef..83f43b82d51 100644 --- a/yt/utilities/minimal_representation.py +++ b/yt/utilities/minimal_representation.py @@ -1,11 +1,12 @@ import abc import json import os +from collections.abc import Sized from uuid import uuid4 import numpy as np -from yt.funcs import compare_dicts, is_sequence +from yt.funcs import compare_dicts from yt.units.yt_array import YTArray, YTQuantity from yt.utilities.on_demand_imports import _h5py as h5py @@ -47,7 +48,7 @@ def _deserialize_from_h5(g, ds): if item == "chunks": continue if "units" in g[item].attrs: - if is_sequence(g[item]): + if isinstance(g[item], Sized): result[item] = ds.arr(g[item][:], g[item].attrs["units"]) else: result[item] = ds.quan(g[item][()], g[item].attrs["units"]) diff --git a/yt/utilities/parallel_tools/parallel_analysis_interface.py b/yt/utilities/parallel_tools/parallel_analysis_interface.py index b64ba701f70..0bca10a0829 100644 --- a/yt/utilities/parallel_tools/parallel_analysis_interface.py +++ b/yt/utilities/parallel_tools/parallel_analysis_interface.py @@ -3,6 +3,7 @@ import os import sys import traceback +from collections.abc import Sized from functools import wraps from io import StringIO @@ -12,7 +13,6 @@ import yt.utilities.logger from yt.config import ytcfg from yt.data_objects.image_array import ImageArray -from yt.funcs import is_sequence from yt.units.unit_registry import UnitRegistry from yt.units.yt_array import YTArray from yt.utilities.exceptions import YTNoDataInObjectError @@ -408,7 +408,7 @@ def from_sizes(cls, sizes): pool = cls() rank = pool.comm.rank for i, size in enumerate(always_iterable(sizes)): - if is_sequence(size): + if isinstance(size, Sized): size, name = size else: name = "workgroup_%02i" % i diff --git a/yt/visualization/base_plot_types.py b/yt/visualization/base_plot_types.py index 164aa7b24bb..d36c5bb2330 100644 --- a/yt/visualization/base_plot_types.py +++ b/yt/visualization/base_plot_types.py @@ -1,16 +1,11 @@ +from collections.abc import Sized from io import BytesIO import matplotlib import numpy as np from packaging.version import parse as parse_version -from yt.funcs import ( - get_brewer_cmap, - get_interactivity, - is_sequence, - matplotlib_style_context, - mylog, -) +from yt.funcs import get_brewer_cmap, get_interactivity, matplotlib_style_context, mylog from ._commons import get_canvas, validate_image_name @@ -72,7 +67,7 @@ def __init__(self, fsize, axrect, figure, axes): self._plot_valid = True if figure is None: - if not is_sequence(fsize): + if not isinstance(fsize, Sized): fsize = (fsize, fsize) self.figure = matplotlib.figure.Figure(figsize=fsize, frameon=True) else: @@ -327,7 +322,7 @@ def _init_image(self, data, cbnorm, cblinthresh, cmap, extent, aspect): def _get_best_layout(self): # Ensure the figure size along the long axis is always equal to _figure_size - if is_sequence(self._figure_size): + if isinstance(self._figure_size, Sized): x_fig_size = self._figure_size[0] y_fig_size = self._figure_size[1] else: diff --git a/yt/visualization/fits_image.py b/yt/visualization/fits_image.py index bc65793586c..36642547d7c 100644 --- a/yt/visualization/fits_image.py +++ b/yt/visualization/fits_image.py @@ -1,5 +1,6 @@ import re import sys +from collections.abc import Sized from numbers import Number as numeric_type import numpy as np @@ -8,7 +9,7 @@ from yt.data_objects.construction_data_containers import YTCoveringGrid from yt.data_objects.image_array import ImageArray from yt.fields.derived_field import DerivedField -from yt.funcs import fix_axis, is_sequence, iter_fields, mylog +from yt.funcs import fix_axis, iter_fields, mylog from yt.units import dimensions from yt.units.unit_object import Unit from yt.units.yt_array import YTArray, YTQuantity @@ -321,7 +322,7 @@ def __init__( else: # If img_data is just an array we use the width and img_ctr # parameters to determine the cell widths - if not is_sequence(width): + if not isinstance(width, Sized): width = [width] * self.dimensionality if isinstance(width[0], YTQuantity): cdelt = [ @@ -862,7 +863,7 @@ def construct_image(ds, axis, data_source, center, image_res, width, length_unit else: width = ds.coordinates.sanitize_width(axis, width, None) unit = str(width[0].units) - if is_sequence(image_res): + if isinstance(image_res, Sized): nx, ny = image_res else: nx, ny = image_res, image_res @@ -881,12 +882,12 @@ def construct_image(ds, axis, data_source, center, image_res, width, length_unit cunit = [length_unit] * 2 ctype = ["LINEAR"] * 2 cdelt = [dx.in_units(length_unit), dy.in_units(length_unit)] - if is_sequence(axis): + if isinstance(axis, Sized): crval = center.in_units(length_unit) else: crval = [center[idx].in_units(length_unit) for idx in axis_wcs[axis]] if hasattr(data_source, "to_frb"): - if is_sequence(axis): + if isinstance(axis, Sized): frb = data_source.to_frb(width[0], (nx, ny), height=width[1]) else: frb = data_source.to_frb(width[0], (nx, ny), center=center, height=width[1]) @@ -1373,7 +1374,7 @@ def __init__( buf = {} width = ds.coordinates.sanitize_width(normal, width, depth) wd = tuple(el.in_units("code_length").v for el in width) - if not is_sequence(image_res): + if not isinstance(image_res, Sized): image_res = (image_res, image_res) res = (image_res[0], image_res[1]) if data_source is None: diff --git a/yt/visualization/line_plot.py b/yt/visualization/line_plot.py index 34838a39c9a..0b0be1f6691 100644 --- a/yt/visualization/line_plot.py +++ b/yt/visualization/line_plot.py @@ -1,8 +1,9 @@ from collections import defaultdict +from collections.abc import Sized import numpy as np -from yt.funcs import is_sequence, mylog +from yt.funcs import mylog from yt.units.unit_object import Unit from yt.units.yt_array import YTArray from yt.visualization.base_plot_types import PlotMPL @@ -260,7 +261,7 @@ def _get_plot_instance(self, field): y_axis_size = 0.7 * fontscale right_buff_size = 0.2 * fontscale - if is_sequence(self.figure_size): + if isinstance(self.figure_size, Sized): figure_size = self.figure_size else: figure_size = (self.figure_size, self.figure_size) @@ -436,7 +437,7 @@ def annotate_title(self, field, title): def _validate_point(point, ds, start=False): - if not is_sequence(point): + if not isinstance(point, Sized): raise RuntimeError("Input point must be array-like") if not isinstance(point, YTArray): point = ds.arr(point, "code_length", dtype=np.float64) diff --git a/yt/visualization/plot_container.py b/yt/visualization/plot_container.py index 062b1ed57ba..0bb2d441434 100644 --- a/yt/visualization/plot_container.py +++ b/yt/visualization/plot_container.py @@ -3,6 +3,7 @@ import os import textwrap from collections import defaultdict +from collections.abc import Sized from functools import wraps import matplotlib @@ -13,7 +14,7 @@ from yt._maintenance.deprecation import issue_deprecation_warning from yt.config import ytcfg from yt.data_objects.time_series import DatasetSeries -from yt.funcs import dictWithFactory, ensure_dir, is_sequence, iter_fields, mylog +from yt.funcs import dictWithFactory, ensure_dir, iter_fields, mylog from yt.units import YTQuantity from yt.units.unit_object import Unit from yt.utilities.definitions import formatted_length_unit_names @@ -253,7 +254,11 @@ def __init__(self, data_source, figure_size, fontsize): self.data_source = data_source self.ds = data_source.ds self.ts = self._initialize_dataset(self.ds) - if is_sequence(figure_size): + if isinstance(figure_size, Sized): + if len(figure_size) != 2: + raise TypeError( + f"Expected a float or a lenght 2 value for figure_size, got {figure_size}" + ) self.figure_size = float(figure_size[0]), float(figure_size[1]) else: self.figure_size = float(figure_size) @@ -399,7 +404,7 @@ def _setup_plots(self): def _initialize_dataset(self, ts): if not isinstance(ts, DatasetSeries): - if not is_sequence(ts): + if not isinstance(ts, Sized): ts = [ts] ts = DatasetSeries(ts) return ts diff --git a/yt/visualization/plot_modifications.py b/yt/visualization/plot_modifications.py index 9fc3e140e78..846e097cd53 100644 --- a/yt/visualization/plot_modifications.py +++ b/yt/visualization/plot_modifications.py @@ -1,5 +1,6 @@ import re import warnings +from collections.abc import Sized from functools import wraps from numbers import Number @@ -11,7 +12,7 @@ from yt.data_objects.selection_objects.cut_region import YTCutRegion from yt.data_objects.static_output import Dataset from yt.frontends.ytdata.data_structures import YTClumpContainer -from yt.funcs import is_sequence, mylog, validate_width_tuple +from yt.funcs import mylog, validate_width_tuple from yt.geometry.geometry_handler import is_curvilinear from yt.geometry.unstructured_mesh_handler import UnstructuredIndex from yt.units import dimensions @@ -1389,7 +1390,7 @@ def __call__(self, plot): "the length keyword in 'axis' units instead. " "Setting code_size overrides length value." ) - if is_sequence(self.code_size): + if isinstance(self.code_size, Sized): self.code_size = plot.data.ds.quan(self.code_size[0], self.code_size[1]) self.code_size = np.float64(self.code_size.in_units(plot.xlim[0].units)) self.code_size = self.code_size * self._pixel_scale(plot)[0] @@ -1601,7 +1602,7 @@ def __init__( def __call__(self, plot): from matplotlib.patches import Circle - if is_sequence(self.radius): + if isinstance(self.radius, Sized): self.radius = plot.data.ds.quan(self.radius[0], self.radius[1]) self.radius = np.float64(self.radius.in_units(plot.xlim[0].units)) if isinstance(self.radius, YTQuantity): @@ -2076,7 +2077,7 @@ def __init__( def __call__(self, plot): data = plot.data - if is_sequence(self.width): + if isinstance(self.width, Sized): validate_width_tuple(self.width) self.width = plot.data.ds.quan(self.width[0], self.width[1]) elif isinstance(self.width, YTQuantity): diff --git a/yt/visualization/plot_window.py b/yt/visualization/plot_window.py index 14c4cff0571..c544951d68e 100644 --- a/yt/visualization/plot_window.py +++ b/yt/visualization/plot_window.py @@ -1,4 +1,5 @@ from collections import defaultdict +from collections.abc import Sized from functools import wraps from numbers import Number @@ -14,7 +15,7 @@ from yt.config import ytcfg from yt.data_objects.image_array import ImageArray from yt.frontends.ytdata.data_structures import YTSpatialPlotDataset -from yt.funcs import fix_axis, fix_unitary, is_sequence, iter_fields, mylog, obj_length +from yt.funcs import fix_axis, fix_unitary, iter_fields, mylog, obj_length from yt.units.unit_object import Unit from yt.units.unit_registry import UnitParseError from yt.units.yt_array import YTArray, YTQuantity @@ -110,10 +111,10 @@ def get_axes_unit(width, ds): """ if ds.no_cgs_equiv_length: return ("code_length",) * 2 - if is_sequence(width): + if isinstance(width, Sized): if isinstance(width[1], str): axes_unit = (width[1], width[1]) - elif is_sequence(width[1]): + elif isinstance(width[1], Sized): axes_unit = (width[0][1], width[1][1]) elif isinstance(width[0], YTArray): axes_unit = (str(width[0].units), str(width[1].units)) @@ -735,7 +736,7 @@ def set_center(self, new_center, unit="code_length"): ) if new_center is None: self.center = None - elif is_sequence(new_center): + elif isinstance(new_center, Sized): if len(new_center) != 2: raise error for el in new_center: @@ -769,7 +770,7 @@ def set_buff_size(self, size): The number of data elements in the buffer on the x and y axes. If a scalar is provided, then the buffer is assumed to be square. """ - if is_sequence(size): + if isinstance(size, Sized): self.buff_size = size else: self.buff_size = (size, size) @@ -2255,7 +2256,7 @@ def __init__( if fontscale < 1.0: fontscale = np.sqrt(fontscale) - if is_sequence(figure_size): + if isinstance(figure_size, Sized): fsize = figure_size[0] else: fsize = figure_size @@ -2454,7 +2455,7 @@ def SlicePlot(ds, normal=None, fields=None, axis=None, *args, **kwargs): # use an AxisAlignedSlicePlot where possible, e.g.: # maybe someone passed normal=[0,0,0.2] when they should have just used "z" - if is_sequence(normal) and not isinstance(normal, str): + if isinstance(normal, Sized) and not isinstance(normal, str): if np.count_nonzero(normal) == 1: normal = ("x", "y", "z")[np.nonzero(normal)[0][0]] else: @@ -2462,7 +2463,7 @@ def SlicePlot(ds, normal=None, fields=None, axis=None, *args, **kwargs): np.divide(normal, np.dot(normal, normal), normal) # by now the normal should be properly set to get either a On/Off Axis plot - if is_sequence(normal) and not isinstance(normal, str): + if isinstance(normal, Sized) and not isinstance(normal, str): # OffAxisSlicePlot has hardcoded origin; remove it if in kwargs if "origin" in kwargs: mylog.warning( diff --git a/yt/visualization/profile_plotter.py b/yt/visualization/profile_plotter.py index eddfd68fd19..05807445802 100644 --- a/yt/visualization/profile_plotter.py +++ b/yt/visualization/profile_plotter.py @@ -2,6 +2,7 @@ import builtins import os from collections import OrderedDict +from collections.abc import Sized from functools import wraps import matplotlib @@ -12,7 +13,7 @@ from yt.data_objects.profiles import create_profile, sanitize_field_tuple_keys from yt.data_objects.static_output import Dataset from yt.frontends.ytdata.data_structures import YTProfileDataset -from yt.funcs import is_sequence, iter_fields, matplotlib_style_context +from yt.funcs import iter_fields, matplotlib_style_context from yt.utilities.exceptions import YTNotInsideNotebook from yt.utilities.logger import ytLogger as mylog @@ -1654,7 +1655,7 @@ def __init__( if fontscale < 1.0: fontscale = np.sqrt(fontscale) - if is_sequence(figure_size): + if isinstance(figure_size, Sized): self._cb_size = 0.0375 * figure_size[0] else: self._cb_size = 0.0375 * figure_size diff --git a/yt/visualization/volume_rendering/camera.py b/yt/visualization/volume_rendering/camera.py index 2c208ce627f..6feeb172cd7 100644 --- a/yt/visualization/volume_rendering/camera.py +++ b/yt/visualization/volume_rendering/camera.py @@ -1,9 +1,10 @@ import weakref +from collections.abc import Sequence, Sized from numbers import Number as numeric_type import numpy as np -from yt.funcs import ensure_numpy_array, is_sequence +from yt.funcs import ensure_numpy_array from yt.units.yt_array import YTArray, YTQuantity from yt.utilities.math_utils import get_rotation_matrix from yt.utilities.orientation import Orientation @@ -13,7 +14,7 @@ def _sanitize_camera_property_units(value, scene): - if is_sequence(value): + if isinstance(value, Sequence): if len(value) == 1: return _sanitize_camera_property_units(value[0], scene) elif isinstance(value, YTArray) and len(value) == 3: @@ -25,7 +26,7 @@ def _sanitize_camera_property_units(value, scene): ): return scene.arr([scene.arr(value[0], value[1]).in_units("unitary")] * 3) if len(value) == 3: - if all([is_sequence(v) for v in value]): + if all([isinstance(v, Sized) for v in value]): if all( [ isinstance(v[0], numeric_type) and isinstance(v[1], str) @@ -258,7 +259,7 @@ def fget(self): return self._resolution def fset(self, value): - if is_sequence(value): + if isinstance(value, Sized): if len(value) != 2: raise RuntimeError else: @@ -333,11 +334,11 @@ def set_defaults_from_data_source(self, data_source): width = np.sqrt((xma - xmi) ** 2 + (yma - ymi) ** 2 + (zma - zmi) ** 2) focus = data_source.get_field_parameter("center") - if is_sequence(width) and len(width) > 1 and isinstance(width[1], str): + if isinstance(width, Sized) and len(width) > 1 and isinstance(width[1], str): width = data_source.ds.quan(width[0], units=width[1]) # Now convert back to code length for subsequent manipulation width = width.in_units("code_length") # .value - if not is_sequence(width): + if not isinstance(width, Sized): width = data_source.ds.arr([width, width, width], units="code_length") # left/right, top/bottom, front/back if not isinstance(width, YTArray): diff --git a/yt/visualization/volume_rendering/off_axis_projection.py b/yt/visualization/volume_rendering/off_axis_projection.py index b371556cee6..ecce7d6fc05 100644 --- a/yt/visualization/volume_rendering/off_axis_projection.py +++ b/yt/visualization/volume_rendering/off_axis_projection.py @@ -1,7 +1,9 @@ +from collections.abc import Sized + import numpy as np from yt.data_objects.api import ImageArray -from yt.funcs import is_sequence, mylog +from yt.funcs import mylog from yt.units.unit_object import Unit from yt.utilities.lib.partitioned_grid import PartitionedGrid from yt.utilities.lib.pixelization_routines import ( @@ -339,10 +341,10 @@ def temp_weightfield(a, b): vol.set_transfer_function(ptf) camera = sc.add_camera(data_source) camera.set_width(width) - if not is_sequence(resolution): + if not isinstance(resolution, Sized): resolution = [resolution] * 2 camera.resolution = resolution - if not is_sequence(width): + if not isinstance(width, Sized): width = data_source.ds.arr([width] * 3) normal = np.array(normal_vector) normal = normal / np.linalg.norm(normal) diff --git a/yt/visualization/volume_rendering/old_camera.py b/yt/visualization/volume_rendering/old_camera.py index e2501c0ed46..3de50a2761b 100644 --- a/yt/visualization/volume_rendering/old_camera.py +++ b/yt/visualization/volume_rendering/old_camera.py @@ -1,11 +1,12 @@ import builtins +from collections.abc import Sized from copy import deepcopy import numpy as np from yt.config import ytcfg from yt.data_objects.api import ImageArray -from yt.funcs import ensure_numpy_array, get_num_threads, get_pbar, is_sequence, mylog +from yt.funcs import ensure_numpy_array, get_num_threads, get_pbar, mylog from yt.geometry.geometry_handler import cached_property from yt.units.yt_array import YTArray from yt.utilities.amr_kdtree.api import AMRKDTree @@ -169,16 +170,16 @@ def __init__( ParallelAnalysisInterface.__init__(self) if ds is not None: self.ds = ds - if not is_sequence(resolution): + if not isinstance(resolution, Sized): resolution = (resolution, resolution) self.resolution = resolution self.sub_samples = sub_samples self.rotation_vector = north_vector - if is_sequence(width) and len(width) > 1 and isinstance(width[1], str): + if isinstance(width, Sized) and len(width) > 1 and isinstance(width[1], str): width = self.ds.quan(width[0], units=width[1]) # Now convert back to code length for subsequent manipulation width = width.in_units("code_length").value - if not is_sequence(width): + if not isinstance(width, width): width = (width, width, width) # left/right, top/bottom, front/back if not isinstance(width, YTArray): width = self.ds.arr(width, units="code_length") @@ -629,7 +630,7 @@ def switch_view( """ if width is None: width = self.width - if not is_sequence(width): + if not isinstance(width, Sized): width = (width, width, width) # left/right, tom/bottom, front/back self.width = width if center is not None: @@ -1010,7 +1011,7 @@ def move_to( final = self.ds.arr(final, units="code_length") if exponential: if final_width is not None: - if not is_sequence(final_width): + if not isinstance(final_width, Sized): final_width = [final_width, final_width, final_width] if not isinstance(final_width, YTArray): final_width = self.ds.arr(final_width, units="code_length") @@ -1025,7 +1026,7 @@ def move_to( dx = position_diff ** (1.0 / n_steps) else: if final_width is not None: - if not is_sequence(final_width): + if not isinstance(final_width, Sized): final_width = [final_width, final_width, final_width] if not isinstance(final_width, YTArray): final_width = self.ds.arr(final_width, units="code_length") @@ -1699,7 +1700,7 @@ def __init__( self.center = np.array(center, dtype="float64") self.radius = radius self.fov = fov - if is_sequence(resolution): + if isinstance(resolution, Sized): raise RuntimeError("Resolution must be a single int") self.resolution = resolution if transfer_function is None: @@ -1814,13 +1815,13 @@ def __init__( self.procs_per_wg = procs_per_wg if ds is not None: self.ds = ds - if not is_sequence(resolution): + if not isinstance(resolution, Sized): resolution = (int(resolution / nimx), int(resolution / nimy)) self.resolution = resolution self.nimx = nimx self.nimy = nimy self.sub_samples = sub_samples - if not is_sequence(width): + if not isinstance(width, Sized): width = (width, width, width) # front/back, left/right, top/bottom self.width = np.array([width[0], width[1], width[2]]) self.center = center diff --git a/yt/visualization/volume_rendering/render_source.py b/yt/visualization/volume_rendering/render_source.py index 8a569699a79..c91794c6af5 100644 --- a/yt/visualization/volume_rendering/render_source.py +++ b/yt/visualization/volume_rendering/render_source.py @@ -1,11 +1,12 @@ import abc +from collections.abc import Sized from functools import wraps import numpy as np from yt.config import ytcfg from yt.data_objects.image_array import ImageArray -from yt.funcs import ensure_numpy_array, is_sequence, mylog +from yt.funcs import ensure_numpy_array, mylog from yt.geometry.grid_geometry_handler import GridIndex from yt.geometry.oct_geometry_handler import OctreeIndex from yt.utilities.amr_kdtree.api import AMRKDTree @@ -993,7 +994,7 @@ def __init__(self, positions, colors=None, color_stride=1, radii=None): if colors is not None: assert colors.ndim == 2 and colors.shape[1] == 4 assert colors.shape[0] == positions.shape[0] - if not is_sequence(radii): + if not isinstance(radii, Sized): if radii is not None: # broadcast the value radii = radii * np.ones(positions.shape[0], dtype="int64") else: # default radii to 0 pixels (i.e. point is 1 pixel wide)