Repository: pandas-dev/pandas (python)

Issue:
DOC: boxplot documentation for layout parameter is not correct. 
### Pandas version checks

- [X] I have checked that the issue still exists on the latest versions of the docs on `main` [here](https://pandas.pydata.org/docs/dev/)


### Location of the documentation

https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.boxplot.html

### Documentation problem

Te doc that describes layout parameter for boxplot needs to be change to accurately represent the implementation. 
The current documentation read: 
```
layout : tuple (rows, columns), optional
For example, (3, 5) will display the subplots using 3 columns and 5 rows, starting from the top-left.
```

### Suggested fix for documentation

```
layout : tuple (rows, columns), optional
For example, (3, 5) will display the subplots using 3 rows and 5 columns, starting from the top-left.
```

Pull request description:
Fix docstring for layout parameter of boxplot
- [X] closes #50646 
- [X] All [code checks passed](https://pandas.pydata.org/pandas-docs/dev/development/contributing_codebase.html#pre-commit).


Patch:
diff --git a/doc/source/development/contributing.rst b/doc/source/development/contributing.rst
index 4e654f68dd..d0bda0ba42 100644
--- a/doc/source/development/contributing.rst
+++ b/doc/source/development/contributing.rst
@@ -1,4 +1,4 @@
-3.. _contributing:
+.. _contributing:
 
 {{ header }}
 
diff --git a/doc/source/reference/indexing.rst b/doc/source/reference/indexing.rst
index 19ae7d2a15..8ae7145287 100644
--- a/doc/source/reference/indexing.rst
+++ b/doc/source/reference/indexing.rst
@@ -385,6 +385,7 @@ Conversion
 .. autosummary::
    :toctree: api/
 
+   DatetimeIndex.as_unit
    DatetimeIndex.to_period
    DatetimeIndex.to_pydatetime
    DatetimeIndex.to_series
@@ -423,6 +424,7 @@ Conversion
 .. autosummary::
    :toctree: api/
 
+   TimedeltaIndex.as_unit
    TimedeltaIndex.to_pytimedelta
    TimedeltaIndex.to_series
    TimedeltaIndex.round
diff --git a/doc/source/whatsnew/v2.0.0.rst b/doc/source/whatsnew/v2.0.0.rst
index 11fefb0826..3ac004ef33 100644
--- a/doc/source/whatsnew/v2.0.0.rst
+++ b/doc/source/whatsnew/v2.0.0.rst
@@ -45,6 +45,7 @@ The ``use_nullable_dtypes`` keyword argument has been expanded to the following
 * :func:`read_sql_query`
 * :func:`read_sql_table`
 * :func:`read_orc`
+* :func:`to_numeric`
 
 Additionally a new global configuration, ``mode.dtype_backend`` can now be used in conjunction with the parameter ``use_nullable_dtypes=True`` in the following functions
 to select the nullable dtypes implementation.
@@ -149,6 +150,7 @@ Other enhancements
 - :meth:`DataFrame.plot.hist` now recognizes ``xlabel`` and ``ylabel`` arguments (:issue:`49793`)
 - Improved error message in :func:`to_datetime` for non-ISO8601 formats, informing users about the position of the first error (:issue:`50361`)
 - Improved error message when trying to align :class:`DataFrame` objects (for example, in :func:`DataFrame.compare`) to clarify that "identically labelled" refers to both index and columns (:issue:`50083`)
+- Added :meth:`DatetimeIndex.as_unit` and :meth:`TimedeltaIndex.as_unit` to convert to different resolutions; supported resolutions are "s", "ms", "us", and "ns" (:issue:`50616`)
 -
 
 .. ---------------------------------------------------------------------------
@@ -788,7 +790,8 @@ Removal of prior version deprecations/changes
 - Removed the deprecated argument ``line_terminator`` from :meth:`DataFrame.to_csv` (:issue:`45302`)
 - Removed the deprecated argument ``label`` from :func:`lreshape` (:issue:`30219`)
 - Arguments after ``expr`` in :meth:`DataFrame.eval` and :meth:`DataFrame.query` are keyword-only (:issue:`47587`)
--
+- Removed :meth:`Index._get_attributes_dict` (:issue:`50648`)
+- Removed :meth:`Series.__array_wrap__` (:issue:`50648`)
 
 .. ---------------------------------------------------------------------------
 .. _whatsnew_200.performance:
diff --git a/pandas/_libs/lib.pyx b/pandas/_libs/lib.pyx
index 89e02ac0fa..176307ef27 100644
--- a/pandas/_libs/lib.pyx
+++ b/pandas/_libs/lib.pyx
@@ -2272,6 +2272,7 @@ def maybe_convert_numeric(
             if convert_empty or seen.coerce_numeric:
                 seen.saw_null()
                 floats[i] = complexes[i] = NaN
+                mask[i] = 1
             else:
                 raise ValueError("Empty string encountered")
         elif util.is_complex_object(val):
@@ -2328,6 +2329,7 @@ def maybe_convert_numeric(
 
                 seen.saw_null()
                 floats[i] = NaN
+                mask[i] = 1
 
     if seen.check_uint64_conflict():
         return (values, None)
diff --git a/pandas/core/arrays/datetimelike.py b/pandas/core/arrays/datetimelike.py
index 0b3249a5d8..1e829cc711 100644
--- a/pandas/core/arrays/datetimelike.py
+++ b/pandas/core/arrays/datetimelike.py
@@ -1971,6 +1971,9 @@ class TimelikeOps(DatetimeLikeArrayMixin):
         return dtype_to_unit(self.dtype)  # type: ignore[arg-type]
 
     def as_unit(self: TimelikeOpsT, unit: str) -> TimelikeOpsT:
+        if unit not in ["s", "ms", "us", "ns"]:
+            raise ValueError("Supported units are 's', 'ms', 'us', 'ns'")
+
         dtype = np.dtype(f"{self.dtype.kind}8[{unit}]")
         new_values = astype_overflowsafe(self._ndarray, dtype, round_ok=True)
 
diff --git a/pandas/core/arrays/interval.py b/pandas/core/arrays/interval.py
index 2672e96473..f47ab83b6b 100644
--- a/pandas/core/arrays/interval.py
+++ b/pandas/core/arrays/interval.py
@@ -1787,5 +1787,7 @@ def _maybe_convert_platform_interval(values) -> ArrayLike:
         values = extract_array(values, extract_numpy=True)
 
     if not hasattr(values, "dtype"):
-        return np.asarray(values)
+        values = np.asarray(values)
+        if is_integer_dtype(values) and values.dtype != np.int64:
+            values = values.astype(np.int64)
     return values
diff --git a/pandas/core/dtypes/cast.py b/pandas/core/dtypes/cast.py
index f3ce104aa4..b3f2426256 100644
--- a/pandas/core/dtypes/cast.py
+++ b/pandas/core/dtypes/cast.py
@@ -35,6 +35,7 @@ from pandas._typing import (
     ArrayLike,
     Dtype,
     DtypeObj,
+    NumpyIndexT,
     Scalar,
     npt,
 )
@@ -65,6 +66,7 @@ from pandas.core.dtypes.common import (
     is_numeric_dtype,
     is_object_dtype,
     is_scalar,
+    is_signed_integer_dtype,
     is_string_dtype,
     is_timedelta64_dtype,
     is_unsigned_integer_dtype,
@@ -412,6 +414,29 @@ def maybe_downcast_numeric(
     return result
 
 
+def maybe_upcast_numeric_to_64bit(arr: NumpyIndexT) -> NumpyIndexT:
+    """
+    If array is a int/uint/float bit size lower than 64 bit, upcast it to 64 bit.
+
+    Parameters
+    ----------
+    arr : ndarray or ExtensionArray
+
+    Returns
+    -------
+    ndarray or ExtensionArray
+    """
+    dtype = arr.dtype
+    if is_signed_integer_dtype(dtype) and dtype != np.int64:
+        return arr.astype(np.int64)
+    elif is_unsigned_integer_dtype(dtype) and dtype != np.uint64:
+        return arr.astype(np.uint64)
+    elif is_float_dtype(dtype) and dtype != np.float64:
+        return arr.astype(np.float64)
+    else:
+        return arr
+
+
 def maybe_cast_pointwise_result(
     result: ArrayLike,
     dtype: DtypeObj,
diff --git a/pandas/core/generic.py b/pandas/core/generic.py
index 561422c868..92c07cc985 100644
--- a/pandas/core/generic.py
+++ b/pandas/core/generic.py
@@ -2009,43 +2009,6 @@ class NDFrame(PandasObject, indexing.IndexingMixin):
     def __array__(self, dtype: npt.DTypeLike | None = None) -> np.ndarray:
         return np.asarray(self._values, dtype=dtype)
 
-    def __array_wrap__(
-        self,
-        result: np.ndarray,
-        context: tuple[Callable, tuple[Any, ...], int] | None = None,
-    ):
-        """
-        Gets called after a ufunc and other functions.
-
-        Parameters
-        ----------
-        result: np.ndarray
-            The result of the ufunc or other function called on the NumPy array
-            returned by __array__
-        context: tuple of (func, tuple, int)
-            This parameter is returned by ufuncs as a 3-element tuple: (name of the
-            ufunc, arguments of the ufunc, domain of the ufunc), but is not set by
-            other numpy functions.q
-
-        Notes
-        -----
-        Series implements __array_ufunc_ so this not called for ufunc on Series.
-        """
-        # Note: at time of dask 2022.01.0, this is still used by dask
-        warnings.warn(
-            "The __array_wrap__ method of DataFrame and Series will be removed in "
-            "a future version",
-            DeprecationWarning,
-            stacklevel=find_stack_level(),
-        )
-        res = lib.item_from_zerodim(result)
-        if is_scalar(res):
-            # e.g. we get here with np.ptp(series)
-            # ptp also requires the item_from_zerodim
-            return res
-        d = self._construct_axes_dict(self._AXIS_ORDERS, copy=False)
-        return self._constructor(res, **d).__finalize__(self, method="__array_wrap__")
-
     @final
     def __array_ufunc__(
         self, ufunc: np.ufunc, method: str, *inputs: Any, **kwargs: Any
diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py
index 775d137523..926880efa5 100644
--- a/pandas/core/indexes/base.py
+++ b/pandas/core/indexes/base.py
@@ -698,22 +698,6 @@ class Index(IndexOpsMixin, PandasObject):
     # --------------------------------------------------------------------
     # Index Internals Methods
 
-    @final
-    def _get_attributes_dict(self) -> dict[str_t, Any]:
-        """
-        Return an attributes dict for my class.
-
-        Temporarily added back for compatibility issue in dask, see
-        https://github.com/pandas-dev/pandas/pull/43895
-        """
-        warnings.warn(
-            "The Index._get_attributes_dict method is deprecated, and will be "
-            "removed in a future version",
-            DeprecationWarning,
-            stacklevel=find_stack_level(),
-        )
-        return {k: getattr(self, k, None) for k in self._attributes}
-
     def _shallow_copy(self: _IndexT, values, name: Hashable = no_default) -> _IndexT:
         """
         Create a new Index with the same class as the caller, don't copy the
diff --git a/pandas/core/indexes/datetimelike.py b/pandas/core/indexes/datetimelike.py
index fde000f84e..002b9832e9 100644
--- a/pandas/core/indexes/datetimelike.py
+++ b/pandas/core/indexes/datetimelike.py
@@ -396,6 +396,25 @@ class DatetimeTimedeltaMixin(DatetimeIndexOpsMixin):
 
     _join_precedence = 10
 
+    @property
+    def unit(self) -> str:
+        return self._data.unit
+
+    def as_unit(self: _TDT, unit: str) -> _TDT:
+        """
+        Convert to a dtype with the given unit resolution.
+
+        Parameters
+        ----------
+        unit : {'s', 'ms', 'us', 'ns'}
+
+        Returns
+        -------
+        same type as self
+        """
+        arr = self._data.as_unit(unit)
+        return type(self)._simple_new(arr, name=self.name)
+
     def _with_freq(self, freq):
         arr = self._data._with_freq(freq)
         return type(self)._simple_new(arr, name=self._name)
diff --git a/pandas/core/indexes/interval.py b/pandas/core/indexes/interval.py
index ae0b7dc511..c6bd7b8aae 100644
--- a/pandas/core/indexes/interval.py
+++ b/pandas/core/indexes/interval.py
@@ -44,6 +44,7 @@ from pandas.core.dtypes.cast import (
     infer_dtype_from_scalar,
     maybe_box_datetimelike,
     maybe_downcast_numeric,
+    maybe_upcast_numeric_to_64bit,
 )
 from pandas.core.dtypes.common import (
     ensure_platform_int,
@@ -59,8 +60,6 @@ from pandas.core.dtypes.common import (
     is_number,
     is_object_dtype,
     is_scalar,
-    is_signed_integer_dtype,
-    is_unsigned_integer_dtype,
 )
 from pandas.core.dtypes.dtypes import IntervalDtype
 from pandas.core.dtypes.missing import is_valid_na_for_dtype
@@ -342,8 +341,11 @@ class IntervalIndex(ExtensionIndex):
     # "Union[IndexEngine, ExtensionEngine]" in supertype "Index"
     @cache_readonly
     def _engine(self) -> IntervalTree:  # type: ignore[override]
+        # IntervalTree does not supports numpy array unless they are 64 bit
         left = self._maybe_convert_i8(self.left)
+        left = maybe_upcast_numeric_to_64bit(left)
         right = self._maybe_convert_i8(self.right)
+        right = maybe_upcast_numeric_to_64bit(right)
         return IntervalTree(left, right, closed=self.closed)
 
     def __contains__(self, key: Any) -> bool:
@@ -520,13 +522,12 @@ class IntervalIndex(ExtensionIndex):
             The original key if no conversion occurred, int if converted scalar,
             Int64Index if converted list-like.
         """
-        original = key
         if is_list_like(key):
             key = ensure_index(key)
-            key = self._maybe_convert_numeric_to_64bit(key)
+            key = maybe_upcast_numeric_to_64bit(key)
 
         if not self._needs_i8_conversion(key):
-            return original
+            return key
 
         scalar = is_scalar(key)
         if is_interval_dtype(key) or isinstance(key, Interval):
@@ -569,20 +570,6 @@ class IntervalIndex(ExtensionIndex):
 
         return key_i8
 
-    def _maybe_convert_numeric_to_64bit(self, idx: Index) -> Index:
-        # IntervalTree only supports 64 bit numpy array
-        dtype = idx.dtype
-        if np.issubclass_(dtype.type, np.number):
-            return idx
-        elif is_signed_integer_dtype(dtype) and dtype != np.int64:
-            return idx.astype(np.int64)
-        elif is_unsigned_integer_dtype(dtype) and dtype != np.uint64:
-            return idx.astype(np.uint64)
-        elif is_float_dtype(dtype) and dtype != np.float64:
-            return idx.astype(np.float64)
-        else:
-            return idx
-
     def _searchsorted_monotonic(self, label, side: Literal["left", "right"] = "left"):
         if not self.is_non_overlapping_monotonic:
             raise KeyError(
diff --git a/pandas/core/tools/numeric.py b/pandas/core/tools/numeric.py
index da47aa549d..a8ae8c47b0 100644
--- a/pandas/core/tools/numeric.py
+++ b/pandas/core/tools/numeric.py
@@ -13,11 +13,13 @@ from pandas._typing import (
 from pandas.core.dtypes.cast import maybe_downcast_numeric
 from pandas.core.dtypes.common import (
     ensure_object,
+    is_bool_dtype,
     is_datetime_or_timedelta_dtype,
     is_decimal,
     is_integer_dtype,
     is_number,
     is_numeric_dtype,
+    is_object_dtype,
     is_scalar,
     needs_i8_conversion,
 )
@@ -27,13 +29,14 @@ from pandas.core.dtypes.generic import (
 )
 
 import pandas as pd
-from pandas.core.arrays.numeric import NumericArray
+from pandas.core.arrays import BaseMaskedArray
 
 
 def to_numeric(
     arg,
     errors: DateTimeErrorChoices = "raise",
     downcast: Literal["integer", "signed", "unsigned", "float"] | None = None,
+    use_nullable_dtypes: bool = False,
 ):
     """
     Convert argument to a numeric type.
@@ -47,7 +50,7 @@ def to_numeric(
     numbers smaller than `-9223372036854775808` (np.iinfo(np.int64).min)
     or larger than `18446744073709551615` (np.iinfo(np.uint64).max) are
     passed in, it is very likely they will be converted to float so that
-    they can stored in an `ndarray`. These warnings apply similarly to
+    they can be stored in an `ndarray`. These warnings apply similarly to
     `Series` since it internally leverages `ndarray`.
 
     Parameters
@@ -78,6 +81,10 @@ def to_numeric(
         the dtype it is to be cast to, so if none of the dtypes
         checked satisfy that specification, no downcasting will be
         performed on the data.
+    use_nullable_dtypes : bool = False
+        Whether or not to use nullable dtypes as default when converting data. If
+        set to True, nullable dtypes are used for all dtypes that have a nullable
+        implementation, even if no nulls are present.
 
     Returns
     -------
@@ -178,11 +185,12 @@ def to_numeric(
     # GH33013: for IntegerArray & FloatingArray extract non-null values for casting
     # save mask to reconstruct the full array after casting
     mask: npt.NDArray[np.bool_] | None = None
-    if isinstance(values, NumericArray):
+    if isinstance(values, BaseMaskedArray):
         mask = values._mask
         values = values._data[~mask]
 
     values_dtype = getattr(values, "dtype", None)
+    new_mask: np.ndarray | None = None
     if is_numeric_dtype(values_dtype):
         pass
     elif is_datetime_or_timedelta_dtype(values_dtype):
@@ -191,13 +199,23 @@ def to_numeric(
         values = ensure_object(values)
         coerce_numeric = errors not in ("ignore", "raise")
         try:
-            values, _ = lib.maybe_convert_numeric(
-                values, set(), coerce_numeric=coerce_numeric
+            values, new_mask = lib.maybe_convert_numeric(  # type: ignore[call-overload]
+                values,
+                set(),
+                coerce_numeric=coerce_numeric,
+                convert_to_masked_nullable=use_nullable_dtypes,
             )
         except (ValueError, TypeError):
             if errors == "raise":
                 raise
 
+    if new_mask is not None:
+        # Remove unnecessary values, is expected later anyway and enables
+        # downcasting
+        values = values[~new_mask]
+    elif use_nullable_dtypes and new_mask is None:
+        new_mask = np.zeros(values.shape, dtype=np.bool_)
+
     # attempt downcast only if the data has been successfully converted
     # to a numerical dtype and if a downcast method has been specified
     if downcast is not None and is_numeric_dtype(values.dtype):
@@ -228,18 +246,31 @@ def to_numeric(
                     if values.dtype == dtype:
                         break
 
-    # GH33013: for IntegerArray & FloatingArray need to reconstruct masked array
-    if mask is not None:
+    # GH33013: for IntegerArray, BooleanArray & FloatingArray need to reconstruct
+    # masked array
+    if (mask is not None or new_mask is not None) and not is_object_dtype(values.dtype):
+        if mask is None:
+            mask = new_mask
+        else:
+            mask = mask.copy()
+        assert isinstance(mask, np.ndarray)
         data = np.zeros(mask.shape, dtype=values.dtype)
         data[~mask] = values
 
         from pandas.core.arrays import (
+            BooleanArray,
             FloatingArray,
             IntegerArray,
         )
 
-        klass = IntegerArray if is_integer_dtype(data.dtype) else FloatingArray
-        values = klass(data, mask.copy())
+        klass: type[IntegerArray] | type[BooleanArray] | type[FloatingArray]
+        if is_integer_dtype(data.dtype):
+            klass = IntegerArray
+        elif is_bool_dtype(data.dtype):
+            klass = BooleanArray
+        else:
+            klass = FloatingArray
+        values = klass(data, mask)
 
     if is_series:
         return arg._constructor(values, index=arg.index, name=arg.name)
diff --git a/pandas/plotting/_core.py b/pandas/plotting/_core.py
index 142a0fe3e1..2dc236a033 100644
--- a/pandas/plotting/_core.py
+++ b/pandas/plotting/_core.py
@@ -282,7 +282,7 @@ figsize : A tuple (width, height) in inches
     The size of the figure to create in matplotlib.
 layout : tuple (rows, columns), optional
     For example, (3, 5) will display the subplots
-    using 3 columns and 5 rows, starting from the top-left.
+    using 3 rows and 5 columns, starting from the top-left.
 return_type : {'axes', 'dict', 'both'} or None, default 'axes'
     The kind of object to return. The default is ``axes``.
 


Test patch:
diff --git a/pandas/tests/arrays/test_timedeltas.py b/pandas/tests/arrays/test_timedeltas.py
index b322a5b575..c8ff9c2402 100644
--- a/pandas/tests/arrays/test_timedeltas.py
+++ b/pandas/tests/arrays/test_timedeltas.py
@@ -29,6 +29,15 @@ class TestNonNano:
         assert tda.dtype == arr.dtype
         assert tda[0].unit == unit
 
+    def test_as_unit_raises(self, tda):
+        # GH#50616
+        with pytest.raises(ValueError, match="Supported units"):
+            tda.as_unit("D")
+
+        tdi = pd.Index(tda)
+        with pytest.raises(ValueError, match="Supported units"):
+            tdi.as_unit("D")
+
     @pytest.mark.parametrize("field", TimedeltaArray._field_ops)
     def test_fields(self, tda, field):
         as_nano = tda._ndarray.astype("m8[ns]")
diff --git a/pandas/tests/base/test_misc.py b/pandas/tests/base/test_misc.py
index a55c013a73..4df55aefdc 100644
--- a/pandas/tests/base/test_misc.py
+++ b/pandas/tests/base/test_misc.py
@@ -84,17 +84,6 @@ def test_ndarray_compat_properties(index_or_series_obj):
     assert Series([1]).item() == 1
 
 
-def test_array_wrap_compat():
-    # Note: at time of dask 2022.01.0, this is still used by eg dask
-    # (https://github.com/dask/dask/issues/8580).
-    # This test is a small dummy ensuring coverage
-    orig = Series([1, 2, 3], dtype="int64", index=["a", "b", "c"])
-    with tm.assert_produces_warning(DeprecationWarning):
-        result = orig.__array_wrap__(np.array([2, 4, 6], dtype="int64"))
-    expected = orig * 2
-    tm.assert_series_equal(result, expected)
-
-
 @pytest.mark.skipif(PYPY, reason="not relevant for PyPy")
 def test_memory_usage(index_or_series_obj):
     obj = index_or_series_obj
diff --git a/pandas/tests/indexes/datetimes/methods/test_snap.py b/pandas/tests/indexes/datetimes/methods/test_snap.py
index bceb37fdc9..7064e9e799 100644
--- a/pandas/tests/indexes/datetimes/methods/test_snap.py
+++ b/pandas/tests/indexes/datetimes/methods/test_snap.py
@@ -7,13 +7,6 @@ from pandas import (
 import pandas._testing as tm
 
 
-def astype_non_nano(dti_nano, unit):
-    # TODO(2.0): remove once DTI supports as_unit
-    dta = dti_nano._data.as_unit(unit)
-    dti = DatetimeIndex(dta, name=dti_nano.name)
-    return dti
-
-
 @pytest.mark.parametrize("tz", [None, "Asia/Shanghai", "Europe/Berlin"])
 @pytest.mark.parametrize("name", [None, "my_dti"])
 @pytest.mark.parametrize("unit", ["ns", "us", "ms", "s"])
@@ -32,12 +25,12 @@ def test_dti_snap(name, tz, unit):
         tz=tz,
         freq="D",
     )
-    dti = astype_non_nano(dti, unit)
+    dti = dti.as_unit(unit)
 
     result = dti.snap(freq="W-MON")
     expected = date_range("12/31/2001", "1/7/2002", name=name, tz=tz, freq="w-mon")
     expected = expected.repeat([3, 4])
-    expected = astype_non_nano(expected, unit)
+    expected = expected.as_unit(unit)
     tm.assert_index_equal(result, expected)
     assert result.tz == expected.tz
     assert result.freq is None
@@ -47,7 +40,7 @@ def test_dti_snap(name, tz, unit):
 
     expected = date_range("1/1/2002", "1/7/2002", name=name, tz=tz, freq="b")
     expected = expected.repeat([1, 1, 1, 2, 2])
-    expected = astype_non_nano(expected, unit)
+    expected = expected.as_unit(unit)
     tm.assert_index_equal(result, expected)
     assert result.tz == expected.tz
     assert result.freq is None
diff --git a/pandas/tests/indexes/interval/test_interval.py b/pandas/tests/indexes/interval/test_interval.py
index 98c21fad1f..aded8a9b59 100644
--- a/pandas/tests/indexes/interval/test_interval.py
+++ b/pandas/tests/indexes/interval/test_interval.py
@@ -415,27 +415,36 @@ class TestIntervalIndex:
         tm.assert_index_equal(result, expected)
 
     @pytest.mark.parametrize(
-        "breaks",
-        [np.arange(5, dtype="int64"), np.arange(5, dtype="float64")],
-        ids=lambda x: str(x.dtype),
+        "make_key",
+        [lambda breaks: breaks, list],
+        ids=["lambda", "list"],
     )
+    def test_maybe_convert_i8_numeric(self, make_key, any_real_numpy_dtype):
+        # GH 20636
+        breaks = np.arange(5, dtype=any_real_numpy_dtype)
+        index = IntervalIndex.from_breaks(breaks)
+        key = make_key(breaks)
+
+        result = index._maybe_convert_i8(key)
+        expected = Index(key)
+        tm.assert_index_equal(result, expected)
+
     @pytest.mark.parametrize(
         "make_key",
         [
             IntervalIndex.from_breaks,
             lambda breaks: Interval(breaks[0], breaks[1]),
-            lambda breaks: breaks,
             lambda breaks: breaks[0],
-            list,
         ],
-        ids=["IntervalIndex", "Interval", "Index", "scalar", "list"],
+        ids=["IntervalIndex", "Interval", "scalar"],
     )
-    def test_maybe_convert_i8_numeric(self, breaks, make_key):
+    def test_maybe_convert_i8_numeric_identical(self, make_key, any_real_numpy_dtype):
         # GH 20636
+        breaks = np.arange(5, dtype=any_real_numpy_dtype)
         index = IntervalIndex.from_breaks(breaks)
         key = make_key(breaks)
 
-        # no conversion occurs for numeric
+        # test if _maybe_convert_i8 won't change key if an Interval or IntervalIndex
         result = index._maybe_convert_i8(key)
         assert result is key
 
diff --git a/pandas/tests/indexes/test_base.py b/pandas/tests/indexes/test_base.py
index 969c6059b8..cf3a9fcc8c 100644
--- a/pandas/tests/indexes/test_base.py
+++ b/pandas/tests/indexes/test_base.py
@@ -1605,14 +1605,6 @@ def test_construct_from_memoryview(klass, extra_kwargs):
     tm.assert_index_equal(result, expected, exact=True)
 
 
-def test_get_attributes_dict_deprecated():
-    # https://github.com/pandas-dev/pandas/pull/44028
-    idx = Index([1, 2, 3, 1])
-    with tm.assert_produces_warning(DeprecationWarning):
-        attrs = idx._get_attributes_dict()
-    assert attrs == {"name": None}
-
-
 @pytest.mark.parametrize("op", [operator.lt, operator.gt])
 def test_nan_comparison_same_object(op):
     # GH#47105
diff --git a/pandas/tests/series/test_constructors.py b/pandas/tests/series/test_constructors.py
index f856f18552..e1f59e610a 100644
--- a/pandas/tests/series/test_constructors.py
+++ b/pandas/tests/series/test_constructors.py
@@ -1587,9 +1587,8 @@ class TestSeriesConstructors:
         ser = Series(arr)
         assert ser.dtype == arr.dtype
 
-        tdi = timedelta_range("00:00:01", periods=3, freq="s")
-        tda = tdi._data.as_unit("s")
-        expected = Series(tda)
+        tdi = timedelta_range("00:00:01", periods=3, freq="s").as_unit("s")
+        expected = Series(tdi)
         assert expected.dtype == arr.dtype
         tm.assert_series_equal(ser, expected)
 
diff --git a/pandas/tests/test_downstream.py b/pandas/tests/test_downstream.py
index 2287110b63..5192b3d4ca 100644
--- a/pandas/tests/test_downstream.py
+++ b/pandas/tests/test_downstream.py
@@ -58,11 +58,7 @@ def test_dask(df):
         pd.set_option("compute.use_numexpr", olduse)
 
 
-@pytest.mark.filterwarnings("ignore:The __array_wrap__:DeprecationWarning")
 def test_dask_ufunc():
-    # At the time of dask 2022.01.0, dask is still directly using __array_wrap__
-    # for some ufuncs (https://github.com/dask/dask/issues/8580).
-
     # dask sets "compute.use_numexpr" to False, so catch the current value
     # and ensure to reset it afterwards to avoid impacting other tests
     olduse = pd.get_option("compute.use_numexpr")
diff --git a/pandas/tests/tools/test_to_numeric.py b/pandas/tests/tools/test_to_numeric.py
index 1347f6eb50..1c0a8301d6 100644
--- a/pandas/tests/tools/test_to_numeric.py
+++ b/pandas/tests/tools/test_to_numeric.py
@@ -807,3 +807,72 @@ def test_to_numeric_large_float_not_downcast_to_float_32(val):
     expected = Series([val])
     result = to_numeric(expected, downcast="float")
     tm.assert_series_equal(result, expected)
+
+
+@pytest.mark.parametrize(
+    "val, dtype", [(1, "Int64"), (1.5, "Float64"), (True, "boolean")]
+)
+def test_to_numeric_use_nullable_dtypes(val, dtype):
+    # GH#50505
+    ser = Series([val], dtype=object)
+    result = to_numeric(ser, use_nullable_dtypes=True)
+    expected = Series([val], dtype=dtype)
+    tm.assert_series_equal(result, expected)
+
+
+@pytest.mark.parametrize(
+    "val, dtype", [(1, "Int64"), (1.5, "Float64"), (True, "boolean")]
+)
+def test_to_numeric_use_nullable_dtypes_na(val, dtype):
+    # GH#50505
+    ser = Series([val, None], dtype=object)
+    result = to_numeric(ser, use_nullable_dtypes=True)
+    expected = Series([val, pd.NA], dtype=dtype)
+    tm.assert_series_equal(result, expected)
+
+
+@pytest.mark.parametrize(
+    "val, dtype, downcast",
+    [(1, "Int8", "integer"), (1.5, "Float32", "float"), (1, "Int8", "signed")],
+)
+def test_to_numeric_use_nullable_dtypes_downcasting(val, dtype, downcast):
+    # GH#50505
+    ser = Series([val, None], dtype=object)
+    result = to_numeric(ser, use_nullable_dtypes=True, downcast=downcast)
+    expected = Series([val, pd.NA], dtype=dtype)
+    tm.assert_series_equal(result, expected)
+
+
+def test_to_numeric_use_nullable_dtypes_downcasting_uint():
+    # GH#50505
+    ser = Series([1, pd.NA], dtype="UInt64")
+    result = to_numeric(ser, use_nullable_dtypes=True, downcast="unsigned")
+    expected = Series([1, pd.NA], dtype="UInt8")
+    tm.assert_series_equal(result, expected)
+
+
+@pytest.mark.parametrize("dtype", ["Int64", "UInt64", "Float64", "boolean"])
+def test_to_numeric_use_nullable_dtypes_already_nullable(dtype):
+    # GH#50505
+    ser = Series([1, pd.NA], dtype=dtype)
+    result = to_numeric(ser, use_nullable_dtypes=True)
+    expected = Series([1, pd.NA], dtype=dtype)
+    tm.assert_series_equal(result, expected)
+
+
+@pytest.mark.parametrize(
+    "use_nullable_dtypes, dtype", [(True, "Float64"), (False, "float64")]
+)
+def test_to_numeric_use_nullable_dtypes_error(use_nullable_dtypes, dtype):
+    # GH#50505
+    ser = Series(["a", "b", ""])
+    expected = ser.copy()
+    with pytest.raises(ValueError, match="Unable to parse string"):
+        to_numeric(ser, use_nullable_dtypes=use_nullable_dtypes)
+
+    result = to_numeric(ser, use_nullable_dtypes=use_nullable_dtypes, errors="ignore")
+    tm.assert_series_equal(result, expected)
+
+    result = to_numeric(ser, use_nullable_dtypes=use_nullable_dtypes, errors="coerce")
+    expected = Series([np.nan, np.nan, np.nan], dtype=dtype)
+    tm.assert_series_equal(result, expected)