Repository: pandas-dev/pandas-stubs (language: python)

Issue:
pandas.DataFrame.from_dict : issue with dtype and columns arguments types
**Describe the bug**
issue with types for `pandas.DataFrame.from_dict` method:

- `dtype` is restricted to str in the stub file when pands allows for `str`, `type` and `None`
- `columns` is restricted to list of strings when pandas allows for much more (at least: str, int, float, datetime)

**To Reproduce**
1. minimal exemple:

```python
import pandas as pd
import datetime

data = {'l1': [1, 2, 3],
        'l2': [4, 5, 6]}

# all of the following are accepted by pandas
# however mypy complains with the last 3
pd.DataFrame.from_dict(data, orient='index')  # OK
pd.DataFrame.from_dict(data, orient='index', dtype='float')  # OK
pd.DataFrame.from_dict(data, orient='index', columns=['a', 'b', 'c'])  # OK
pd.DataFrame.from_dict(data, orient='index', dtype=float)  # NOK
pd.DataFrame.from_dict(data, orient='index', dtype=None)  # NOK
pd.DataFrame.from_dict(data, orient='index',
                       columns=[1.0, 2, datetime.datetime.now()])  # NOK
```

2. type checker :  `mypy`
3. typing errors: 

```
from_dict_test.py:12: error: Argument "dtype" to "from_dict" of "DataFrame" has incompatible type "type[float]"; expected "str"  [arg-type]
from_dict_test.py:13: error: Argument "dtype" to "from_dict" of "DataFrame" has incompatible type "None"; expected "str"  [arg-type]
from_dict_test.py:15: error: List item 0 has incompatible type "float"; expected "str"  [list-item]
from_dict_test.py:15: error: List item 1 has incompatible type "int"; expected "str"  [list-item]
from_dict_test.py:15: error: List item 2 has incompatible type "datetime"; expected "str"  [list-item]
```

**Please complete the following information:**
 - OS: Windows
 - Windows 10 22H2   build: 19045.4170
 - Python 3.12.2 | packaged by Anaconda, Inc. | (main, Feb 27 2024, 17:28:07) [MSC v.1916 64 bit (AMD64)] on win32
 - mypy                          1.9.0
 - pandas-stubs                  2.2.0.240218

pandas.DataFrame.from_dict : issue with dtype and columns arguments types
**Describe the bug**
issue with types for `pandas.DataFrame.from_dict` method:

- `dtype` is restricted to str in the stub file when pands allows for `str`, `type` and `None`
- `columns` is restricted to list of strings when pandas allows for much more (at least: str, int, float, datetime)

**To Reproduce**
1. minimal exemple:

```python
import pandas as pd
import datetime

data = {'l1': [1, 2, 3],
        'l2': [4, 5, 6]}

# all of the following are accepted by pandas
# however mypy complains with the last 3
pd.DataFrame.from_dict(data, orient='index')  # OK
pd.DataFrame.from_dict(data, orient='index', dtype='float')  # OK
pd.DataFrame.from_dict(data, orient='index', columns=['a', 'b', 'c'])  # OK
pd.DataFrame.from_dict(data, orient='index', dtype=float)  # NOK
pd.DataFrame.from_dict(data, orient='index', dtype=None)  # NOK
pd.DataFrame.from_dict(data, orient='index',
                       columns=[1.0, 2, datetime.datetime.now()])  # NOK
```

2. type checker :  `mypy`
3. typing errors: 

```
from_dict_test.py:12: error: Argument "dtype" to "from_dict" of "DataFrame" has incompatible type "type[float]"; expected "str"  [arg-type]
from_dict_test.py:13: error: Argument "dtype" to "from_dict" of "DataFrame" has incompatible type "None"; expected "str"  [arg-type]
from_dict_test.py:15: error: List item 0 has incompatible type "float"; expected "str"  [list-item]
from_dict_test.py:15: error: List item 1 has incompatible type "int"; expected "str"  [list-item]
from_dict_test.py:15: error: List item 2 has incompatible type "datetime"; expected "str"  [list-item]
```

**Please complete the following information:**
 - OS: Windows
 - Windows 10 22H2   build: 19045.4170
 - Python 3.12.2 | packaged by Anaconda, Inc. | (main, Feb 27 2024, 17:28:07) [MSC v.1916 64 bit (AMD64)] on win32
 - mypy                          1.9.0
 - pandas-stubs                  2.2.0.240218

pandas.DataFrame.from_dict : issue with dtype and columns arguments types
**Describe the bug**
issue with types for `pandas.DataFrame.from_dict` method:

- `dtype` is restricted to str in the stub file when pands allows for `str`, `type` and `None`
- `columns` is restricted to list of strings when pandas allows for much more (at least: str, int, float, datetime)

**To Reproduce**
1. minimal exemple:

