From ea91291b6bea95b30ac767af3d381ca4beb81758 Mon Sep 17 00:00:00 2001 From: richard Date: Thu, 8 Sep 2022 22:04:00 -0400 Subject: [PATCH 01/17] API: Add pandas.api.typing --- doc/source/reference/index.rst | 23 ++++++++++++++----- doc/source/whatsnew/v2.0.0.rst | 1 + pandas/api/__init__.py | 2 ++ pandas/api/typing/__init__.py | 40 ++++++++++++++++++++++++++++++++++ pandas/tests/api/test_api.py | 2 +- 5 files changed, 62 insertions(+), 6 deletions(-) create mode 100644 pandas/api/typing/__init__.py diff --git a/doc/source/reference/index.rst b/doc/source/reference/index.rst index 37cb6767f760e..4e39b67d366f8 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 intermediates 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/whatsnew/v2.0.0.rst b/doc/source/whatsnew/v2.0.0.rst index b1387e9717079..51d83962fb00f 100644 --- a/doc/source/whatsnew/v2.0.0.rst +++ b/doc/source/whatsnew/v2.0.0.rst @@ -497,6 +497,7 @@ Other API changes methods to get a full slice (for example ``df.loc[:]`` or ``df[:]``) (:issue:`49469`) - Disallow computing ``cumprod`` for :class:`Timedelta` object; previously this returned incorrect values (:issue:`50246`) - :func:`to_datetime` with ``unit`` of either "Y" or "M" will now raise if a sequence contains a non-round ``float`` value, matching the ``Timestamp`` behavior (:issue:`50301`) +- :class:`DataFrameGroupBy` and :class:`SeriesGroupBy` have been added to ``pandas.api.typing`` (:issue:`48577`) - .. --------------------------------------------------------------------------- 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..4a405207fbc97 --- /dev/null +++ b/pandas/api/typing/__init__.py @@ -0,0 +1,40 @@ +""" +Public API classes that store intermediate results useful for type-hinting. +""" + +from pandas.core.groupby import ( + DataFrameGroupBy, + SeriesGroupBy, +) +from pandas.core.resample import ( + Resampler, + TimeGrouper, +) +from pandas.core.window import ( + Expanding, + ExponentialMovingWindow, + Rolling, + Window, +) + +from pandas.io.formats.style import Styler +from pandas.io.json._json import JsonReader +from pandas.io.stata import ( + StataReader, + StataWriter, +) + +__all__ = [ + "DataFrameGroupBy", + "Expanding", + "ExponentialMovingWindow", + "JsonReader", + "Resampler", + "Rolling", + "SeriesGroupBy", + "StataWriter", + "StataReader", + "Styler", + "TimeGrouper", + "Window", +] diff --git a/pandas/tests/api/test_api.py b/pandas/tests/api/test_api.py index 995b1668046d2..46c729221a0ff 100644 --- a/pandas/tests/api/test_api.py +++ b/pandas/tests/api/test_api.py @@ -235,7 +235,7 @@ def test_depr(self): class TestApi(Base): - allowed = ["types", "extensions", "indexers", "interchange"] + allowed = ["types", "extensions", "indexers", "interchange", "typing"] def test_api(self): self.check(api, self.allowed) From 985627c150acdddf3f1c4f94297813edbf8e5a2e Mon Sep 17 00:00:00 2001 From: richard Date: Sat, 31 Dec 2022 10:07:31 -0500 Subject: [PATCH 02/17] whatsnew note --- doc/source/whatsnew/v2.0.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v2.0.0.rst b/doc/source/whatsnew/v2.0.0.rst index 51d83962fb00f..0b11581aedd14 100644 --- a/doc/source/whatsnew/v2.0.0.rst +++ b/doc/source/whatsnew/v2.0.0.rst @@ -497,7 +497,7 @@ Other API changes methods to get a full slice (for example ``df.loc[:]`` or ``df[:]``) (:issue:`49469`) - Disallow computing ``cumprod`` for :class:`Timedelta` object; previously this returned incorrect values (:issue:`50246`) - :func:`to_datetime` with ``unit`` of either "Y" or "M" will now raise if a sequence contains a non-round ``float`` value, matching the ``Timestamp`` behavior (:issue:`50301`) -- :class:`DataFrameGroupBy` and :class:`SeriesGroupBy` have been added to ``pandas.api.typing`` (:issue:`48577`) +- Classes that are useful for type-hinting have been added to the public API in the new submodule ``pandas.api.typing`` (:issue:`48577`) - .. --------------------------------------------------------------------------- From d4e6e091302e33e568741e2052a97cae7a611af9 Mon Sep 17 00:00:00 2001 From: Richard Shadrach Date: Sun, 1 Jan 2023 18:00:27 -0500 Subject: [PATCH 03/17] Don't import Styler --- pandas/api/typing/__init__.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pandas/api/typing/__init__.py b/pandas/api/typing/__init__.py index 4a405207fbc97..e91d95ee82b48 100644 --- a/pandas/api/typing/__init__.py +++ b/pandas/api/typing/__init__.py @@ -17,7 +17,8 @@ Window, ) -from pandas.io.formats.style import Styler +# TODO: Can't import Styler without impacting registered matplotlib converters +# from pandas.io.formats.style import Styler from pandas.io.json._json import JsonReader from pandas.io.stata import ( StataReader, @@ -34,7 +35,8 @@ "SeriesGroupBy", "StataWriter", "StataReader", - "Styler", + # See TODO above + # "Styler", "TimeGrouper", "Window", ] From 3dd6cf81e0ff09a3c981e1b28674ff6140764dad Mon Sep 17 00:00:00 2001 From: Richard Shadrach Date: Mon, 2 Jan 2023 07:29:05 -0500 Subject: [PATCH 04/17] Test fixup for Styler --- pandas/api/typing/__init__.py | 6 ++---- pandas/tests/plotting/test_converter.py | 1 + 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/pandas/api/typing/__init__.py b/pandas/api/typing/__init__.py index e91d95ee82b48..4a405207fbc97 100644 --- a/pandas/api/typing/__init__.py +++ b/pandas/api/typing/__init__.py @@ -17,8 +17,7 @@ Window, ) -# TODO: Can't import Styler without impacting registered matplotlib converters -# from pandas.io.formats.style import Styler +from pandas.io.formats.style import Styler from pandas.io.json._json import JsonReader from pandas.io.stata import ( StataReader, @@ -35,8 +34,7 @@ "SeriesGroupBy", "StataWriter", "StataReader", - # See TODO above - # "Styler", + "Styler", "TimeGrouper", "Window", ] diff --git a/pandas/tests/plotting/test_converter.py b/pandas/tests/plotting/test_converter.py index 8ab15abeca7fd..702236d3d6b6e 100644 --- a/pandas/tests/plotting/test_converter.py +++ b/pandas/tests/plotting/test_converter.py @@ -48,6 +48,7 @@ def test_registry_mpl_resets(): code = ( "import matplotlib.units as units; " "import matplotlib.dates as mdates; " + "import matplotlib.pyplot as plt; " "n_conv = len(units.registry); " "import pandas as pd; " "pd.plotting.register_matplotlib_converters(); " From 8f953a538cd22ea709a7acc01203f21481a18ffe Mon Sep 17 00:00:00 2001 From: richard Date: Thu, 8 Sep 2022 22:04:00 -0400 Subject: [PATCH 05/17] API: Add pandas.api.typing --- doc/source/reference/index.rst | 23 +++++++++++++++---- doc/source/whatsnew/v2.0.0.rst | 1 + pandas/api/__init__.py | 2 ++ pandas/api/typing/__init__.py | 42 ++++++++++++++++++++++++++++++++++ pandas/io/formats/style.py | 21 +++++++---------- pandas/tests/api/test_api.py | 2 +- 6 files changed, 72 insertions(+), 19 deletions(-) create mode 100644 pandas/api/typing/__init__.py diff --git a/doc/source/reference/index.rst b/doc/source/reference/index.rst index 37cb6767f760e..4e39b67d366f8 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 intermediates 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/whatsnew/v2.0.0.rst b/doc/source/whatsnew/v2.0.0.rst index bbecf3fee01f3..2c068545345ef 100644 --- a/doc/source/whatsnew/v2.0.0.rst +++ b/doc/source/whatsnew/v2.0.0.rst @@ -600,6 +600,7 @@ Other API changes - Disallow computing ``cumprod`` for :class:`Timedelta` object; previously this returned incorrect values (:issue:`50246`) - Loading a JSON file with duplicate columns using ``read_json(orient='split')`` renames columns to avoid duplicates, as :func:`read_csv` and the other readers do (:issue:`50370`) - :func:`to_datetime` with ``unit`` of either "Y" or "M" will now raise if a sequence contains a non-round ``float`` value, matching the ``Timestamp`` behavior (:issue:`50301`) +- Classes that are useful for type-hinting have been added to the public API in the new submodule ``pandas.api.typing`` (:issue:`48577`) - .. --------------------------------------------------------------------------- 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..e91d95ee82b48 --- /dev/null +++ b/pandas/api/typing/__init__.py @@ -0,0 +1,42 @@ +""" +Public API classes that store intermediate results useful for type-hinting. +""" + +from pandas.core.groupby import ( + DataFrameGroupBy, + SeriesGroupBy, +) +from pandas.core.resample import ( + Resampler, + TimeGrouper, +) +from pandas.core.window import ( + Expanding, + ExponentialMovingWindow, + Rolling, + Window, +) + +# TODO: Can't import Styler without impacting registered matplotlib converters +# from pandas.io.formats.style import Styler +from pandas.io.json._json import JsonReader +from pandas.io.stata import ( + StataReader, + StataWriter, +) + +__all__ = [ + "DataFrameGroupBy", + "Expanding", + "ExponentialMovingWindow", + "JsonReader", + "Resampler", + "Rolling", + "SeriesGroupBy", + "StataWriter", + "StataReader", + # See TODO above + # "Styler", + "TimeGrouper", + "Window", +] diff --git a/pandas/io/formats/style.py b/pandas/io/formats/style.py index 442f2ab72a1e2..eeb5daf4537b5 100644 --- a/pandas/io/formats/style.py +++ b/pandas/io/formats/style.py @@ -52,9 +52,6 @@ from pandas.core.shared_docs import _shared_docs from pandas.io.formats.format import save_to_buffer - -jinja2 = import_optional_dependency("jinja2", extra="DataFrame.style requires jinja2.") - from pandas.io.formats.style_render import ( CSSProperties, CSSStyles, @@ -71,20 +68,15 @@ if TYPE_CHECKING: from matplotlib.colors import Colormap -try: - import matplotlib as mpl - import matplotlib.pyplot as plt - - has_mpl = True -except ImportError: - has_mpl = False - @contextmanager def _mpl(func: Callable) -> Generator[tuple[Any, Any], None, None]: - if has_mpl: + try: + import matplotlib as mpl + import matplotlib.pyplot as plt + yield plt, mpl - else: + except ImportError: raise ImportError(f"{func.__name__} requires matplotlib.") @@ -3420,6 +3412,9 @@ def from_custom_template( Has the correct ``env``,``template_html``, ``template_html_table`` and ``template_html_style`` class attributes set. """ + jinja2 = import_optional_dependency( + "jinja2", extra="DataFrame.style requires jinja2." + ) loader = jinja2.ChoiceLoader([jinja2.FileSystemLoader(searchpath), cls.loader]) # mypy doesn't like dynamically-defined classes diff --git a/pandas/tests/api/test_api.py b/pandas/tests/api/test_api.py index e448e1bce9146..a9d06c94b216d 100644 --- a/pandas/tests/api/test_api.py +++ b/pandas/tests/api/test_api.py @@ -235,7 +235,7 @@ def test_depr(self): class TestApi(Base): - allowed = ["types", "extensions", "indexers", "interchange"] + allowed = ["types", "extensions", "indexers", "interchange", "typing"] def test_api(self): self.check(api, self.allowed) From e94061f7240701246b7c8d6880fbc552c8c3b372 Mon Sep 17 00:00:00 2001 From: richard Date: Sun, 22 Jan 2023 21:14:57 -0500 Subject: [PATCH 06/17] Add back Styler --- pandas/api/typing/__init__.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/pandas/api/typing/__init__.py b/pandas/api/typing/__init__.py index e91d95ee82b48..4a405207fbc97 100644 --- a/pandas/api/typing/__init__.py +++ b/pandas/api/typing/__init__.py @@ -17,8 +17,7 @@ Window, ) -# TODO: Can't import Styler without impacting registered matplotlib converters -# from pandas.io.formats.style import Styler +from pandas.io.formats.style import Styler from pandas.io.json._json import JsonReader from pandas.io.stata import ( StataReader, @@ -35,8 +34,7 @@ "SeriesGroupBy", "StataWriter", "StataReader", - # See TODO above - # "Styler", + "Styler", "TimeGrouper", "Window", ] From 44edcdb14a3b25a8c0ea060fa5c18d6aa52ec171 Mon Sep 17 00:00:00 2001 From: Richard Shadrach Date: Mon, 23 Jan 2023 20:41:26 -0500 Subject: [PATCH 07/17] Revert Styler changes --- pandas/api/typing/__init__.py | 6 ++++-- pandas/io/formats/style.py | 21 +++++++++++++-------- pandas/tests/plotting/test_converter.py | 1 - 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/pandas/api/typing/__init__.py b/pandas/api/typing/__init__.py index 4a405207fbc97..232477a548734 100644 --- a/pandas/api/typing/__init__.py +++ b/pandas/api/typing/__init__.py @@ -17,7 +17,8 @@ Window, ) -from pandas.io.formats.style import Styler +# 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, @@ -34,7 +35,8 @@ "SeriesGroupBy", "StataWriter", "StataReader", - "Styler", + # See TODO above + # "Styler", "TimeGrouper", "Window", ] diff --git a/pandas/io/formats/style.py b/pandas/io/formats/style.py index eeb5daf4537b5..442f2ab72a1e2 100644 --- a/pandas/io/formats/style.py +++ b/pandas/io/formats/style.py @@ -52,6 +52,9 @@ from pandas.core.shared_docs import _shared_docs from pandas.io.formats.format import save_to_buffer + +jinja2 = import_optional_dependency("jinja2", extra="DataFrame.style requires jinja2.") + from pandas.io.formats.style_render import ( CSSProperties, CSSStyles, @@ -68,15 +71,20 @@ if TYPE_CHECKING: from matplotlib.colors import Colormap +try: + import matplotlib as mpl + import matplotlib.pyplot as plt + + has_mpl = True +except ImportError: + has_mpl = False + @contextmanager def _mpl(func: Callable) -> Generator[tuple[Any, Any], None, None]: - try: - import matplotlib as mpl - import matplotlib.pyplot as plt - + if has_mpl: yield plt, mpl - except ImportError: + else: raise ImportError(f"{func.__name__} requires matplotlib.") @@ -3412,9 +3420,6 @@ def from_custom_template( Has the correct ``env``,``template_html``, ``template_html_table`` and ``template_html_style`` class attributes set. """ - jinja2 = import_optional_dependency( - "jinja2", extra="DataFrame.style requires jinja2." - ) loader = jinja2.ChoiceLoader([jinja2.FileSystemLoader(searchpath), cls.loader]) # mypy doesn't like dynamically-defined classes diff --git a/pandas/tests/plotting/test_converter.py b/pandas/tests/plotting/test_converter.py index 702236d3d6b6e..8ab15abeca7fd 100644 --- a/pandas/tests/plotting/test_converter.py +++ b/pandas/tests/plotting/test_converter.py @@ -48,7 +48,6 @@ def test_registry_mpl_resets(): code = ( "import matplotlib.units as units; " "import matplotlib.dates as mdates; " - "import matplotlib.pyplot as plt; " "n_conv = len(units.registry); " "import pandas as pd; " "pd.plotting.register_matplotlib_converters(); " From 04a88d97df45b46a8015f52cbeca02be00ca377f Mon Sep 17 00:00:00 2001 From: Richard Shadrach Date: Tue, 24 Jan 2023 17:40:52 -0500 Subject: [PATCH 08/17] Point to pandas.api.typing for GroupBy objects --- pandas/core/shared_docs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/core/shared_docs.py b/pandas/core/shared_docs.py index 486fab62d93e7..de4f594b30997 100644 --- a/pandas/core/shared_docs.py +++ b/pandas/core/shared_docs.py @@ -153,7 +153,7 @@ Returns ------- -%(klass)sGroupBy +pandas.api.typing.%(klass)sGroupBy Returns a groupby object that contains information about the groups. See Also From 7a8b1aae79a806302e82764e37af0ddff3d29806 Mon Sep 17 00:00:00 2001 From: Richard Shadrach Date: Mon, 6 Feb 2023 17:50:33 -0500 Subject: [PATCH 09/17] Add references to pandas.api.typing --- pandas/api/typing/__init__.py | 6 +----- pandas/core/generic.py | 2 +- pandas/core/groupby/groupby.py | 19 +++++++++++++++++-- pandas/core/groupby/grouper.py | 4 +++- pandas/core/window/ewm.py | 2 +- pandas/core/window/expanding.py | 2 +- pandas/core/window/rolling.py | 4 ++-- pandas/io/json/_json.py | 5 +++-- pandas/io/stata.py | 2 +- 9 files changed, 30 insertions(+), 16 deletions(-) diff --git a/pandas/api/typing/__init__.py b/pandas/api/typing/__init__.py index 232477a548734..85fb8718aef16 100644 --- a/pandas/api/typing/__init__.py +++ b/pandas/api/typing/__init__.py @@ -20,10 +20,7 @@ # 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, - StataWriter, -) +from pandas.io.stata import StataReader __all__ = [ "DataFrameGroupBy", @@ -33,7 +30,6 @@ "Resampler", "Rolling", "SeriesGroupBy", - "StataWriter", "StataReader", # See TODO above # "Styler", diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 6008e6b6cb566..ec869d35f4b23 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -8484,7 +8484,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 26e1105ea879d..77a7d9293c3d9 100644 --- a/pandas/core/groupby/groupby.py +++ b/pandas/core/groupby/groupby.py @@ -2580,8 +2580,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 grouper, with type depending on the data being resampled, + with our resampler appended. See Also -------- @@ -2667,6 +2670,10 @@ def resample(self, rule, *args, **kwargs): def rolling(self, *args, **kwargs) -> RollingGroupby: """ Return a rolling grouper, providing rolling functionality per group. + + Returns + ------- + pandas.api.typing.RollingGroupby """ from pandas.core.window import RollingGroupby @@ -2685,6 +2692,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 @@ -2701,6 +2712,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 045acae89dba9..c2dd131f06b67 100644 --- a/pandas/core/groupby/grouper.py +++ b/pandas/core/groupby/grouper.py @@ -119,7 +119,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/window/ewm.py b/pandas/core/window/ewm.py index c0a7b2b7cc361..212a870d90317 100644 --- a/pandas/core/window/ewm.py +++ b/pandas/core/window/ewm.py @@ -228,7 +228,7 @@ class ExponentialMovingWindow(BaseWindow): Returns ------- - ``ExponentialMovingWindow`` subclass + ``pandas.api.typing.ExponentialMovingWindow`` subclass See Also -------- diff --git a/pandas/core/window/expanding.py b/pandas/core/window/expanding.py index 6147f0f43c558..6fd873095b2ef 100644 --- a/pandas/core/window/expanding.py +++ b/pandas/core/window/expanding.py @@ -69,7 +69,7 @@ class Expanding(RollingAndExpandingMixin): Returns ------- - ``Expanding`` subclass + ``pandas.api.typing.Expanding`` subclass See Also -------- diff --git a/pandas/core/window/rolling.py b/pandas/core/window/rolling.py index ef0524e48f9e2..d96b34ef4c8e2 100644 --- a/pandas/core/window/rolling.py +++ b/pandas/core/window/rolling.py @@ -962,9 +962,9 @@ class Window(BaseWindow): Returns ------- - ``Window`` subclass if a ``win_type`` is passed + ``pandas.api.typing.Window`` subclass if a ``win_type`` is passed - ``Rolling`` subclass if ``win_type`` is not passed + ``pandas.api.typing.Rolling`` subclass if ``win_type`` is not passed See Also -------- diff --git a/pandas/io/json/_json.py b/pandas/io/json/_json.py index 66991eab54671..9462a33c8ad3b 100644 --- a/pandas/io/json/_json.py +++ b/pandas/io/json/_json.py @@ -655,8 +655,9 @@ def read_json( Returns ------- - Series or DataFrame - The type returned depends on the value of `typ`. + Series or 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 fd6ffe5c165ab..3a2dfb7b079d5 100644 --- a/pandas/io/stata.py +++ b/pandas/io/stata.py @@ -154,7 +154,7 @@ Returns ------- -DataFrame or StataReader +DataFrame or pandas.api.typing.StataReader See Also -------- From b0423afca12d10a054e147b68ed169c09a533eb3 Mon Sep 17 00:00:00 2001 From: Richard Shadrach Date: Sat, 11 Feb 2023 07:13:09 -0500 Subject: [PATCH 10/17] fixup --- doc/source/reference/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/reference/index.rst b/doc/source/reference/index.rst index 4e39b67d366f8..bc1202b3d5554 100644 --- a/doc/source/reference/index.rst +++ b/doc/source/reference/index.rst @@ -19,7 +19,7 @@ The following subpackages are public. - ``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 intermediates results but should not be + 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. From 940a33eb8add467fe804334f41eed4a28b607e60 Mon Sep 17 00:00:00 2001 From: Richard Shadrach Date: Sat, 11 Feb 2023 08:16:26 -0500 Subject: [PATCH 11/17] Refinements --- pandas/api/typing/__init__.py | 12 ++++++++++++ pandas/core/window/ewm.py | 2 +- pandas/core/window/expanding.py | 2 +- pandas/core/window/rolling.py | 6 +++--- pandas/io/json/_json.py | 2 +- 5 files changed, 18 insertions(+), 6 deletions(-) diff --git a/pandas/api/typing/__init__.py b/pandas/api/typing/__init__.py index 85fb8718aef16..4c535bf81d3b6 100644 --- a/pandas/api/typing/__init__.py +++ b/pandas/api/typing/__init__.py @@ -7,13 +7,19 @@ SeriesGroupBy, ) from pandas.core.resample import ( + DatetimeIndexResamplerGroupby, + PeriodIndexResamplerGroupby, Resampler, + TimedeltaIndexResamplerGroupby, TimeGrouper, ) from pandas.core.window import ( Expanding, + ExpandingGroupby, ExponentialMovingWindow, + ExponentialMovingWindowGroupby, Rolling, + RollingGroupby, Window, ) @@ -24,15 +30,21 @@ __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/window/ewm.py b/pandas/core/window/ewm.py index 03a67d5c8df8e..4101be674035f 100644 --- a/pandas/core/window/ewm.py +++ b/pandas/core/window/ewm.py @@ -228,7 +228,7 @@ class ExponentialMovingWindow(BaseWindow): Returns ------- - ``pandas.api.typing.ExponentialMovingWindow`` subclass + pandas.api.typing.ExponentialMovingWindow See Also -------- diff --git a/pandas/core/window/expanding.py b/pandas/core/window/expanding.py index 6fd873095b2ef..a28eb1e8d763b 100644 --- a/pandas/core/window/expanding.py +++ b/pandas/core/window/expanding.py @@ -69,7 +69,7 @@ class Expanding(RollingAndExpandingMixin): Returns ------- - ``pandas.api.typing.Expanding`` subclass + pandas.api.typing.Expanding See Also -------- diff --git a/pandas/core/window/rolling.py b/pandas/core/window/rolling.py index d96b34ef4c8e2..dce3c5c381a86 100644 --- a/pandas/core/window/rolling.py +++ b/pandas/core/window/rolling.py @@ -962,9 +962,9 @@ class Window(BaseWindow): Returns ------- - ``pandas.api.typing.Window`` subclass if a ``win_type`` is passed - - ``pandas.api.typing.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, + and instance of Rolling is returned. See Also -------- diff --git a/pandas/io/json/_json.py b/pandas/io/json/_json.py index 1d01d928b4216..53784a60b99f8 100644 --- a/pandas/io/json/_json.py +++ b/pandas/io/json/_json.py @@ -671,7 +671,7 @@ def read_json( Returns ------- - Series or DataFrame or pandas.api.typing.JsonReader + 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``. From 56a248057132d63f309f821fb115a22681ac7346 Mon Sep 17 00:00:00 2001 From: richard Date: Mon, 13 Feb 2023 20:47:39 -0500 Subject: [PATCH 12/17] Add references to User Guide; fixup docstrings --- doc/source/user_guide/groupby.rst | 6 ++++-- doc/source/user_guide/io.rst | 6 +++--- doc/source/user_guide/timeseries.rst | 5 +++-- doc/source/user_guide/window.rst | 16 ++++++++-------- pandas/core/groupby/groupby.py | 4 ++-- pandas/core/resample.py | 2 +- pandas/core/window/rolling.py | 2 +- 7 files changed, 22 insertions(+), 19 deletions(-) diff --git a/doc/source/user_guide/groupby.rst b/doc/source/user_guide/groupby.rst index 2fdd36d861e15..8c6eda536b1ff 100644 --- a/doc/source/user_guide/groupby.rst +++ b/doc/source/user_guide/groupby.rst @@ -118,6 +118,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 @@ -1317,8 +1318,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 ec082cb90e75c..b5b265970277a 100644 --- a/doc/source/user_guide/io.rst +++ b/doc/source/user_guide/io.rst @@ -2068,7 +2068,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 df2508397ff34..6a995123ce01d 100644 --- a/doc/source/user_guide/timeseries.rst +++ b/doc/source/user_guide/timeseries.rst @@ -1748,8 +1748,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/pandas/core/groupby/groupby.py b/pandas/core/groupby/groupby.py index e8f7113f6227d..d14797756565f 100644 --- a/pandas/core/groupby/groupby.py +++ b/pandas/core/groupby/groupby.py @@ -2578,8 +2578,8 @@ def resample(self, rule, *args, **kwargs): pandas.api.typing.DatetimeIndexResamplerGroupby, pandas.api.typing.PeriodIndexResamplerGroupby, or pandas.api.typing.TimedeltaIndexResamplerGroupby - Return a new grouper, with type depending on the data being resampled, - with our resampler appended. + Return a new groupby object, with type depending on the data + being resampled. See Also -------- diff --git a/pandas/core/resample.py b/pandas/core/resample.py index 1d03baff33297..1ef2cca772e7e 100644 --- a/pandas/core/resample.py +++ b/pandas/core/resample.py @@ -1545,7 +1545,7 @@ def get_resampler_for_grouping( # .resample uses 'on' similar to how .groupby uses 'key' tg = TimeGrouper(freq=rule, key=on, **kwargs) resampler = tg._get_resampler(groupby.obj, kind=kind) - return resampler._get_resampler_for_grouping(groupby=groupby, key=tg.key) + return resampler._get_resampbler_for_grouping(groupby=groupby, key=tg.key) class TimeGrouper(Grouper): diff --git a/pandas/core/window/rolling.py b/pandas/core/window/rolling.py index 0542a2a58a6ff..15c65a96a6e6e 100644 --- a/pandas/core/window/rolling.py +++ b/pandas/core/window/rolling.py @@ -966,7 +966,7 @@ class Window(BaseWindow): ------- pandas.api.typing.Window or pandas.api.typing.Rolling An instance of Window is returned if ``win_type`` is passed. Otherwise, - and instance of Rolling is returned. + an instance of Rolling is returned. See Also -------- From 0e279f4ee730177f0f5b023b99368d7c544cc1dc Mon Sep 17 00:00:00 2001 From: Richard Shadrach Date: Tue, 14 Feb 2023 17:42:08 -0500 Subject: [PATCH 13/17] Add references --- doc/source/reference/groupby.rst | 4 +++- doc/source/reference/resampling.rst | 3 ++- doc/source/reference/window.rst | 9 ++++++--- 3 files changed, 11 insertions(+), 5 deletions(-) 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/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: From 1b8189c6713ce74822622aba9962620f8ce1479e Mon Sep 17 00:00:00 2001 From: Richard Shadrach Date: Tue, 14 Feb 2023 17:42:30 -0500 Subject: [PATCH 14/17] fixup --- pandas/core/resample.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/core/resample.py b/pandas/core/resample.py index 1ef2cca772e7e..1d03baff33297 100644 --- a/pandas/core/resample.py +++ b/pandas/core/resample.py @@ -1545,7 +1545,7 @@ def get_resampler_for_grouping( # .resample uses 'on' similar to how .groupby uses 'key' tg = TimeGrouper(freq=rule, key=on, **kwargs) resampler = tg._get_resampler(groupby.obj, kind=kind) - return resampler._get_resampbler_for_grouping(groupby=groupby, key=tg.key) + return resampler._get_resampler_for_grouping(groupby=groupby, key=tg.key) class TimeGrouper(Grouper): From 0dd0e2e357bf7e5e0a68f7513c6f34cc71400d97 Mon Sep 17 00:00:00 2001 From: richard Date: Thu, 23 Feb 2023 22:20:56 -0500 Subject: [PATCH 15/17] Move whatsnew to 2.1.0 --- doc/source/whatsnew/v2.0.0.rst | 1 - doc/source/whatsnew/v2.1.0.rst | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/source/whatsnew/v2.0.0.rst b/doc/source/whatsnew/v2.0.0.rst index 11f0f18d9eca8..d6242f9b3d116 100644 --- a/doc/source/whatsnew/v2.0.0.rst +++ b/doc/source/whatsnew/v2.0.0.rst @@ -818,7 +818,6 @@ Other API changes - :class:`DataFrame` and :class:`DataFrameGroupBy` aggregations (e.g. "sum") with object-dtype columns no longer infer non-object dtypes for their results, explicitly call ``result.infer_objects(copy=False)`` on the result to obtain the old behavior (:issue:`51205`, :issue:`49603`) - Division by zero with :class:`ArrowDtype` dtypes returns ``-inf``, ``nan``, or ``inf`` depending on the numerator, instead of raising (:issue:`51541`) - Added :func:`pandas.api.types.is_any_real_numeric_dtype` to check for real numeric dtypes (:issue:`51152`) -- Classes that are useful for type-hinting have been added to the public API in the new submodule ``pandas.api.typing`` (:issue:`48577`) - .. note:: diff --git a/doc/source/whatsnew/v2.1.0.rst b/doc/source/whatsnew/v2.1.0.rst index f6a6c81bfe25d..5c5b4153eac64 100644 --- a/doc/source/whatsnew/v2.1.0.rst +++ b/doc/source/whatsnew/v2.1.0.rst @@ -28,7 +28,7 @@ enhancement2 Other enhancements ^^^^^^^^^^^^^^^^^^ -- +- Classes that are useful for type-hinting have been added to the public API in the new submodule ``pandas.api.typing`` (:issue:`48577`) - .. --------------------------------------------------------------------------- From 0e8cb7af982f2f096d7f3bd3ed1efd0d3a475500 Mon Sep 17 00:00:00 2001 From: richard Date: Thu, 16 Mar 2023 22:24:45 -0400 Subject: [PATCH 16/17] Docstring fixup --- pandas/core/groupby/grouper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/core/groupby/grouper.py b/pandas/core/groupby/grouper.py index 21683959ff758..2588e063de5d1 100644 --- a/pandas/core/groupby/grouper.py +++ b/pandas/core/groupby/grouper.py @@ -121,7 +121,7 @@ class Grouper: Returns ------- Grouper or pandas.api.typing.TimeGrouper - A TimeGrouper is returned if ``freq`` is not ``None`. Otherwise, a Grouper + A TimeGrouper is returned if ``freq`` is not ``None``. Otherwise, a Grouper is returned. Examples From df0d343b7545c1c37cfab6a8d11b1d2d370cfc39 Mon Sep 17 00:00:00 2001 From: Richard Shadrach Date: Sun, 16 Apr 2023 08:17:15 -0400 Subject: [PATCH 17/17] Test dir of api.typing --- pandas/tests/api/test_api.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/pandas/tests/api/test_api.py b/pandas/tests/api/test_api.py index 174228b6a067f..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: @@ -237,10 +238,31 @@ def test_depr(self): class TestApi(Base): 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 = [