Skip to content

Commit 73f9d27

Browse files
committed
Merge remote-tracking branch 'upstream/main' into tst/ref/test_sql
2 parents e523283 + 6f950c1 commit 73f9d27

35 files changed

+282
-125
lines changed

doc/source/user_guide/timeseries.rst

+15-15
Original file line numberDiff line numberDiff line change
@@ -890,7 +890,7 @@ into ``freq`` keyword arguments. The available date offsets and associated frequ
890890
:class:`~pandas.tseries.offsets.CBMonthBegin` or :class:`~pandas.tseries.offsets.CustomBusinessMonthBegin`, ``'CBMS'``, "custom business month begin"
891891
:class:`~pandas.tseries.offsets.SemiMonthEnd`, ``'SM'``, "15th (or other day_of_month) and calendar month end"
892892
:class:`~pandas.tseries.offsets.SemiMonthBegin`, ``'SMS'``, "15th (or other day_of_month) and calendar month begin"
893-
:class:`~pandas.tseries.offsets.QuarterEnd`, ``'Q'``, "calendar quarter end"
893+
:class:`~pandas.tseries.offsets.QuarterEnd`, ``'QE'``, "calendar quarter end"
894894
:class:`~pandas.tseries.offsets.QuarterBegin`, ``'QS'``, "calendar quarter begin"
895895
:class:`~pandas.tseries.offsets.BQuarterEnd`, ``'BQ``, "business quarter end"
896896
:class:`~pandas.tseries.offsets.BQuarterBegin`, ``'BQS'``, "business quarter begin"
@@ -1254,7 +1254,7 @@ frequencies. We will refer to these aliases as *offset aliases*.
12541254
"SMS", "semi-month start frequency (1st and 15th)"
12551255
"BMS", "business month start frequency"
12561256
"CBMS", "custom business month start frequency"
1257-
"Q", "quarter end frequency"
1257+
"QE", "quarter end frequency"
12581258
"BQ", "business quarter end frequency"
12591259
"QS", "quarter start frequency"
12601260
"BQS", "business quarter start frequency"
@@ -1373,18 +1373,18 @@ For some frequencies you can specify an anchoring suffix:
13731373
"W\-THU", "weekly frequency (Thursdays)"
13741374
"W\-FRI", "weekly frequency (Fridays)"
13751375
"W\-SAT", "weekly frequency (Saturdays)"
1376-
"(B)Q(S)\-DEC", "quarterly frequency, year ends in December. Same as 'Q'"
1377-
"(B)Q(S)\-JAN", "quarterly frequency, year ends in January"
1378-
"(B)Q(S)\-FEB", "quarterly frequency, year ends in February"
1379-
"(B)Q(S)\-MAR", "quarterly frequency, year ends in March"
1380-
"(B)Q(S)\-APR", "quarterly frequency, year ends in April"
1381-
"(B)Q(S)\-MAY", "quarterly frequency, year ends in May"
1382-
"(B)Q(S)\-JUN", "quarterly frequency, year ends in June"
1383-
"(B)Q(S)\-JUL", "quarterly frequency, year ends in July"
1384-
"(B)Q(S)\-AUG", "quarterly frequency, year ends in August"
1385-
"(B)Q(S)\-SEP", "quarterly frequency, year ends in September"
1386-
"(B)Q(S)\-OCT", "quarterly frequency, year ends in October"
1387-
"(B)Q(S)\-NOV", "quarterly frequency, year ends in November"
1376+
"(B)Q(E)(S)\-DEC", "quarterly frequency, year ends in December. Same as 'QE'"
1377+
"(B)Q(E)(S)\-JAN", "quarterly frequency, year ends in January"
1378+
"(B)Q(E)(S)\-FEB", "quarterly frequency, year ends in February"
1379+
"(B)Q(E)(S)\-MAR", "quarterly frequency, year ends in March"
1380+
"(B)Q(E)(S)\-APR", "quarterly frequency, year ends in April"
1381+
"(B)Q(E)(S)\-MAY", "quarterly frequency, year ends in May"
1382+
"(B)Q(E)(S)\-JUN", "quarterly frequency, year ends in June"
1383+
"(B)Q(E)(S)\-JUL", "quarterly frequency, year ends in July"
1384+
"(B)Q(E)(S)\-AUG", "quarterly frequency, year ends in August"
1385+
"(B)Q(E)(S)\-SEP", "quarterly frequency, year ends in September"
1386+
"(B)Q(E)(S)\-OCT", "quarterly frequency, year ends in October"
1387+
"(B)Q(E)(S)\-NOV", "quarterly frequency, year ends in November"
13881388
"(B)Y(S)\-DEC", "annual frequency, anchored end of December. Same as 'Y'"
13891389
"(B)Y(S)\-JAN", "annual frequency, anchored end of January"
13901390
"(B)Y(S)\-FEB", "annual frequency, anchored end of February"
@@ -1692,7 +1692,7 @@ the end of the interval.
16921692
.. warning::
16931693

