Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

API: expose pandas.errors #15541

Closed
wants to merge 12 commits into from
26 changes: 26 additions & 0 deletions doc/source/whatsnew/v0.20.0.txt
Expand Up @@ -75,6 +75,28 @@ Commonly called 'unix epoch' or POSIX time.

pd.to_datetime([1, 2, 3], unit='D')

.. _whatsnew_0200.enhancements.errors:

pandas errors
^^^^^^^^^^^^^

We are adding a standard public location for all pandas exceptions & warnings ``pandas.errors``. (:issue:`14800`). Previously
these exceptions & warnings could be imported from ``pandas.core.common`` or ``pandas.io.common``. These exceptions and warnings
will be removed from the ``*.common`` locations in a future release. (:issue:`15541`)

The following are now part of this API:

.. code-block:: python

['DtypeWarning',
'EmptyDataError',
'OutOfBoundsDatetime',
'ParserError',
'ParserWarning',
'PerformanceWarning',
'UnsortedIndexError',
'UnsupportedFunctionCall']

.. _whatsnew_0200.enhancements.groupby_access:

Groupby Enhancements
Expand Down Expand Up @@ -859,6 +881,10 @@ Other API Changes
- ``NaT`` will now correctly return ``np.nan`` for ``Timedelta`` and ``Period`` accessors such as ``days`` and ``quarter`` (:issue:`15782`)
- ``NaT`` will now returns ``NaT`` for ``tz_localize`` and ``tz_convert``
methods (:issue:`15830`)
- ``DataFrame`` and ``Panel`` constructors with invalid input will now raise ``ValueError`` rather than ``PandasError``, if called with scalar inputs and not axes (:issue:`15541`)

- ``DataFrame`` and ``Panel`` constructors with invalid input will now raise ``ValueError`` rather than ``pandas.core.common.PandasError``, if called with scalar inputs and not axes; The exception ``PandasError`` is removed as well. (:issue:`15541`)
- The exception ``pandas.core.common.AmbiguousIndexError`` is removed as it is not referenced (:issue:`15541`)

.. _whatsnew_0200.deprecations:

Expand Down
3 changes: 2 additions & 1 deletion pandas/__init__.py
Expand Up @@ -62,7 +62,8 @@

json = _DeprecatedModule(deprmod='pandas.json', deprmodto='pandas.io.json.libjson')
parser = _DeprecatedModule(deprmod='pandas.parser', deprmodto='pandas.io.libparsers')
lib = _DeprecatedModule(deprmod='pandas.lib', deprmodto='pandas._libs.lib')
lib = _DeprecatedModule(deprmod='pandas.lib', deprmodto='pandas._libs.lib',
moved={'infer_dtype': 'pandas.api.lib.infer_dtype'})
tslib = _DeprecatedModule(deprmod='pandas.tslib', deprmodto='pandas._libs.tslib')

# use the closest tagged version if possible
Expand Down
110 changes: 96 additions & 14 deletions pandas/_libs/src/inference.pyx
Expand Up @@ -218,9 +218,91 @@ cdef _try_infer_map(v):
return None


def infer_dtype(object _values):
def infer_dtype(object value):
"""
we are coercing to an ndarray here
Effeciently infer the type of a passed val, or list-like
array of values. Return a string describing the type.

Parameters
----------
value : scalar, list, ndarray, or pandas type

Returns
-------
string describing the common type of the input data.
Results can include:

- string
- unicode
- bytes
- floating
- integer
- mixed-integer
- mixed-integer-float
- complex
- categorical
- boolean
- datetime64
- datetime
- date
- timedelta64
- timedelta
- time
- period
- mixed

Raises
------
TypeError if ndarray-like but cannot infer the dtype

Notes
-----
- 'mixed' is the catchall for anything that is not otherwise
specialized
- 'mixed-integer-float' are floats and integers
- 'mixed-integer' are integers mixed with non-integers

Examples
--------
>>> infer_dtype(['foo', 'bar'])
'string'

>>> infer_dtype([b'foo', b'bar'])
'bytes'

>>> infer_dtype([1, 2, 3])
'integer'

>>> infer_dtype([1, 2, 3.5])
'mixed-integer-float'

>>> infer_dtype([1.0, 2.0, 3.5])
'floating'

>>> infer_dtype(['a', 1])
'mixed-integer'

>>> infer_dtype([True, False])
'boolean'

>>> infer_dtype([True, False, np.nan])
'mixed'

>>> infer_dtype([pd.Timestamp('20130101')])
'datetime'

>>> infer_dtype([datetime.date(2013, 1, 1)])
'date'

>>> infer_dtype([np.datetime64('2013-01-01')])
'datetime64'

>>> infer_dtype([datetime.timedelta(0, 1, 1)])
'timedelta'

>>> infer_dtype(pd.Series(list('aabc')).astype('category'))
'categorical'

"""

