Repository: pandas-dev/pandas
Pull request: TST: setitem preserving period[D] dtype
- [X] closes #39763 
- [x] [Tests added and passed](https://pandas.pydata.org/pandas-docs/dev/development/contributing_codebase.html#writing-tests) if fixing a bug or adding a new feature
- [x] All [code checks passed](https://pandas.pydata.org/pandas-docs/dev/development/contributing_codebase.html#pre-commit).
- [ ] Added [type annotations](https://pandas.pydata.org/pandas-docs/dev/development/contributing_codebase.html#type-hints) to new arguments/methods/functions.
- [ ] Added an entry in the latest `doc/source/whatsnew/vX.X.X.rst` file if fixing a bug or adding a new feature.


Problem statement:
BUG: setitem with ArrayManager not preserving PeriodDtype
cc @jorisvandenbossche this is coming up the quantile tests with --array-manager

```
index = pd.period_range("2016-01-01", periods=9, freq="D", name="A")
obj = pd.DataFrame(index).copy()

obj.iloc[:] = index._na_value

>>> obj.dtypes
A    datetime64[ns]
dtype: object
```

We'd like to keep `period[D]` here.

Hints from issue discussion:
That seems fixed with https://github.com/pandas-dev/pandas/pull/39578 (`setitem` is not yet implemented for ArrayManager on master)
fixed on main, may need test
take

Commit message: TST: setitem preserving period[D] dtype

Patch to review:
diff --git a/pandas/tests/frame/indexing/test_setitem.py b/pandas/tests/frame/indexing/test_setitem.py
index 049874a4dd46f..252b63f387045 100644
--- a/pandas/tests/frame/indexing/test_setitem.py
+++ b/pandas/tests/frame/indexing/test_setitem.py
@@ -379,6 +379,15 @@ def test_setitem_complete_column_with_array(self):
         assert expected["d"].dtype == arr.dtype
         tm.assert_frame_equal(df, expected)
 
+    def test_setitem_periodd_dtype(self):
+        # GH 39763
+        rng = period_range("2016-01-01", periods=9, freq="D", name="A")
+        df = DataFrame(rng)
+        expected = df.dtypes
+        df.iloc[:] = rng._na_value
+        result = df.dtypes
+        tm.assert_equal(result, expected)
+
     @pytest.mark.parametrize("dtype", ["f8", "i8", "u8"])
     def test_setitem_bool_with_numeric_index(self, dtype):
         # GH#36319


Code review comments:
diff_hunk: @@ -379,6 +379,15 @@ def test_setitem_complete_column_with_array(self):
         assert expected["d"].dtype == arr.dtype
         tm.assert_frame_equal(df, expected)
 
+    def test_setitem_periodd_dtype(self):
+        # GH 39763
+        rng = period_range("2016-01-01", periods=9, freq="D", name="A")
+        df = DataFrame(rng)
+        expected = df.dtypes
+        df.iloc[:] = rng._na_value
+        result = df.dtypes
+        tm.assert_equal(result, expected)
path: pandas/tests/frame/indexing/test_setitem.py
text: @user1:
Please construct the expected DataFrame and use `tm.assert_frame_equal`

@author:
> Please construct the expected DataFrame and use tm.assert_frame_equal

I'm a bit confused here, I thought that way but after executing this line `df.iloc[:] = rng._na_value` we get following o/p

```py
# o/p of  df.iloc[:] = rng._na_value
	A
0	NaT
1	NaT
2	NaT
3	NaT
4	NaT
5	NaT
6	NaT
7	NaT
8	NaT

# And it's data type
# -> df.dtypes
A    period[D]
dtype: object
```
and that was a  `result`.

but for `expected` when I tried creating the same data frame and changing its type to `period[D]` it did not work.
```py
expected = pd.DataFrame({"A": ['NaT', 'NaT', 'NaT', 'NaT', 'NaT', 'NaT', 'NaT', 'NaT', 'NaT']})
expected.astype(obj.dtypes) # 1 did not work
expected.astype("period[D]") # 2 did not work
expected.dtypes

# o/p
A    object
dtype: object
```

as per your suggestion, we can create a new data frame using period_range and compare using `tm.assert_frame_equal` here dtypes would be the same but the data is different so the test will fail.

I hope I'm able to describe the confusion clearly here.
Please let me know your thoughts on this.


@user1:
```
In [3]: pd.DataFrame({"A": ["NaT"]}, dtype="period[D]")
Out[3]: 
     A
0  NaT

In [4]: pd.DataFrame({"A": ["NaT"]}, dtype="period[D]").dtypes
Out[4]: 
A    period[D]
dtype: object
```

diff_hunk: @@ -379,6 +379,15 @@ def test_setitem_complete_column_with_array(self):
         assert expected["d"].dtype == arr.dtype
         tm.assert_frame_equal(df, expected)
 
+    def test_setitem_periodd_dtype(self):
path: pandas/tests/frame/indexing/test_setitem.py
text: @user1:
typo extra "d"

@author:
> typo extra "d"

Originally its `period[D]` but to name a function I thought this would be fine.

But I think there are ways we can rename
1. `..._period_d_dtpye(self)`
2. `..._period_dtype(self)`

What do you think?

@user2:
`_period_d_dtype` is fine

@author:
Okay! sounds good 👍
Thanks