From de1d11bdfe6fb5c08da1a6ce04ae534a757cec38 Mon Sep 17 00:00:00 2001 From: Simon Hawkins Date: Wed, 6 Mar 2019 14:32:48 +0000 Subject: [PATCH 01/10] REF: custom Exception for safe_sort --- pandas/core/arrays/categorical.py | 3 ++- pandas/core/indexes/base.py | 7 ++++--- pandas/core/sorting.py | 11 ++++++++--- pandas/errors/__init__.py | 7 +++++++ pandas/tests/test_algos.py | 9 +++------ pandas/tests/test_sorting.py | 12 ++++-------- 6 files changed, 28 insertions(+), 21 deletions(-) diff --git a/pandas/core/arrays/categorical.py b/pandas/core/arrays/categorical.py index 7f77a5dcce613..ad01a20b10464 100644 --- a/pandas/core/arrays/categorical.py +++ b/pandas/core/arrays/categorical.py @@ -9,6 +9,7 @@ import pandas.compat as compat from pandas.compat import lzip, u from pandas.compat.numpy import function as nv +from pandas.errors import SortError from pandas.util._decorators import ( Appender, Substitution, cache_readonly, deprecate_kwarg) from pandas.util._validators import validate_bool_kwarg, validate_fillna_kwargs @@ -356,7 +357,7 @@ def __init__(self, values, categories=None, ordered=None, dtype=None, if dtype.categories is None: try: codes, categories = factorize(values, sort=True) - except TypeError: + except SortError: codes, categories = factorize(values, sort=False) if dtype.ordered: # raise, as we don't have a sortable data structure and so diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index dee181fc1c569..88c0de893e1dd 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -13,6 +13,7 @@ import pandas.compat as compat from pandas.compat import range, set_function_name, u from pandas.compat.numpy import function as nv +from pandas.errors import SortError from pandas.util._decorators import Appender, Substitution, cache_readonly from pandas.core.dtypes.cast import maybe_cast_to_integer_array @@ -2344,7 +2345,7 @@ def union(self, other, sort=None): if sort is None: try: result = sorting.safe_sort(result) - except TypeError as e: + except SortError as e: warnings.warn("{}, sort order is undefined for " "incomparable objects".format(e), RuntimeWarning, stacklevel=3) @@ -2503,7 +2504,7 @@ def difference(self, other, sort=None): if sort is None: try: the_diff = sorting.safe_sort(the_diff) - except TypeError: + except SortError: pass return this._shallow_copy(the_diff, name=result_name, freq=None) @@ -2579,7 +2580,7 @@ def symmetric_difference(self, other, result_name=None, sort=None): if sort is None: try: the_diff = sorting.safe_sort(the_diff) - except TypeError: + except SortError: pass attribs = self._get_attributes_dict() diff --git a/pandas/core/sorting.py b/pandas/core/sorting.py index ef69939d6e978..596917b646d1e 100644 --- a/pandas/core/sorting.py +++ b/pandas/core/sorting.py @@ -5,6 +5,7 @@ from pandas._libs import algos, hashtable, lib from pandas._libs.hashtable import unique_label_indices from pandas.compat import PY3, long, string_types +from pandas.errors import SortError from pandas.core.dtypes.cast import infer_dtype_from_array from pandas.core.dtypes.common import ( @@ -430,8 +431,9 @@ def safe_sort(values, labels=None, na_sentinel=-1, assume_unique=False): ------ TypeError * If ``values`` is not list-like or if ``labels`` is neither None - nor list-like - * If ``values`` cannot be sorted + nor list-like. + pandas.error.SortError + * If ``values`` cannot be sorted. ValueError * If ``labels`` is not None and ``values`` contain duplicates. """ @@ -449,7 +451,10 @@ def sort_mixed(values): # order ints before strings, safe in py3 str_pos = np.array([isinstance(x, string_types) for x in values], dtype=bool) - nums = np.sort(values[~str_pos]) + try: + nums = np.sort(values[~str_pos]) + except TypeError as e: + raise SortError(e) from e strs = np.sort(values[str_pos]) return np.concatenate([nums, np.asarray(strs, dtype=object)]) diff --git a/pandas/errors/__init__.py b/pandas/errors/__init__.py index 7d5a7f1a99e41..344c3bb929891 100644 --- a/pandas/errors/__init__.py +++ b/pandas/errors/__init__.py @@ -157,6 +157,13 @@ class MergeError(ValueError): """ +class SortError(TypeError): + """ + Error raised when problems arise during sorting due to problems + with input data. Subclass of `TypeError`. + """ + + class NullFrequencyError(ValueError): """ Error raised when a null `freq` attribute is used in an operation diff --git a/pandas/tests/test_algos.py b/pandas/tests/test_algos.py index 3f75c508d22f9..7241af3e0eae0 100644 --- a/pandas/tests/test_algos.py +++ b/pandas/tests/test_algos.py @@ -11,8 +11,9 @@ from pandas._libs import ( algos as libalgos, groupby as libgroupby, hashtable as ht) -from pandas.compat import PY2, lrange, range +from pandas.compat import lrange, range from pandas.compat.numpy import np_array_datetime64_compat +from pandas.errors import SortError import pandas.util._test_decorators as td from pandas.core.dtypes.dtypes import CategoricalDtype as CDT @@ -224,15 +225,11 @@ def test_factorize_tuple_list(self, data, expected_label, expected_level): dtype=object) tm.assert_numpy_array_equal(result[1], expected_level_array) - @pytest.mark.skipif(PY2, reason="pytest.raises match regex fails") def test_complex_sorting(self): # gh 12666 - check no segfault x17 = np.array([complex(i) for i in range(17)], dtype=object) - msg = (r"'(<|>)' not supported between instances of 'complex' and" - r" 'complex'|" - r"unorderable types: complex\(\) > complex\(\)") - with pytest.raises(TypeError, match=msg): + with pytest.raises(SortError, match="complex.*complex"): algos.factorize(x17[::-1], sort=True) def test_float64_factorize(self, writable): diff --git a/pandas/tests/test_sorting.py b/pandas/tests/test_sorting.py index 7528566e8326e..56bc8ff36f0cb 100644 --- a/pandas/tests/test_sorting.py +++ b/pandas/tests/test_sorting.py @@ -7,7 +7,7 @@ from numpy import nan import pytest -from pandas.compat import PY2 +from pandas.errors import SortError from pandas import DataFrame, MultiIndex, Series, compat, concat, merge from pandas.core import common as com @@ -405,21 +405,17 @@ def test_mixed_integer_from_list(self): expected = np.array([0, 0, 1, 'a', 'b', 'b'], dtype=object) tm.assert_numpy_array_equal(result, expected) - @pytest.mark.skipif(PY2, reason="pytest.raises match regex fails") def test_unsortable(self): # GH 13714 arr = np.array([1, 2, datetime.now(), 0, 3], dtype=object) - msg = (r"'(<|>)' not supported between instances of ('" - r"datetime\.datetime' and 'int'|'int' and 'datetime\.datetime" - r"')|" - r"unorderable types: int\(\) > datetime\.datetime\(\)") + msg = "int.*datetime|datetime.*int" if compat.PY2: # RuntimeWarning: tp_compare didn't return -1 or -2 for exception with warnings.catch_warnings(): - with pytest.raises(TypeError, match=msg): + with pytest.raises(SortError, match=msg): safe_sort(arr) else: - with pytest.raises(TypeError, match=msg): + with pytest.raises(SortError, match=msg): safe_sort(arr) def test_exceptions(self): From 230dba149452285850377cbf1808674957731a98 Mon Sep 17 00:00:00 2001 From: Simon Hawkins Date: Wed, 6 Mar 2019 15:22:23 +0000 Subject: [PATCH 02/10] fix py2 invalid syntax --- pandas/core/sorting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/core/sorting.py b/pandas/core/sorting.py index 596917b646d1e..de5e8ad0d7ac2 100644 --- a/pandas/core/sorting.py +++ b/pandas/core/sorting.py @@ -454,7 +454,7 @@ def sort_mixed(values): try: nums = np.sort(values[~str_pos]) except TypeError as e: - raise SortError(e) from e + raise SortError(e) strs = np.sort(values[str_pos]) return np.concatenate([nums, np.asarray(strs, dtype=object)]) From a99e3a2f311e05eab4dfdfa5e7909de66e0560e7 Mon Sep 17 00:00:00 2001 From: Simon Hawkins Date: Wed, 6 Mar 2019 16:12:21 +0000 Subject: [PATCH 03/10] fix py2 failures --- pandas/core/sorting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/core/sorting.py b/pandas/core/sorting.py index de5e8ad0d7ac2..d0bd268e99ddf 100644 --- a/pandas/core/sorting.py +++ b/pandas/core/sorting.py @@ -453,9 +453,9 @@ def sort_mixed(values): dtype=bool) try: nums = np.sort(values[~str_pos]) + strs = np.sort(values[str_pos]) except TypeError as e: raise SortError(e) - strs = np.sort(values[str_pos]) return np.concatenate([nums, np.asarray(strs, dtype=object)]) sorter = None From e6160714025bf9e76db30b87b6b285f54cdf6e69 Mon Sep 17 00:00:00 2001 From: Simon Hawkins Date: Wed, 6 Mar 2019 16:52:46 +0000 Subject: [PATCH 04/10] relax regex --- pandas/tests/test_algos.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/tests/test_algos.py b/pandas/tests/test_algos.py index 7241af3e0eae0..94068fda325eb 100644 --- a/pandas/tests/test_algos.py +++ b/pandas/tests/test_algos.py @@ -229,7 +229,7 @@ def test_complex_sorting(self): # gh 12666 - check no segfault x17 = np.array([complex(i) for i in range(17)], dtype=object) - with pytest.raises(SortError, match="complex.*complex"): + with pytest.raises(SortError, match="complex"): algos.factorize(x17[::-1], sort=True) def test_float64_factorize(self, writable): From c868ffb49e9d7ad3fa8a9c7ffeaafc9fc7b8744c Mon Sep 17 00:00:00 2001 From: Simon Hawkins Date: Wed, 27 Mar 2019 14:48:04 +0000 Subject: [PATCH 05/10] fix merge conflict unused import --- pandas/tests/test_algos.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/tests/test_algos.py b/pandas/tests/test_algos.py index 3a770476190cc..32a3f421d1d6b 100644 --- a/pandas/tests/test_algos.py +++ b/pandas/tests/test_algos.py @@ -11,7 +11,7 @@ from pandas._libs import ( algos as libalgos, groupby as libgroupby, hashtable as ht) -from pandas.compat import lrange, range +from pandas.compat import lrange from pandas.compat.numpy import np_array_datetime64_compat from pandas.errors import SortError import pandas.util._test_decorators as td From e6c78141298cf5160ab496589decd73cea0f653e Mon Sep 17 00:00:00 2001 From: Simon Hawkins Date: Wed, 27 Mar 2019 14:56:09 +0000 Subject: [PATCH 06/10] move SortError to core.sorting --- pandas/core/arrays/categorical.py | 2 +- pandas/core/indexes/base.py | 2 +- pandas/core/sorting.py | 12 +++++++++--- pandas/errors/__init__.py | 7 ------- pandas/tests/test_algos.py | 2 +- pandas/tests/test_sorting.py | 2 +- 6 files changed, 13 insertions(+), 14 deletions(-) diff --git a/pandas/core/arrays/categorical.py b/pandas/core/arrays/categorical.py index fc34f4124246e..f793b17a42d3c 100644 --- a/pandas/core/arrays/categorical.py +++ b/pandas/core/arrays/categorical.py @@ -11,7 +11,7 @@ import pandas.compat as compat from pandas.compat import lzip from pandas.compat.numpy import function as nv -from pandas.errors import SortError +from pandas.core.sorting import SortError from pandas.util._decorators import ( Appender, Substitution, cache_readonly, deprecate_kwarg) from pandas.util._validators import validate_bool_kwarg, validate_fillna_kwargs diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index 11c46ac969dfa..158243ae167f1 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -14,7 +14,7 @@ import pandas.compat as compat from pandas.compat import set_function_name from pandas.compat.numpy import function as nv -from pandas.errors import SortError +from pandas.core.sorting import SortError from pandas.util._decorators import Appender, Substitution, cache_readonly from pandas.core.dtypes.cast import maybe_cast_to_integer_array diff --git a/pandas/core/sorting.py b/pandas/core/sorting.py index 4886433fa0d17..e8c0d6e75b7d4 100644 --- a/pandas/core/sorting.py +++ b/pandas/core/sorting.py @@ -6,7 +6,6 @@ from pandas._libs import algos, hashtable, lib from pandas._libs.hashtable import unique_label_indices from pandas.compat import PY3, string_types -from pandas.errors import SortError from pandas.core.dtypes.cast import infer_dtype_from_array from pandas.core.dtypes.common import ( @@ -18,6 +17,13 @@ _INT64_MAX = np.iinfo(np.int64).max +class SortError(TypeError): + """ + Error raised when problems arise during sorting due to problems + with input data. Subclass of `TypeError`. + """ + + def get_group_index(labels, shape, sort, xnull): """ For the particular label_list, gets the offsets into the hypothetical list @@ -439,7 +445,7 @@ def safe_sort(values, labels=None, na_sentinel=-1, assume_unique=False): TypeError * If ``values`` is not list-like or if ``labels`` is neither None nor list-like. - pandas.error.SortError + SortError * If ``values`` cannot be sorted. ValueError * If ``labels`` is not None and ``values`` contain duplicates. @@ -462,7 +468,7 @@ def sort_mixed(values): nums = np.sort(values[~str_pos]) strs = np.sort(values[str_pos]) except TypeError as e: - raise SortError(e) + raise SortError(e) from e return np.concatenate([nums, np.asarray(strs, dtype=object)]) sorter = None diff --git a/pandas/errors/__init__.py b/pandas/errors/__init__.py index a1200adc89dd0..3b8904f4c1ef6 100644 --- a/pandas/errors/__init__.py +++ b/pandas/errors/__init__.py @@ -157,13 +157,6 @@ class MergeError(ValueError): """ -class SortError(TypeError): - """ - Error raised when problems arise during sorting due to problems - with input data. Subclass of `TypeError`. - """ - - class NullFrequencyError(ValueError): """ Error raised when a null `freq` attribute is used in an operation diff --git a/pandas/tests/test_algos.py b/pandas/tests/test_algos.py index 32a3f421d1d6b..fb097b4a8c868 100644 --- a/pandas/tests/test_algos.py +++ b/pandas/tests/test_algos.py @@ -13,7 +13,7 @@ algos as libalgos, groupby as libgroupby, hashtable as ht) from pandas.compat import lrange from pandas.compat.numpy import np_array_datetime64_compat -from pandas.errors import SortError +from pandas.core.sorting import SortError import pandas.util._test_decorators as td from pandas.core.dtypes.dtypes import CategoricalDtype as CDT diff --git a/pandas/tests/test_sorting.py b/pandas/tests/test_sorting.py index 4fba773c574f1..c8d6102c4f3b1 100644 --- a/pandas/tests/test_sorting.py +++ b/pandas/tests/test_sorting.py @@ -6,7 +6,7 @@ from numpy import nan import pytest -from pandas.errors import SortError +from pandas.core.sorting import SortError from pandas import ( DataFrame, MultiIndex, Series, compat, concat, merge, to_datetime) From 8ee7bea0aa6540630f7de3d9982db86bb1b005f2 Mon Sep 17 00:00:00 2001 From: Simon Hawkins Date: Wed, 27 Mar 2019 17:11:58 +0000 Subject: [PATCH 07/10] make SortError internal to factorize --- pandas/core/algorithms.py | 16 +++++++++++----- pandas/tests/test_algos.py | 3 ++- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/pandas/core/algorithms.py b/pandas/core/algorithms.py index 80bf7214e7a27..7f684711b3042 100644 --- a/pandas/core/algorithms.py +++ b/pandas/core/algorithms.py @@ -616,7 +616,7 @@ def factorize(values, sort=False, order=None, na_sentinel=-1, size_hint=None): na_value=na_value) if sort and len(uniques) > 0: - from pandas.core.sorting import safe_sort + from pandas.core.sorting import safe_sort, SortError if na_sentinel == -1: # GH-25409 take_1d only works for na_sentinels of -1 try: @@ -626,13 +626,19 @@ def factorize(values, sort=False, order=None, na_sentinel=-1, size_hint=None): uniques = uniques.take(order) except TypeError: # Mixed types, where uniques.argsort fails. + try: + uniques, labels = safe_sort(uniques, labels, + na_sentinel=na_sentinel, + assume_unique=True) + except SortError as e: + raise TypeError(e) from e + else: + try: uniques, labels = safe_sort(uniques, labels, na_sentinel=na_sentinel, assume_unique=True) - else: - uniques, labels = safe_sort(uniques, labels, - na_sentinel=na_sentinel, - assume_unique=True) + except SortError as e: + raise TypeError(e) from e uniques = _reconstruct_data(uniques, dtype, original) diff --git a/pandas/tests/test_algos.py b/pandas/tests/test_algos.py index fb097b4a8c868..ef902efac2d7d 100644 --- a/pandas/tests/test_algos.py +++ b/pandas/tests/test_algos.py @@ -229,8 +229,9 @@ def test_complex_sorting(self): # gh 12666 - check no segfault x17 = np.array([complex(i) for i in range(17)], dtype=object) - with pytest.raises(SortError, match="complex"): + with pytest.raises(TypeError, match="complex") as excinfo: algos.factorize(x17[::-1], sort=True) + assert type(excinfo.value.__cause__) == SortError def test_float64_factorize(self, writable): data = np.array([1.0, 1e8, 1.0, 1e-8, 1e8, 1.0], dtype=np.float64) From a8cc46bc595059258e7dbe465353ca69a64c2cd9 Mon Sep 17 00:00:00 2001 From: Simon Hawkins Date: Wed, 27 Mar 2019 20:24:05 +0000 Subject: [PATCH 08/10] isort imports --- pandas/core/arrays/categorical.py | 3 +-- pandas/core/indexes/base.py | 2 +- pandas/tests/test_algos.py | 2 +- pandas/tests/test_sorting.py | 4 +--- 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/pandas/core/arrays/categorical.py b/pandas/core/arrays/categorical.py index f793b17a42d3c..4c6f92c3960ed 100644 --- a/pandas/core/arrays/categorical.py +++ b/pandas/core/arrays/categorical.py @@ -11,7 +11,6 @@ import pandas.compat as compat from pandas.compat import lzip from pandas.compat.numpy import function as nv -from pandas.core.sorting import SortError from pandas.util._decorators import ( Appender, Substitution, cache_readonly, deprecate_kwarg) from pandas.util._validators import validate_bool_kwarg, validate_fillna_kwargs @@ -36,7 +35,7 @@ from pandas.core.base import NoNewAttributesMixin, PandasObject, _shared_docs import pandas.core.common as com from pandas.core.missing import interpolate_2d -from pandas.core.sorting import nargsort +from pandas.core.sorting import SortError, nargsort from pandas.io.formats import console from pandas.io.formats.terminal import get_terminal_size diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index 158243ae167f1..eba3cde9b721c 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -14,7 +14,6 @@ import pandas.compat as compat from pandas.compat import set_function_name from pandas.compat.numpy import function as nv -from pandas.core.sorting import SortError from pandas.util._decorators import Appender, Substitution, cache_readonly from pandas.core.dtypes.cast import maybe_cast_to_integer_array @@ -44,6 +43,7 @@ import pandas.core.missing as missing from pandas.core.ops import get_op_result_name, make_invalid_op import pandas.core.sorting as sorting +from pandas.core.sorting import SortError from pandas.core.strings import StringMethods from pandas.io.formats.printing import ( diff --git a/pandas/tests/test_algos.py b/pandas/tests/test_algos.py index ef902efac2d7d..6f4f0f0fa28e4 100644 --- a/pandas/tests/test_algos.py +++ b/pandas/tests/test_algos.py @@ -13,7 +13,6 @@ algos as libalgos, groupby as libgroupby, hashtable as ht) from pandas.compat import lrange from pandas.compat.numpy import np_array_datetime64_compat -from pandas.core.sorting import SortError import pandas.util._test_decorators as td from pandas.core.dtypes.dtypes import CategoricalDtype as CDT @@ -25,6 +24,7 @@ import pandas.core.algorithms as algos from pandas.core.arrays import DatetimeArray import pandas.core.common as com +from pandas.core.sorting import SortError import pandas.util.testing as tm from pandas.util.testing import assert_almost_equal diff --git a/pandas/tests/test_sorting.py b/pandas/tests/test_sorting.py index c8d6102c4f3b1..3adb8f3aba0eb 100644 --- a/pandas/tests/test_sorting.py +++ b/pandas/tests/test_sorting.py @@ -6,13 +6,11 @@ from numpy import nan import pytest -from pandas.core.sorting import SortError - from pandas import ( DataFrame, MultiIndex, Series, compat, concat, merge, to_datetime) from pandas.core import common as com from pandas.core.sorting import ( - decons_group_index, get_group_index, is_int64_overflow_possible, + SortError, decons_group_index, get_group_index, is_int64_overflow_possible, lexsort_indexer, nargsort, safe_sort) from pandas.util import testing as tm from pandas.util.testing import assert_frame_equal, assert_series_equal From 28885391e90acb082038fbc6aaf06c7520bb7e6d Mon Sep 17 00:00:00 2001 From: Simon Hawkins Date: Wed, 27 Mar 2019 20:57:06 +0000 Subject: [PATCH 09/10] fix ci failure --- pandas/core/arrays/categorical.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas/core/arrays/categorical.py b/pandas/core/arrays/categorical.py index 4c6f92c3960ed..75b64a06fe8e8 100644 --- a/pandas/core/arrays/categorical.py +++ b/pandas/core/arrays/categorical.py @@ -35,7 +35,7 @@ from pandas.core.base import NoNewAttributesMixin, PandasObject, _shared_docs import pandas.core.common as com from pandas.core.missing import interpolate_2d -from pandas.core.sorting import SortError, nargsort +from pandas.core.sorting import nargsort from pandas.io.formats import console from pandas.io.formats.terminal import get_terminal_size @@ -357,7 +357,7 @@ def __init__(self, values, categories=None, ordered=None, dtype=None, if dtype.categories is None: try: codes, categories = factorize(values, sort=True) - except SortError: + except TypeError: codes, categories = factorize(values, sort=False) if dtype.ordered: # raise, as we don't have a sortable data structure and so From 7af86395f7b5ad60f1d730826471c69039f95eff Mon Sep 17 00:00:00 2001 From: Simon Hawkins Date: Wed, 27 Mar 2019 21:36:09 +0000 Subject: [PATCH 10/10] raise TypeError for backwards compatibility --- pandas/core/indexes/base.py | 5 ++++- pandas/core/reshape/merge.py | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index eba3cde9b721c..8409bae7d5e54 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -2433,7 +2433,10 @@ def intersection(self, other, sort=False): taken = other.take(indexer) if sort is None: - taken = sorting.safe_sort(taken.values) + try: + taken = sorting.safe_sort(taken.values) + except sorting.SortError as e: + raise TypeError(e) from e if self.name != other.name: name = None else: diff --git a/pandas/core/reshape/merge.py b/pandas/core/reshape/merge.py index cd5c853c6efe4..edbea5696277c 100644 --- a/pandas/core/reshape/merge.py +++ b/pandas/core/reshape/merge.py @@ -1738,7 +1738,10 @@ def _sort_labels(uniques, left, right): llength = len(left) labels = np.concatenate([left, right]) - _, new_labels = sorting.safe_sort(uniques, labels, na_sentinel=-1) + try: + _, new_labels = sorting.safe_sort(uniques, labels, na_sentinel=-1) + except sorting.SortError as e: + raise TypeError(e) from e new_labels = ensure_int64(new_labels) new_left, new_right = new_labels[:llength], new_labels[llength:]