cdef:
Expand All @@ -229,27 +311,27 @@ def infer_dtype(object _values):
ndarray values
bint seen_pdnat = False, seen_val = False

if isinstance(_values, np.ndarray):
values = _values
elif hasattr(_values, 'dtype'):
if isinstance(value, np.ndarray):
values = value
elif hasattr(value, 'dtype'):

# this will handle ndarray-like
# e.g. categoricals
try:
values = getattr(_values, '_values', getattr(
_values, 'values', _values))
values = getattr(value, '_values', getattr(
value, 'values', value))
except:
val = _try_infer_map(_values)
if val is not None:
return val
value = _try_infer_map(value)
if value is not None:
return value

# its ndarray like but we can't handle
raise ValueError("cannot infer type for {0}".format(type(_values)))
raise ValueError("cannot infer type for {0}".format(type(value)))

else:
if not isinstance(_values, list):
_values = list(_values)
values = list_to_object_array(_values)
if not isinstance(value, list):
value = list(value)
values = list_to_object_array(value)

values = getattr(values, 'values', values)
val = _try_infer_map(values)
Expand Down
5 changes: 5 additions & 0 deletions pandas/api/lib/__init__.py
@@ -0,0 +1,5 @@
# flake8: noqa

""" public toolkit API """

from pandas._libs.lib import infer_dtype
2 changes: 1 addition & 1 deletion pandas/compat/numpy/function.py
Expand Up @@ -21,7 +21,7 @@
from numpy import ndarray
from pandas.util.validators import (validate_args, validate_kwargs,
validate_args_and_kwargs)
from pandas.core.common import UnsupportedFunctionCall
from pandas.errors import UnsupportedFunctionCall
from pandas.types.common import is_integer, is_bool
from pandas.compat import OrderedDict

Expand Down
7 changes: 4 additions & 3 deletions pandas/computation/align.py
Expand Up @@ -9,7 +9,8 @@

import pandas as pd
from pandas import compat
import pandas.core.common as com
from pandas.errors import PerformanceWarning
from pandas.core.common import flatten
from pandas.computation.common import _result_type_many


Expand Down Expand Up @@ -101,7 +102,7 @@ def _align_core(terms):
'than an order of magnitude on term {1!r}, '
'by more than {2:.4g}; performance may '
'suffer'.format(axis, terms[i].name, ordm),
category=pd.core.common.PerformanceWarning,
category=PerformanceWarning,
stacklevel=6)

if transpose:
Expand All @@ -121,7 +122,7 @@ def _align(terms):
"""Align a set of terms"""
try:
# flatten the parse tree (a nested list, really)
terms = list(com.flatten(terms))
terms = list(flatten(terms))
except TypeError:
# can't iterate so it must just be a constant or single variable
if isinstance(terms.value, pd.core.generic.NDFrame):
Expand Down
30 changes: 4 additions & 26 deletions pandas/core/common.py
Expand Up @@ -20,6 +20,10 @@
from pandas.api import types
from pandas.types import common

# compat
from pandas.errors import ( # noqa
PerformanceWarning, UnsupportedFunctionCall, UnsortedIndexError)

# back-compat of public API
# deprecate these functions
m = sys.modules['pandas.core.common']
Expand Down Expand Up @@ -73,14 +77,6 @@ def array_equivalent(*args, **kwargs):
return missing.array_equivalent(*args, **kwargs)


