From 4d697b7ee42a7d907d93e4af79eeb3617f5e4884 Mon Sep 17 00:00:00 2001 From: "brute4s99 [LAPTOP]" Date: Wed, 3 Oct 2018 01:25:45 +0530 Subject: [PATCH 1/6] Fix #22903 for lib.is_scalar missing PEP 3141 numbers --- doc/source/whatsnew/v0.24.0.rst | 3 ++ pandas/_libs/lib.pyx | 42 ++++++++++++++++++++++++--- pandas/tests/dtypes/test_inference.py | 6 ++-- 3 files changed, 45 insertions(+), 6 deletions(-) diff --git a/doc/source/whatsnew/v0.24.0.rst b/doc/source/whatsnew/v0.24.0.rst index f94aa3d320b75..22f2add40c451 100644 --- a/doc/source/whatsnew/v0.24.0.rst +++ b/doc/source/whatsnew/v0.24.0.rst @@ -465,6 +465,7 @@ For situations where you need an ``ndarray`` of ``Interval`` objects, use np.asarray(idx) idx.values.astype(object) + .. _whatsnew_0240.api.timezone_offset_parsing: Parsing Datetime Strings with Timezone Offsets @@ -1471,6 +1472,7 @@ Other - :meth:`DataFrame.nlargest` and :meth:`DataFrame.nsmallest` now returns the correct n values when keep != 'all' also when tied on the first columns (:issue:`22752`) - :meth:`~pandas.io.formats.style.Styler.bar` now also supports tablewise application (in addition to rowwise and columnwise) with ``axis=None`` and setting clipping range with ``vmin`` and ``vmax`` (:issue:`21548` and :issue:`21526`). ``NaN`` values are also handled properly. - Logical operations ``&, |, ^`` between :class:`Series` and :class:`Index` will no longer raise ``ValueError`` (:issue:`22092`) +- Checking PEP 3141 numbers in :func:`~pandas.api.types.is_scalar` function returns ``True`` (:issue:`22903`) - Bug in :meth:`DataFrame.combine_first` in which column types were unexpectedly converted to float (:issue:`20699`) .. _whatsnew_0.24.0.contributors: @@ -1479,3 +1481,4 @@ Contributors ~~~~~~~~~~~~ .. contributors:: v0.23.4..HEAD + diff --git a/pandas/_libs/lib.pyx b/pandas/_libs/lib.pyx index e89c8fa579687..16fedee8ef122 100644 --- a/pandas/_libs/lib.pyx +++ b/pandas/_libs/lib.pyx @@ -1,5 +1,8 @@ # -*- coding: utf-8 -*- from decimal import Decimal +from fractions import Fraction +from numbers import Number + import sys import cython @@ -15,7 +18,6 @@ from cpython.datetime cimport (PyDateTime_Check, PyDate_Check, PyDateTime_IMPORT) PyDateTime_IMPORT - import numpy as np cimport numpy as cnp from numpy cimport (ndarray, PyArray_GETITEM, @@ -104,7 +106,10 @@ def memory_usage_of_objects(arr: object[:]) -> int64_t: def is_scalar(val: object) -> bool: """ Return True if given value is scalar. - + + Parameters + ---------- + val : input argument of any type This includes: - numpy array scalar (e.g. np.int64) - Python builtin numerics @@ -116,12 +121,42 @@ def is_scalar(val: object) -> bool: - instances of decimal.Decimal - Interval - DateOffset + - Fraction + - Number + Returns + ------- + True if the given value is scalar, False otherwise. + + Examples + -------- + >>> dt = pd.datetime.datetime(2018, 10, 3) + >>> pd.is_scalar(dt) + True + + >>> pd.api.types.is_scalar([2, 3]) + False + + >>> pd.api.types.is_scalar({0:1, 2:3}) + False + + >>> pd.api.types.is_scalar((0, 2)) + False + + pandas supports PEP 3141 numbers: + + >>> from fractions import Fraction + >>> pd.api.types.is_scalar(Fraction(3, 5)) + True + + >>> from numbers import Number + >>> pd.api.types.is_scalar(Number()) + True """ return (cnp.PyArray_IsAnyScalar(val) # As of numpy-1.9, PyArray_IsAnyScalar misses bytearrays on Py3. - or isinstance(val, bytes) + or isinstance(val,(bytes, Fraction, Number)) # We differ from numpy (as of 1.10), which claims that None is # not scalar in np.isscalar(). or val is None @@ -133,7 +168,6 @@ def is_scalar(val: object) -> bool: or is_interval(val) or util.is_offset_object(val)) - def item_from_zerodim(val: object) -> object: """ If the value is a zerodim array, return the item it contains. diff --git a/pandas/tests/dtypes/test_inference.py b/pandas/tests/dtypes/test_inference.py index f2552cffc6651..4b1d1fae1bdb2 100644 --- a/pandas/tests/dtypes/test_inference.py +++ b/pandas/tests/dtypes/test_inference.py @@ -10,10 +10,11 @@ import re from datetime import datetime, date, timedelta, time from decimal import Decimal +from numbers import Number +from fractions import Fraction import numpy as np import pytz import pytest - import pandas as pd from pandas._libs import lib, iNaT, missing as libmissing from pandas import (Series, Index, DataFrame, Timedelta, @@ -1183,6 +1184,8 @@ def test_is_scalar_builtin_scalars(self): assert is_scalar(None) assert is_scalar(True) assert is_scalar(False) + assert is_scalar(Number()) + assert is_scalar(Fraction()) assert is_scalar(0.) assert is_scalar(np.nan) assert is_scalar('foobar') @@ -1247,7 +1250,6 @@ def test_is_scalar_pandas_containers(self): assert not is_scalar(Index([])) assert not is_scalar(Index([1])) - def test_datetimeindex_from_empty_datetime64_array(): for unit in ['ms', 'us', 'ns']: idx = DatetimeIndex(np.array([], dtype='datetime64[%s]' % unit)) From 965a9109a2d3891b6b62d92de3fc919163570942 Mon Sep 17 00:00:00 2001 From: "brute4s99 [LAPTOP]" Date: Tue, 9 Oct 2018 13:24:23 +0530 Subject: [PATCH 2/6] Fixed linting issues --- pandas/_libs/lib.pyx | 3 ++- pandas/tests/dtypes/test_inference.py | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/pandas/_libs/lib.pyx b/pandas/_libs/lib.pyx index 16fedee8ef122..48b00ae3a1646 100644 --- a/pandas/_libs/lib.pyx +++ b/pandas/_libs/lib.pyx @@ -156,7 +156,7 @@ def is_scalar(val: object) -> bool: return (cnp.PyArray_IsAnyScalar(val) # As of numpy-1.9, PyArray_IsAnyScalar misses bytearrays on Py3. - or isinstance(val,(bytes, Fraction, Number)) + or isinstance(val, (bytes, Fraction, Number)) # We differ from numpy (as of 1.10), which claims that None is # not scalar in np.isscalar(). or val is None @@ -168,6 +168,7 @@ def is_scalar(val: object) -> bool: or is_interval(val) or util.is_offset_object(val)) + def item_from_zerodim(val: object) -> object: """ If the value is a zerodim array, return the item it contains. diff --git a/pandas/tests/dtypes/test_inference.py b/pandas/tests/dtypes/test_inference.py index 4b1d1fae1bdb2..fd3222cd1119b 100644 --- a/pandas/tests/dtypes/test_inference.py +++ b/pandas/tests/dtypes/test_inference.py @@ -1250,6 +1250,7 @@ def test_is_scalar_pandas_containers(self): assert not is_scalar(Index([])) assert not is_scalar(Index([1])) + def test_datetimeindex_from_empty_datetime64_array(): for unit in ['ms', 'us', 'ns']: idx = DatetimeIndex(np.array([], dtype='datetime64[%s]' % unit)) From ecac1d12b2d9f32993a7391713a31b988c484444 Mon Sep 17 00:00:00 2001 From: Piyush Aggarwal Date: Tue, 9 Oct 2018 14:12:35 +0530 Subject: [PATCH 3/6] more fixes for lib.pyx (PEP 3141 is_scalar()) --- pandas/_libs/lib.pyx | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/pandas/_libs/lib.pyx b/pandas/_libs/lib.pyx index 48b00ae3a1646..7b00f58cd685d 100644 --- a/pandas/_libs/lib.pyx +++ b/pandas/_libs/lib.pyx @@ -109,24 +109,24 @@ def is_scalar(val: object) -> bool: Parameters ---------- - val : input argument of any type + val : object This includes: - - numpy array scalar (e.g. np.int64) - - Python builtin numerics - - Python builtin byte arrays and strings - - None - - instances of datetime.datetime - - instances of datetime.timedelta - - Period - - instances of decimal.Decimal - - Interval - - DateOffset - - Fraction - - Number + * numpy array scalar (e.g. np.int64) + * Python builtin numerics + * Python builtin byte arrays and strings + * None + * instances of datetime.datetime + * instances of datetime.timedelta + * Period + * instances of decimal.Decimal + * Interval + * DateOffset + * Fraction + * Number Returns ------- - True if the given value is scalar, False otherwise. + a bool object. Examples -------- From 1b431c54ccc425de263ea76a3bb4cec87b9fe610 Mon Sep 17 00:00:00 2001 From: "brute4s99 [LAPTOP]" Date: Mon, 19 Nov 2018 02:34:31 +0530 Subject: [PATCH 4/6] pep8 and indentation fixes --- pandas/_libs/lib.pyx | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/pandas/_libs/lib.pyx b/pandas/_libs/lib.pyx index 7b00f58cd685d..c101656325ea2 100644 --- a/pandas/_libs/lib.pyx +++ b/pandas/_libs/lib.pyx @@ -110,23 +110,25 @@ def is_scalar(val: object) -> bool: Parameters ---------- val : object - This includes: - * numpy array scalar (e.g. np.int64) - * Python builtin numerics - * Python builtin byte arrays and strings - * None - * instances of datetime.datetime - * instances of datetime.timedelta - * Period - * instances of decimal.Decimal - * Interval - * DateOffset - * Fraction - * Number + This includes: + + - numpy array scalar (e.g. np.int64) + - Python builtin numerics + - Python builtin byte arrays and strings + - None + - datetime.datetime + - datetime.timedelta + - Period + - decimal.Decimal + - Interval + - DateOffset + - Fraction + - Number Returns ------- - a bool object. + bool + Return True if given object is scalar, False otherwise Examples -------- @@ -137,7 +139,7 @@ def is_scalar(val: object) -> bool: >>> pd.api.types.is_scalar([2, 3]) False - >>> pd.api.types.is_scalar({0:1, 2:3}) + >>> pd.api.types.is_scalar({0: 1, 2: 3}) False >>> pd.api.types.is_scalar((0, 2)) From b2cb68f27e806eeadbe28420be129ae6fff3ceab Mon Sep 17 00:00:00 2001 From: Jeff Reback Date: Sun, 18 Nov 2018 18:05:42 -0500 Subject: [PATCH 5/6] whitespace --- pandas/_libs/lib.pyx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pandas/_libs/lib.pyx b/pandas/_libs/lib.pyx index c101656325ea2..2c31a87d524ca 100644 --- a/pandas/_libs/lib.pyx +++ b/pandas/_libs/lib.pyx @@ -106,7 +106,7 @@ def memory_usage_of_objects(arr: object[:]) -> int64_t: def is_scalar(val: object) -> bool: """ Return True if given value is scalar. - + Parameters ---------- val : object @@ -129,7 +129,7 @@ def is_scalar(val: object) -> bool: ------- bool Return True if given object is scalar, False otherwise - + Examples -------- >>> dt = pd.datetime.datetime(2018, 10, 3) @@ -138,15 +138,15 @@ def is_scalar(val: object) -> bool: >>> pd.api.types.is_scalar([2, 3]) False - + >>> pd.api.types.is_scalar({0: 1, 2: 3}) False - + >>> pd.api.types.is_scalar((0, 2)) False - + pandas supports PEP 3141 numbers: - + >>> from fractions import Fraction >>> pd.api.types.is_scalar(Fraction(3, 5)) True From e5f084aa0da7d89e88354aab8615238cab2549fa Mon Sep 17 00:00:00 2001 From: "brute4s99 [LAPTOP]" Date: Tue, 20 Nov 2018 03:23:38 +0530 Subject: [PATCH 6/6] Removed Number() example from is_scalar() --- pandas/_libs/lib.pyx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pandas/_libs/lib.pyx b/pandas/_libs/lib.pyx index 2c31a87d524ca..ad538ff103c2f 100644 --- a/pandas/_libs/lib.pyx +++ b/pandas/_libs/lib.pyx @@ -150,10 +150,6 @@ def is_scalar(val: object) -> bool: >>> from fractions import Fraction >>> pd.api.types.is_scalar(Fraction(3, 5)) True - - >>> from numbers import Number - >>> pd.api.types.is_scalar(Number()) - True """ return (cnp.PyArray_IsAnyScalar(val)