16941694
The default values for ``label`` and ``closed`` is '**left**' for all
1695-
frequency offsets except for 'ME', 'Y', 'Q', 'BME', 'BY', 'BQ', and 'W'
1695+
frequency offsets except for 'ME', 'Y', 'QE', 'BME', 'BY', 'BQ', and 'W'
16961696
which all have a default of 'right'.
16971697

16981698
This might unintendedly lead to looking ahead, where the value for a later

doc/source/whatsnew/v0.18.0.rst

+11-3
Original file line numberDiff line numberDiff line change
@@ -808,11 +808,19 @@ Upsampling operations take you from a lower frequency to a higher frequency. The
808808
performed with the ``Resampler`` objects with :meth:`~Resampler.backfill`,
809809
:meth:`~Resampler.ffill`, :meth:`~Resampler.fillna` and :meth:`~Resampler.asfreq` methods.
810810

811-
.. ipython:: python
811+
.. code-block:: ipython
812812
813-
s = pd.Series(np.arange(5, dtype='int64'),
813+
In [89]: s = pd.Series(np.arange(5, dtype='int64'),
814814
index=pd.date_range('2010-01-01', periods=5, freq='Q'))
815-
s
815+
816+
In [90]: s
817+
Out[90]:
818+
2010-03-31 0
819+
2010-06-30 1
820+
2010-09-30 2
821+
2010-12-31 3
822+
2011-03-31 4
823+
Freq: Q-DEC, Length: 5, dtype: int64
816824
817825
Previously
818826

doc/source/whatsnew/v2.1.2.rst

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ Bug fixes
3535
- Fixed bug in :meth:`Series.str.extractall` for :class:`ArrowDtype` dtype being converted to object (:issue:`53846`)
3636
- Fixed bug where PDEP-6 warning about setting an item of an incompatible dtype was being shown when creating a new conditional column (:issue:`55025`)
3737
- Silence ``Period[B]`` warnings introduced by :issue:`53446` during normal plotting activity (:issue:`55138`)
38+
- Fixed bug in :class:`Series` constructor not inferring string dtype when ``NA`` is the first value and ``infer_string`` is set (:issue:` 55655`)
3839

3940
.. ---------------------------------------------------------------------------
4041
.. _whatsnew_212.other:

doc/source/whatsnew/v2.2.0.rst

+21-2
Original file line numberDiff line numberDiff line change
@@ -210,8 +210,8 @@ Other API changes
210210
Deprecations
211211
~~~~~~~~~~~~
212212

213-
Deprecate alias ``M`` in favour of ``ME`` for offsets
214-
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
213+
Deprecate aliases ``M`` and ``Q`` in favour of ``ME`` and ``QE`` for offsets
214+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
215215

216216
The alias ``M`` is deprecated in favour of ``ME`` for offsets, please use ``ME`` for "month end" instead of ``M`` (:issue:`9586`)
217217

@@ -232,6 +232,25 @@ For example:
232232
233233
pd.date_range('2020-01-01', periods=3, freq='ME')
234234
235+
The alias ``Q`` is deprecated in favour of ``QE`` for offsets, please use ``QE`` for "quarter end" instead of ``Q`` (:issue:`9586`)
236+
237+
For example:
238+
239+
*Previous behavior*:
240+
241+
.. code-block:: ipython
242+
243+
In [8]: pd.date_range('2020-01-01', periods=3, freq='Q-NOV')
244+
Out[8]:
245+
DatetimeIndex(['2020-02-29', '2020-05-31', '2020-08-31'],
246+
dtype='datetime64[ns]', freq='Q-NOV')
247+
248+
*Future behavior*:
249+
250+
.. ipython:: python
251+
252+
pd.date_range('2020-01-01', periods=3, freq='QE-NOV')
253+
235254
Other Deprecations
236255
^^^^^^^^^^^^^^^^^^
237256
- Changed :meth:`Timedelta.resolution_string` to return ``h``, ``min``, ``s``, ``ms``, ``us``, and ``ns`` instead of ``H``, ``T``, ``S``, ``L``, ``U``, and ``N``, for compatibility with respective deprecations in frequency aliases (:issue:`52536`)

pandas/_libs/lib.pyx

+3
Original file line numberDiff line numberDiff line change
@@ -2665,6 +2665,9 @@ def maybe_convert_objects(ndarray[object] objects,
26652665
else:
26662666
seen.object_ = True
26672667
break
2668+
elif val is C_NA:
2669+
seen.object_ = True
2670+
continue
26682671
else:
26692672
seen.object_ = True
26702673
break

pandas/_libs/parsers.pyx

+4-4
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ cdef extern from "pandas/parser/tokenizer.h":
228228
# pick one, depending on whether the converter requires GIL
229229
double (*double_converter)(const char *, char **,
230230
char, char, char,
231-
int, int *, int *) nogil
231+
int, int *, int *) noexcept nogil
232232

233233
# error handling
234234
char *warn_msg
@@ -1605,7 +1605,7 @@ cdef _categorical_convert(parser_t *parser, int64_t col,
16051605

16061606
# -> ndarray[f'|S{width}']
16071607
cdef _to_fw_string(parser_t *parser, int64_t col, int64_t line_start,
1608-
int64_t line_end, int64_t width):
1608+
int64_t line_end, int64_t width) noexcept:
16091609
cdef:
16101610
char *data
16111611
ndarray result
@@ -1621,7 +1621,7 @@ cdef _to_fw_string(parser_t *parser, int64_t col, int64_t line_start,
16211621

16221622
cdef void _to_fw_string_nogil(parser_t *parser, int64_t col,
16231623
int64_t line_start, int64_t line_end,
1624-
size_t width, char *data) nogil:
1624+
size_t width, char *data) noexcept nogil:
16251625
cdef:
16261626
int64_t i
16271627
coliter_t it
@@ -1677,7 +1677,7 @@ cdef _try_double(parser_t *parser, int64_t col,
16771677
cdef int _try_double_nogil(parser_t *parser,
16781678
float64_t (*double_converter)(
16791679
const char *, char **, char,
1680-
char, char, int, int *, int *) nogil,
1680+
char, char, int, int *, int *) noexcept nogil,
16811681
int64_t col, int64_t line_start, int64_t line_end,
16821682
bint na_filter, kh_str_starts_t *na_hashset,
16831683
bint use_na_flist,

pandas/_libs/tslibs/dtypes.pyx

+26-1
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,19 @@ OFFSET_TO_PERIOD_FREQSTR: dict = {
201201
"us": "us",
202202
"ns": "ns",
203203
"h": "h",
204-
"Q": "Q",
204+
"QE": "Q",
205+
"QE-DEC": "Q-DEC",
206+
"QE-JAN": "Q-JAN",
207+
"QE-FEB": "Q-FEB",
208+
"QE-MAR": "Q-MAR",
209+
"QE-APR": "Q-APR",
210+
"QE-MAY": "Q-MAY",
211+
"QE-JUN": "Q-JUN",
212+
"QE-JUL": "Q-JUL",
213+
"QE-AUG": "Q-AUG",
214+
"QE-SEP": "Q-SEP",
215+
"QE-OCT": "Q-OCT",
216+
"QE-NOV": "Q-NOV",
205217
"W": "W",
206218
"ME": "M",
207219
"Y": "Y",
@@ -211,6 +223,19 @@ OFFSET_TO_PERIOD_FREQSTR: dict = {
211223
}
212224
OFFSET_DEPR_FREQSTR: dict[str, str]= {
213225
"M": "ME",
226+
"Q": "QE",
227+
"Q-DEC": "QE-DEC",
228+
"Q-JAN": "QE-JAN",
229+
"Q-FEB": "QE-FEB",
230+
"Q-MAR": "QE-MAR",
231+
"Q-APR": "QE-APR",
232+
"Q-MAY": "QE-MAY",
233+
"Q-JUN": "QE-JUN",
234+
"Q-JUL": "QE-JUL",
235+
"Q-AUG": "QE-AUG",
236+
"Q-SEP": "QE-SEP",
237+
"Q-OCT": "QE-OCT",
238+
"Q-NOV": "QE-NOV",
214239
}
215240
cdef dict c_OFFSET_TO_PERIOD_FREQSTR = OFFSET_TO_PERIOD_FREQSTR
216241
cdef dict c_OFFSET_DEPR_FREQSTR = OFFSET_DEPR_FREQSTR

pandas/_libs/tslibs/offsets.pyx

+4-4
Original file line numberDiff line numberDiff line change
@@ -2767,7 +2767,7 @@ cdef class QuarterEnd(QuarterOffset):
27672767
Timestamp('2022-03-31 00:00:00')
27682768
"""
27692769
_default_starting_month = 3
2770-
_prefix = "Q"
2770+
_prefix = "QE"
27712771
_day_opt = "end"
27722772

27732773
cdef readonly:
@@ -4585,7 +4585,7 @@ prefix_mapping = {
45854585
Second, # 's'
45864586
Minute, # 'min'
45874587
Micro, # 'us'
4588-
QuarterEnd, # 'Q'
4588+
QuarterEnd, # 'QE'
45894589
QuarterBegin, # 'QS'
45904590
Milli, # 'ms'
45914591
Hour, # 'h'
@@ -4603,7 +4603,7 @@ opattern = re.compile(
46034603

46044604
_lite_rule_alias = {
46054605
"W": "W-SUN",
4606-
"Q": "Q-DEC",
4606+
"QE": "QE-DEC",
46074607

46084608
"Y": "Y-DEC", # YearEnd(month=12),
46094609
"YS": "YS-JAN", # YearBegin(month=1),
@@ -4617,7 +4617,7 @@ _lite_rule_alias = {
46174617
"ns": "ns",
46184618
}
46194619

4620-
_dont_uppercase = {"h", "bh", "cbh", "MS", "ms", "s", "me"}
4620+
_dont_uppercase = {"h", "bh", "cbh", "MS", "ms", "s", "me", "qe"}
46214621

46224622

46234623
INVALID_FREQ_ERR_MSG = "Invalid frequency: {0}"

pandas/core/indexes/accessors.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ class DatetimeProperties(Properties):
284284
2 2
285285
dtype: int32
286286
287-
>>> quarters_series = pd.Series(pd.date_range("2000-01-01", periods=3, freq="q"))
287+
>>> quarters_series = pd.Series(pd.date_range("2000-01-01", periods=3, freq="QE"))
288288
>>> quarters_series
289289
0 2000-03-31
290290
1 2000-06-30

pandas/core/resample.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -2130,7 +2130,7 @@ def __init__(
21302130
else:
21312131
freq = to_offset(freq)
21322132

2133-
end_types = {"ME", "Y", "Q", "BME", "BY", "BQ", "W"}
2133+
end_types = {"ME", "Y", "QE", "BME", "BY", "BQ", "W"}
21342134
rule = freq.rule_code
21352135
if rule in end_types or ("-" in rule and rule[: rule.find("-")] in end_types):
21362136
if closed is None:
@@ -2329,7 +2329,7 @@ def _adjust_bin_edges(
23292329
if self.freq.name in ("BME", "ME", "W") or self.freq.name.split("-")[0] in (
23302330
"BQ",
23312331
"BY",
2332-
"Q",
2332+
"QE",
23332333
"Y",
23342334
"W",
23352335
):

pandas/io/json/_table_schema.py

+8-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from pandas._libs import lib
1616
from pandas._libs.json import ujson_loads
1717
from pandas._libs.tslibs import timezones
18+
from pandas._libs.tslibs.dtypes import freq_to_period_freqstr
1819
from pandas.util._exceptions import find_stack_level
1920

2021
from pandas.core.dtypes.base import _registry as registry
@@ -34,6 +35,8 @@
3435
from pandas import DataFrame
3536
import pandas.core.common as com
3637

38+
from pandas.tseries.frequencies import to_offset
39+
3740
if TYPE_CHECKING:
3841
from pandas._typing import (
3942
DtypeObj,
@@ -207,8 +210,12 @@ def convert_json_field_to_pandas_type(field) -> str | CategoricalDtype:
207210
if field.get("tz"):
208211
return f"datetime64[ns, {field['tz']}]"
209212
elif field.get("freq"):
213+
# GH#9586 rename frequency M to ME for offsets
214+
offset = to_offset(field["freq"])
215+
freq_n, freq_name = offset.n, offset.name
216+
freq = freq_to_period_freqstr(freq_n, freq_name)
210217
# GH#47747 using datetime over period to minimize the change surface
211-
return f"period[{field['freq']}]"
218+
return f"period[{freq}]"
212219
else:
213220
return "datetime64[ns]"
214221
elif typ == "any":

pandas/tests/arithmetic/test_datetime64.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1076,7 +1076,7 @@ def test_dt64arr_add_dtlike_raises(self, tz_naive_fixture, box_with_array):
10761076
# Note: freq here includes both Tick and non-Tick offsets; this is
10771077
# relevant because historically integer-addition was allowed if we had
10781078
# a freq.
1079-
@pytest.mark.parametrize("freq", ["h", "D", "W", "2ME", "MS", "Q", "B", None])
1079+
@pytest.mark.parametrize("freq", ["h", "D", "W", "2ME", "MS", "QE", "B", None])
10801080
@pytest.mark.parametrize("dtype", [None, "uint8"])
10811081
def test_dt64arr_addsub_intlike(
10821082
self, request, dtype, box_with_array, freq, tz_naive_fixture

pandas/tests/arrays/test_datetimelike.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030

3131

3232
# TODO: more freq variants
33-
@pytest.fixture(params=["D", "B", "W", "ME", "Q", "Y"])
33+
@pytest.fixture(params=["D", "B", "W", "ME", "QE", "Y"])
3434
def freqstr(request):
3535
"""Fixture returning parametrized frequency in string format."""
3636
return request.param

pandas/tests/arrays/test_datetimes.py

+19
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,25 @@ def test_iter_zoneinfo_fold(self, tz):
746746
assert str(left) == str(right2)
747747
assert left.utcoffset() == right2.utcoffset()
748748

749+
@pytest.mark.parametrize(
750+
"freq, freq_depr",
751+
[
752+
("2ME", "2M"),
753+
("2QE", "2Q"),
754+
("2QE-SEP", "2Q-SEP"),
755+
],
756+
)
757+
def test_date_range_frequency_M_Q_deprecated(self, freq, freq_depr):
758+
# GH#9586
759+
depr_msg = (
760+
f"'{freq_depr[1:]}' will be deprecated, please use '{freq[1:]}' instead."
761+
)
762+
763+
expected = pd.date_range("1/1/2000", periods=4, freq=freq)
764+
with tm.assert_produces_warning(FutureWarning, match=depr_msg):
765+
result = pd.date_range("1/1/2000", periods=4, freq=freq_depr)
766+
tm.assert_index_equal(result, expected)
767+
749768

750769
def test_factorize_sort_without_freq():
751770
dta = DatetimeArray._from_sequence([0, 2, 1])

pandas/tests/frame/methods/test_asfreq.py

+17-6
Original file line numberDiff line numberDiff line change
@@ -234,12 +234,23 @@ def test_asfreq_2ME(self, freq, freq_half):
234234
result = DataFrame({"s": Series([0.0, 2.0, 4.0], index=index)})
235235
tm.assert_frame_equal(result, expected)
236236

237-
def test_asfreq_frequency_M_deprecated(self):
238-
depr_msg = "'M' will be deprecated, please use 'ME' instead."
237+
@pytest.mark.parametrize(
238+
"freq, freq_depr",
239+
[
240+
("2ME", "2M"),
241+
("2QE", "2Q"),
242+
("2QE-SEP", "2Q-SEP"),
243+
],
244+
)
245+
def test_asfreq_frequency_M_Q_deprecated(self, freq, freq_depr):
246+
# GH#9586
247+
depr_msg = (
248+
f"'{freq_depr[1:]}' will be deprecated, please use '{freq[1:]}' instead."
249+
)
239250

240-
index = date_range("1/1/2000", periods=4, freq="ME")
251+
index = date_range("1/1/2000", periods=4, freq=f"{freq[1:]}")
241252
df = DataFrame({"s": Series([0.0, 1.0, 2.0, 3.0], index=index)})
242-
expected = df.asfreq(freq="5ME")
253+
expected = df.asfreq(freq=freq)
243254
with tm.assert_produces_warning(FutureWarning, match=depr_msg):
244-
result = df.asfreq(freq="5M")
245-
tm.assert_frame_equal(result, expected)
255+
result = df.asfreq(freq=freq_depr)
256+
tm.assert_frame_equal(result, expected)

pandas/tests/frame/test_nonunique_indexes.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def test_setattr_columns_vs_construct_with_columns(self):
2929
check(df, expected)
3030

3131
def test_setattr_columns_vs_construct_with_columns_datetimeindx(self):
32-
idx = date_range("20130101", periods=4, freq="Q-NOV")
32+
idx = date_range("20130101", periods=4, freq="QE-NOV")
3333
df = DataFrame(
3434
[[1, 1, 1, 5], [1, 1, 2, 5], [2, 1, 3, 5]], columns=["a", "a", "a", "a"]
3535
)

pandas/tests/groupby/test_timegrouper.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ def test_timegrouper_with_reg_groups(self):
336336
)
337337
tm.assert_frame_equal(result, expected)
338338

339-
@pytest.mark.parametrize("freq", ["D", "ME", "Y", "Q-APR"])
339+
@pytest.mark.parametrize("freq", ["D", "ME", "Y", "QE-APR"])
340340
def test_timegrouper_with_reg_groups_freq(self, freq):
341341
# GH 6764 multiple grouping with/without sort
342342
df = DataFrame(

0 commit comments

Comments
 (0)