class PandasError(Exception):
pass


class PerformanceWarning(Warning):
pass


class SettingWithCopyError(ValueError):
pass

Expand All @@ -89,24 +85,6 @@ class SettingWithCopyWarning(Warning):
pass


class AmbiguousIndexError(PandasError, KeyError):
pass


class UnsupportedFunctionCall(ValueError):
pass


class UnsortedIndexError(KeyError):
""" Error raised when attempting to get a slice of a MultiIndex
and the index has not been lexsorted. Subclass of `KeyError`.

.. versionadded:: 0.20.0

"""
pass


class AbstractMethodError(NotImplementedError):
"""Raise this error instead of NotImplementedError for abstract methods
while keeping compatibility with Python 2 and Python 3.
Expand Down
4 changes: 2 additions & 2 deletions pandas/core/frame.py
Expand Up @@ -56,7 +56,7 @@
is_named_tuple)
from pandas.types.missing import isnull, notnull

from pandas.core.common import (PandasError, _try_sort,
from pandas.core.common import (_try_sort,
_default_index,
_values_from_object,
_maybe_box_datetimelike,
Expand Down Expand Up @@ -347,7 +347,7 @@ def __init__(self, data=None, index=None, columns=None, dtype=None,
mgr = self._init_ndarray(values, index, columns, dtype=dtype,
copy=False)
else:
raise PandasError('DataFrame constructor not properly called!')
raise ValueError('DataFrame constructor not properly called!')

NDFrame.__init__(self, mgr, fastpath=True)

Expand Down
2 changes: 1 addition & 1 deletion pandas/core/indexing.py
Expand Up @@ -1140,7 +1140,7 @@ def _convert_to_indexer(self, obj, axis=0, is_setter=False):
ix[['foo', 'bar', 'baz']] -> [i, j, k] (indices of foo, bar, baz)

Going by Zen of Python?
"In the face of ambiguity, refuse the temptation to guess."
'In the face of ambiguity, refuse the temptation to guess.'
raise AmbiguousIndexError with integer labels?
- No, prefer label-based indexing
"""
Expand Down
4 changes: 2 additions & 2 deletions pandas/core/ops.py
Expand Up @@ -21,8 +21,8 @@
from pandas.compat import bind_method
import pandas.core.missing as missing

from pandas.core.common import (_values_from_object, _maybe_match_name,
PerformanceWarning)
from pandas.errors import PerformanceWarning
from pandas.core.common import _values_from_object, _maybe_match_name
from pandas.types.missing import notnull, isnull
from pandas.types.common import (needs_i8_conversion,
is_datetimelike_v_numeric,
Expand Down
8 changes: 4 additions & 4 deletions pandas/core/panel.py
Expand Up @@ -21,7 +21,7 @@
from pandas import compat
from pandas.compat import (map, zip, range, u, OrderedDict, OrderedDefaultdict)
from pandas.compat.numpy import function as nv
from pandas.core.common import PandasError, _try_sort, _default_index
from pandas.core.common import _try_sort, _default_index
from pandas.core.frame import DataFrame
from pandas.core.generic import NDFrame, _shared_docs
from pandas.core.index import (Index, MultiIndex, _ensure_index,
Expand Down Expand Up @@ -174,7 +174,7 @@ def _init_data(self, data, copy, dtype, **kwargs):
copy=False)
copy = False
else: # pragma: no cover
raise PandasError('Panel constructor not properly called!')
raise ValueError('Panel constructor not properly called!')

NDFrame.__init__(self, mgr, axes=axes, copy=copy, dtype=dtype)

Expand Down Expand Up @@ -1150,8 +1150,8 @@ def _construct_return_type(self, result, axes=None):
return self._constructor_sliced(
result, **self._extract_axes_for_slice(self, axes))

raise PandasError('invalid _construct_return_type [self->%s] '
'[result->%s]' % (self, result))
raise ValueError('invalid _construct_return_type [self->%s] '
'[result->%s]' % (self, result))

def _wrap_result(self, result, axis):
axis = self._get_axis_name(axis)
Expand Down