ENH: raise ValueError if invalid period freq pass to asfreq when the index of df is a PeriodIndex
State: closed

xref #55785, #52064

`PeriodIndex.asfreq` silently converts for offsets such as `offsets.MonthBegin()`, offsets.BusinessMonthEnd(), etc. (with no attribute '`_period_dtype_code'`) frequency to period frequency (in this case `'M'`).

Reproducible Example:
```
>>> import pandas as pd
>>> from pandas.tseries import offsets
>>>
>>> index = pd.PeriodIndex(["2020-01-01", "2021-01-01"], freq="Q")
>>> index.asfreq(freq=offsets.MonthBegin(1))
PeriodIndex(['2020-03', '2021-03'], dtype='period[M]')
>>>
>>> index.asfreq(freq=offsets.BusinessMonthEnd(1)) 
PeriodIndex(['2020-03', '2021-03'], dtype='period[M]')
```
the correct behaviour would be raising an Error:
```
>>> index.asfreq(freq=offsets.MonthBegin(1))
ValueError: <MonthBegin> is not supported as period frequency
```

Another problem: so far in the example below
```
>>> index = pd.PeriodIndex(["2020-01-01", "2021-01-01"], freq="M")
>>> index.asfreq(freq='BMS')
```
we get on main
```
AttributeError: 'pandas._libs.tslibs.offsets.BusinessMonthBegin' object has no attribute '_period_dtype_code'
```
the correct behaviour would be raising an Error:
```
ValueError: BMS is not supported as period frequency
```
added to the definition of asfreq a check if `string` denoting frequency is supported as period frequency. If the index of a DataFrame is a PeriodIndex and the frequency is invalid period frequency a `ValueError` is raised.

Labels:
name: Frequency
description: DateOffsets

Comments:
@MarcoGorelli, could you please take a look at this PR?
> nice one - does this mean it's also possible to get rid of the `except` in
> 
> https://github.com/pandas-dev/pandas/blob/acd914dedba087b3642e110aadac665006da23c0/pandas/core/resample.py#L2814-L2820
> 
> ?

I am afraid we can't rid of this block yet. When I removed this check the `test_asfreq_invalid_period_freq` in `pandas/tests/resample/test_period_index.py` failed. 

Without this block we silently convert index, for example:
```
index = pd.PeriodIndex(["2020-01-01", "2021-01-01"], freq="Q")
df = pd.DataFrame({"a": pd.Series([0, 1], index=index)})
res = df.asfreq(freq=offsets.BusinessMonthEnd(1))
print(res.index)

PeriodIndex(['2020-03', '2021-03'], dtype='period[M]')
```
> should be good thanks, just one minor comment
> 
> does this change anything since 2.2? if so, I'd say that a whatsnew note in 3.0 is warranted (or in 2.2.1 if it should be backported, for example if anything introduced in 2.2 wasn't correct and needs fixing here)

yes, I think we have an incorrect conversion in 2.2
```
>>> index = pd.PeriodIndex(["2020-01-01", "2021-01-01"], freq="M")
>>> index.asfreq(freq=offsets.MonthBegin(1))
PeriodIndex(['2020-03', '2021-03'], dtype='period[M]')
>>>
>>> index.asfreq(freq=offsets.YearBegin(1))
PeriodIndex(['2020', '2021'], dtype='period[Y-DEC]')
>>>
>>> index.asfreq(freq=offsets.BusinessMonthEnd(1))
PeriodIndex(['2020-03', '2021-03'], dtype='period[M]')
```
I fixed it in this PR and added an entry the 2.2.1. Now we raise a ValueError, e.g.
```
>>> index.asfreq(freq=offsets.MonthBegin(1))
ValueError: <MonthBegin> is not supported as period frequency
```
Owee, I'm MrMeeseeks, Look at me.

There seem to be a conflict, please backport manually. Here are approximate instructions:

1. Checkout backport branch and update it.

```
git checkout 2.2.x
git pull
```

2. Cherry pick the first parent branch of the this PR on top of the older branch:
```
git cherry-pick -x -m1 cb97ce6e496e7d1df76f06550c0fe8c4590ff3ce
```

3. You will likely have some merge/cherry-pick conflict here, fix them and commit:

```
git commit -am 'Backport PR #56945: ENH: raise ValueError if invalid period freq pass to asfreq when the index of df is a PeriodIndex'
```

4. Push to a named branch:

```
git push YOURFORK 2.2.x:auto-backport-of-pr-56945-on-2.2.x
```

5. Create a PR against branch 2.2.x, I would have named this PR:

> "Backport PR #56945 on branch 2.2.x (ENH: raise ValueError if invalid period freq pass to asfreq when the index of df is a PeriodIndex)"

And apply the correct labels and milestones.

Congratulations — you did some good work! Hopefully your backport PR will be tested by the continuous integration and merged soon!

Remember to remove the `Still Needs Manual Backport` label once the PR gets merged.

If these instructions are inaccurate, feel free to [suggest an improvement](https://github.com/MeeseeksBox/MeeseeksDev).
                
thanks @MarcoGorelli, for helping me with this PR!