@@ -36,67 +36,70 @@ This also allows type checking for operations on series that contain date/time d
3636the following example that creates two series of datetimes with corresponding arithmetic.
3737
3838``` python
39+ import pandas as pd
40+ from typing import reveal_type
41+
3942s1 = pd.Series(pd.to_datetime([" 2022-05-01" , " 2022-06-01" ]))
4043reveal_type(s1)
4144s2 = pd.Series(pd.to_datetime([" 2022-05-15" , " 2022-06-15" ]))
4245reveal_type(s2)
4346td = s1 - s2
4447reveal_type(td)
4548ssum = s1 + s2
46- reveal_type(ssum)
4749```
4850
49- The above code (without the ` reveal_type() ` statements) will raise an ` Exception ` on the computation of ` ssum ` because it is
51+ The above code (without the ` reveal_type() ` statements) will get an error on the computation of ` ssum ` because it is
5052inappropriate to add two series containing ` Timestamp ` values. The types will be
51- revealed as follows:
53+ revealed by ` mypy ` as follows:
5254
5355``` text
54- ttest.py:4 : note: Revealed type is "pandas.core.series.TimestampSeries "
55- ttest.py:6 : note: Revealed type is "pandas.core.series.TimestampSeries "
56- ttest.py:8 : note: Revealed type is "pandas.core.series.TimedeltaSeries"
57- ttest.py:10: note: Revealed type is "builtins.Exception"
56+ ttest.py:5 : note: Revealed type is "pandas.core.series.Series[pandas._libs.tslibs.timestamps.Timestamp] "
57+ ttest.py:7 : note: Revealed type is "pandas.core.series.Series[pandas._libs.tslibs.timestamps.Timestamp] "
58+ ttest.py:9 : note: Revealed type is "pandas.core.series.TimedeltaSeries"
59+ ttest.py:10: error: Unsupported operand types for + ("Series[Timestamp]" and "Series[Timestamp]") [operator]
5860```
5961
60- The type ` TimestampSeries ` is the result of creating a series from ` pd.to_datetime() ` , while
61- the type ` TimedeltaSeries ` is the result of subtracting two ` TimestampSeries ` as well as
62+ The type ` Series[Timestamp] ` is the result of creating a series from ` pd.to_datetime() ` , while
63+ the type ` TimedeltaSeries ` is the result of subtracting two ` Series[Timestamp] ` as well as
6264the result of ` pd.to_timedelta() ` .
6365
64- ### Generic Series have restricted arithmetic
66+ ### Progressive arithmetic typing for generic Series
6567
6668Consider the following Series from a DataFrame:
6769
6870``` python
6971import pandas as pd
7072from typing_extensions import reveal_type
71- from typing import TYPE_CHECKING , cast
72-
73- if TYPE_CHECKING :
74- from pandas.core.series import TimestampSeries # noqa: F401
7573
7674
77- frame = pd.DataFrame({" timestamp" : [pd.Timestamp(2025 , 8 , 26 )], " tag" : [" one" ], " value" : [1.0 ]})
75+ frame = pd.DataFrame({" timestamp" : [pd.Timestamp(2025 , 9 , 15 )], " tag" : [" one" ], " value" : [1.0 ]})
7876values = frame[" value" ]
7977reveal_type(values) # type checker: Series[Any], runtime: Series
8078new_values = values + 2
8179
8280timestamps = frame[" timestamp" ]
83- reveal_type(timestamps) # type checker: Series[Any], runtime: Series
84- reveal_type(timestamps - pd.Timestamp(2025 , 7 , 12 )) # type checker: Unknown and error, runtime: Series
85- reveal_type(cast(" TimestampSeries" , timestamps) - pd.Timestamp(2025 , 7 , 12 )) # type checker: TimedeltaSeries, runtime: Series
81+ reveal_type(timestamps - pd.Timestamp(2025 , 7 , 12 )) # type checker: TimedeltaSeries, runtime: Series
8682
8783tags = frame[" tag" ]
88- reveal_type(" suffix" + tags) # type checker: Never , runtime: Series
84+ reveal_type(" suffix" + tags) # type checker: Series[str] , runtime: Series
8985```
9086
91- Since they are taken from a DataFrame, all three of them, ` values ` , ` timestamps `
87+ Since these Series are taken from a DataFrame, all three of them, ` values ` , ` timestamps `
9288and ` tags ` , are recognized by type checkers as ` Series[Any] ` . The code snippet
93- runs fine at runtime. In the stub for type checking, however, we restrict
94- generic Series to perform arithmetic operations only with numeric types, and
95- give ` Series[Any] ` for the results. For ` Timedelta ` , ` Timestamp ` , ` str ` , etc.,
96- arithmetic is restricted to ` Series[Any] ` and the result is either undefined,
97- showing ` Unknown ` and errors, or ` Never ` . Users are encouraged to cast such
98- generic Series to ones with concrete types, so that type checkers can provide
99- meaningful results.
89+ runs fine at runtime. In the stub for type checking, when there is only one
90+ valid outcome, we provide the typing of this outcome as the result. For
91+ example, if a ` Timestamp ` is subtracted from a ` Series[Any] ` , or a ` str `
92+ is added to a ` Series[Any] ` , valid outcomes can only be ` TimedeltaSeries ` and
93+ ` Series[str] ` , respectively, which will be realized when the left operands
94+ are actually ` Series[Timestamp] ` and ` Series[str] ` , respectively.
95+
96+ Note that static type checkers cannot determine the contents of a ` Series[Any] `
97+ at runtime. Users are invited to verify the results provided progressivly by the
98+ type checkers and be warned if they are unreasonable.
99+
100+ When there are several possible valid outcomes of an arithmetic expression,
101+ for example numeric types ` Series[bool] ` , ` Series[int] ` , etc., ` Series[Any] `
102+ will be given as the resulting type of the arithmetic operation.
100103
101104### Interval is Generic
102105
0 commit comments