diff --git a/doc/source/reference/extensions.rst b/doc/source/reference/extensions.rst index 374e1395b42f7..c072237850d82 100644 --- a/doc/source/reference/extensions.rst +++ b/doc/source/reference/extensions.rst @@ -69,6 +69,6 @@ behaves correctly. api.indexers.check_bool_array_indexer -The sentinel ``pandas.api.extensions._no_default`` is used as the default +The sentinel ``pandas.api.extensions.no_default`` is used as the default value in some methods. Use an ``is`` comparison to check if the user provides a non-default value. diff --git a/pandas/_libs/lib.pyx b/pandas/_libs/lib.pyx index f88989b5e8d0e..2b8ba06aa8a82 100644 --- a/pandas/_libs/lib.pyx +++ b/pandas/_libs/lib.pyx @@ -2232,14 +2232,14 @@ def maybe_convert_objects(ndarray[object] objects, bint try_float=0, return objects -# Note: _no_default is exported to the public API in pandas.api.extensions -_no_default = object() #: Sentinel indicating the default value. +# Note: no_default is exported to the public API in pandas.api.extensions +no_default = object() #: Sentinel indicating the default value. @cython.boundscheck(False) @cython.wraparound(False) def map_infer_mask(ndarray arr, object f, const uint8_t[:] mask, bint convert=1, - object na_value=_no_default, object dtype=object): + object na_value=no_default, object dtype=object): """ Substitute for np.vectorize with pandas-friendly dtype inference. @@ -2270,7 +2270,7 @@ def map_infer_mask(ndarray arr, object f, const uint8_t[:] mask, bint convert=1, result = np.empty(n, dtype=dtype) for i in range(n): if mask[i]: - if na_value is _no_default: + if na_value is no_default: val = arr[i] else: val = na_value diff --git a/pandas/api/extensions/__init__.py b/pandas/api/extensions/__init__.py index 1f782e10396e3..a7e84bb046e61 100644 --- a/pandas/api/extensions/__init__.py +++ b/pandas/api/extensions/__init__.py @@ -1,5 +1,5 @@ """Public API for extending pandas objects.""" -from pandas._libs.lib import _no_default # noqa: F401 +from pandas._libs.lib import no_default # noqa: F401 from pandas.core.dtypes.dtypes import ( # noqa: F401 ExtensionDtype, diff --git a/pandas/core/arrays/base.py b/pandas/core/arrays/base.py index 1be6f5886cb75..9723343ea7af5 100644 --- a/pandas/core/arrays/base.py +++ b/pandas/core/arrays/base.py @@ -351,7 +351,7 @@ def __iter__(self): for i in range(len(self)): yield self[i] - def to_numpy(self, dtype=None, copy=False, na_value=lib._no_default): + def to_numpy(self, dtype=None, copy=False, na_value=lib.no_default): """ Convert to a NumPy ndarray. @@ -378,9 +378,9 @@ def to_numpy(self, dtype=None, copy=False, na_value=lib._no_default): numpy.ndarray """ result = np.asarray(self, dtype=dtype) - if copy or na_value is not lib._no_default: + if copy or na_value is not lib.no_default: result = result.copy() - if na_value is not lib._no_default: + if na_value is not lib.no_default: result[self.isna()] = na_value return result diff --git a/pandas/core/arrays/boolean.py b/pandas/core/arrays/boolean.py index 9ef1c4b1bbb1c..3ba632660a325 100644 --- a/pandas/core/arrays/boolean.py +++ b/pandas/core/arrays/boolean.py @@ -317,7 +317,7 @@ def __getitem__(self, item): return type(self)(self._data[item], self._mask[item]) def to_numpy( - self, dtype=None, copy=False, na_value: "Scalar" = lib._no_default, + self, dtype=None, copy=False, na_value: "Scalar" = lib.no_default, ): """ Convert to a NumPy Array. @@ -377,7 +377,7 @@ def to_numpy( >>> a.to_numpy(dtype="bool", na_value=False) array([ True, False, False]) """ - if na_value is lib._no_default: + if na_value is lib.no_default: na_value = libmissing.NA if dtype is None: dtype = object diff --git a/pandas/core/arrays/integer.py b/pandas/core/arrays/integer.py index 0922f4ac6f71d..337ff7f448586 100644 --- a/pandas/core/arrays/integer.py +++ b/pandas/core/arrays/integer.py @@ -376,16 +376,16 @@ def __getitem__(self, item): return type(self)(self._data[item], self._mask[item]) - def _coerce_to_ndarray(self, dtype=None, na_value=lib._no_default): + def _coerce_to_ndarray(self, dtype=None, na_value=lib.no_default): """ coerce to an ndarary of object dtype """ if dtype is None: dtype = object - if na_value is lib._no_default and is_float_dtype(dtype): + if na_value is lib.no_default and is_float_dtype(dtype): na_value = np.nan - elif na_value is lib._no_default: + elif na_value is lib.no_default: na_value = libmissing.NA if is_integer_dtype(dtype): diff --git a/pandas/core/arrays/numpy_.py b/pandas/core/arrays/numpy_.py index ec6f9278f6bf7..55499291d3f4a 100644 --- a/pandas/core/arrays/numpy_.py +++ b/pandas/core/arrays/numpy_.py @@ -421,13 +421,13 @@ def skew(self, axis=None, dtype=None, out=None, keepdims=False, skipna=True): # ------------------------------------------------------------------------ # Additional Methods - def to_numpy(self, dtype=None, copy=False, na_value=lib._no_default): + def to_numpy(self, dtype=None, copy=False, na_value=lib.no_default): result = np.asarray(self._ndarray, dtype=dtype) - if (copy or na_value is not lib._no_default) and result is self._ndarray: + if (copy or na_value is not lib.no_default) and result is self._ndarray: result = result.copy() - if na_value is not lib._no_default: + if na_value is not lib.no_default: result[self.isna()] = na_value return result diff --git a/pandas/core/base.py b/pandas/core/base.py index 319ca142fc041..66d7cd59dcfa4 100644 --- a/pandas/core/base.py +++ b/pandas/core/base.py @@ -768,7 +768,7 @@ def array(self) -> ExtensionArray: return result - def to_numpy(self, dtype=None, copy=False, na_value=lib._no_default, **kwargs): + def to_numpy(self, dtype=None, copy=False, na_value=lib.no_default, **kwargs): """ A NumPy ndarray representing the values in this Series or Index. @@ -874,9 +874,9 @@ def to_numpy(self, dtype=None, copy=False, na_value=lib._no_default, **kwargs): result = np.asarray(self._values, dtype=dtype) # TODO(GH-24345): Avoid potential double copy - if copy or na_value is not lib._no_default: + if copy or na_value is not lib.no_default: result = result.copy() - if na_value is not lib._no_default: + if na_value is not lib.no_default: result[self.isna()] = na_value return result diff --git a/pandas/core/computation/eval.py b/pandas/core/computation/eval.py index 72a0fda9098fd..51892b8c02d87 100644 --- a/pandas/core/computation/eval.py +++ b/pandas/core/computation/eval.py @@ -8,7 +8,7 @@ from typing import Optional import warnings -from pandas._libs.lib import _no_default +from pandas._libs.lib import no_default from pandas.util._validators import validate_bool_kwarg from pandas.core.computation.engines import _engines @@ -171,7 +171,7 @@ def eval( expr, parser="pandas", engine: Optional[str] = None, - truediv=_no_default, + truediv=no_default, local_dict=None, global_dict=None, resolvers=(), @@ -288,7 +288,7 @@ def eval( inplace = validate_bool_kwarg(inplace, "inplace") - if truediv is not _no_default: + if truediv is not no_default: warnings.warn( "The `truediv` parameter in pd.eval is deprecated and will be " "removed in a future version.", diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 1edcf581c5131..24c794cd710a9 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -106,10 +106,6 @@ Name or list of names to sort by""", ) -# sentinel value to use as kwarg in place of None when None has special meaning -# and needs to be distinguished from a user explicitly passing None. -sentinel = object() - def _single_replace(self, to_replace, method, inplace, limit): """ @@ -1086,7 +1082,7 @@ def rename(self, *args, **kwargs): return result.__finalize__(self) @rewrite_axis_style_signature("mapper", [("copy", True), ("inplace", False)]) - def rename_axis(self, mapper=sentinel, **kwargs): + def rename_axis(self, mapper=lib.no_default, **kwargs): """ Set the name of the axis for the index or columns. @@ -1211,7 +1207,7 @@ class name monkey 2 2 """ axes, kwargs = self._construct_axes_from_arguments( - (), kwargs, sentinel=sentinel + (), kwargs, sentinel=lib.no_default ) copy = kwargs.pop("copy", True) inplace = kwargs.pop("inplace", False) @@ -1227,7 +1223,7 @@ class name inplace = validate_bool_kwarg(inplace, "inplace") - if mapper is not sentinel: + if mapper is not lib.no_default: # Use v0.23 behavior if a scalar or list non_mapper = is_scalar(mapper) or ( is_list_like(mapper) and not is_dict_like(mapper) @@ -1243,7 +1239,7 @@ class name for axis in range(self._AXIS_LEN): v = axes.get(self._AXIS_NAMES[axis]) - if v is sentinel: + if v is lib.no_default: continue non_mapper = is_scalar(v) or (is_list_like(v) and not is_dict_like(v)) if non_mapper: diff --git a/pandas/core/indexes/datetimes.py b/pandas/core/indexes/datetimes.py index c2edfd53e1207..88b841e7d4a88 100644 --- a/pandas/core/indexes/datetimes.py +++ b/pandas/core/indexes/datetimes.py @@ -421,7 +421,7 @@ def _get_time_micros(self): values = self._data._local_timestamps() return fields.get_time_micros(values) - def to_series(self, keep_tz=lib._no_default, index=None, name=None): + def to_series(self, keep_tz=lib.no_default, index=None, name=None): """ Create a Series with both index and values equal to the index keys useful with map for returning an indexer based on an index. @@ -466,7 +466,7 @@ def to_series(self, keep_tz=lib._no_default, index=None, name=None): if name is None: name = self.name - if keep_tz is not lib._no_default: + if keep_tz is not lib.no_default: if keep_tz: warnings.warn( "The 'keep_tz' keyword in DatetimeIndex.to_series " diff --git a/pandas/core/indexes/multi.py b/pandas/core/indexes/multi.py index db9806a046305..ea8d4d2329d09 100644 --- a/pandas/core/indexes/multi.py +++ b/pandas/core/indexes/multi.py @@ -61,8 +61,6 @@ dict(klass="MultiIndex", target_klass="MultiIndex or list of tuples") ) -_no_default_names = object() - class MultiIndexUIntEngine(libindex.BaseMultiIndexCodesEngine, libindex.UInt64Engine): """ @@ -373,7 +371,7 @@ def _verify_integrity( return new_codes @classmethod - def from_arrays(cls, arrays, sortorder=None, names=_no_default_names): + def from_arrays(cls, arrays, sortorder=None, names=lib.no_default): """ Convert arrays to MultiIndex. @@ -427,7 +425,7 @@ def from_arrays(cls, arrays, sortorder=None, names=_no_default_names): raise ValueError("all arrays must be same length") codes, levels = factorize_from_iterables(arrays) - if names is _no_default_names: + if names is lib.no_default: names = [getattr(arr, "name", None) for arr in arrays] return MultiIndex( @@ -497,7 +495,7 @@ def from_tuples(cls, tuples, sortorder=None, names=None): return MultiIndex.from_arrays(arrays, sortorder=sortorder, names=names) @classmethod - def from_product(cls, iterables, sortorder=None, names=_no_default_names): + def from_product(cls, iterables, sortorder=None, names=lib.no_default): """ Make a MultiIndex from the cartesian product of multiple iterables. @@ -548,7 +546,7 @@ def from_product(cls, iterables, sortorder=None, names=_no_default_names): iterables = list(iterables) codes, levels = factorize_from_iterables(iterables) - if names is _no_default_names: + if names is lib.no_default: names = [getattr(it, "name", None) for it in iterables] codes = cartesian_product(codes) diff --git a/pandas/io/formats/html.py b/pandas/io/formats/html.py index 020b4952f5549..b46b2f6c671d6 100644 --- a/pandas/io/formats/html.py +++ b/pandas/io/formats/html.py @@ -7,6 +7,8 @@ from pandas._config import get_option +from pandas._libs import lib + from pandas.core.dtypes.generic import ABCMultiIndex from pandas import option_context @@ -245,7 +247,7 @@ def _write_col_header(self, indent: int) -> None: if self.fmt.sparsify: # GH3547 - sentinel = object() + sentinel = lib.no_default else: sentinel = False levels = self.columns.format(sparsify=sentinel, adjoin=False, names=False) @@ -451,7 +453,7 @@ def _write_hierarchical_rows( if self.fmt.sparsify: # GH3547 - sentinel = object() + sentinel = lib.no_default levels = frame.index.format(sparsify=sentinel, adjoin=False, names=False) level_lengths = get_level_lengths(levels, sentinel) diff --git a/pandas/io/formats/style.py b/pandas/io/formats/style.py index 30d850faddd9f..8570875569e44 100644 --- a/pandas/io/formats/style.py +++ b/pandas/io/formats/style.py @@ -15,6 +15,7 @@ from pandas._config import get_option +from pandas._libs import lib from pandas.compat._optional import import_optional_dependency from pandas.util._decorators import Appender @@ -1475,8 +1476,7 @@ def _get_level_lengths(index, hidden_elements=None): Result is a dictionary of (level, initial_position): span """ - sentinel = object() - levels = index.format(sparsify=sentinel, adjoin=False, names=False) + levels = index.format(sparsify=lib.no_default, adjoin=False, names=False) if hidden_elements is None: hidden_elements = [] @@ -1492,10 +1492,10 @@ def _get_level_lengths(index, hidden_elements=None): for j, row in enumerate(lvl): if not get_option("display.multi_sparse"): lengths[(i, j)] = 1 - elif (row != sentinel) and (j not in hidden_elements): + elif (row is not lib.no_default) and (j not in hidden_elements): last_label = j lengths[(i, last_label)] = 1 - elif row != sentinel: + elif row is not lib.no_default: # even if its hidden, keep track of it in case # length >1 and later elements are visible last_label = j diff --git a/pandas/tests/extension/decimal/array.py b/pandas/tests/extension/decimal/array.py index b67703c7f80e0..85bd5f7a33fe1 100644 --- a/pandas/tests/extension/decimal/array.py +++ b/pandas/tests/extension/decimal/array.py @@ -5,12 +5,10 @@ import numpy as np -from pandas._libs import lib - from pandas.core.dtypes.base import ExtensionDtype import pandas as pd -from pandas.api.extensions import register_extension_dtype +from pandas.api.extensions import no_default, register_extension_dtype from pandas.core.arrays import ExtensionArray, ExtensionScalarOpsMixin @@ -86,7 +84,7 @@ def _from_factorized(cls, values, original): _HANDLED_TYPES = (decimal.Decimal, numbers.Number, np.ndarray) - def to_numpy(self, dtype=None, copy=False, na_value=lib._no_default, decimals=None): + def to_numpy(self, dtype=None, copy=False, na_value=no_default, decimals=None): result = np.asarray(self, dtype=dtype) if decimals is not None: result = np.asarray([round(x, decimals) for x in result])