@@ -37,6 +37,7 @@ the following example that creates two series of datetimes with corresponding ar
37
37
38
38
``` python
39
39
import pandas as pd
40
+ from typing import reveal_type
40
41
41
42
s1 = pd.Series(pd.to_datetime([" 2022-05-01" , " 2022-06-01" ]))
42
43
reveal_type(s1)
@@ -45,26 +46,61 @@ reveal_type(s2)
45
46
td = s1 - s2
46
47
reveal_type(td)
47
48
ssum = s1 + s2
48
- reveal_type(ssum)
49
49
```
50
50
51
- The above code (without the ` reveal_type() ` statements) will get a ` Never `
52
- 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
53
52
inappropriate to add two series containing ` Timestamp ` values. The types will be
54
- revealed as follows:
53
+ revealed by ` mypy ` as follows:
55
54
56
55
``` text
57
- ttest.py:4: note: Revealed type is "pandas.core.series.Series[pandas._libs.tslibs.timestamps.Timestamp]"
58
- ttest.py:6: note: Revealed type is "pandas.core.series.Series[pandas._libs.tslibs.timestamps.Timestamp]"
59
- ttest.py:8: note: Revealed type is "pandas.core.series.Series[pandas._libs.tslibs.timedeltas.Timedelta]"
60
- ttest.py:9: error: Need type annotation for "ssum" [var-annotated]
61
- ttest.py:10: note: Revealed type is "Never"
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.Series[pandas._libs.tslibs.timestamps.Timedelta]"
59
+ ttest.py:10: error: Unsupported operand types for + ("Series[Timestamp]" and "Series[Timestamp]") [operator]
62
60
```
63
61
64
62
The type ` Series[Timestamp] ` is the result of creating a series from ` pd.to_datetime() ` , while
65
63
the type ` Series[Timedelta] ` is the result of subtracting two ` Series[Timestamp] ` as well as
66
64
the result of ` pd.to_timedelta() ` .
67
65
66
+ ### Progressive arithmetic typing for generic Series
67
+
68
+ Consider the following Series from a DataFrame:
69
+
70
+ ``` python
71
+ import pandas as pd
72
+ from typing_extensions import reveal_type
73
+
74
+
75
+ frame = pd.DataFrame({" timestamp" : [pd.Timestamp(2025 , 9 , 15 )], " tag" : [" one" ], " value" : [1.0 ]})
76
+ values = frame[" value" ]
77
+ reveal_type(values) # type checker: Series[Any], runtime: Series
78
+ new_values = values + 2
79
+
80
+ timestamps = frame[" timestamp" ]
81
+ reveal_type(timestamps - pd.Timestamp(2025 , 7 , 12 )) # type checker: TimedeltaSeries, runtime: Series
82
+
83
+ tags = frame[" tag" ]
84
+ reveal_type(" suffix" + tags) # type checker: Series[str], runtime: Series
85
+ ```
86
+
87
+ Since these Series are taken from a DataFrame, all three of them, ` values ` , ` timestamps `
88
+ and ` tags ` , are recognized by type checkers as ` Series[Any] ` . The code snippet
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.
103
+
68
104
### Interval is Generic
69
105
70
106
A pandas ` Interval ` can be a time interval, an interval of integers, or an interval of
0 commit comments