Skip to content

Commit ff37521

Browse files
committed
chore(philosophy): first draft
1 parent b487bc9 commit ff37521

File tree

1 file changed

+19
-18
lines changed

1 file changed

+19
-18
lines changed

docs/philosophy.md

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -63,42 +63,43 @@ The type `Series[Timestamp]` is the result of creating a series from `pd.to_date
6363
the type `TimedeltaSeries` is the result of subtracting two `Series[Timestamp]` as well as
6464
the result of `pd.to_timedelta()`.
6565

66-
### Generic Series have restricted arithmetic
66+
### Progressive arithmetic typing for generic Series
6767

6868
Consider the following Series from a DataFrame:
6969

7070
```python
7171
import pandas as pd
7272
from 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]})
8076
values = frame["value"]
8177
reveal_type(values) # type checker: Series[Any], runtime: Series
8278
new_values = values + 2
8379

8480
timestamps = 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

8983
tags = 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`
9488
and `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

Comments
 (0)