diff --git a/doc/source/reference/groupby.rst b/doc/source/reference/groupby.rst index 8374b0c739f89..771163ae1b0bc 100644 --- a/doc/source/reference/groupby.rst +++ b/doc/source/reference/groupby.rst @@ -7,7 +7,9 @@ GroupBy ======= .. currentmodule:: pandas.core.groupby -GroupBy objects are returned by groupby calls: :func:`pandas.DataFrame.groupby`, :func:`pandas.Series.groupby`, etc. +:class:`pandas.api.typing.DataFrameGroupBy` and :class:`pandas.api.typing.SeriesGroupBy` +instances are returned by groupby calls :func:`pandas.DataFrame.groupby` and +:func:`pandas.Series.groupby` respectively. Indexing, iteration ------------------- diff --git a/doc/source/reference/index.rst b/doc/source/reference/index.rst index 37cb6767f760e..bc1202b3d5554 100644 --- a/doc/source/reference/index.rst +++ b/doc/source/reference/index.rst @@ -9,11 +9,24 @@ API reference This page gives an overview of all public pandas objects, functions and methods. All classes and functions exposed in ``pandas.*`` namespace are public. -Some subpackages are public which include ``pandas.errors``, -``pandas.plotting``, and ``pandas.testing``. Public functions in -``pandas.io`` and ``pandas.tseries`` submodules are mentioned in -the documentation. ``pandas.api.types`` subpackage holds some -public functions related to data types in pandas. +The following subpackages are public. + + - ``pandas.errors``: Custom exception and warnings classes that are raised by pandas. + - ``pandas.plotting``: Plotting public API. + - ``pandas.testing``: Functions that are useful for writing tests involving pandas objects. + - ``pandas.api.extensions``: Functions and classes for extending pandas objects. + - ``pandas.api.indexers``: Functions and classes for rolling window indexers. + - ``pandas.api.interchange``: DataFrame interchange protocol. + - ``pandas.api.types``: Datatype classes and functions. + - ``pandas.api.typing``: Classes that may be necessary for type-hinting. These are + classes that are encountered as intermediate results but should not be + instantiated directly by users. These classes are not to be confused with + classes from the `pandas-stubs `_ + package which has classes in addition to those that occur in pandas for type-hinting. + +In addition, public functions in ``pandas.io`` and ``pandas.tseries`` submodules +are mentioned in the documentation. + .. warning:: diff --git a/doc/source/reference/resampling.rst b/doc/source/reference/resampling.rst index e0228481e6ed4..edbc8090fc849 100644 --- a/doc/source/reference/resampling.rst +++ b/doc/source/reference/resampling.rst @@ -7,7 +7,8 @@ Resampling ========== .. currentmodule:: pandas.core.resample -Resampler objects are returned by resample calls: :func:`pandas.DataFrame.resample`, :func:`pandas.Series.resample`. +:class:`pandas.api.typing.Resampler` instances are returned by +resample calls: :func:`pandas.DataFrame.resample`, :func:`pandas.Series.resample`. Indexing, iteration ~~~~~~~~~~~~~~~~~~~ diff --git a/doc/source/reference/window.rst b/doc/source/reference/window.rst index 0839bb2e52efd..14af2b8a120e0 100644 --- a/doc/source/reference/window.rst +++ b/doc/source/reference/window.rst @@ -6,9 +6,12 @@ Window ====== -Rolling objects are returned by ``.rolling`` calls: :func:`pandas.DataFrame.rolling` and :func:`pandas.Series.rolling`. -Expanding objects are returned by ``.expanding`` calls: :func:`pandas.DataFrame.expanding` and :func:`pandas.Series.expanding`. -ExponentialMovingWindow objects are returned by ``.ewm`` calls: :func:`pandas.DataFrame.ewm` and :func:`pandas.Series.ewm`. +:class:`pandas.api.typing.Rolling` instances are returned by ``.rolling`` calls: +:func:`pandas.DataFrame.rolling` and :func:`pandas.Series.rolling`. +:class:`pandas.api.typing.Expanding` instances are returned by ``.expanding`` calls: +:func:`pandas.DataFrame.expanding` and :func:`pandas.Series.expanding`. +:class:`pandas.api.typing.ExponentialMovingWindow` instances are returned by ``.ewm`` +calls: :func:`pandas.DataFrame.ewm` and :func:`pandas.Series.ewm`. .. _api.functions_rolling: diff --git a/doc/source/user_guide/groupby.rst b/doc/source/user_guide/groupby.rst index 6585ea158e9e9..f74012cf51d4a 100644 --- a/doc/source/user_guide/groupby.rst +++ b/doc/source/user_guide/groupby.rst @@ -128,6 +128,7 @@ consider the following ``DataFrame``: df On a DataFrame, we obtain a GroupBy object by calling :meth:`~DataFrame.groupby`. +This method returns a ``pandas.api.typing.DataFrameGroupBy`` instance. We could naturally group by either the ``A`` or ``B`` columns, or both: .. ipython:: python @@ -1419,8 +1420,9 @@ Groupby a specific column with the desired frequency. This is like resampling. df.groupby([pd.Grouper(freq="1M", key="Date"), "Buyer"])[["Quantity"]].sum() -You have an ambiguous specification in that you have a named index and a column -that could be potential groupers. +When ``freq`` is specified, the object returned by ``pd.Grouper`` will be an +instance of ``pandas.api.typing.TimeGrouper``. You have an ambiguous specification +in that you have a named index and a column that could be potential groupers. .. ipython:: python diff --git a/doc/source/user_guide/io.rst b/doc/source/user_guide/io.rst index dd6ea6eccc85c..c34d5f3c467a2 100644 --- a/doc/source/user_guide/io.rst +++ b/doc/source/user_guide/io.rst @@ -2069,7 +2069,7 @@ is ``None``. To explicitly force ``Series`` parsing, pass ``typ=series`` seconds, milliseconds, microseconds or nanoseconds respectively. * ``lines`` : reads file as one json object per line. * ``encoding`` : The encoding to use to decode py3 bytes. -* ``chunksize`` : when used in combination with ``lines=True``, return a JsonReader which reads in ``chunksize`` lines per iteration. +* ``chunksize`` : when used in combination with ``lines=True``, return a ``pandas.api.typing.JsonReader`` which reads in ``chunksize`` lines per iteration. * ``engine``: Either ``"ujson"``, the built-in JSON parser, or ``"pyarrow"`` which dispatches to pyarrow's ``pyarrow.json.read_json``. The ``"pyarrow"`` is only available when ``lines=True`` @@ -5991,7 +5991,7 @@ Reading from Stata format ''''''''''''''''''''''''' The top-level function ``read_stata`` will read a dta file and return -either a ``DataFrame`` or a :class:`~pandas.io.stata.StataReader` that can +either a ``DataFrame`` or a :class:`pandas.api.typing.StataReader` that can be used to read the file incrementally. .. ipython:: python @@ -5999,7 +5999,7 @@ be used to read the file incrementally. pd.read_stata("stata.dta") Specifying a ``chunksize`` yields a -:class:`~pandas.io.stata.StataReader` instance that can be used to +:class:`pandas.api.typing.StataReader` instance that can be used to read ``chunksize`` lines from the file at a time. The ``StataReader`` object can be used as an iterator. diff --git a/doc/source/user_guide/timeseries.rst b/doc/source/user_guide/timeseries.rst index 2c93efb128613..0b73a7aea8b10 100644 --- a/doc/source/user_guide/timeseries.rst +++ b/doc/source/user_guide/timeseries.rst @@ -1750,8 +1750,9 @@ We can instead only resample those groups where we have points as follows: Aggregation ~~~~~~~~~~~ -Similar to the :ref:`aggregating API `, :ref:`groupby API `, and the :ref:`window API `, -a ``Resampler`` can be selectively resampled. +The ``resample()`` method returns a ``pandas.api.typing.Resampler`` instance. Similar to +the :ref:`aggregating API `, :ref:`groupby API `, +and the :ref:`window API `, a ``Resampler`` can be selectively resampled. Resampling a ``DataFrame``, the default will be to act on all columns with the same function. diff --git a/doc/source/user_guide/window.rst b/doc/source/user_guide/window.rst index e08fa81c5fa09..99e57cacca05a 100644 --- a/doc/source/user_guide/window.rst +++ b/doc/source/user_guide/window.rst @@ -37,14 +37,14 @@ pandas supports 4 types of windowing operations: #. Expanding window: Accumulating window over the values. #. Exponentially Weighted window: Accumulating and exponentially weighted window over the values. -============================= ================= =========================== =========================== ======================== =================================== =========================== -Concept Method Returned Object Supports time-based windows Supports chained groupby Supports table method Supports online operations -============================= ================= =========================== =========================== ======================== =================================== =========================== -Rolling window ``rolling`` ``Rolling`` Yes Yes Yes (as of version 1.3) No -Weighted window ``rolling`` ``Window`` No No No No -Expanding window ``expanding`` ``Expanding`` No Yes Yes (as of version 1.3) No -Exponentially Weighted window ``ewm`` ``ExponentialMovingWindow`` No Yes (as of version 1.2) No Yes (as of version 1.3) -============================= ================= =========================== =========================== ======================== =================================== =========================== +============================= ================= ============================================= =========================== ======================== =================================== =========================== +Concept Method Returned Object Supports time-based windows Supports chained groupby Supports table method Supports online operations +============================= ================= ============================================= =========================== ======================== =================================== =========================== +Rolling window ``rolling`` ``pandas.typing.api.Rolling`` Yes Yes Yes (as of version 1.3) No +Weighted window ``rolling`` ``pandas.typing.api.Window`` No No No No +Expanding window ``expanding`` ``pandas.typing.api.Expanding`` No Yes Yes (as of version 1.3) No +Exponentially Weighted window ``ewm`` ``pandas.typing.api.ExponentialMovingWindow`` No Yes (as of version 1.2) No Yes (as of version 1.3) +============================= ================= ============================================= =========================== ======================== =================================== =========================== As noted above, some operations support specifying a window based on a time offset: diff --git a/doc/source/whatsnew/v2.1.0.rst b/doc/source/whatsnew/v2.1.0.rst index 4c1399a0defe7..cb1792c626b55 100644 --- a/doc/source/whatsnew/v2.1.0.rst +++ b/doc/source/whatsnew/v2.1.0.rst @@ -86,6 +86,7 @@ Other enhancements - Add dtype of categories to ``repr`` information of :class:`CategoricalDtype` (:issue:`52179`) - Added to the escape mode "latex-math" preserving without escaping all characters between "\(" and "\)" in formatter (:issue:`51903`) - Adding ``engine_kwargs`` parameter to :meth:`DataFrame.read_excel` (:issue:`52214`) +- Classes that are useful for type-hinting have been added to the public API in the new submodule ``pandas.api.typing`` (:issue:`48577`) - Implemented ``__from_arrow__`` on :class:`DatetimeTZDtype`. (:issue:`52201`) - Implemented ``__pandas_priority__`` to allow custom types to take precedence over :class:`DataFrame`, :class:`Series`, :class:`Index`, or :class:`ExtensionArray` for arithmetic operations, :ref:`see the developer guide ` (:issue:`48347`) - Improve error message when having incompatible columns using :meth:`DataFrame.merge` (:issue:`51861`) diff --git a/pandas/api/__init__.py b/pandas/api/__init__.py index 9d4f721225d93..a0d42b6541fdf 100644 --- a/pandas/api/__init__.py +++ b/pandas/api/__init__.py @@ -4,6 +4,7 @@ indexers, interchange, types, + typing, ) __all__ = [ @@ -11,4 +12,5 @@ "extensions", "indexers", "types", + "typing", ] diff --git a/pandas/api/typing/__init__.py b/pandas/api/typing/__init__.py new file mode 100644 index 0000000000000..4c535bf81d3b6 --- /dev/null +++ b/pandas/api/typing/__init__.py @@ -0,0 +1,50 @@ +""" +Public API classes that store intermediate results useful for type-hinting. +""" + +from pandas.core.groupby import ( + DataFrameGroupBy, + SeriesGroupBy, +) +from pandas.core.resample import ( + DatetimeIndexResamplerGroupby, + PeriodIndexResamplerGroupby, + Resampler, + TimedeltaIndexResamplerGroupby, + TimeGrouper, +) +from pandas.core.window import ( + Expanding, + ExpandingGroupby, + ExponentialMovingWindow, + ExponentialMovingWindowGroupby, + Rolling, + RollingGroupby, + Window, +) + +# TODO: Can't import Styler without importing jinja2 +# from pandas.io.formats.style import Styler +from pandas.io.json._json import JsonReader +from pandas.io.stata import StataReader + +__all__ = [ + "DataFrameGroupBy", + "DatetimeIndexResamplerGroupby", + "Expanding", + "ExpandingGroupby", + "ExponentialMovingWindow", + "ExponentialMovingWindowGroupby", + "JsonReader", + "PeriodIndexResamplerGroupby", + "Resampler", + "Rolling", + "RollingGroupby", + "SeriesGroupBy", + "StataReader", + # See TODO above + # "Styler", + "TimedeltaIndexResamplerGroupby", + "TimeGrouper", + "Window", +] diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 9a1ba12482570..582a043a8a78a 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -8681,7 +8681,7 @@ def resample( Returns ------- - pandas.core.Resampler + pandas.api.typing.Resampler :class:`~pandas.core.Resampler` object. See Also diff --git a/pandas/core/groupby/groupby.py b/pandas/core/groupby/groupby.py index 8e7f27f180c98..a370300100866 100644 --- a/pandas/core/groupby/groupby.py +++ b/pandas/core/groupby/groupby.py @@ -2641,8 +2641,11 @@ def resample(self, rule, *args, **kwargs): Returns ------- - Grouper - Return a new grouper with our resampler appended. + pandas.api.typing.DatetimeIndexResamplerGroupby, + pandas.api.typing.PeriodIndexResamplerGroupby, or + pandas.api.typing.TimedeltaIndexResamplerGroupby + Return a new groupby object, with type depending on the data + being resampled. See Also -------- @@ -2806,7 +2809,7 @@ def rolling(self, *args, **kwargs) -> RollingGroupby: Returns ------- - RollingGroupby + pandas.api.typing.RollingGroupby Return a new grouper with our rolling appended. See Also @@ -2869,6 +2872,10 @@ def expanding(self, *args, **kwargs) -> ExpandingGroupby: """ Return an expanding grouper, providing expanding functionality per group. + + Returns + ------- + pandas.api.typing.ExpandingGroupby """ from pandas.core.window import ExpandingGroupby @@ -2885,6 +2892,10 @@ def expanding(self, *args, **kwargs) -> ExpandingGroupby: def ewm(self, *args, **kwargs) -> ExponentialMovingWindowGroupby: """ Return an ewm grouper, providing ewm functionality per group. + + Returns + ------- + pandas.api.typing.ExponentialMovingWindowGroupby """ from pandas.core.window import ExponentialMovingWindowGroupby diff --git a/pandas/core/groupby/grouper.py b/pandas/core/groupby/grouper.py index 1cc20d5bc68f9..13f43c1bf64a3 100644 --- a/pandas/core/groupby/grouper.py +++ b/pandas/core/groupby/grouper.py @@ -120,7 +120,9 @@ class Grouper: Returns ------- - A specification for a groupby instruction + Grouper or pandas.api.typing.TimeGrouper + A TimeGrouper is returned if ``freq`` is not ``None``. Otherwise, a Grouper + is returned. Examples -------- diff --git a/pandas/core/shared_docs.py b/pandas/core/shared_docs.py index 410fa8a3312a9..8344430ca5bb9 100644 --- a/pandas/core/shared_docs.py +++ b/pandas/core/shared_docs.py @@ -178,7 +178,7 @@ Returns ------- -%(klass)sGroupBy +pandas.api.typing.%(klass)sGroupBy Returns a groupby object that contains information about the groups. See Also diff --git a/pandas/core/window/ewm.py b/pandas/core/window/ewm.py index 8dec71b692700..295a9ecac7fb8 100644 --- a/pandas/core/window/ewm.py +++ b/pandas/core/window/ewm.py @@ -231,7 +231,7 @@ class ExponentialMovingWindow(BaseWindow): Returns ------- - ``ExponentialMovingWindow`` subclass + pandas.api.typing.ExponentialMovingWindow See Also -------- diff --git a/pandas/core/window/expanding.py b/pandas/core/window/expanding.py index b3caa189bd579..fc22ff6c0522a 100644 --- a/pandas/core/window/expanding.py +++ b/pandas/core/window/expanding.py @@ -72,7 +72,7 @@ class Expanding(RollingAndExpandingMixin): Returns ------- - ``Expanding`` subclass + pandas.api.typing.Expanding See Also -------- diff --git a/pandas/core/window/rolling.py b/pandas/core/window/rolling.py index 630af2b594940..57fda0a84c751 100644 --- a/pandas/core/window/rolling.py +++ b/pandas/core/window/rolling.py @@ -965,9 +965,9 @@ class Window(BaseWindow): Returns ------- - ``Window`` subclass if a ``win_type`` is passed - - ``Rolling`` subclass if ``win_type`` is not passed + pandas.api.typing.Window or pandas.api.typing.Rolling + An instance of Window is returned if ``win_type`` is passed. Otherwise, + an instance of Rolling is returned. See Also -------- diff --git a/pandas/io/json/_json.py b/pandas/io/json/_json.py index f73d372a920a8..3b5c14027e7a7 100644 --- a/pandas/io/json/_json.py +++ b/pandas/io/json/_json.py @@ -665,8 +665,9 @@ def read_json( Returns ------- - Series or DataFrame - The type returned depends on the value of `typ`. + Series, DataFrame, or pandas.api.typing.JsonReader + A JsonReader is returned when ``chunksize`` is not ``0`` or ``None``. + Otherwise, the type returned depends on the value of ``typ``. See Also -------- diff --git a/pandas/io/stata.py b/pandas/io/stata.py index ca6586899da4c..3dddce98b35be 100644 --- a/pandas/io/stata.py +++ b/pandas/io/stata.py @@ -156,7 +156,7 @@ Returns ------- -DataFrame or StataReader +DataFrame or pandas.api.typing.StataReader See Also -------- diff --git a/pandas/tests/api/test_api.py b/pandas/tests/api/test_api.py index 463ed6051e910..c2e89a2db12ee 100644 --- a/pandas/tests/api/test_api.py +++ b/pandas/tests/api/test_api.py @@ -5,6 +5,7 @@ import pandas as pd from pandas import api import pandas._testing as tm +from pandas.api import typing as api_typing class Base: @@ -236,11 +237,32 @@ def test_depr(self): class TestApi(Base): - allowed = ["types", "extensions", "indexers", "interchange"] + allowed = ["types", "extensions", "indexers", "interchange", "typing"] + allowed_typing = [ + "DataFrameGroupBy", + "DatetimeIndexResamplerGroupby", + "Expanding", + "ExpandingGroupby", + "ExponentialMovingWindow", + "ExponentialMovingWindowGroupby", + "JsonReader", + "PeriodIndexResamplerGroupby", + "Resampler", + "Rolling", + "RollingGroupby", + "SeriesGroupBy", + "StataReader", + "TimedeltaIndexResamplerGroupby", + "TimeGrouper", + "Window", + ] def test_api(self): self.check(api, self.allowed) + def test_api_typing(self): + self.check(api_typing, self.allowed_typing) + class TestTesting(Base): funcs = [