```python
import pandas as pd
import datetime

data = {'l1': [1, 2, 3],
        'l2': [4, 5, 6]}

# all of the following are accepted by pandas
# however mypy complains with the last 3
pd.DataFrame.from_dict(data, orient='index')  # OK
pd.DataFrame.from_dict(data, orient='index', dtype='float')  # OK
pd.DataFrame.from_dict(data, orient='index', columns=['a', 'b', 'c'])  # OK
pd.DataFrame.from_dict(data, orient='index', dtype=float)  # NOK
pd.DataFrame.from_dict(data, orient='index', dtype=None)  # NOK
pd.DataFrame.from_dict(data, orient='index',
                       columns=[1.0, 2, datetime.datetime.now()])  # NOK
```

2. type checker :  `mypy`
3. typing errors: 

```
from_dict_test.py:12: error: Argument "dtype" to "from_dict" of "DataFrame" has incompatible type "type[float]"; expected "str"  [arg-type]
from_dict_test.py:13: error: Argument "dtype" to "from_dict" of "DataFrame" has incompatible type "None"; expected "str"  [arg-type]
from_dict_test.py:15: error: List item 0 has incompatible type "float"; expected "str"  [list-item]
from_dict_test.py:15: error: List item 1 has incompatible type "int"; expected "str"  [list-item]
from_dict_test.py:15: error: List item 2 has incompatible type "datetime"; expected "str"  [list-item]
```

**Please complete the following information:**
 - OS: Windows
 - Windows 10 22H2   build: 19045.4170
 - Python 3.12.2 | packaged by Anaconda, Inc. | (main, Feb 27 2024, 17:28:07) [MSC v.1916 64 bit (AMD64)] on win32
 - mypy                          1.9.0
 - pandas-stubs                  2.2.0.240218



Discussion / hints:
Thanks for the report.

There are multiple issues with the stub for `DataFrame.from_dict()`.
- Argument `dtype` should be `AsTypeArg | None`
- Argument `columns` should be `Axes | None`, but only if `orient==Literal["index"]`

So those updates could be done to the stubs, with an appropriate overload to handle the `columns` argument only being accepted for `orient=="index"` .

PR with tests welcome.

I think I can handle that, I'll give it a try anyway. Thanks for the tips
Thanks for the report.

There are multiple issues with the stub for `DataFrame.from_dict()`.
- Argument `dtype` should be `AsTypeArg | None`
- Argument `columns` should be `Axes | None`, but only if `orient==Literal["index"]`

So those updates could be done to the stubs, with an appropriate overload to handle the `columns` argument only being accepted for `orient=="index"` .

PR with tests welcome.

I think I can handle that, I'll give it a try anyway. Thanks for the tips
Thanks for the report.

There are multiple issues with the stub for `DataFrame.from_dict()`.
- Argument `dtype` should be `AsTypeArg | None`
- Argument `columns` should be `Axes | None`, but only if `orient==Literal["index"]`

So those updates could be done to the stubs, with an appropriate overload to handle the `columns` argument only being accepted for `orient=="index"` .

PR with tests welcome.

I think I can handle that, I'll give it a try anyway. Thanks for the tips

Fix patch:
diff --git a/pandas-stubs/_libs/tslibs/timestamps.pyi b/pandas-stubs/_libs/tslibs/timestamps.pyi
index af856ae6..9df14b3d 100644
--- a/pandas-stubs/_libs/tslibs/timestamps.pyi
+++ b/pandas-stubs/_libs/tslibs/timestamps.pyi
@@ -219,7 +219,7 @@ class Timestamp(datetime):
     @overload
     def __sub__(self, other: TimedeltaSeries) -> TimestampSeries: ...
     @overload
