Repository: pandas-dev/pandas
Pull request #57902 (2024-03-18 21:39:52)

REF: Avoid new object creation when reverse slicing when possible

jbrockmendel: No objection but why? Is this a perf thing or a style thing?
mroeschke: Just a minor perf thing; avoiding extra memory allocations where possible

Patch:
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 190ea32203..41f1c4c689 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -78,7 +78,7 @@ repos:
     hooks:
     -   id: pylint
         stages: [manual]
-        args: [--load-plugins=pylint.extensions.redefined_loop_name]
+        args: [--load-plugins=pylint.extensions.redefined_loop_name, --fail-on=I0021]
     -   id: pylint
         alias: redefined-outer-name
         name: Redefining name from outer scope
diff --git a/doc/source/_static/css/getting_started.css b/doc/source/_static/css/getting_started.css
index 0d53bbde94..b02311eb66 100644
--- a/doc/source/_static/css/getting_started.css
+++ b/doc/source/_static/css/getting_started.css
@@ -248,6 +248,7 @@ ul.task-bullet > li > p:first-child {
 }
 
 .tutorial-card .card-header {
+  --bs-card-cap-color: var(--pst-color-text-base);
   cursor: pointer;
   background-color: var(--pst-color-surface);
   border: 1px solid var(--pst-color-border)
@@ -269,7 +270,7 @@ ul.task-bullet > li > p:first-child {
 
 
 .tutorial-card .gs-badge-link a {
-  color: var(--pst-color-text-base);
+  color: var(--pst-color-primary-text);
   text-decoration: none;
 }
 
diff --git a/doc/source/user_guide/missing_data.rst b/doc/source/user_guide/missing_data.rst
index aea7688c06..2e104ac06f 100644
--- a/doc/source/user_guide/missing_data.rst
+++ b/doc/source/user_guide/missing_data.rst
@@ -88,7 +88,7 @@ To detect these missing value, use the :func:`isna` or :func:`notna` methods.
 
 .. warning::
 
-   Experimental: the behaviour of :class:`NA`` can still change without warning.
+   Experimental: the behaviour of :class:`NA` can still change without warning.
 
 Starting from pandas 1.0, an experimental :class:`NA` value (singleton) is
 available to represent scalar missing values. The goal of :class:`NA` is provide a
@@ -105,7 +105,7 @@ dtype, it will use :class:`NA`:
     s[2]
     s[2] is pd.NA
 
-Currently, pandas does not yet use those data types using :class:`NA` by default
+Currently, pandas does not use those data types using :class:`NA` by default in
 a :class:`DataFrame` or :class:`Series`, so you need to specify
 the dtype explicitly. An easy way to convert to those dtypes is explained in the
 :ref:`conversion section <missing_data.NA.conversion>`.
@@ -253,8 +253,8 @@ Conversion
 ^^^^^^^^^^
 
 If you have a :class:`DataFrame` or :class:`Series` using ``np.nan``,
-:meth:`Series.convert_dtypes` and :meth:`DataFrame.convert_dtypes`
-in :class:`DataFrame` that can convert data to use the data types that use :class:`NA`
+:meth:`DataFrame.convert_dtypes` and :meth:`Series.convert_dtypes`, respectively,
+will convert your data to use the nullable data types supporting :class:`NA`,
 such as :class:`Int64Dtype` or :class:`ArrowDtype`. This is especially helpful after reading
 in data sets from IO methods where data types were inferred.
 
diff --git a/doc/source/whatsnew/v3.0.0.rst b/doc/source/whatsnew/v3.0.0.rst
index cb211b0b72..f3fcdcdb79 100644
--- a/doc/source/whatsnew/v3.0.0.rst
+++ b/doc/source/whatsnew/v3.0.0.rst
@@ -357,6 +357,7 @@ MultiIndex
 I/O
 ^^^
 - Bug in :meth:`DataFrame.to_excel` when writing empty :class:`DataFrame` with :class:`MultiIndex` on both axes (:issue:`57696`)
+- Now all ``Mapping`` s are pretty printed correctly. Before only literal ``dict`` s were. (:issue:`57915`)
 -
 -
 
diff --git a/pandas/_libs/tslibs/util.pxd b/pandas/_libs/tslibs/util.pxd
index e4ac3a9e16..a5822e57d3 100644
--- a/pandas/_libs/tslibs/util.pxd
+++ b/pandas/_libs/tslibs/util.pxd
@@ -185,11 +185,11 @@ cdef inline const char* get_c_string(str py_string) except NULL:
     return get_c_string_buf_and_size(py_string, NULL)
 
 
-cdef inline bytes string_encode_locale(str py_string) noexcept:
+cdef inline bytes string_encode_locale(str py_string):
     """As opposed to PyUnicode_Encode, use current system locale to encode."""
     return PyUnicode_EncodeLocale(py_string, NULL)
 
 
-cdef inline object char_to_string_locale(const char* data) noexcept:
+cdef inline object char_to_string_locale(const char* data):
     """As opposed to PyUnicode_FromString, use current system locale to decode."""
     return PyUnicode_DecodeLocale(data, NULL)
diff --git a/pandas/core/arrays/datetimelike.py b/pandas/core/arrays/datetimelike.py
index ba2c936b75..745774b34a 100644
--- a/pandas/core/arrays/datetimelike.py
+++ b/pandas/core/arrays/datetimelike.py
@@ -2371,11 +2371,12 @@ class TimelikeOps(DatetimeLikeArrayMixin):
     ):
         if self.freq is not None:
             # We must be unique, so can short-circuit (and retain freq)
-            codes = np.arange(len(self), dtype=np.intp)
-            uniques = self.copy()  # TODO: copy or view?
             if sort and self.freq.n < 0:
-                codes = codes[::-1]
-                uniques = uniques[::-1]
+                codes = np.arange(len(self) - 1, -1, -1, dtype=np.intp)
+                uniques = self[::-1]
+            else:
+                codes = np.arange(len(self), dtype=np.intp)
+                uniques = self.copy()  # TODO: copy or view?
             return codes, uniques
 
         if sort:
diff --git a/pandas/core/base.py b/pandas/core/base.py
index 33b3731967..987136ffdf 100644
--- a/pandas/core/base.py
+++ b/pandas/core/base.py
@@ -87,12 +87,6 @@ if TYPE_CHECKING:
 
 
 _shared_docs: dict[str, str] = {}
-_indexops_doc_kwargs = {
-    "klass": "IndexOpsMixin",
-    "inplace": "",
-    "unique": "IndexOpsMixin",
-    "duplicated": "IndexOpsMixin",
-}
 
 
 class PandasObject(DirNamesMixin):
diff --git a/pandas/core/dtypes/astype.py b/pandas/core/dtypes/astype.py
index d351d13fdf..086f7d2da6 100644
--- a/pandas/core/dtypes/astype.py
+++ b/pandas/core/dtypes/astype.py
@@ -37,8 +37,6 @@ if TYPE_CHECKING:
 
     from pandas.core.arrays import ExtensionArray
 
-_dtype_obj = np.dtype(object)
-
 
 @overload
 def _astype_nansafe(
diff --git a/pandas/core/groupby/indexing.py b/pandas/core/groupby/indexing.py
index 75c0a062b5..c658f625d5 100644
--- a/pandas/core/groupby/indexing.py
+++ b/pandas/core/groupby/indexing.py
@@ -114,7 +114,6 @@ class GroupByIndexingMixin:
         4  b  5
         """
         if TYPE_CHECKING:
-            # pylint: disable-next=used-before-assignment
             groupby_self = cast(groupby.GroupBy, self)
         else:
             groupby_self = self
diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py
index c2df773326..62facb89a2 100644
--- a/pandas/core/indexes/base.py
+++ b/pandas/core/indexes/base.py
@@ -2116,7 +2116,7 @@ class Index(IndexOpsMixin, PandasObject):
         if not isinstance(level, (tuple, list)):
             level = [level]
 
-        levnums = sorted(self._get_level_number(lev) for lev in level)[::-1]
+        levnums = sorted((self._get_level_number(lev) for lev in level), reverse=True)
 
         return self._drop_level_numbers(levnums)
 
@@ -7154,6 +7154,43 @@ class Index(IndexOpsMixin, PandasObject):
         return (len(self),)
 
 
+def maybe_sequence_to_range(sequence) -> Any | range:
+    """
+    Convert a 1D, non-pandas sequence to a range if possible.
+
+    Returns the input if not possible.
+
+    Parameters
+    ----------
+    sequence : 1D sequence
+    names : sequence of str
+
+    Returns
+    -------
+    Any : input or range
+    """
+    if isinstance(sequence, (ABCSeries, Index)):
+        return sequence
+    np_sequence = np.asarray(sequence)
+    if np_sequence.dtype.kind != "i" or len(np_sequence) == 1:
+        return sequence
+    elif len(np_sequence) == 0:
+        return range(0)
+    diff = np_sequence[1] - np_sequence[0]
+    if diff == 0:
+        return sequence
+    elif len(np_sequence) == 2:
+        return range(np_sequence[0], np_sequence[1] + diff, diff)
+    maybe_range_indexer, remainder = np.divmod(np_sequence - np_sequence[0], diff)
+    if (
+        lib.is_range_indexer(maybe_range_indexer, len(maybe_range_indexer))
+        and not remainder.any()
+    ):
+        return range(np_sequence[0], np_sequence[-1] + diff, diff)
+    else:
+        return sequence
+
+
 def ensure_index_from_sequences(sequences, names=None) -> Index:
     """
     Construct an index from sequences of data.
@@ -7172,8 +7209,8 @@ def ensure_index_from_sequences(sequences, names=None) -> Index:
 
     Examples
     --------
-    >>> ensure_index_from_sequences([[1, 2, 3]], names=["name"])
-    Index([1, 2, 3], dtype='int64', name='name')
+    >>> ensure_index_from_sequences([[1, 2, 4]], names=["name"])
+    Index([1, 2, 4], dtype='int64', name='name')
 
     >>> ensure_index_from_sequences([["a", "a"], ["a", "b"]], names=["L1", "L2"])
     MultiIndex([('a', 'a'),
@@ -7189,8 +7226,9 @@ def ensure_index_from_sequences(sequences, names=None) -> Index:
     if len(sequences) == 1:
         if names is not None:
             names = names[0]
-        return Index(sequences[0], name=names)
+        return Index(maybe_sequence_to_range(sequences[0]), name=names)
     else:
+        # TODO: Apply maybe_sequence_to_range to sequences?
         return MultiIndex.from_arrays(sequences, names=names)
 
 
diff --git a/pandas/core/indexes/multi.py b/pandas/core/indexes/multi.py
index 2cb05dadd5..2e554bc848 100644
--- a/pandas/core/indexes/multi.py
+++ b/pandas/core/indexes/multi.py
@@ -3589,7 +3589,7 @@ class MultiIndex(Index):
                 new_order = key_order_map[self.codes[i][indexer]]
             elif isinstance(k, slice) and k.step is not None and k.step < 0:
                 # flip order for negative step
-                new_order = np.arange(n)[::-1][indexer]
+                new_order = np.arange(n - 1, -1, -1)[indexer]
             elif isinstance(k, slice) and k.start is None and k.stop is None:
                 # slice(None) should not determine order GH#31330
                 new_order = np.ones((n,), dtype=np.intp)[indexer]
diff --git a/pandas/core/indexes/range.py b/pandas/core/indexes/range.py
index 82bf8d7c70..0ba3c22093 100644
--- a/pandas/core/indexes/range.py
+++ b/pandas/core/indexes/range.py
@@ -29,7 +29,6 @@ from pandas.util._decorators import (
     doc,
 )
 
-from pandas.core.dtypes import missing
 from pandas.core.dtypes.base import ExtensionDtype
 from pandas.core.dtypes.common import (
     ensure_platform_int,
@@ -65,6 +64,12 @@ _empty_range = range(0)
 _dtype_int64 = np.dtype(np.int64)
 
 
+def min_fitting_element(start: int, step: int, lower_limit: int) -> int:
+    """Returns the smallest element greater than or equal to the limit"""
+    no_steps = -(-(lower_limit - start) // abs(step))
+    return start + abs(step) * no_steps
+
+
 class RangeIndex(Index):
     """
     Immutable Index implementing a monotonic integer range.
@@ -475,28 +480,13 @@ class RangeIndex(Index):
         if values.dtype.kind == "i" and values.ndim == 1:
             # GH 46675 & 43885: If values is equally spaced, return a
             # more memory-compact RangeIndex instead of Index with 64-bit dtype
-            if len(values) == 0:
-                return type(self)._simple_new(_empty_range, name=name)
-            elif len(values) == 1:
+            if len(values) == 1:
                 start = values[0]
                 new_range = range(start, start + self.step, self.step)
                 return type(self)._simple_new(new_range, name=name)
-            diff = values[1] - values[0]
-            if not missing.isna(diff) and diff != 0:
-                if len(values) == 2:
-                    # Can skip is_range_indexer check
-                    new_range = range(values[0], values[-1] + diff, diff)
-                    return type(self)._simple_new(new_range, name=name)
-                else:
-                    maybe_range_indexer, remainder = np.divmod(values - values[0], diff)
-                    if (
-                        lib.is_range_indexer(
-                            maybe_range_indexer, len(maybe_range_indexer)
-                        )
-                        and not remainder.any()
-                    ):
-                        new_range = range(values[0], values[-1] + diff, diff)
-                        return type(self)._simple_new(new_range, name=name)
+            maybe_range = ibase.maybe_sequence_to_range(values)
+            if isinstance(maybe_range, range):
+                return type(self)._simple_new(maybe_range, name=name)
         return self._constructor._simple_new(values, name=name)
 
     def _view(self) -> Self:
@@ -586,25 +576,30 @@ class RangeIndex(Index):
         kwargs.pop("kind", None)  # e.g. "mergesort" is irrelevant
         nv.validate_argsort(args, kwargs)
 
+        start, stop, step = None, None, None
         if self._range.step > 0:
-            result = np.arange(len(self), dtype=np.intp)
+            if ascending:
+                start = len(self)
+            else:
+                start, stop, step = len(self) - 1, -1, -1
+        elif ascending:
+            start, stop, step = len(self) - 1, -1, -1
         else:
-            result = np.arange(len(self) - 1, -1, -1, dtype=np.intp)
+            start = len(self)
 
-        if not ascending:
-            result = result[::-1]
-        return result
+        return np.arange(start, stop, step, dtype=np.intp)
 
     def factorize(
         self,
         sort: bool = False,
         use_na_sentinel: bool = True,
     ) -> tuple[npt.NDArray[np.intp], RangeIndex]:
-        codes = np.arange(len(self), dtype=np.intp)
-        uniques = self
         if sort and self.step < 0:
-            codes = codes[::-1]
-            uniques = uniques[::-1]
+            codes = np.arange(len(self) - 1, -1, -1, dtype=np.intp)
+            uniques = self[::-1]
+        else:
+            codes = np.arange(len(self), dtype=np.intp)
+            uniques = self
         return codes, uniques
 
     def equals(self, other: object) -> bool:
@@ -715,26 +710,15 @@ class RangeIndex(Index):
         # intersection disregarding the lower bounds
         tmp_start = first.start + (second.start - first.start) * first.step // gcd * s
         new_step = first.step * second.step // gcd
-        new_range = range(tmp_start, int_high, new_step)
-        new_index = self._simple_new(new_range)
 
         # adjust index to limiting interval
-        new_start = new_index._min_fitting_element(int_low)
-        new_range = range(new_start, new_index.stop, new_index.step)
-        new_index = self._simple_new(new_range)
+        new_start = min_fitting_element(tmp_start, new_step, int_low)
+        new_range = range(new_start, int_high, new_step)
 
-        if (self.step < 0 and other.step < 0) is not (new_index.step < 0):
-            new_index = new_index[::-1]
+        if (self.step < 0 and other.step < 0) is not (new_range.step < 0):
+            new_range = new_range[::-1]
 
-        if sort is None:
-            new_index = new_index.sort_values()
-
-        return new_index
-
-    def _min_fitting_element(self, lower_limit: int) -> int:
-        """Returns the smallest element greater than or equal to the limit"""
-        no_steps = -(-(lower_limit - self.start) // abs(self.step))
-        return self.start + abs(self.step) * no_steps
+        return self._simple_new(new_range)
 
     def _extended_gcd(self, a: int, b: int) -> tuple[int, int, int]:
         """
@@ -920,9 +904,9 @@ class RangeIndex(Index):
                 # e.g. range(10) and range(0, 10, 3)
                 return super()._difference(other, sort=sort)
 
-        new_index = type(self)._simple_new(new_rng, name=res_name)
         if first is not self._range:
-            new_index = new_index[::-1]
+            new_rng = new_rng[::-1]
+        new_index = type(self)._simple_new(new_rng, name=res_name)
 
         return new_index
 
diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py
index c7a938dbc4..c8a2e11dce 100644
--- a/pandas/core/indexing.py
+++ b/pandas/core/indexing.py
@@ -1145,7 +1145,7 @@ class _LocationIndexer(NDFrameIndexerBase):
         # GH#41369 Loop in reverse order ensures indexing along columns before rows
         # which selects only necessary blocks which avoids dtype conversion if possible
         axis = len(tup) - 1
-        for key in tup[::-1]:
+        for key in reversed(tup):
             if com.is_null_slice(key):
                 axis -= 1
                 continue
diff --git a/pandas/core/internals/managers.py b/pandas/core/internals/managers.py
index d920ebc60d..af851e1fc8 100644
--- a/pandas/core/internals/managers.py
+++ b/pandas/core/internals/managers.py
@@ -1549,9 +1549,9 @@ class BlockManager(libinternals.BlockManager, BaseBlockManager):
             self._blklocs = np.append(self._blklocs, 0)
             self._blknos = np.append(self._blknos, len(self.blocks))
         elif loc == 0:
-            # np.append is a lot faster, let's use it if we can.
-            self._blklocs = np.append(self._blklocs[::-1], 0)[::-1]
-            self._blknos = np.append(self._blknos[::-1], len(self.blocks))[::-1]
+            # As of numpy 1.26.4, np.concatenate faster than np.append
+            self._blklocs = np.concatenate([[0], self._blklocs])
+            self._blknos = np.concatenate([[len(self.blocks)], self._blknos])
         else:
             new_blklocs, new_blknos = libinternals.update_blklocs_and_blknos(
                 self.blklocs, self.blknos, loc, len(self.blocks)
diff --git a/pandas/core/reshape/reshape.py b/pandas/core/reshape/reshape.py
index b28010c13d..ff358e8ba3 100644
--- a/pandas/core/reshape/reshape.py
+++ b/pandas/core/reshape/reshape.py
@@ -910,9 +910,10 @@ def stack_v3(frame: DataFrame, level: list[int]) -> Series | DataFrame:
         raise ValueError("Columns with duplicate values are not supported in stack")
 
     # If we need to drop `level` from columns, it needs to be in descending order
+    set_levels = set(level)
     drop_levnums = sorted(level, reverse=True)
     stack_cols = frame.columns._drop_level_numbers(
-        [k for k in range(frame.columns.nlevels) if k not in level][::-1]
+        [k for k in range(frame.columns.nlevels - 1, -1, -1) if k not in set_levels]
     )
     if len(level) > 1:
         # Arrange columns in the order we want to take them, e.g. level=[2, 0, 1]
@@ -936,7 +937,7 @@ def stack_v3(frame: DataFrame, level: list[int]) -> Series | DataFrame:
                 idx = (idx,)
             gen = iter(idx)
             column_indexer = tuple(
-                next(gen) if k in level else slice(None)
+                next(gen) if k in set_levels else slice(None)
                 for k in range(frame.columns.nlevels)
             )
             data = frame.loc[:, column_indexer]
diff --git a/pandas/core/series.py b/pandas/core/series.py
index 8a7c153120..08e56cb492 100644
--- a/pandas/core/series.py
+++ b/pandas/core/series.py
@@ -5510,9 +5510,9 @@ class Series(base.IndexOpsMixin, NDFrame):  # type: ignore[misc]
             replacements = updated_replacements
             default = default.astype(common_dtype)
 
-        counter = reversed(range(len(conditions)))
+        counter = range(len(conditions) - 1, -1, -1)
         for position, condition, replacement in zip(
-            counter, conditions[::-1], replacements[::-1]
+            counter, reversed(conditions), reversed(replacements)
         ):
             try:
                 default = default.mask(
diff --git a/pandas/core/sorting.py b/pandas/core/sorting.py
index 4774b013fc..493e856c6d 100644
--- a/pandas/core/sorting.py
+++ b/pandas/core/sorting.py
@@ -2,6 +2,7 @@
 
 from __future__ import annotations
 
+import itertools
 from typing import (
     TYPE_CHECKING,
     Callable,
@@ -334,13 +335,15 @@ def lexsort_indexer(
         raise ValueError(f"invalid na_position: {na_position}")
 
     if isinstance(orders, bool):
-        orders = [orders] * len(keys)
+        orders = itertools.repeat(orders, len(keys))
     elif orders is None:
-        orders = [True] * len(keys)
+        orders = itertools.repeat(True, len(keys))
+    else:
+        orders = reversed(orders)
 
     labels = []
 
-    for k, order in zip(keys, orders):
+    for k, order in zip(reversed(keys), orders):
         k = ensure_key_mapped(k, key)
         if codes_given:
             codes = cast(np.ndarray, k)
@@ -361,7 +364,7 @@ def lexsort_indexer(
 
         labels.append(codes)
 
-    return np.lexsort(labels[::-1])
+    return np.lexsort(labels)
 
 
 def nargsort(
diff --git a/pandas/core/tools/datetimes.py b/pandas/core/tools/datetimes.py
index b8b1d39d4e..2aeb1aff07 100644
--- a/pandas/core/tools/datetimes.py
+++ b/pandas/core/tools/datetimes.py
@@ -993,7 +993,6 @@ def to_datetime(
         errors=errors,
         exact=exact,
     )
-    # pylint: disable-next=used-before-assignment
     result: Timestamp | NaTType | Series | Index
 
     if isinstance(arg, Timestamp):
diff --git a/pandas/io/formats/printing.py b/pandas/io/formats/printing.py
index 214d1d7079..0bd4f2935f 100644
--- a/pandas/io/formats/printing.py
+++ b/pandas/io/formats/printing.py
@@ -187,8 +187,8 @@ def pprint_thing(
     _nest_lvl : internal use only. pprint_thing() is mutually-recursive
         with pprint_sequence, this argument is used to keep track of the
         current nesting level, and limit it.
-    escape_chars : list or dict, optional
-        Characters to escape. If a dict is passed the values are the
+    escape_chars : list[str] or Mapping[str, str], optional
+        Characters to escape. If a Mapping is passed the values are the
         replacements
     default_escapes : bool, default False
         Whether the input escape characters replaces or adds to the defaults
@@ -204,11 +204,11 @@ def pprint_thing(
         thing: Any, escape_chars: EscapeChars | None = escape_chars
     ) -> str:
         translate = {"\t": r"\t", "\n": r"\n", "\r": r"\r"}
-        if isinstance(escape_chars, dict):
+        if isinstance(escape_chars, Mapping):
             if default_escapes:
                 translate.update(escape_chars)
             else:
-                translate = escape_chars
+                translate = escape_chars  # type: ignore[assignment]
             escape_chars = list(escape_chars.keys())
         else:
             escape_chars = escape_chars or ()
@@ -220,7 +220,7 @@ def pprint_thing(
 
     if hasattr(thing, "__next__"):
         return str(thing)
-    elif isinstance(thing, dict) and _nest_lvl < get_option(
+    elif isinstance(thing, Mapping) and _nest_lvl < get_option(
         "display.pprint_nest_depth"
     ):
         result = _pprint_dict(


Test patch:
diff --git a/pandas/conftest.py b/pandas/conftest.py
index 9302c581fd..50a94b35c2 100644
--- a/pandas/conftest.py
+++ b/pandas/conftest.py
@@ -1231,10 +1231,6 @@ def tz_aware_fixture(request):
     return request.param
 
 
-# Generate cartesian product of tz_aware_fixture:
-tz_aware_fixture2 = tz_aware_fixture
-
-
 _UTCS = ["utc", "dateutil/UTC", utc, tzutc(), timezone.utc]
 if zoneinfo is not None:
     _UTCS.append(zoneinfo.ZoneInfo("UTC"))
diff --git a/pandas/tests/indexes/ranges/test_range.py b/pandas/tests/indexes/ranges/test_range.py
index 72762db21b..c9ddbf4464 100644
--- a/pandas/tests/indexes/ranges/test_range.py
+++ b/pandas/tests/indexes/ranges/test_range.py
@@ -9,6 +9,7 @@ from pandas import (
     RangeIndex,
 )
 import pandas._testing as tm
+from pandas.core.indexes.range import min_fitting_element
 
 
 class TestRangeIndex:
@@ -419,21 +420,21 @@ class TestRangeIndex:
         assert 2 == result[0]
 
     def test_min_fitting_element(self):
-        result = RangeIndex(0, 20, 2)._min_fitting_element(1)
+        result = min_fitting_element(0, 2, 1)
         assert 2 == result
 
-        result = RangeIndex(1, 6)._min_fitting_element(1)
+        result = min_fitting_element(1, 1, 1)
         assert 1 == result
 
-        result = RangeIndex(18, -2, -2)._min_fitting_element(1)
+        result = min_fitting_element(18, -2, 1)
         assert 2 == result
 
-        result = RangeIndex(5, 0, -1)._min_fitting_element(1)
+        result = min_fitting_element(5, -1, 1)
         assert 1 == result
 
         big_num = 500000000000000000000000
 
-        result = RangeIndex(5, big_num * 2, 1)._min_fitting_element(big_num)
+        result = min_fitting_element(5, 1, big_num)
         assert big_num == result
 
     def test_slice_specialised(self, simple_index):
diff --git a/pandas/tests/indexes/ranges/test_setops.py b/pandas/tests/indexes/ranges/test_setops.py
index d417b8b743..ac24ff828c 100644
--- a/pandas/tests/indexes/ranges/test_setops.py
+++ b/pandas/tests/indexes/ranges/test_setops.py
@@ -93,12 +93,12 @@ class TestRangeIndexSetOps:
         # GH 17296: intersect two decreasing RangeIndexes
         first = RangeIndex(10, -2, -2)
         other = RangeIndex(5, -4, -1)
-        expected = first.astype(int).intersection(other.astype(int), sort=sort)
-        result = first.intersection(other, sort=sort).astype(int)
+        expected = RangeIndex(start=4, stop=-2, step=-2)
+        result = first.intersection(other, sort=sort)
         tm.assert_index_equal(result, expected)
 
         # reversed
-        result = other.intersection(first, sort=sort).astype(int)
+        result = other.intersection(first, sort=sort)
         tm.assert_index_equal(result, expected)
 
         index = RangeIndex(5, name="foo")
diff --git a/pandas/tests/indexes/test_base.py b/pandas/tests/indexes/test_base.py
index 4c703c3af9..beee14197b 100644
--- a/pandas/tests/indexes/test_base.py
+++ b/pandas/tests/indexes/test_base.py
@@ -1514,8 +1514,10 @@ class TestIndexUtils:
     @pytest.mark.parametrize(
         "data, names, expected",
         [
-            ([[1, 2, 3]], None, Index([1, 2, 3])),
-            ([[1, 2, 3]], ["name"], Index([1, 2, 3], name="name")),
+            ([[1, 2, 4]], None, Index([1, 2, 4])),
+            ([[1, 2, 4]], ["name"], Index([1, 2, 4], name="name")),
+            ([[1, 2, 3]], None, RangeIndex(1, 4)),
+            ([[1, 2, 3]], ["name"], RangeIndex(1, 4, name="name")),
             (
                 [["a", "a"], ["c", "d"]],
                 None,
@@ -1530,7 +1532,7 @@ class TestIndexUtils:
     )
     def test_ensure_index_from_sequences(self, data, names, expected):
         result = ensure_index_from_sequences(data, names)
-        tm.assert_index_equal(result, expected)
+        tm.assert_index_equal(result, expected, exact=True)
 
     def test_ensure_index_mixed_closed_intervals(self):
         # GH27172
diff --git a/pandas/tests/io/formats/test_printing.py b/pandas/tests/io/formats/test_printing.py
index acf2bc72c6..1009dfec53 100644
--- a/pandas/tests/io/formats/test_printing.py
+++ b/pandas/tests/io/formats/test_printing.py
@@ -1,5 +1,6 @@
 # Note! This file is aimed specifically at pandas.io.formats.printing utility
 # functions, not the general printing of pandas objects.
+from collections.abc import Mapping
 import string
 
 import pandas._config.config as cf
@@ -16,6 +17,17 @@ def test_adjoin():
     assert adjoined == expected
 
 
+class MyMapping(Mapping):
+    def __getitem__(self, key):
+        return 4
+
+    def __iter__(self):
+        return iter(["a", "b"])
+
+    def __len__(self):
+        return 2
+
+
 class TestPPrintThing:
     def test_repr_binary_type(self):
         letters = string.ascii_letters
@@ -42,6 +54,12 @@ class TestPPrintThing:
     def test_repr_set(self):
         assert printing.pprint_thing({1}) == "{1}"
 
+    def test_repr_dict(self):
+        assert printing.pprint_thing({"a": 4, "b": 4}) == "{'a': 4, 'b': 4}"
+
+    def test_repr_mapping(self):
+        assert printing.pprint_thing(MyMapping()) == "{'a': 4, 'b': 4}"
+
 
 class TestFormatBase:
     def test_adjoin(self):
diff --git a/pandas/tests/io/formats/test_to_latex.py b/pandas/tests/io/formats/test_to_latex.py
index b9d5f04cb2..1de53993fe 100644
--- a/pandas/tests/io/formats/test_to_latex.py
+++ b/pandas/tests/io/formats/test_to_latex.py
@@ -1311,7 +1311,6 @@ class TestToLatexMultiindex:
         )
         col_names = [n if (bool(n) and 1 in axes) else "" for n in names]
         observed = df.to_latex(multirow=False)
-        # pylint: disable-next=consider-using-f-string
         expected = r"""\begin{tabular}{llrrrr}
 \toprule
  & %s & \multicolumn{2}{r}{1} & \multicolumn{2}{r}{2} \\
diff --git a/pandas/tests/io/xml/conftest.py b/pandas/tests/io/xml/conftest.py
index 40a94f27e9..8900b0dc46 100644
--- a/pandas/tests/io/xml/conftest.py
+++ b/pandas/tests/io/xml/conftest.py
@@ -11,7 +11,7 @@ def xml_data_path():
     Examples
     --------
     >>> def test_read_xml(xml_data_path):
-    ...     read_xml(xml_data_path / "file.xsl")
+    ...     pd.read_xml(xml_data_path / "file.xsl")
     """
     return Path(__file__).parent.parent / "data" / "xml"
 
@@ -24,7 +24,7 @@ def xml_books(xml_data_path, datapath):
     Examples
     --------
     >>> def test_read_xml(xml_books):
-    ...     read_xml(xml_books)
+    ...     pd.read_xml(xml_books)
     """
     return datapath(xml_data_path / "books.xml")
 
@@ -37,7 +37,7 @@ def xml_doc_ch_utf(xml_data_path, datapath):
     Examples
     --------
     >>> def test_read_xml(xml_doc_ch_utf):
-    ...     read_xml(xml_doc_ch_utf)
+    ...     pd.read_xml(xml_doc_ch_utf)
     """
     return datapath(xml_data_path / "doc_ch_utf.xml")
 
@@ -50,7 +50,7 @@ def xml_baby_names(xml_data_path, datapath):
     Examples
     --------
     >>> def test_read_xml(xml_baby_names):
-    ...     read_xml(xml_baby_names)
+    ...     pd.read_xml(xml_baby_names)
     """
     return datapath(xml_data_path / "baby_names.xml")
 
@@ -63,7 +63,7 @@ def kml_cta_rail_lines(xml_data_path, datapath):
     Examples
     --------
     >>> def test_read_xml(kml_cta_rail_lines):
-    ...     read_xml(
+    ...     pd.read_xml(
     ...         kml_cta_rail_lines,
     ...         xpath=".//k:Placemark",
     ...         namespaces={"k": "http://www.opengis.net/kml/2.2"},
@@ -80,7 +80,7 @@ def xsl_flatten_doc(xml_data_path, datapath):
 
     Examples
     --------
-    >>> def test_read_xsl(xsl_flatten_doc):
+    >>> def test_read_xsl(xsl_flatten_doc, mode):
     ...     with open(
     ...         xsl_flatten_doc, mode, encoding="utf-8" if mode == "r" else None
     ...     ) as f:
@@ -96,7 +96,7 @@ def xsl_row_field_output(xml_data_path, datapath):
 
     Examples
     --------
-    >>> def test_read_xsl(xsl_row_field_output):
+    >>> def test_read_xsl(xsl_row_field_output, mode):
     ...     with open(
     ...         xsl_row_field_output, mode, encoding="utf-8" if mode == "r" else None
     ...     ) as f:
diff --git a/pandas/tests/series/test_iteration.py b/pandas/tests/series/test_iteration.py
index edc8245523..1e0fa7fae1 100644
--- a/pandas/tests/series/test_iteration.py
+++ b/pandas/tests/series/test_iteration.py
@@ -4,12 +4,10 @@ class TestIteration:
 
     def test_iter_datetimes(self, datetime_series):
         for i, val in enumerate(datetime_series):
-            # pylint: disable-next=unnecessary-list-index-lookup
             assert val == datetime_series.iloc[i]
 
     def test_iter_strings(self, string_series):
         for i, val in enumerate(string_series):
-            # pylint: disable-next=unnecessary-list-index-lookup
             assert val == string_series.iloc[i]
 
     def test_iteritems_datetimes(self, datetime_series):