@@ -63,42 +63,43 @@ The type `Series[Timestamp]` is the result of creating a series from `pd.to_date
6363the type ` TimedeltaSeries ` is the result of subtracting two ` Series[Timestamp] ` as well as
6464the result of ` pd.to_timedelta() ` .
6565
66- ### Generic Series have restricted arithmetic
66+ ### Progressive arithmetic typing for generic Series
6767
6868Consider the following Series from a DataFrame:
6969
7070``` python
7171import pandas as pd
7272from typing_extensions import reveal_type
73- from typing import TYPE_CHECKING , cast
7473
75- if TYPE_CHECKING :
76- from pandas.core.series import TimestampSeries # noqa: F401
7774
78-
79- 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 ]})
8076values = frame[" value" ]
8177reveal_type(values) # type checker: Series[Any], runtime: Series
8278new_values = values + 2
8379
8480timestamps = frame[" timestamp" ]
85- reveal_type(timestamps) # type checker: Series[Any], runtime: Series
86- reveal_type(timestamps - pd.Timestamp(2025 , 7 , 12 )) # type checker: Unknown and error, runtime: Series
87- 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
8882
8983tags = frame[" tag" ]
90- reveal_type(" suffix" + tags) # type checker: Never , runtime: Series
84+ reveal_type(" suffix" + tags) # type checker: Series[str] , runtime: Series
9185```
9286
93- 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 `
9488and ` tags ` , are recognized by type checkers as ` Series[Any] ` . The code snippet
95- runs fine at runtime. In the stub for type checking, however, we restrict
96- generic Series to perform arithmetic operations only with numeric types, and
97- give ` Series[Any] ` for the results. For ` Timedelta ` , ` Timestamp ` , ` str ` , etc.,
98- arithmetic is restricted to ` Series[Any] ` and the result is either undefined,
99- showing ` Unknown ` and errors, or ` Never ` . Users are encouraged to cast such
100- generic Series to ones with concrete types, so that type checkers can provide
101- 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 typing.
102103
103104### Interval is Generic
104105
0 commit comments