-    def __sub__(  # pyright: ignore[reportIncompatibleMethodOverride]
+    def __sub__(
         self, other: npt.NDArray[np.timedelta64]
     ) -> npt.NDArray[np.datetime64]: ...
     @overload
diff --git a/pandas-stubs/core/frame.pyi b/pandas-stubs/core/frame.pyi
index 7ce2f5d6..44b3a080 100644
--- a/pandas-stubs/core/frame.pyi
+++ b/pandas-stubs/core/frame.pyi
@@ -272,13 +272,22 @@ class DataFrame(NDFrame, OpsMixin):
     def dot(self, other: Series) -> Series: ...
     def __matmul__(self, other): ...
     def __rmatmul__(self, other): ...
+    @overload
+    @classmethod
+    def from_dict(
+        cls,
+        data: dict[Any, Any],
+        orient: Literal["index"],
+        dtype: AstypeArg | None = ...,
+        columns: Axes | None = ...,
+    ) -> DataFrame: ...
+    @overload
     @classmethod
     def from_dict(
         cls,
         data: dict[Any, Any],
-        orient: Literal["columns", "index", "tight"] = ...,
-        dtype: _str = ...,
-        columns: list[_str] = ...,
+        orient: Literal["columns", "tight"] = ...,
+        dtype: AstypeArg | None = ...,
     ) -> DataFrame: ...
     def to_numpy(
         self,


Test patch:
diff --git a/tests/test_frame.py b/tests/test_frame.py
index af3183b9..099d608b 100644
--- a/tests/test_frame.py
+++ b/tests/test_frame.py
@@ -1438,25 +1438,114 @@ def test_types_to_dict() -> None:
 
 
 def test_types_from_dict() -> None:
-    pd.DataFrame.from_dict({"col_1": [3, 2, 1, 0], "col_2": ["a", "b", "c", "d"]})
-    pd.DataFrame.from_dict({1: [3, 2, 1, 0], 2: ["a", "b", "c", "d"]})
-    pd.DataFrame.from_dict({"a": {1: 2}, "b": {3: 4, 1: 4}}, orient="index")
-    pd.DataFrame.from_dict({"a": {"row1": 2}, "b": {"row2": 4, "row1": 4}})
-    pd.DataFrame.from_dict({"a": (1, 2, 3), "b": (2, 4, 5)})
-    pd.DataFrame.from_dict(
-        data={"col_1": {"a": 1}, "col_2": {"a": 1, "b": 2}}, orient="columns"
+    check(
+        assert_type(
+            pd.DataFrame.from_dict(
+                {"col_1": [3, 2, 1, 0], "col_2": ["a", "b", "c", "d"]}
+            ),
+            pd.DataFrame,
+        ),
+        pd.DataFrame,
+    )
+    check(
+        assert_type(
+            pd.DataFrame.from_dict({1: [3, 2, 1, 0], 2: ["a", "b", "c", "d"]}),
+            pd.DataFrame,
+        ),
+        pd.DataFrame,
+    )
+    check(
+        assert_type(
+            pd.DataFrame.from_dict({"a": {1: 2}, "b": {3: 4, 1: 4}}, orient="index"),
+            pd.DataFrame,
+        ),
+        pd.DataFrame,
+    )
+    check(
+        assert_type(
+            pd.DataFrame.from_dict({"a": {"row1": 2}, "b": {"row2": 4, "row1": 4}}),
+            pd.DataFrame,
+        ),
+        pd.DataFrame,
+    )
+    check(
+        assert_type(
+            pd.DataFrame.from_dict({"a": (1, 2, 3), "b": (2, 4, 5)}), pd.DataFrame
+        ),
+        pd.DataFrame,
+    )
+    check(
+        assert_type(
+            pd.DataFrame.from_dict(
+                data={"col_1": {"a": 1}, "col_2": {"a": 1, "b": 2}}, orient="columns"
+            ),
+            pd.DataFrame,
+        ),
+        pd.DataFrame,
     )
     # orient param accepting "tight" added in 1.4.0 https://pandas.pydata.org/docs/whatsnew/v1.4.0.html
-    pd.DataFrame.from_dict(
-        data={
-            "index": [("a", "b"), ("a", "c")],
-            "columns": [("x", 1), ("y", 2)],
-            "data": [[1, 3], [2, 4]],
-            "index_names": ["n1", "n2"],
-            "column_names": ["z1", "z2"],
-        },
-        orient="tight",
+    check(
+        assert_type(
+            pd.DataFrame.from_dict(
+                data={
+                    "index": [("a", "b"), ("a", "c")],
+                    "columns": [("x", 1), ("y", 2)],
+                    "data": [[1, 3], [2, 4]],
+                    "index_names": ["n1", "n2"],
+                    "column_names": ["z1", "z2"],
+                },
+                orient="tight",
+            ),
+            pd.DataFrame,
+        ),
+        pd.DataFrame,
+    )
+    # added following #896
+    data = {"l1": [1, 2, 3], "l2": [4, 5, 6]}
+    # testing `dtype`
+    check(
+        assert_type(
+            pd.DataFrame.from_dict(data, orient="index", dtype="float"), pd.DataFrame
+        ),
+        pd.DataFrame,
+    )
+    check(
+        assert_type(
+            pd.DataFrame.from_dict(data, orient="index", dtype=float), pd.DataFrame
+        ),
+        pd.DataFrame,
+    )
+    check(
+        assert_type(
+            pd.DataFrame.from_dict(data, orient="index", dtype=None), pd.DataFrame
+        ),
+        pd.DataFrame,
     )
+    # testing `columns`
+    check(
+        assert_type(
+            pd.DataFrame.from_dict(data, orient="index", columns=["a", "b", "c"]),
+            pd.DataFrame,
+        ),
+        pd.DataFrame,
+    )
+    check(
+        assert_type(
+            pd.DataFrame.from_dict(
+                data, orient="index", columns=[1.0, 2, datetime.datetime.now()]
+            ),
+            pd.DataFrame,
+        ),
+        pd.DataFrame,
+    )
+    if TYPE_CHECKING_INVALID_USAGE:
+        check(
+            assert_type(  # type: ignore[assert-type]
+                pd.DataFrame.from_dict(data, orient="columns", columns=["a", "b", "c"]),  # type: ignore[call-overload] # pyright: ignore[reportArgumentType]
+                pd.DataFrame,
+            ),
+            pd.DataFrame,
+        )
 
 
 def test_pipe() -> None: