Skip to content

Commit 12eb535

Browse files
committed
Merge branch 'master' into stable-dupe-sort
2 parents 546b9fa + baddf02 commit 12eb535

File tree

169 files changed

+2481
-2249
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

169 files changed

+2481
-2249
lines changed

.github/workflows/ci.yml

-6
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,6 @@ jobs:
3737
ci/code_checks.sh lint
3838
if: always()
3939

40-
- name: Dependencies consistency
41-
run: |
42-
source activate pandas-dev
43-
ci/code_checks.sh dependencies
44-
if: always()
45-
4640
- name: Checks on imported code
4741
run: |
4842
source activate pandas-dev

ci/code_checks.sh

+13-51
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,10 @@
1515
# $ ./ci/code_checks.sh code # checks on imported code
1616
# $ ./ci/code_checks.sh doctests # run doctests
1717
# $ ./ci/code_checks.sh docstrings # validate docstring errors
18-
# $ ./ci/code_checks.sh dependencies # check that dependencies are consistent
1918
# $ ./ci/code_checks.sh typing # run static type analysis
2019

21-
[[ -z "$1" || "$1" == "lint" || "$1" == "patterns" || "$1" == "code" || "$1" == "doctests" || "$1" == "docstrings" || "$1" == "dependencies" || "$1" == "typing" ]] || \
22-
{ echo "Unknown command $1. Usage: $0 [lint|patterns|code|doctests|docstrings|dependencies|typing]"; exit 9999; }
20+
[[ -z "$1" || "$1" == "lint" || "$1" == "patterns" || "$1" == "code" || "$1" == "doctests" || "$1" == "docstrings" || "$1" == "typing" ]] || \
21+
{ echo "Unknown command $1. Usage: $0 [lint|patterns|code|doctests|docstrings|typing]"; exit 9999; }
2322

2423
BASE_DIR="$(dirname $0)/.."
2524
RET=0
@@ -38,6 +37,12 @@ function invgrep {
3837
return $((! $EXIT_STATUS))
3938
}
4039

40+
function check_namespace {
41+
local -r CLASS="${1}"
42+
grep -R -l --include "*.py" " ${CLASS}(" pandas/tests | xargs grep -n "pd\.${CLASS}("
43+
test $? -gt 0
44+
}
45+
4146
if [[ "$GITHUB_ACTIONS" == "true" ]]; then
4247
FLAKE8_FORMAT="##[error]%(path)s:%(row)s:%(col)s:%(code)s:%(text)s"
4348
INVGREP_PREPEND="##[error]"
@@ -48,31 +53,6 @@ fi
4853
### LINTING ###
4954
if [[ -z "$CHECK" || "$CHECK" == "lint" ]]; then
5055

51-
echo "black --version"
52-
black --version
53-
54-
MSG='Checking black formatting' ; echo $MSG
55-
black . --check
56-
RET=$(($RET + $?)) ; echo $MSG "DONE"
57-
58-
# `setup.cfg` contains the list of error codes that are being ignored in flake8
59-
60-
echo "flake8 --version"
61-
flake8 --version
62-
63-
# pandas/_libs/src is C code, so no need to search there.
64-
MSG='Linting .py code' ; echo $MSG
65-
flake8 --format="$FLAKE8_FORMAT" .
66-
RET=$(($RET + $?)) ; echo $MSG "DONE"
67-
68-
MSG='Linting .pyx and .pxd code' ; echo $MSG
69-
flake8 --format="$FLAKE8_FORMAT" pandas --append-config=flake8/cython.cfg
70-
RET=$(($RET + $?)) ; echo $MSG "DONE"
71-
72-
MSG='Linting .pxi.in' ; echo $MSG
73-
flake8 --format="$FLAKE8_FORMAT" pandas/_libs --append-config=flake8/cython-template.cfg
74-
RET=$(($RET + $?)) ; echo $MSG "DONE"
75-
7656
# Check that cython casting is of the form `<type>obj` as opposed to `<type> obj`;
7757
# it doesn't make a difference, but we want to be internally consistent.
7858
# Note: this grep pattern is (intended to be) equivalent to the python
@@ -125,19 +105,6 @@ if [[ -z "$CHECK" || "$CHECK" == "lint" ]]; then
125105
fi
126106
RET=$(($RET + $?)) ; echo $MSG "DONE"
127107

128-
echo "isort --version-number"
129-
isort --version-number
130-
131-
# Imports - Check formatting using isort see setup.cfg for settings
132-
MSG='Check import format using isort' ; echo $MSG
133-
ISORT_CMD="isort --quiet --check-only pandas asv_bench scripts web"
134-
if [[ "$GITHUB_ACTIONS" == "true" ]]; then
135-
eval $ISORT_CMD | awk '{print "##[error]" $0}'; RET=$(($RET + ${PIPESTATUS[0]}))
136-
else
137-
eval $ISORT_CMD
138-
fi
139-
RET=$(($RET + $?)) ; echo $MSG "DONE"
140-
141108
fi
142109

143110
### PATTERNS ###
@@ -234,6 +201,11 @@ if [[ -z "$CHECK" || "$CHECK" == "patterns" ]]; then
234201
MSG='Check code for instances of os.remove' ; echo $MSG
235202
invgrep -R --include="*.py*" --exclude "common.py" --exclude "test_writers.py" --exclude "test_store.py" -E "os\.remove" pandas/tests/
236203
RET=$(($RET + $?)) ; echo $MSG "DONE"
204+
205+
MSG='Check for inconsistent use of pandas namespace in tests' ; echo $MSG
206+
check_namespace "Series"
207+
RET=$(($RET + $?))
208+
echo $MSG "DONE"
237209
fi
238210

239211
### CODE ###
@@ -354,15 +326,6 @@ if [[ -z "$CHECK" || "$CHECK" == "docstrings" ]]; then
354326

355327
fi
356328

357-
### DEPENDENCIES ###
358-
if [[ -z "$CHECK" || "$CHECK" == "dependencies" ]]; then
359-
360-
MSG='Check that requirements-dev.txt has been generated from environment.yml' ; echo $MSG
361-
$BASE_DIR/scripts/generate_pip_deps_from_conda.py --compare --azure
362-
RET=$(($RET + $?)) ; echo $MSG "DONE"
363-
364-
fi
365-
366329
### TYPING ###
367330
if [[ -z "$CHECK" || "$CHECK" == "typing" ]]; then
368331

@@ -374,5 +337,4 @@ if [[ -z "$CHECK" || "$CHECK" == "typing" ]]; then
374337
RET=$(($RET + $?)) ; echo $MSG "DONE"
375338
fi
376339

377-
378340
exit $RET

doc/source/getting_started/index.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -533,7 +533,7 @@ pandas has great support for time series and has an extensive set of tools for w
533533
<div id="collapseTen" class="collapse" data-parent="#accordion">
534534
<div class="card-body">
535535

536-
Data sets do not only contain numerical data. pandas provides a wide range of functions to cleaning textual data and extract useful information from it.
536+
Data sets do not only contain numerical data. pandas provides a wide range of functions to clean textual data and extract useful information from it.
537537

538538
.. raw:: html
539539

doc/source/index.rst.template

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pandas documentation
1717
`Source Repository <https://github.com/pandas-dev/pandas>`__ |
1818
`Issues & Ideas <https://github.com/pandas-dev/pandas/issues>`__ |
1919
`Q&A Support <https://stackoverflow.com/questions/tagged/pandas>`__ |
20-
`Mailing List <https://groups.google.com/forum/#!forum/pydata>`__
20+
`Mailing List <https://groups.google.com/g/pydata>`__
2121

2222
:mod:`pandas` is an open source, BSD-licensed library providing high-performance,
2323
easy-to-use data structures and data analysis tools for the `Python <https://www.python.org/>`__

doc/source/whatsnew/v1.1.4.rst

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ Fixed regressions
2121
- Fixed regression in :meth:`Series.astype` converting ``None`` to ``"nan"`` when casting to string (:issue:`36904`)
2222
- Fixed regression in :class:`RollingGroupby` causing a segmentation fault with Index of dtype object (:issue:`36727`)
2323
- Fixed regression in :meth:`DataFrame.resample(...).apply(...)` raised ``AttributeError`` when input was a :class:`DataFrame` and only a :class:`Series` was evaluated (:issue:`36951`)
24+
- Fixed regression in :class:`PeriodDtype` comparing both equal and unequal to its string representation (:issue:`37265`)
2425

2526
.. ---------------------------------------------------------------------------
2627

doc/source/whatsnew/v1.2.0.rst

+2-2
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,7 @@ Conversion
409409
Strings
410410
^^^^^^^
411411
- Bug in :meth:`Series.to_string`, :meth:`DataFrame.to_string`, and :meth:`DataFrame.to_latex` adding a leading space when ``index=False`` (:issue:`24980`)
412-
-
412+
- Bug in :func:`to_numeric` raising a ``TypeError`` when attempting to convert a string dtype :class:`Series` containing only numeric strings and ``NA`` (:issue:`37262`)
413413
-
414414

415415

