diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d507680f64..08cf87f28b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -18,7 +18,7 @@ ci: repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.5.0 + rev: v4.6.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer @@ -36,7 +36,7 @@ repos: additional_dependencies: [black==24.3.0] - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.4.0 + rev: v0.4.3 hooks: - id: ruff-format types_or: [ python, pyi, jupyter ] @@ -50,7 +50,7 @@ repos: - id: rst-backticks - repo: https://github.com/MarcoGorelli/cython-lint - rev: v0.16.0 + rev: v0.16.2 hooks: - id: cython-lint args: [--no-pycodestyle] diff --git a/yt/_maintenance/backports.py b/yt/_maintenance/backports.py index f3ee778243..78577af3e4 100644 --- a/yt/_maintenance/backports.py +++ b/yt/_maintenance/backports.py @@ -52,7 +52,7 @@ def __new__(cls, *values): if len(values) == 3: # check that errors argument is a string if not isinstance(values[2], str): - raise TypeError("errors must be a string, not %r" % (values[2])) + raise TypeError("errors must be a string, not %r" % (values[2])) # noqa: UP031 value = str(*values) member = str.__new__(cls, value) member._value_ = value diff --git a/yt/data_objects/analyzer_objects.py b/yt/data_objects/analyzer_objects.py index b6824b6249..97610f8273 100644 --- a/yt/data_objects/analyzer_objects.py +++ b/yt/data_objects/analyzer_objects.py @@ -67,7 +67,7 @@ class QuantityProxy(AnalysisTask): def __repr__(self): # Stolen from YTDataContainer.__repr__ s = f"{self.__class__.__name__}: " - s += ", ".join(["%s" % list(self.args)]) + s += ", ".join([str(list(self.args))]) s += ", ".join(f"{k}={v}" for k, v in self.kwargs.items()) return s diff --git a/yt/data_objects/construction_data_containers.py b/yt/data_objects/construction_data_containers.py index adcf01532c..03c10f92c1 100644 --- a/yt/data_objects/construction_data_containers.py +++ b/yt/data_objects/construction_data_containers.py @@ -880,10 +880,11 @@ def get_data(self, fields=None): fill, gen, part, alias = self._split_fields(fields_to_get) except NeedsGridType as e: if self._num_ghost_zones == 0: + num_ghost_zones = self._num_ghost_zones raise RuntimeError( "Attempting to access a field that needs ghost zones, but " - "num_ghost_zones = %s. You should create the covering grid " - "with nonzero num_ghost_zones." % self._num_ghost_zones + f"{num_ghost_zones = }. You should create the covering grid " + "with nonzero num_ghost_zones." ) from e else: raise diff --git a/yt/data_objects/level_sets/clump_info_items.py b/yt/data_objects/level_sets/clump_info_items.py index 798aecc30b..d0c727f310 100644 --- a/yt/data_objects/level_sets/clump_info_items.py +++ b/yt/data_objects/level_sets/clump_info_items.py @@ -109,7 +109,7 @@ def _distance_to_main_clump(clump, units="pc"): distance = np.sqrt(((master_com - my_com) ** 2).sum()) distance.convert_to_units("pc") return ( - "Distance from master center of mass: %%.6e %s." % units, + f"Distance from master center of mass: %.6e {units}.", distance.in_units(units), ) diff --git a/yt/data_objects/static_output.py b/yt/data_objects/static_output.py index 5c546a1849..57f6507dcd 100644 --- a/yt/data_objects/static_output.py +++ b/yt/data_objects/static_output.py @@ -1395,7 +1395,7 @@ def set_units(self): new_unit, my_u.base_value / (1 + self.current_redshift), dimensions.length, - "\\rm{%s}/(1+z)" % my_unit, + f"\\rm{{{my_unit}}}/(1+z)", prefixable=True, ) self.unit_registry.modify("a", 1 / (1 + self.current_redshift)) diff --git a/yt/fields/derived_field.py b/yt/fields/derived_field.py index 42b6ff6636..7e90277b2d 100644 --- a/yt/fields/derived_field.py +++ b/yt/fields/derived_field.py @@ -303,7 +303,7 @@ def get_label(self, projected=False): name = self.display_name # Start with the field name - data_label = r"$\rm{%s}" % name + data_label = rf"$\rm{{{name}}}" # Grab the correct units if projected: diff --git a/yt/fields/particle_fields.py b/yt/fields/particle_fields.py index c52bd2a0b4..7db9bfabea 100644 --- a/yt/fields/particle_fields.py +++ b/yt/fields/particle_fields.py @@ -110,7 +110,7 @@ def particle_count(field, data): function=particle_count, validators=[ValidateSpatial()], units="", - display_name=r"\mathrm{%s Count}" % ptype_dn, + display_name=rf"\mathrm{{{ptype_dn} Count}}", ) def particle_mass(field, data): @@ -125,7 +125,7 @@ def particle_mass(field, data): sampling_type="cell", function=particle_mass, validators=[ValidateSpatial()], - display_name=r"\mathrm{%s Mass}" % ptype_dn, + display_name=rf"\mathrm{{{ptype_dn} Mass}}", units=unit_system["mass"], ) @@ -144,7 +144,7 @@ def particle_density(field, data): sampling_type="cell", function=particle_density, validators=[ValidateSpatial()], - display_name=r"\mathrm{%s Density}" % ptype_dn, + display_name=rf"\mathrm{{{ptype_dn} Density}}", units=unit_system["density"], ) @@ -160,7 +160,7 @@ def particle_cic(field, data): sampling_type="cell", function=particle_cic, validators=[ValidateSpatial()], - display_name=r"\mathrm{%s CIC Density}" % ptype_dn, + display_name=rf"\mathrm{{{ptype_dn} CIC Density}}", units=unit_system["density"], ) diff --git a/yt/fields/vector_operations.py b/yt/fields/vector_operations.py index 0c3cbe0a2f..99e0544539 100644 --- a/yt/fields/vector_operations.py +++ b/yt/fields/vector_operations.py @@ -133,7 +133,7 @@ def _los_field(field, data): function=_los_field, units=field_units, validators=validators, - display_name=r"\mathrm{Line of Sight %s}" % basename.capitalize(), + display_name=rf"\mathrm{{Line of Sight {basename.capitalize()}}}", ) diff --git a/yt/frontends/adaptahop/data_structures.py b/yt/frontends/adaptahop/data_structures.py index d36bcff4a2..e8cb853568 100644 --- a/yt/frontends/adaptahop/data_structures.py +++ b/yt/frontends/adaptahop/data_structures.py @@ -107,7 +107,7 @@ def _guess_headers_from_file(self, filename) -> None: pass if not ok: - raise OSError("Could not read headers from file %s" % filename) + raise OSError(f"Could not read headers from file {filename}") istart = fpu.tell() fpu.seek(0, 2) @@ -130,7 +130,7 @@ def _guess_headers_from_file(self, filename) -> None: continue if not ok: - raise OSError("Could not guess fields from file %s" % filename) + raise OSError(f"Could not guess fields from file {filename}") self._header_attributes = header_attributes self._halo_attributes = attributes diff --git a/yt/frontends/boxlib/fields.py b/yt/frontends/boxlib/fields.py index 5e32ad83e7..8ce65068a7 100644 --- a/yt/frontends/boxlib/fields.py +++ b/yt/frontends/boxlib/fields.py @@ -488,7 +488,7 @@ def setup_fluid_fields(self): sampling_type="cell", function=func, units=unit_system["density"], - display_name=r"\rho %s" % tex_label, + display_name=rf"\rho {tex_label}", ) # Most of the time our species will be of the form @@ -507,7 +507,7 @@ def setup_fluid_fields(self): elif field.startswith("omegadot("): nice_name, tex_label = _nice_species_name(field) - display_name = r"\dot{\omega}\left[%s\right]" % tex_label + display_name = rf"\dot{{\omega}}\left[{tex_label}\right]" # Overwrite field to use nicer tex_label'ed display_name self.add_output_field( ("boxlib", field), diff --git a/yt/frontends/enzo/simulation_handling.py b/yt/frontends/enzo/simulation_handling.py index 8733e40f84..5fb432650a 100644 --- a/yt/frontends/enzo/simulation_handling.py +++ b/yt/frontends/enzo/simulation_handling.py @@ -88,7 +88,7 @@ def _set_units(self): new_unit, self.unit_registry.lut[my_unit][0], dimensions.length, - "\\rm{%s}/(1+z)" % my_unit, + f"\\rm{{{my_unit}}}/(1+z)", prefixable=True, ) self.length_unit = self.quan( diff --git a/yt/frontends/fits/misc.py b/yt/frontends/fits/misc.py index 2da062b203..8362c6fa81 100644 --- a/yt/frontends/fits/misc.py +++ b/yt/frontends/fits/misc.py @@ -287,6 +287,6 @@ def _repr_html_(self): img = base64.b64encode(f.read()).decode() ret += ( r'
' % img + rf'src="data:image/png;base64,{img}">
' ) return ret diff --git a/yt/frontends/flash/data_structures.py b/yt/frontends/flash/data_structures.py index 7d617f07a1..abc8d0d654 100644 --- a/yt/frontends/flash/data_structures.py +++ b/yt/frontends/flash/data_structures.py @@ -246,7 +246,7 @@ def _set_code_unit_attributes(self): else: raise RuntimeError( "Runtime parameter unitsystem with " - "value %s is unrecognized" % self["unitsystem"] + f"value {self['unitsystem']} is unrecognized" ) else: b_factor = 1.0 diff --git a/yt/frontends/gadget/simulation_handling.py b/yt/frontends/gadget/simulation_handling.py index 505382aeca..b53c08ec89 100644 --- a/yt/frontends/gadget/simulation_handling.py +++ b/yt/frontends/gadget/simulation_handling.py @@ -81,7 +81,7 @@ def _set_units(self): new_unit, self.unit_registry.lut[my_unit][0], dimensions.length, - "\\rm{%s}/(1+z)" % my_unit, + f"\\rm{{{my_unit}}}/(1+z)", prefixable=True, ) self.length_unit = self.quan( diff --git a/yt/frontends/ramses/data_structures.py b/yt/frontends/ramses/data_structures.py index 97cc7c5af2..851cf29b88 100644 --- a/yt/frontends/ramses/data_structures.py +++ b/yt/frontends/ramses/data_structures.py @@ -417,7 +417,7 @@ def __init__( elif num_ghost_zones < 0: raise RuntimeError( "Cannot initialize a domain subset with a negative number " - "of ghost zones, was called with num_ghost_zones=%s" % num_ghost_zones + f"of ghost zones, was called with {num_ghost_zones=}" ) @property @@ -1038,8 +1038,8 @@ def caster(val): if rheader["ordering type"] != "hilbert" and self._bbox is not None: raise NotImplementedError( - "The ordering %s is not compatible with the `bbox` argument." - % rheader["ordering type"] + f"The ordering {rheader['ordering type']} " + "is not compatible with the `bbox` argument." ) self.parameters.update(rheader) self.domain_left_edge = np.zeros(3, dtype="float64") diff --git a/yt/frontends/sph/data_structures.py b/yt/frontends/sph/data_structures.py index 7d0e9c696d..3c65b7171d 100644 --- a/yt/frontends/sph/data_structures.py +++ b/yt/frontends/sph/data_structures.py @@ -59,8 +59,8 @@ def sph_smoothing_style(self): def sph_smoothing_style(self, value): if value not in self._sph_smoothing_styles: raise ValueError( - "Smoothing style not implemented: %s, please " - "select one of the following: " % value, + f"Smoothing style not implemented: {value}, " + "please select one of the following: ", self._sph_smoothing_styles, ) diff --git a/yt/frontends/tipsy/data_structures.py b/yt/frontends/tipsy/data_structures.py index 70d3e1cb77..d27c7f38d5 100644 --- a/yt/frontends/tipsy/data_structures.py +++ b/yt/frontends/tipsy/data_structures.py @@ -118,7 +118,7 @@ def _parse_parameter_file(self): # the snapshot time and particle counts. f = open(self.parameter_filename, "rb") - hh = self.endian + "".join("%s" % (b) for a, b in self._header_spec) + hh = self.endian + "".join(str(b) for a, b in self._header_spec) hvals = { a: c for (a, b), c in zip( diff --git a/yt/funcs.py b/yt/funcs.py index 94547af091..2c44d521f8 100644 --- a/yt/funcs.py +++ b/yt/funcs.py @@ -1086,12 +1086,20 @@ def array_like_field(data, x, field): return data.ds.quan(x, units) +def _full_type_name(obj: object = None, /, *, cls: Optional[type] = None) -> str: + if cls is not None and obj is not None: + raise TypeError("_full_type_name takes an object or a class, but not both") + if cls is None: + cls = obj.__class__ + prefix = f"{cls.__module__}." if cls.__module__ != "builtins" else "" + return f"{prefix}{cls.__name__}" + + def validate_3d_array(obj): if not is_sequence(obj) or len(obj) != 3: raise TypeError( - "Expected an array of size (3,), received '{}' of length {}".format( - str(type(obj)).split("'")[1], len(obj) - ) + f"Expected an array of size (3,), " + f"received {_full_type_name(obj)!r} of length {len(obj)}" ) @@ -1135,23 +1143,21 @@ def validate_float(obj): ): raise TypeError( "Expected a numeric value (or tuple of format " - "(float, String)), received an inconsistent tuple " - "'%s'." % str(obj) + f"(float, String)), received an inconsistent tuple {str(obj)!r}." ) else: return if is_sequence(obj) and (len(obj) != 1 or not isinstance(obj[0], numeric_type)): raise TypeError( "Expected a numeric value (or size-1 array), " - "received '{}' of length {}".format(str(type(obj)).split("'")[1], len(obj)) + f"received {_full_type_name(obj)!r} of length {len(obj)}" ) def validate_sequence(obj): if obj is not None and not is_sequence(obj): raise TypeError( - "Expected an iterable object, " - "received '%s'" % str(type(obj)).split("'")[1] + "Expected an iterable object, " f"received {_full_type_name(obj)!r}" ) @@ -1181,9 +1187,8 @@ def is_valid_field_key(key): def validate_object(obj, data_type): if obj is not None and not isinstance(obj, data_type): raise TypeError( - "Expected an object of '{}' type, received '{}'".format( - str(data_type).split("'")[1], str(type(obj)).split("'")[1] - ) + f"Expected an object of {_full_type_name(cls=data_type)!r} type, " + f"received {_full_type_name(obj)!r}" ) @@ -1209,13 +1214,13 @@ def validate_center(center): raise TypeError( "Expected 'center' to be in ['c', 'center', " "'m', 'max', 'min'] or the prefix to be " - "'max_'/'min_', received '%s'." % center + f"'max_'/'min_', received {center!r}." ) elif not isinstance(center, (numeric_type, YTQuantity)) and not is_sequence(center): raise TypeError( "Expected 'center' to be a numeric object of type " "list/tuple/np.ndarray/YTArray/YTQuantity, " - "received '%s'." % str(type(center)).split("'")[1] + f"received {_full_type_name(center)}." ) diff --git a/yt/geometry/coordinates/cartesian_coordinates.py b/yt/geometry/coordinates/cartesian_coordinates.py index 95812c4d91..775de8c6a5 100644 --- a/yt/geometry/coordinates/cartesian_coordinates.py +++ b/yt/geometry/coordinates/cartesian_coordinates.py @@ -593,8 +593,8 @@ def _ortho_pixelize( mask = mask.transpose() else: raise NotImplementedError( - "A pixelization routine has not been implemented for %s " - "data objects" % str(type(data_source)) + "A pixelization routine has not been implemented for " + f"{type(data_source)} data objects" ) buff = buff.transpose() mask = mask.transpose() diff --git a/yt/utilities/cosmology.py b/yt/utilities/cosmology.py index cb415bc766..691d86e1c4 100644 --- a/yt/utilities/cosmology.py +++ b/yt/utilities/cosmology.py @@ -95,7 +95,7 @@ def __init__( new_unit, my_u.base_value, dimensions.length, - "\\rm{%s}/(1+z)" % my_unit, + f"\\rm{{{my_unit}}}/(1+z)", prefixable=True, ) self.unit_registry = unit_registry diff --git a/yt/utilities/on_demand_imports.py b/yt/utilities/on_demand_imports.py index e77a482e34..839617f4a5 100644 --- a/yt/utilities/on_demand_imports.py +++ b/yt/utilities/on_demand_imports.py @@ -180,8 +180,8 @@ def __init__(self, pkg_name, exc: Optional[BaseException] = None): # relatively short. Discussion related to this is in # yt-project/yt#1966 self.error = ImportError( - "This functionality requires the %s " - "package to be installed." % self.pkg_name + f"This functionality requires the {self.pkg_name} " + "package to be installed." ) else: self.error = ImportError( diff --git a/yt/utilities/particle_generator.py b/yt/utilities/particle_generator.py index c41bd68a95..a0957e9b38 100644 --- a/yt/utilities/particle_generator.py +++ b/yt/utilities/particle_generator.py @@ -36,7 +36,7 @@ def __init__(self, ds, num_particles, field_list, ptype="io"): except Exception as e: raise KeyError( "You must specify position fields: " - + " ".join("particle_position_%s" % ax for ax in "xyz") + + " ".join(f"particle_position_{ax}" for ax in "xyz") ) from e self.index_index = self.field_list.index((ptype, "particle_index")) diff --git a/yt/visualization/_commons.py b/yt/visualization/_commons.py index 49fdc33c15..99d4b919a2 100644 --- a/yt/visualization/_commons.py +++ b/yt/visualization/_commons.py @@ -258,8 +258,8 @@ def get_default_from_config(data_source, *, field, keys, defaults): def _get_units_label(units: str) -> str: if r"\frac" in units: - return r"$\ \ \left(%s\right)$" % units + return rf"$\ \ \left({units}\right)$" elif units: - return r"$\ \ (%s)$" % units + return rf"$\ \ ({units})$" else: return "" diff --git a/yt/visualization/fixed_resolution.py b/yt/visualization/fixed_resolution.py index 05fdae3db8..d2da6a29e1 100644 --- a/yt/visualization/fixed_resolution.py +++ b/yt/visualization/fixed_resolution.py @@ -825,7 +825,7 @@ def _generate_image_and_mask(self, item) -> None: norm = self.ds.quan(dpx * dpy, "code_length**2").in_base() buff /= norm.v units = data.units / norm.units - info["label"] = "%s $\\rm{Density}$" % info["label"] + info["label"] += " $\\rm{Density}$" else: units = data.units diff --git a/yt/visualization/image_writer.py b/yt/visualization/image_writer.py index e9326d23cc..87bd9189e9 100644 --- a/yt/visualization/image_writer.py +++ b/yt/visualization/image_writer.py @@ -137,7 +137,7 @@ def write_bitmap(bitmap_array, filename, max_val=None, transpose=False): if len(bitmap_array.shape) != 3 or bitmap_array.shape[-1] not in (3, 4): raise RuntimeError( "Expecting image array of shape (N,M,3) or " - "(N,M,4), received %s" % str(bitmap_array.shape) + f"(N,M,4), received {str(bitmap_array.shape)}" ) if bitmap_array.dtype != np.uint8: diff --git a/yt/visualization/plot_modifications.py b/yt/visualization/plot_modifications.py index fd90ca03cc..ca69ff6549 100644 --- a/yt/visualization/plot_modifications.py +++ b/yt/visualization/plot_modifications.py @@ -1244,9 +1244,9 @@ def __call__(self, plot): y[i] = right_edge_y[n] - (12 * (yy1 - yy0) / ypix) else: raise RuntimeError( - "Unrecognized id_loc value ('%s'). " + f"Unrecognized id_loc value ({self.id_loc!r}). " "Allowed values are 'lower left', lower right', " - "'upper left', and 'upper right'." % self.id_loc + "'upper left', and 'upper right'." ) xi, yi = self._sanitize_xy_order(plot, x[i], y[i]) plot._axes.text(xi, yi, "%d" % block_ids[n], clip_on=True) diff --git a/yt/visualization/plot_window.py b/yt/visualization/plot_window.py index bb6cae9c9d..4534d7325c 100644 --- a/yt/visualization/plot_window.py +++ b/yt/visualization/plot_window.py @@ -1195,9 +1195,9 @@ def _setup_plots(self): if colorbar_label is None: colorbar_label = image.info["label"] if getattr(self, "moment", 1) == 2: - colorbar_label = "%s \\rm{Standard Deviation}" % colorbar_label + colorbar_label = f"{colorbar_label} \\rm{{Standard Deviation}}" if hasattr(self, "projected"): - colorbar_label = "$\\rm{Projected }$ %s" % colorbar_label + colorbar_label = f"$\\rm{{Projected }}$ {colorbar_label}" if units is not None and units != "": colorbar_label += _get_units_label(units) diff --git a/yt/visualization/tests/test_save.py b/yt/visualization/tests/test_save.py index 31ec9e230a..2612e8054d 100644 --- a/yt/visualization/tests/test_save.py +++ b/yt/visualization/tests/test_save.py @@ -76,8 +76,8 @@ def test_suffix_clashing(ext, simple_sliceplot, tmp_path): target = (tmp_path / "myfile").with_suffix(ext) expected_warning = re.compile( - r"Received two valid image formats '%s' \(from filename\) " - r"and 'png' \(from suffix\)\. The former is ignored\." % ext[1:] + rf"Received two valid image formats {ext.removeprefix('.')!r} " + r"\(from filename\) and 'png' \(from suffix\)\. The former is ignored\." ) with pytest.warns(UserWarning, match=expected_warning): diff --git a/yt/visualization/volume_rendering/lens.py b/yt/visualization/volume_rendering/lens.py index 0e19b7e0a1..7335cebe34 100644 --- a/yt/visualization/volume_rendering/lens.py +++ b/yt/visualization/volume_rendering/lens.py @@ -137,10 +137,11 @@ def project_to_plane(self, camera, pos, res=None): return px, py, dz def __repr__(self): - disp = ":\n\tlens_type:plane-parallel\n\tviewpoint:%s" % ( - self.viewpoint + return ( + ":\n" + "\tlens_type:plane-parallel\n" + f"\tviewpoint:{self.viewpoint}" ) - return disp class PerspectiveLens(Lens): diff --git a/yt/visualization/volume_rendering/render_source.py b/yt/visualization/volume_rendering/render_source.py index 6943d04ed7..aff769543f 100644 --- a/yt/visualization/volume_rendering/render_source.py +++ b/yt/visualization/volume_rendering/render_source.py @@ -290,7 +290,7 @@ def transfer_function(self, value): if not isinstance(value, valid_types): raise RuntimeError( "transfer_function not a valid type, " - "received object of type %s" % type(value) + f"received object of type {type(value)}" ) if isinstance(value, ProjectionTransferFunction): self.sampler_type = "projection" diff --git a/yt/visualization/volume_rendering/scene.py b/yt/visualization/volume_rendering/scene.py index e45033cb14..ca8207cfbe 100644 --- a/yt/visualization/volume_rendering/scene.py +++ b/yt/visualization/volume_rendering/scene.py @@ -141,8 +141,8 @@ def add_source(self, render_source, keyname=None): lens_str = str(self.camera.lens) if "fisheye" in lens_str or "spherical" in lens_str: raise NotImplementedError( - "Line annotation sources are not supported for %s." - % (type(self.camera.lens).__name__), + "Line annotation sources are not supported " + f"for {type(self.camera.lens).__name__}." ) if isinstance(render_source, (LineSource, PointSource)): diff --git a/yt/visualization/volume_rendering/utils.py b/yt/visualization/volume_rendering/utils.py index d275f37b41..60340aca2a 100644 --- a/yt/visualization/volume_rendering/utils.py +++ b/yt/visualization/volume_rendering/utils.py @@ -26,7 +26,7 @@ def data_source_or_all(data_source): raise RuntimeError( "The data_source is not a valid 3D data container.\n" "Expected an object of type YTSelectionContainer3D but received " - "an object of type %s." % type(data_source) + f"an object of type {type(data_source)}." ) return data_source