@@ -524,7 +524,7 @@ Other
524524
- Bug in :meth:`DataFrame.replace` and :meth:`Series.replace` incorrectly raising ``AssertionError`` instead of ``ValueError`` when invalid parameter combinations are passed (:issue:`36045`)
525525
- Bug in :meth:`DataFrame.replace` and :meth:`Series.replace` with numeric values and string ``to_replace`` (:issue:`34789`)
526526
- Fixed bug in metadata propagation incorrectly copying DataFrame columns as metadata when the column name overlaps with the metadata name (:issue:`37037`)
527-
- Fixed metadata propagation in the :class:`Series.dt` and :class:`Series.str` accessors (:issue:`28283`)
527+
- Fixed metadata propagation in the :class:`Series.dt` and :class:`Series.str` accessors and :class:`DataFrame.duplicated` and ::class:`DataFrame.stack` methods (:issue:`28283`)
528528
- Bug in :meth:`Index.union` behaving differently depending on whether operand is a :class:`Index` or other list-like (:issue:`36384`)
529529
- Passing an array with 2 or more dimensions to the :class:`Series` constructor now raises the more specific ``ValueError``, from a bare ``Exception`` previously (:issue:`35744`)
530530

pandas/_libs/lib.pyx

+1-1
Original file line numberDiff line numberDiff line change
@@ -2019,7 +2019,7 @@ def maybe_convert_numeric(ndarray[object] values, set na_values,
20192019
elif util.is_bool_object(val):
20202020
floats[i] = uints[i] = ints[i] = bools[i] = val
20212021
seen.bool_ = True
2022-
elif val is None:
2022+
elif val is None or val is C_NA:
20232023
seen.saw_null()
20242024
floats[i] = complexes[i] = NaN
20252025
elif hasattr(val, '__len__') and len(val) == 0:

pandas/_testing.py

+46-19
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import gzip
77
import operator
88
import os
9+
import re
910
from shutil import rmtree
1011
import string
1112
import tempfile
@@ -2546,10 +2547,11 @@ def wrapper(*args, **kwargs):
25462547

25472548
@contextmanager
25482549
def assert_produces_warning(
2549-
expected_warning=Warning,
2550+
expected_warning: Optional[Union[Type[Warning], bool]] = Warning,
25502551
filter_level="always",
2551-
check_stacklevel=True,
2552-
raise_on_extra_warnings=True,
2552+
check_stacklevel: bool = True,
2553+
raise_on_extra_warnings: bool = True,
2554+
match: Optional[str] = None,
25532555
):
25542556
"""
25552557
Context manager for running code expected to either raise a specific
@@ -2584,6 +2586,8 @@ class for all warnings. To check that no warning is returned,
25842586
raise_on_extra_warnings : bool, default True
25852587
Whether extra warnings not of the type `expected_warning` should
25862588
cause the test to fail.
2589+
match : str, optional
2590+
Match warning message.
25872591
25882592
Examples
25892593
--------
@@ -2610,28 +2614,28 @@ class for all warnings. To check that no warning is returned,
26102614
with warnings.catch_warnings(record=True) as w:
26112615

26122616
saw_warning = False
2617+
matched_message = False
2618+
26132619
warnings.simplefilter(filter_level)
26142620
yield w
26152621
extra_warnings = []
26162622

26172623
for actual_warning in w:
2618-
if expected_warning and issubclass(
2619-
actual_warning.category, expected_warning
2620-
):
2624+
if not expected_warning:
2625+
continue
2626+
2627+
expected_warning = cast(Type[Warning], expected_warning)
2628+
if issubclass(actual_warning.category, expected_warning):
26212629
saw_warning = True
26222630

26232631
if check_stacklevel and issubclass(
26242632
actual_warning.category, (FutureWarning, DeprecationWarning)
26252633
):
2626-
from inspect import getframeinfo, stack
2634+
_assert_raised_with_correct_stacklevel(actual_warning)
2635+
2636+
if match is not None and re.search(match, str(actual_warning.message)):
2637+
matched_message = True
26272638

2628-
caller = getframeinfo(stack()[2][0])
2629-
msg = (
2630-
"Warning not set with correct stacklevel. "
2631-
f"File where warning is raised: {actual_warning.filename} != "
2632-
f"{caller.filename}. Warning message: {actual_warning.message}"
2633-
)
2634-
assert actual_warning.filename == caller.filename, msg
26352639
else:
26362640
extra_warnings.append(
26372641
(
@@ -2641,18 +2645,41 @@ class for all warnings. To check that no warning is returned,
26412645
actual_warning.lineno,
26422646
)
26432647
)
2648+
26442649
if expected_warning:
2645-
msg = (
2646-
f"Did not see expected warning of class "
2647-
f"{repr(expected_warning.__name__)}"
2648-
)
2649-
assert saw_warning, msg
2650+
expected_warning = cast(Type[Warning], expected_warning)
2651+
if not saw_warning:
2652+
raise AssertionError(
2653+
f"Did not see expected warning of class "
2654+
f"{repr(expected_warning.__name__)}"
2655+
)
2656+
2657+
if match and not matched_message:
2658+
raise AssertionError(
2659+
f"Did not see warning {repr(expected_warning.__name__)} "
2660+
f"matching {match}"
2661+
)
2662+
26502663
if raise_on_extra_warnings and extra_warnings:
26512664
raise AssertionError(
26522665
f"Caused unexpected warning(s): {repr(extra_warnings)}"
26532666
)
26542667

26552668

2669+
def _assert_raised_with_correct_stacklevel(
2670+
actual_warning: warnings.WarningMessage,
2671+
) -> None:
2672+
from inspect import getframeinfo, stack
2673+
2674+
caller = getframeinfo(stack()[3][0])
2675+
msg = (
2676+
"Warning not set with correct stacklevel. "
2677+
f"File where warning is raised: {actual_warning.filename} != "
2678+
f"{caller.filename}. Warning message: {actual_warning.message}"
2679+
)
2680+
assert actual_warning.filename == caller.filename, msg
2681+
2682+
26562683
class RNGContext:
26572684
"""
26582685
Context manager to set the numpy random number generator speed. Returns

pandas/_typing.py

+6
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@
3838
from pandas.core.indexes.base import Index
3939
from pandas.core.series import Series
4040

41+
from pandas.io.formats.format import EngFormatter
42+
4143
# array-like
4244

4345
AnyArrayLike = TypeVar("AnyArrayLike", "ExtensionArray", "Index", "Series", np.ndarray)
@@ -127,6 +129,10 @@
127129
EncodingVar = TypeVar("EncodingVar", str, None, Optional[str])
128130

129131

132+
# type of float formatter in DataFrameFormatter
133+
FloatFormatType = Union[str, Callable, "EngFormatter"]
134+
135+
130136
@dataclass
131137
class IOargs(Generic[ModeVar, EncodingVar]):
132138
"""

pandas/core/arrays/datetimelike.py

+7-8
Original file line numberDiff line numberDiff line change
@@ -444,7 +444,7 @@ def _validate_comparison_value(self, other, opname: str):
444444

445445
else:
446446
try:
447-
other = self._validate_listlike(other, opname, allow_object=True)
447+
other = self._validate_listlike(other, allow_object=True)
448448
self._check_compatible_with(other)
449449
except TypeError as err:
450450
if is_object_dtype(getattr(other, "dtype", None)):
@@ -548,7 +548,7 @@ def _validate_scalar(self, value, msg: Optional[str] = None):
548548

549549
return value
550550

551-
def _validate_listlike(self, value, opname: str, allow_object: bool = False):
551+
def _validate_listlike(self, value, allow_object: bool = False):
552552
if isinstance(value, type(self)):
553553
return value
554554

@@ -578,18 +578,17 @@ def _validate_listlike(self, value, opname: str, allow_object: bool = False):
578578

579579
elif not type(self)._is_recognized_dtype(value.dtype):
580580
raise TypeError(
581-
f"{opname} requires compatible dtype or scalar, "
582-
f"not {type(value).__name__}"
581+
f"value should be a '{self._scalar_type.__name__}', 'NaT', "
582+
f"or array of those. Got '{type(value).__name__}' instead."
583583
)
584-
585584
return value
586585

587586
def _validate_searchsorted_value(self, value):
588587
msg = "searchsorted requires compatible dtype or scalar"
589588
if not is_list_like(value):
590589
value = self._validate_scalar(value, msg)
591590
else:
592-
value = self._validate_listlike(value, "searchsorted")
591+
value = self._validate_listlike(value)
593592

594593
rv = self._unbox(value)
595594
return self._rebox_native(rv)
@@ -600,7 +599,7 @@ def _validate_setitem_value(self, value):
600599
f"or array of those. Got '{type(value).__name__}' instead."
601600
)
602601
if is_list_like(value):
603-
value = self._validate_listlike(value, "setitem")
602+
value = self._validate_listlike(value)
604603
else:
605604
value = self._validate_scalar(value, msg)
606605

@@ -622,7 +621,7 @@ def _validate_where_value(self, other):
622621
if not is_list_like(other):
623622
other = self._validate_scalar(other, msg)
624623
else:
625-
other = self._validate_listlike(other, "where")
624+
other = self._validate_listlike(other)
626625

627626
return self._unbox(other, setitem=True)
628627

pandas/core/dtypes/dtypes.py

+3
Original file line numberDiff line numberDiff line change
@@ -907,6 +907,9 @@ def __eq__(self, other: Any) -> bool:
907907

908908
return isinstance(other, PeriodDtype) and self.freq == other.freq
909909

910+
def __ne__(self, other: Any) -> bool:
911+
return not self.__eq__(other)
912+
910913
def __setstate__(self, state):
911914
# for pickle compat. __getstate__ is defined in the
912915
# PandasExtensionDtype superclass and uses the public properties to

0 commit comments

Comments
 (0)