From eec40cd4fb2bb6c23a49d76b4274a580e0298488 Mon Sep 17 00:00:00 2001 From: Jeff Reback Date: Wed, 15 Mar 2017 11:56:02 -0400 Subject: [PATCH 01/12] add pandas.api.lib add infer_dtype to pandas.api.lib --- pandas/api/lib/__init__.py | 5 +++++ pandas/tests/api/test_lib.py | 11 +++++++++++ setup.py | 1 + 3 files changed, 17 insertions(+) create mode 100644 pandas/api/lib/__init__.py create mode 100644 pandas/tests/api/test_lib.py diff --git a/pandas/api/lib/__init__.py b/pandas/api/lib/__init__.py new file mode 100644 index 0000000000000..c86bfc6148655 --- /dev/null +++ b/pandas/api/lib/__init__.py @@ -0,0 +1,5 @@ +# flake8: noqa + +""" public toolkit API """ + +from pandas._libs.lib import infer_dtype diff --git a/pandas/tests/api/test_lib.py b/pandas/tests/api/test_lib.py new file mode 100644 index 0000000000000..4632d551e574e --- /dev/null +++ b/pandas/tests/api/test_lib.py @@ -0,0 +1,11 @@ +# -*- coding: utf-8 -*- + +import pytest +import pandas # noqa + + +@pytest.mark.parametrize('f', ['infer_dtype']) +def test_importable(f): + from pandas.api import lib + e = getattr(lib, f) + assert e is not None diff --git a/setup.py b/setup.py index 1b471f76ac5e6..89be053249346 100755 --- a/setup.py +++ b/setup.py @@ -631,6 +631,7 @@ def pxd(name): packages=['pandas', 'pandas.api', 'pandas.api.types', + 'pandas.api.lib', 'pandas.compat', 'pandas.compat.numpy', 'pandas.computation', From 991fbb4dd05318454248ce841fd4ccd63a12624b Mon Sep 17 00:00:00 2001 From: Jeff Reback Date: Wed, 1 Mar 2017 14:04:48 -0500 Subject: [PATCH 02/12] API: expose pandas.errors move all exception / warning impls (and references) from pandas.core.common and pandas.io.common closes #14800 --- doc/source/whatsnew/v0.20.0.txt | 18 ++++ pandas/compat/numpy/function.py | 2 +- pandas/computation/align.py | 7 +- pandas/core/common.py | 31 ++----- pandas/core/frame.py | 3 +- pandas/core/ops.py | 4 +- pandas/core/panel.py | 3 +- pandas/errors/__init__.py | 63 ++++++++++++++ pandas/indexes/multi.py | 6 +- pandas/io/common.py | 45 ++-------- pandas/io/excel.py | 4 +- pandas/io/html.py | 3 +- pandas/io/packers.py | 2 +- pandas/io/parsers.py | 5 +- pandas/io/parsers.pyx | 6 +- pandas/io/pytables.py | 3 +- pandas/lib.py | 5 +- pandas/tests/api/test_api.py | 81 +----------------- pandas/tests/api/test_types.py | 83 +++++++++++++++++++ pandas/tests/computation/test_eval.py | 5 +- .../tests/frame/test_axis_select_reindex.py | 2 +- pandas/tests/frame/test_constructors.py | 7 +- pandas/tests/frame/test_to_csv.py | 2 +- pandas/tests/groupby/test_groupby.py | 4 +- pandas/tests/indexes/datetimes/test_ops.py | 2 +- pandas/tests/indexes/test_multi.py | 2 +- pandas/tests/indexing/test_ix.py | 2 +- pandas/tests/indexing/test_multiindex.py | 2 +- pandas/tests/io/parser/common.py | 3 +- pandas/tests/io/parser/dialect.py | 2 +- pandas/tests/io/parser/dtypes.py | 2 +- pandas/tests/io/parser/skiprows.py | 2 +- pandas/tests/io/parser/test_unsupported.py | 2 +- pandas/tests/io/test_common.py | 18 ---- pandas/tests/io/test_packers.py | 2 +- pandas/tests/test_errors.py | 51 ++++++++++++ pandas/tests/test_window.py | 2 +- pandas/tests/tseries/test_resample.py | 2 +- pandas/tseries/index.py | 4 +- pandas/tslib.py | 2 +- setup.py | 1 + 41 files changed, 286 insertions(+), 209 deletions(-) create mode 100644 pandas/errors/__init__.py create mode 100644 pandas/tests/api/test_types.py create mode 100644 pandas/tests/test_errors.py diff --git a/doc/source/whatsnew/v0.20.0.txt b/doc/source/whatsnew/v0.20.0.txt index 63aea96ef3369..79b35e02ba311 100644 --- a/doc/source/whatsnew/v0.20.0.txt +++ b/doc/source/whatsnew/v0.20.0.txt @@ -75,6 +75,24 @@ 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: + +.. ipython:: python + + import pprint + from pandas import errors + excs = [ e for e in dir(errors) if not e.startswith('_') ] + pprint.pprint(excs) + .. _whatsnew_0200.enhancements.groupby_access: Groupby Enhancements diff --git a/pandas/compat/numpy/function.py b/pandas/compat/numpy/function.py index f448a9aad04c6..1dd22795533fc 100644 --- a/pandas/compat/numpy/function.py +++ b/pandas/compat/numpy/function.py @@ -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 diff --git a/pandas/computation/align.py b/pandas/computation/align.py index 4e12d58a4ab85..b4c80f4d493af 100644 --- a/pandas/computation/align.py +++ b/pandas/computation/align.py @@ -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 @@ -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: @@ -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): diff --git a/pandas/core/common.py b/pandas/core/common.py index 93e24dce8b623..79eb770552531 100644 --- a/pandas/core/common.py +++ b/pandas/core/common.py @@ -20,6 +20,11 @@ from pandas.api import types from pandas.types import common +# compat +from pandas.errors import ( # noqa + PandasError, PerformanceWarning, + AmbiguousIndexError, UnsupportedFunctionCall, UnsortedIndexError) + # back-compat of public API # deprecate these functions m = sys.modules['pandas.core.common'] @@ -73,14 +78,6 @@ def array_equivalent(*args, **kwargs): return missing.array_equivalent(*args, **kwargs) -class PandasError(Exception): - pass - - -class PerformanceWarning(Warning): - pass - - class SettingWithCopyError(ValueError): pass @@ -89,24 +86,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. diff --git a/pandas/core/frame.py b/pandas/core/frame.py index ffae22447cc65..d75dc8b2fbec3 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -56,7 +56,8 @@ is_named_tuple) from pandas.types.missing import isnull, notnull -from pandas.core.common import (PandasError, _try_sort, +from pandas.errors import PandasError +from pandas.core.common import (_try_sort, _default_index, _values_from_object, _maybe_box_datetimelike, diff --git a/pandas/core/ops.py b/pandas/core/ops.py index 5dac8a7e4d2da..9e777fd94de66 100644 --- a/pandas/core/ops.py +++ b/pandas/core/ops.py @@ -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, diff --git a/pandas/core/panel.py b/pandas/core/panel.py index 5ab3c44b175fe..0748ab12e8005 100644 --- a/pandas/core/panel.py +++ b/pandas/core/panel.py @@ -21,7 +21,8 @@ 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.errors import PandasError +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, diff --git a/pandas/errors/__init__.py b/pandas/errors/__init__.py new file mode 100644 index 0000000000000..3b232a2e8dd97 --- /dev/null +++ b/pandas/errors/__init__.py @@ -0,0 +1,63 @@ +# flake8: noqa + +""" expose public exceptions & warnings """ + +from pandas._libs.tslib import OutOfBoundsDatetime + + +class PandasError(Exception): + pass + + +class PerformanceWarning(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 ParserError(ValueError): + """ + Exception that is thrown by an error is encountered in `pd.read_csv` + """ + pass + + +class DtypeWarning(Warning): + """ + Warning that is raised whenever `pd.read_csv` encounters non- + uniform dtypes in a column(s) of a given CSV file + """ + pass + + +class EmptyDataError(ValueError): + """ + Exception that is thrown in `pd.read_csv` (by both the C and + Python engines) when empty data or header is encountered + """ + pass + + +class ParserWarning(Warning): + """ + Warning that is raised in `pd.read_csv` whenever it is necessary + to change parsers (generally from 'c' to 'python') contrary to the + one specified by the user due to lack of support or functionality for + parsing particular attributes of a CSV file with the requsted engine + """ + pass diff --git a/pandas/indexes/multi.py b/pandas/indexes/multi.py index e6ae0605d4758..f12b10ae682fa 100644 --- a/pandas/indexes/multi.py +++ b/pandas/indexes/multi.py @@ -19,12 +19,10 @@ is_list_like, is_scalar) from pandas.types.missing import isnull, array_equivalent +from pandas.errors import PerformanceWarning, UnsortedIndexError from pandas.core.common import (_values_from_object, is_bool_indexer, - is_null_slice, - PerformanceWarning, - UnsortedIndexError) - + is_null_slice) import pandas.core.base as base from pandas.util.decorators import (Appender, cache_readonly, diff --git a/pandas/io/common.py b/pandas/io/common.py index e42d218d7925f..8bc7217db87f9 100644 --- a/pandas/io/common.py +++ b/pandas/io/common.py @@ -12,6 +12,14 @@ from pandas.core.common import AbstractMethodError from pandas.types.common import is_number +# compat +from pandas.errors import (ParserError, DtypeWarning, # noqa + EmptyDataError, ParserWarning) + +# gh-12665: Alias for now and remove later. +CParserError = ParserError + + try: from s3fs import S3File need_text_wrapping = (BytesIO, S3File) @@ -69,43 +77,6 @@ def urlopen(*args, **kwargs): _VALID_URLS.discard('') -class ParserError(ValueError): - """ - Exception that is thrown by an error is encountered in `pd.read_csv` - """ - pass - - -# gh-12665: Alias for now and remove later. -CParserError = ParserError - - -class DtypeWarning(Warning): - """ - Warning that is raised whenever `pd.read_csv` encounters non- - uniform dtypes in a column(s) of a given CSV file - """ - pass - - -class EmptyDataError(ValueError): - """ - Exception that is thrown in `pd.read_csv` (by both the C and - Python engines) when empty data or header is encountered - """ - pass - - -class ParserWarning(Warning): - """ - Warning that is raised in `pd.read_csv` whenever it is necessary - to change parsers (generally from 'c' to 'python') contrary to the - one specified by the user due to lack of support or functionality for - parsing particular attributes of a CSV file with the requsted engine - """ - pass - - class BaseIterator(object): """Subclass this and provide a "__next__()" method to obtain an iterator. Useful only when the object being iterated is non-reusable (e.g. OK for a diff --git a/pandas/io/excel.py b/pandas/io/excel.py index d324855bc2f4d..6d136869fc73f 100644 --- a/pandas/io/excel.py +++ b/pandas/io/excel.py @@ -15,9 +15,9 @@ from pandas.core.frame import DataFrame from pandas.io.parsers import TextParser +from pandas.errors import EmptyDataError from pandas.io.common import (_is_url, _urlopen, _validate_header_arg, - EmptyDataError, get_filepath_or_buffer, - _NA_VALUES) + get_filepath_or_buffer, _NA_VALUES) from pandas.tseries.period import Period from pandas.io.json import libjson from pandas.compat import (map, zip, reduce, range, lrange, u, add_metaclass, diff --git a/pandas/io/html.py b/pandas/io/html.py index 8a3709dba2176..7b58e612de2df 100644 --- a/pandas/io/html.py +++ b/pandas/io/html.py @@ -13,7 +13,8 @@ import numpy as np from pandas.types.common import is_list_like -from pandas.io.common import (EmptyDataError, _is_url, urlopen, +from pandas.errors import EmptyDataError +from pandas.io.common import (_is_url, urlopen, parse_url, _validate_header_arg) from pandas.io.parsers import TextParser from pandas.compat import (lrange, lmap, u, string_types, iteritems, diff --git a/pandas/io/packers.py b/pandas/io/packers.py index 4662e8b635d3f..ca5a27ee5b68e 100644 --- a/pandas/io/packers.py +++ b/pandas/io/packers.py @@ -59,7 +59,7 @@ from pandas.sparse.api import SparseSeries, SparseDataFrame from pandas.sparse.array import BlockIndex, IntIndex from pandas.core.generic import NDFrame -from pandas.core.common import PerformanceWarning +from pandas.errors import PerformanceWarning from pandas.io.common import get_filepath_or_buffer from pandas.core.internals import BlockManager, make_block, _safe_reshape import pandas.core.internals as internals diff --git a/pandas/io/parsers.py b/pandas/io/parsers.py index 30b88de91ef76..0ebd2876982ec 100755 --- a/pandas/io/parsers.py +++ b/pandas/io/parsers.py @@ -29,10 +29,11 @@ from pandas.core import algorithms from pandas.core.common import AbstractMethodError from pandas.io.date_converters import generic_parser +from pandas.errors import ParserWarning, ParserError, EmptyDataError from pandas.io.common import (get_filepath_or_buffer, _validate_header_arg, _get_handle, UnicodeReader, UTF8Recoder, - BaseIterator, ParserError, EmptyDataError, - ParserWarning, _NA_VALUES, _infer_compression) + BaseIterator, + _NA_VALUES, _infer_compression) from pandas.tseries import tools from pandas.util.decorators import Appender diff --git a/pandas/io/parsers.pyx b/pandas/io/parsers.pyx index 3728cda559050..4053e726d0a04 100644 --- a/pandas/io/parsers.pyx +++ b/pandas/io/parsers.pyx @@ -13,12 +13,12 @@ from cpython cimport (PyObject, PyBytes_FromString, PyUnicode_Check, PyUnicode_AsUTF8String, PyErr_Occurred, PyErr_Fetch) from cpython.ref cimport PyObject, Py_XDECREF -from pandas.io.common import (ParserError, DtypeWarning, - EmptyDataError, ParserWarning) +from pandas.errors import (ParserError, DtypeWarning, + EmptyDataError, ParserWarning) # Import CParserError as alias of ParserError for backwards compatibility. # Ultimately, we want to remove this import. See gh-12665 and gh-14479. -from pandas.io.common import CParserError +CParserError = ParserError cdef extern from "Python.h": object PyUnicode_FromString(char *v) diff --git a/pandas/io/pytables.py b/pandas/io/pytables.py index f75a4761e0948..9b525b76b0f17 100644 --- a/pandas/io/pytables.py +++ b/pandas/io/pytables.py @@ -32,7 +32,8 @@ from pandas.sparse.array import BlockIndex, IntIndex from pandas.core.base import StringMixin from pandas.formats.printing import adjoin, pprint_thing -from pandas.core.common import _asarray_tuplesafe, PerformanceWarning +from pandas.errors import PerformanceWarning +from pandas.core.common import _asarray_tuplesafe from pandas.core.algorithms import match, unique from pandas.core.categorical import Categorical, _factorize_from_iterables from pandas.core.internals import (BlockManager, make_block, diff --git a/pandas/lib.py b/pandas/lib.py index 6c26627a97de3..859a78060fcc1 100644 --- a/pandas/lib.py +++ b/pandas/lib.py @@ -2,6 +2,7 @@ import warnings warnings.warn("The pandas.lib module is deprecated and will be " - "removed in a future version. Please import from " - "the pandas._libs.lib instead", FutureWarning, stacklevel=2) + "removed in a future version. These are private functions " + "and can be accessed from pandas._libs.lib instead", + FutureWarning, stacklevel=2) from pandas._libs.lib import * diff --git a/pandas/tests/api/test_api.py b/pandas/tests/api/test_api.py index 73222c246fc70..7de8fc25f687b 100644 --- a/pandas/tests/api/test_api.py +++ b/pandas/tests/api/test_api.py @@ -1,12 +1,9 @@ # -*- coding: utf-8 -*- from warnings import catch_warnings -import numpy as np import pandas as pd -from pandas.core import common as com from pandas import api -from pandas.api import types from pandas.util import testing as tm @@ -33,7 +30,7 @@ class TestPDApi(Base, tm.TestCase): # top-level sub-packages lib = ['api', 'compat', 'computation', 'core', - 'indexes', 'formats', 'pandas', + 'indexes', 'formats', 'errors', 'pandas', 'test', 'tools', 'tseries', 'sparse', 'types', 'util', 'options', 'io'] @@ -129,80 +126,6 @@ def test_api(self): self.check(api, self.allowed) -class TestTypes(Base, tm.TestCase): - - allowed = ['is_any_int_dtype', 'is_bool', 'is_bool_dtype', - 'is_categorical', 'is_categorical_dtype', 'is_complex', - 'is_complex_dtype', 'is_datetime64_any_dtype', - 'is_datetime64_dtype', 'is_datetime64_ns_dtype', - 'is_datetime64tz_dtype', 'is_datetimetz', 'is_dtype_equal', - 'is_extension_type', 'is_float', 'is_float_dtype', - 'is_floating_dtype', 'is_int64_dtype', 'is_integer', - 'is_integer_dtype', 'is_number', 'is_numeric_dtype', - 'is_object_dtype', 'is_scalar', 'is_sparse', - 'is_string_dtype', 'is_signed_integer_dtype', - 'is_timedelta64_dtype', 'is_timedelta64_ns_dtype', - 'is_unsigned_integer_dtype', 'is_period', - 'is_period_dtype', 'is_re', 'is_re_compilable', - 'is_dict_like', 'is_iterator', - 'is_list_like', 'is_hashable', - 'is_named_tuple', 'is_sequence', - 'pandas_dtype'] - - def test_types(self): - - self.check(types, self.allowed) - - def check_deprecation(self, fold, fnew): - with tm.assert_produces_warning(DeprecationWarning): - try: - result = fold('foo') - expected = fnew('foo') - self.assertEqual(result, expected) - except TypeError: - self.assertRaises(TypeError, - lambda: fnew('foo')) - except AttributeError: - self.assertRaises(AttributeError, - lambda: fnew('foo')) - - def test_deprecation_core_common(self): - - # test that we are in fact deprecating - # the pandas.core.common introspectors - for t in self.allowed: - self.check_deprecation(getattr(com, t), getattr(types, t)) - - def test_deprecation_core_common_array_equivalent(self): - - with tm.assert_produces_warning(DeprecationWarning): - com.array_equivalent(np.array([1, 2]), np.array([1, 2])) - - def test_deprecation_core_common_moved(self): - - # these are in pandas.types.common - l = ['is_datetime_arraylike', - 'is_datetime_or_timedelta_dtype', - 'is_datetimelike', - 'is_datetimelike_v_numeric', - 'is_datetimelike_v_object', - 'is_datetimetz', - 'is_int_or_datetime_dtype', - 'is_period_arraylike', - 'is_string_like', - 'is_string_like_dtype'] - - from pandas.types import common as c - for t in l: - self.check_deprecation(getattr(com, t), getattr(c, t)) - - def test_removed_from_core_common(self): - - for t in ['is_null_datelike_scalar', - 'ensure_float']: - self.assertRaises(AttributeError, lambda: getattr(com, t)) - - class TestDatetoolsDeprecation(tm.TestCase): def test_deprecation_access_func(self): @@ -271,4 +194,4 @@ class TestTSLib(tm.TestCase): def test_deprecation_access_func(self): with catch_warnings(record=True): - pd.tslib.Timestamp + pd.tslib.Timestamp('20160101') diff --git a/pandas/tests/api/test_types.py b/pandas/tests/api/test_types.py new file mode 100644 index 0000000000000..686de4a196034 --- /dev/null +++ b/pandas/tests/api/test_types.py @@ -0,0 +1,83 @@ +# -*- coding: utf-8 -*- + +import numpy as np + +from pandas.core import common as com +from pandas.api import types +from pandas.util import testing as tm + +from .test_api import Base + + +class TestTypes(Base, tm.TestCase): + + allowed = ['is_any_int_dtype', 'is_bool', 'is_bool_dtype', + 'is_categorical', 'is_categorical_dtype', 'is_complex', + 'is_complex_dtype', 'is_datetime64_any_dtype', + 'is_datetime64_dtype', 'is_datetime64_ns_dtype', + 'is_datetime64tz_dtype', 'is_datetimetz', 'is_dtype_equal', + 'is_extension_type', 'is_float', 'is_float_dtype', + 'is_floating_dtype', 'is_int64_dtype', 'is_integer', + 'is_integer_dtype', 'is_number', 'is_numeric_dtype', + 'is_object_dtype', 'is_scalar', 'is_sparse', + 'is_string_dtype', 'is_signed_integer_dtype', + 'is_timedelta64_dtype', 'is_timedelta64_ns_dtype', + 'is_unsigned_integer_dtype', 'is_period', + 'is_period_dtype', 'is_re', 'is_re_compilable', + 'is_dict_like', 'is_iterator', + 'is_list_like', 'is_hashable', + 'is_named_tuple', 'is_sequence', + 'pandas_dtype'] + + def test_types(self): + + self.check(types, self.allowed) + + def check_deprecation(self, fold, fnew): + with tm.assert_produces_warning(DeprecationWarning): + try: + result = fold('foo') + expected = fnew('foo') + self.assertEqual(result, expected) + except TypeError: + self.assertRaises(TypeError, + lambda: fnew('foo')) + except AttributeError: + self.assertRaises(AttributeError, + lambda: fnew('foo')) + + def test_deprecation_core_common(self): + + # test that we are in fact deprecating + # the pandas.core.common introspectors + for t in self.allowed: + self.check_deprecation(getattr(com, t), getattr(types, t)) + + def test_deprecation_core_common_array_equivalent(self): + + with tm.assert_produces_warning(DeprecationWarning): + com.array_equivalent(np.array([1, 2]), np.array([1, 2])) + + def test_deprecation_core_common_moved(self): + + # these are in pandas.types.common + l = ['is_datetime_arraylike', + 'is_datetime_or_timedelta_dtype', + 'is_datetimelike', + 'is_datetimelike_v_numeric', + 'is_datetimelike_v_object', + 'is_datetimetz', + 'is_int_or_datetime_dtype', + 'is_period_arraylike', + 'is_string_like', + 'is_string_like_dtype'] + + from pandas.types import common as c + for t in l: + self.check_deprecation(getattr(com, t), getattr(c, t)) + + def test_removed_from_core_common(self): + + for t in ['is_null_datelike_scalar', + 'ensure_float']: + self.assertRaises(AttributeError, lambda: getattr(com, t)) diff --git a/pandas/tests/computation/test_eval.py b/pandas/tests/computation/test_eval.py index 81e9b7c77a81b..97ed88b1dc22b 100644 --- a/pandas/tests/computation/test_eval.py +++ b/pandas/tests/computation/test_eval.py @@ -10,6 +10,7 @@ from pandas.types.common import is_list_like, is_scalar import pandas as pd from pandas.core import common as com +from pandas.errors import PerformanceWarning from pandas import DataFrame, Series, Panel, date_range from pandas.util.testing import makeCustomDataframe as mkdf @@ -1023,7 +1024,7 @@ def test_performance_warning_for_poor_alignment(self, engine, parser): df = DataFrame(randn(1000, 10)) s = Series(randn(10000)) if engine == 'numexpr': - seen = pd.core.common.PerformanceWarning + seen = PerformanceWarning else: seen = False @@ -1045,7 +1046,7 @@ def test_performance_warning_for_poor_alignment(self, engine, parser): is_python_engine = engine == 'python' if not is_python_engine: - wrn = pd.core.common.PerformanceWarning + wrn = PerformanceWarning else: wrn = False diff --git a/pandas/tests/frame/test_axis_select_reindex.py b/pandas/tests/frame/test_axis_select_reindex.py index 839ceb5368240..7ed2bfb601eb8 100644 --- a/pandas/tests/frame/test_axis_select_reindex.py +++ b/pandas/tests/frame/test_axis_select_reindex.py @@ -16,7 +16,7 @@ assert_frame_equal, assertRaisesRegexp) -from pandas.core.common import PerformanceWarning +from pandas.errors import PerformanceWarning import pandas.util.testing as tm from pandas.tests.frame.common import TestData diff --git a/pandas/tests/frame/test_constructors.py b/pandas/tests/frame/test_constructors.py index ba7e45d7e66fb..6349e07d50dc5 100644 --- a/pandas/tests/frame/test_constructors.py +++ b/pandas/tests/frame/test_constructors.py @@ -20,9 +20,8 @@ from pandas import (DataFrame, Index, Series, isnull, MultiIndex, Timedelta, Timestamp, date_range) -from pandas.core.common import PandasError +from pandas.errors import PandasError import pandas as pd -import pandas.core.common as com import pandas._libs.lib as lib import pandas.util.testing as tm @@ -1242,8 +1241,8 @@ def test_constructor_single_value(self): dtype=object), index=[1, 2], columns=['a', 'c'])) - self.assertRaises(com.PandasError, DataFrame, 'a', [1, 2]) - self.assertRaises(com.PandasError, DataFrame, 'a', columns=['a', 'c']) + self.assertRaises(PandasError, DataFrame, 'a', [1, 2]) + self.assertRaises(PandasError, DataFrame, 'a', columns=['a', 'c']) with tm.assertRaisesRegexp(TypeError, 'incompatible data and dtype'): DataFrame('a', [1, 2], ['a', 'c'], float) diff --git a/pandas/tests/frame/test_to_csv.py b/pandas/tests/frame/test_to_csv.py index e49dfffc48803..927b9f6a48718 100644 --- a/pandas/tests/frame/test_to_csv.py +++ b/pandas/tests/frame/test_to_csv.py @@ -8,7 +8,7 @@ import numpy as np from pandas.compat import (lmap, range, lrange, StringIO, u) -from pandas.io.common import ParserError +from pandas.errors import ParserError from pandas import (DataFrame, Index, Series, MultiIndex, Timestamp, date_range, read_csv, compat, to_datetime) import pandas as pd diff --git a/pandas/tests/groupby/test_groupby.py b/pandas/tests/groupby/test_groupby.py index 83502434e6053..c17c98c5448be 100644 --- a/pandas/tests/groupby/test_groupby.py +++ b/pandas/tests/groupby/test_groupby.py @@ -8,7 +8,7 @@ from pandas import (date_range, bdate_range, Timestamp, isnull, Index, MultiIndex, DataFrame, Series, concat, Panel) -from pandas.core.common import UnsupportedFunctionCall +from pandas.errors import UnsupportedFunctionCall, PerformanceWarning from pandas.util.testing import (assert_panel_equal, assert_frame_equal, assert_series_equal, assert_almost_equal, assert_index_equal, assertRaisesRegexp) @@ -3475,7 +3475,7 @@ def test_groupby_multiindex_not_lexsorted(self): tm.assert_frame_equal(lexsorted_df, not_lexsorted_df) expected = lexsorted_df.groupby('a').mean() - with tm.assert_produces_warning(com.PerformanceWarning): + with tm.assert_produces_warning(PerformanceWarning): result = not_lexsorted_df.groupby('a').mean() tm.assert_frame_equal(expected, result) diff --git a/pandas/tests/indexes/datetimes/test_ops.py b/pandas/tests/indexes/datetimes/test_ops.py index 4681879d708c4..4be9999982f12 100644 --- a/pandas/tests/indexes/datetimes/test_ops.py +++ b/pandas/tests/indexes/datetimes/test_ops.py @@ -7,7 +7,7 @@ import pandas as pd import pandas._libs.tslib as tslib import pandas.util.testing as tm -from pandas.core.common import PerformanceWarning +from pandas.errors import PerformanceWarning from pandas.tseries.index import cdate_range from pandas import (DatetimeIndex, PeriodIndex, Series, Timestamp, Timedelta, date_range, TimedeltaIndex, _np_version_under1p10, Index, diff --git a/pandas/tests/indexes/test_multi.py b/pandas/tests/indexes/test_multi.py index 0c274b2f6c4ff..470526043234f 100644 --- a/pandas/tests/indexes/test_multi.py +++ b/pandas/tests/indexes/test_multi.py @@ -15,7 +15,7 @@ from pandas import (CategoricalIndex, DataFrame, Index, MultiIndex, compat, date_range, period_range) from pandas.compat import PY3, long, lrange, lzip, range, u -from pandas.core.common import PerformanceWarning, UnsortedIndexError +from pandas.errors import PerformanceWarning, UnsortedIndexError from pandas.indexes.base import InvalidIndexError from pandas._libs import lib from pandas._libs.lib import Timestamp diff --git a/pandas/tests/indexing/test_ix.py b/pandas/tests/indexing/test_ix.py index e68e8015a2f39..b12d1eb97f88b 100644 --- a/pandas/tests/indexing/test_ix.py +++ b/pandas/tests/indexing/test_ix.py @@ -9,7 +9,7 @@ from pandas.compat import lrange from pandas import Series, DataFrame, option_context, MultiIndex from pandas.util import testing as tm -from pandas.core.common import PerformanceWarning +from pandas.errors import PerformanceWarning class TestIX(tm.TestCase): diff --git a/pandas/tests/indexing/test_multiindex.py b/pandas/tests/indexing/test_multiindex.py index ed943202872a7..1fc0a87764b94 100644 --- a/pandas/tests/indexing/test_multiindex.py +++ b/pandas/tests/indexing/test_multiindex.py @@ -5,7 +5,7 @@ from pandas import (Panel, Series, MultiIndex, DataFrame, Timestamp, Index, date_range) from pandas.util import testing as tm -from pandas.core.common import PerformanceWarning, UnsortedIndexError +from pandas.errors import PerformanceWarning, UnsortedIndexError from pandas.tests.indexing.common import _mklbl diff --git a/pandas/tests/io/parser/common.py b/pandas/tests/io/parser/common.py index 2c8bca490f274..7faf485b65d10 100644 --- a/pandas/tests/io/parser/common.py +++ b/pandas/tests/io/parser/common.py @@ -19,7 +19,8 @@ from pandas import compat from pandas.compat import (StringIO, BytesIO, PY3, range, lrange, u) -from pandas.io.common import DtypeWarning, EmptyDataError, URLError +from pandas.errors import DtypeWarning, EmptyDataError +from pandas.io.common import URLError from pandas.io.parsers import TextFileReader, TextParser diff --git a/pandas/tests/io/parser/dialect.py b/pandas/tests/io/parser/dialect.py index ee50cf812f72e..82871628e54d6 100644 --- a/pandas/tests/io/parser/dialect.py +++ b/pandas/tests/io/parser/dialect.py @@ -9,7 +9,7 @@ from pandas import DataFrame from pandas.compat import StringIO -from pandas.io.common import ParserWarning +from pandas.errors import ParserWarning import pandas.util.testing as tm diff --git a/pandas/tests/io/parser/dtypes.py b/pandas/tests/io/parser/dtypes.py index fa95c18c4d7a9..8066718363803 100644 --- a/pandas/tests/io/parser/dtypes.py +++ b/pandas/tests/io/parser/dtypes.py @@ -12,7 +12,7 @@ from pandas import DataFrame, Series, Index, MultiIndex, Categorical from pandas.compat import StringIO from pandas.types.dtypes import CategoricalDtype -from pandas.io.common import ParserWarning +from pandas.errors import ParserWarning class DtypeTests(object): diff --git a/pandas/tests/io/parser/skiprows.py b/pandas/tests/io/parser/skiprows.py index c53e6a1579267..cb1b656e42be2 100644 --- a/pandas/tests/io/parser/skiprows.py +++ b/pandas/tests/io/parser/skiprows.py @@ -12,7 +12,7 @@ import pandas.util.testing as tm from pandas import DataFrame -from pandas.io.common import EmptyDataError +from pandas.errors import EmptyDataError from pandas.compat import StringIO, range, lrange diff --git a/pandas/tests/io/parser/test_unsupported.py b/pandas/tests/io/parser/test_unsupported.py index 48dd5d4ba506b..14146a3ad1e9a 100644 --- a/pandas/tests/io/parser/test_unsupported.py +++ b/pandas/tests/io/parser/test_unsupported.py @@ -13,7 +13,7 @@ import pandas.util.testing as tm from pandas.compat import StringIO -from pandas.io.common import ParserError +from pandas.errors import ParserError from pandas.io.parsers import read_csv, read_table diff --git a/pandas/tests/io/test_common.py b/pandas/tests/io/test_common.py index 3c980cae3351a..c08d235b07c9e 100644 --- a/pandas/tests/io/test_common.py +++ b/pandas/tests/io/test_common.py @@ -11,7 +11,6 @@ from pandas.compat import is_platform_windows, StringIO from pandas import read_csv, concat -import pandas as pd try: from pathlib import Path @@ -89,23 +88,6 @@ def test_iterator(self): tm.assert_frame_equal(first, expected.iloc[[0]]) tm.assert_frame_equal(concat(it), expected.iloc[1:]) - def test_error_rename(self): - # see gh-12665 - try: - raise common.CParserError() - except common.ParserError: - pass - - try: - raise common.ParserError() - except common.CParserError: - pass - - try: - raise common.ParserError() - except pd.parser.CParserError: - pass - class TestMMapWrapper(tm.TestCase): diff --git a/pandas/tests/io/test_packers.py b/pandas/tests/io/test_packers.py index efa8587d64657..1b6b0fc62f913 100644 --- a/pandas/tests/io/test_packers.py +++ b/pandas/tests/io/test_packers.py @@ -10,7 +10,7 @@ from pandas.compat import u, PY3 from pandas import (Series, DataFrame, Panel, MultiIndex, bdate_range, date_range, period_range, Index, Categorical) -from pandas.core.common import PerformanceWarning +from pandas.errors import PerformanceWarning from pandas.io.packers import to_msgpack, read_msgpack import pandas.util.testing as tm from pandas.util.testing import (ensure_clean, diff --git a/pandas/tests/test_errors.py b/pandas/tests/test_errors.py new file mode 100644 index 0000000000000..19de66dc598b8 --- /dev/null +++ b/pandas/tests/test_errors.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- + +import pytest +import pandas # noqa +import pandas as pd + + +@pytest.mark.parametrize( + "exc", ['PandasError', 'AmbiguousIndexError', + 'UnsupportedFunctionCall', 'UnsortedIndexError', + 'OutOfBoundsDatetime', + 'ParserError', 'PerformanceWarning', 'DtypeWarning', + 'EmptyDataError', 'ParserWarning']) +def test_exception_importable(exc): + from pandas import errors + e = getattr(errors, exc) + assert e is not None + + # check that we can raise on them + with pytest.raises(e): + raise e() + + +def test_catch_oob(): + from pandas import errors + + try: + pd.Timestamp('15000101') + except errors.OutOfBoundsDatetime: + pass + + +def test_error_rename(): + # see gh-12665 + from pandas.errors import ParserError + from pandas.io.common import CParserError + + try: + raise CParserError() + except ParserError: + pass + + try: + raise ParserError() + except CParserError: + pass + + try: + raise ParserError() + except pd.parser.CParserError: + pass diff --git a/pandas/tests/test_window.py b/pandas/tests/test_window.py index fe03d7886e661..ceb12c6c03074 100644 --- a/pandas/tests/test_window.py +++ b/pandas/tests/test_window.py @@ -16,7 +16,7 @@ import pandas.core.window as rwindow import pandas.tseries.offsets as offsets from pandas.core.base import SpecificationError -from pandas.core.common import UnsupportedFunctionCall +from pandas.errors import UnsupportedFunctionCall import pandas.util.testing as tm from pandas.compat import range, zip, PY3 diff --git a/pandas/tests/tseries/test_resample.py b/pandas/tests/tseries/test_resample.py index 57a655b0b7610..57e5a1631f8e8 100755 --- a/pandas/tests/tseries/test_resample.py +++ b/pandas/tests/tseries/test_resample.py @@ -14,7 +14,7 @@ from pandas.types.generic import ABCSeries, ABCDataFrame from pandas.compat import range, lrange, zip, product, OrderedDict from pandas.core.base import SpecificationError -from pandas.core.common import UnsupportedFunctionCall +from pandas.errors import UnsupportedFunctionCall from pandas.core.groupby import DataError from pandas.tseries.frequencies import MONTHS, DAYS from pandas.tseries.frequencies import to_offset diff --git a/pandas/tseries/index.py b/pandas/tseries/index.py index 9123131a6dccf..f6b54e547c1b9 100644 --- a/pandas/tseries/index.py +++ b/pandas/tseries/index.py @@ -25,8 +25,8 @@ from pandas.types.missing import isnull import pandas.types.concat as _concat -from pandas.core.common import (_values_from_object, _maybe_box, - PerformanceWarning) +from pandas.errors import PerformanceWarning +from pandas.core.common import _values_from_object, _maybe_box from pandas.core.index import Index, Int64Index, Float64Index from pandas.indexes.base import _index_shared_docs diff --git a/pandas/tslib.py b/pandas/tslib.py index 3ecbffa20700d..82d2733ed3171 100644 --- a/pandas/tslib.py +++ b/pandas/tslib.py @@ -3,6 +3,6 @@ import warnings warnings.warn("The pandas.tslib module is deprecated and will be " "removed in a future version. Please import from " - "the pandas._libs.tslib instead", FutureWarning, stacklevel=2) + "the pandas or pandas.api.exceptions instead", FutureWarning, stacklevel=2) from pandas._libs.tslib import (Timestamp, Timedelta, NaT, OutOfBoundsDatetime) diff --git a/setup.py b/setup.py index 89be053249346..96b25f7427370 100755 --- a/setup.py +++ b/setup.py @@ -637,6 +637,7 @@ def pxd(name): 'pandas.computation', 'pandas.core', 'pandas.indexes', + 'pandas.errors', 'pandas.io', 'pandas.io.json', 'pandas.io.sas', From 92b2fdcf63cb608ba6651ed80aa2f783a97fc4da Mon Sep 17 00:00:00 2001 From: Jeff Reback Date: Wed, 22 Mar 2017 16:38:02 -0400 Subject: [PATCH 03/12] corrections --- pandas/errors/__init__.py | 11 ++++------- pandas/tslib.py | 2 +- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/pandas/errors/__init__.py b/pandas/errors/__init__.py index 3b232a2e8dd97..fa8333b17aafb 100644 --- a/pandas/errors/__init__.py +++ b/pandas/errors/__init__.py @@ -21,28 +21,27 @@ class UnsupportedFunctionCall(ValueError): class UnsortedIndexError(KeyError): - """ Error raised when attempting to get a slice of a MultiIndex + """ + 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 ParserError(ValueError): """ Exception that is thrown by an error is encountered in `pd.read_csv` """ - pass class DtypeWarning(Warning): """ - Warning that is raised whenever `pd.read_csv` encounters non- + Warning that is raised for a dtype incompatiblity. This is + can happen whenever `pd.read_csv` encounters non- uniform dtypes in a column(s) of a given CSV file """ - pass class EmptyDataError(ValueError): @@ -50,7 +49,6 @@ class EmptyDataError(ValueError): Exception that is thrown in `pd.read_csv` (by both the C and Python engines) when empty data or header is encountered """ - pass class ParserWarning(Warning): @@ -60,4 +58,3 @@ class ParserWarning(Warning): one specified by the user due to lack of support or functionality for parsing particular attributes of a CSV file with the requsted engine """ - pass diff --git a/pandas/tslib.py b/pandas/tslib.py index 82d2733ed3171..3d96dc496c0de 100644 --- a/pandas/tslib.py +++ b/pandas/tslib.py @@ -3,6 +3,6 @@ import warnings warnings.warn("The pandas.tslib module is deprecated and will be " "removed in a future version. Please import from " - "the pandas or pandas.api.exceptions instead", FutureWarning, stacklevel=2) + "the pandas or pandas.errors instead", FutureWarning, stacklevel=2) from pandas._libs.tslib import (Timestamp, Timedelta, NaT, OutOfBoundsDatetime) From 7e8432d6bc212d96b5f2489d903c5efee99332f7 Mon Sep 17 00:00:00 2001 From: Jeff Reback Date: Mon, 27 Mar 2017 09:38:07 -0400 Subject: [PATCH 04/12] remove need for PandasError sub-class --- doc/source/whatsnew/v0.20.0.txt | 2 ++ pandas/core/common.py | 2 +- pandas/core/frame.py | 3 +-- pandas/core/panel.py | 7 +++---- pandas/errors/__init__.py | 6 +----- pandas/tests/frame/test_constructors.py | 7 +++---- pandas/tests/test_errors.py | 2 +- pandas/tseries/index.py | 6 ++---- 8 files changed, 14 insertions(+), 21 deletions(-) diff --git a/doc/source/whatsnew/v0.20.0.txt b/doc/source/whatsnew/v0.20.0.txt index 79b35e02ba311..a907d5c118488 100644 --- a/doc/source/whatsnew/v0.20.0.txt +++ b/doc/source/whatsnew/v0.20.0.txt @@ -877,6 +877,8 @@ 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`) + .. _whatsnew_0200.deprecations: diff --git a/pandas/core/common.py b/pandas/core/common.py index 79eb770552531..3dc6fe0729d21 100644 --- a/pandas/core/common.py +++ b/pandas/core/common.py @@ -22,7 +22,7 @@ # compat from pandas.errors import ( # noqa - PandasError, PerformanceWarning, + PerformanceWarning, AmbiguousIndexError, UnsupportedFunctionCall, UnsortedIndexError) # back-compat of public API diff --git a/pandas/core/frame.py b/pandas/core/frame.py index d75dc8b2fbec3..237af0f85e866 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -56,7 +56,6 @@ is_named_tuple) from pandas.types.missing import isnull, notnull -from pandas.errors import PandasError from pandas.core.common import (_try_sort, _default_index, _values_from_object, @@ -348,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) diff --git a/pandas/core/panel.py b/pandas/core/panel.py index 0748ab12e8005..9e95023ccb359 100644 --- a/pandas/core/panel.py +++ b/pandas/core/panel.py @@ -21,7 +21,6 @@ from pandas import compat from pandas.compat import (map, zip, range, u, OrderedDict, OrderedDefaultdict) from pandas.compat.numpy import function as nv -from pandas.errors import PandasError from pandas.core.common import _try_sort, _default_index from pandas.core.frame import DataFrame from pandas.core.generic import NDFrame, _shared_docs @@ -175,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) @@ -1151,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) diff --git a/pandas/errors/__init__.py b/pandas/errors/__init__.py index fa8333b17aafb..5a23086dcc60d 100644 --- a/pandas/errors/__init__.py +++ b/pandas/errors/__init__.py @@ -5,14 +5,10 @@ from pandas._libs.tslib import OutOfBoundsDatetime -class PandasError(Exception): - pass - - class PerformanceWarning(Warning): pass -class AmbiguousIndexError(PandasError, KeyError): +class AmbiguousIndexError(KeyError): pass diff --git a/pandas/tests/frame/test_constructors.py b/pandas/tests/frame/test_constructors.py index 6349e07d50dc5..1ab292649a973 100644 --- a/pandas/tests/frame/test_constructors.py +++ b/pandas/tests/frame/test_constructors.py @@ -20,7 +20,6 @@ from pandas import (DataFrame, Index, Series, isnull, MultiIndex, Timedelta, Timestamp, date_range) -from pandas.errors import PandasError import pandas as pd import pandas._libs.lib as lib import pandas.util.testing as tm @@ -773,7 +772,7 @@ def test_constructor_more(self): # corner, silly # TODO: Fix this Exception to be better... - with tm.assertRaisesRegexp(PandasError, 'constructor not ' + with tm.assertRaisesRegexp(ValueError, 'constructor not ' 'properly called'): DataFrame((1, 2, 3)) @@ -1241,8 +1240,8 @@ def test_constructor_single_value(self): dtype=object), index=[1, 2], columns=['a', 'c'])) - self.assertRaises(PandasError, DataFrame, 'a', [1, 2]) - self.assertRaises(PandasError, DataFrame, 'a', columns=['a', 'c']) + self.assertRaises(ValueError, DataFrame, 'a', [1, 2]) + self.assertRaises(ValueError, DataFrame, 'a', columns=['a', 'c']) with tm.assertRaisesRegexp(TypeError, 'incompatible data and dtype'): DataFrame('a', [1, 2], ['a', 'c'], float) diff --git a/pandas/tests/test_errors.py b/pandas/tests/test_errors.py index 19de66dc598b8..ffecd9f0f3faa 100644 --- a/pandas/tests/test_errors.py +++ b/pandas/tests/test_errors.py @@ -6,7 +6,7 @@ @pytest.mark.parametrize( - "exc", ['PandasError', 'AmbiguousIndexError', + "exc", ['AmbiguousIndexError', 'UnsupportedFunctionCall', 'UnsortedIndexError', 'OutOfBoundsDatetime', 'ParserError', 'PerformanceWarning', 'DtypeWarning', diff --git a/pandas/tseries/index.py b/pandas/tseries/index.py index f6b54e547c1b9..8fa842a836051 100644 --- a/pandas/tseries/index.py +++ b/pandas/tseries/index.py @@ -618,8 +618,7 @@ def _has_same_tz(self, other): def _cached_range(cls, start=None, end=None, periods=None, offset=None, name=None): if start is None and end is None: - # I somewhat believe this should never be raised externally and - # therefore should be a `PandasError` but whatever... + # I somewhat believe this should never be raised externally raise TypeError('Must specify either start or end.') if start is not None: start = Timestamp(start) @@ -630,8 +629,7 @@ def _cached_range(cls, start=None, end=None, periods=None, offset=None, 'Must either specify period or provide both start and end.') if offset is None: - # This can't happen with external-facing code, therefore - # PandasError + # This can't happen with external-facing code raise TypeError('Must provide offset.') drc = _daterange_cache From e91901db66289261f105427aaefe7843478ca581 Mon Sep 17 00:00:00 2001 From: Jeff Reback Date: Mon, 27 Mar 2017 09:46:37 -0400 Subject: [PATCH 05/12] DOC: better docs on infer_type --- doc/source/whatsnew/v0.20.0.txt | 17 +++++---- pandas/_libs/src/inference.pyx | 61 +++++++++++++++++++++++++-------- 2 files changed, 58 insertions(+), 20 deletions(-) diff --git a/doc/source/whatsnew/v0.20.0.txt b/doc/source/whatsnew/v0.20.0.txt index a907d5c118488..846a7c6acec51 100644 --- a/doc/source/whatsnew/v0.20.0.txt +++ b/doc/source/whatsnew/v0.20.0.txt @@ -86,12 +86,17 @@ will be removed from the ``*.common`` locations in a future release. (:issue:`15 The following are now part of this API: -.. ipython:: python - - import pprint - from pandas import errors - excs = [ e for e in dir(errors) if not e.startswith('_') ] - pprint.pprint(excs) +.. code-block:: python + + ['AmbiguousIndexError', + 'DtypeWarning', + 'EmptyDataError', + 'OutOfBoundsDatetime', + 'ParserError', + 'ParserWarning', + 'PerformanceWarning', + 'UnsortedIndexError', + 'UnsupportedFunctionCall'] .. _whatsnew_0200.enhancements.groupby_access: diff --git a/pandas/_libs/src/inference.pyx b/pandas/_libs/src/inference.pyx index 933fc8fb1cc9b..1076cba3919c2 100644 --- a/pandas/_libs/src/inference.pyx +++ b/pandas/_libs/src/inference.pyx @@ -218,9 +218,42 @@ 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: + - floating + - integer + - mixed-integer + - mixed-integer-float + - complex + - categorical + - boolean + - datetime64 + - datetime + - date + - timedelta64 + - timedelta + - time + - period + - string + - unicode + - bytes + - mixed + + Raises + ------ + TypeError if ndarray-like but cannot infer the dtype + """ cdef: @@ -229,27 +262,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) From 35d225fc73e997b31ef4f63860b17bf94e18176f Mon Sep 17 00:00:00 2001 From: Jeff Reback Date: Mon, 27 Mar 2017 14:18:44 -0400 Subject: [PATCH 06/12] more examples --- pandas/_libs/src/inference.pyx | 48 ++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/pandas/_libs/src/inference.pyx b/pandas/_libs/src/inference.pyx index 1076cba3919c2..3cae3d511b44e 100644 --- a/pandas/_libs/src/inference.pyx +++ b/pandas/_libs/src/inference.pyx @@ -254,6 +254,54 @@ def infer_dtype(object value): ------ 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: From 57546309abc0d393fd19a94ee66a0704250bc689 Mon Sep 17 00:00:00 2001 From: Jeff Reback Date: Mon, 27 Mar 2017 17:21:19 -0400 Subject: [PATCH 07/12] fix doc-string --- pandas/_libs/src/inference.pyx | 37 +++++++++++++++++----------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/pandas/_libs/src/inference.pyx b/pandas/_libs/src/inference.pyx index 3cae3d511b44e..b0fb7048f154c 100644 --- a/pandas/_libs/src/inference.pyx +++ b/pandas/_libs/src/inference.pyx @@ -231,24 +231,25 @@ def infer_dtype(object value): ------- string describing the common type of the input data. Results can include: - - floating - - integer - - mixed-integer - - mixed-integer-float - - complex - - categorical - - boolean - - datetime64 - - datetime - - date - - timedelta64 - - timedelta - - time - - period - - string - - unicode - - bytes - - mixed + + - string + - unicode + - bytes + - floating + - integer + - mixed-integer + - mixed-integer-float + - complex + - categorical + - boolean + - datetime64 + - datetime + - date + - timedelta64 + - timedelta + - time + - period + - mixed Raises ------ From 2bb1fbde6fdb167253b553f5b7b392abad674537 Mon Sep 17 00:00:00 2001 From: Jeff Reback Date: Mon, 27 Mar 2017 17:29:57 -0400 Subject: [PATCH 08/12] remove AmbiguousIndexError, completely unused --- pandas/core/common.py | 3 +-- pandas/core/indexing.py | 2 +- pandas/errors/__init__.py | 9 ++++----- pandas/tests/test_errors.py | 3 +-- 4 files changed, 7 insertions(+), 10 deletions(-) diff --git a/pandas/core/common.py b/pandas/core/common.py index 3dc6fe0729d21..bf4acf1fbf257 100644 --- a/pandas/core/common.py +++ b/pandas/core/common.py @@ -22,8 +22,7 @@ # compat from pandas.errors import ( # noqa - PerformanceWarning, - AmbiguousIndexError, UnsupportedFunctionCall, UnsortedIndexError) + PerformanceWarning, UnsupportedFunctionCall, UnsortedIndexError) # back-compat of public API # deprecate these functions diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py index 61a847ccf1523..9e22bdd5facc4 100755 --- a/pandas/core/indexing.py +++ b/pandas/core/indexing.py @@ -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 """ diff --git a/pandas/errors/__init__.py b/pandas/errors/__init__.py index 5a23086dcc60d..19bff3d570a0e 100644 --- a/pandas/errors/__init__.py +++ b/pandas/errors/__init__.py @@ -6,11 +6,10 @@ class PerformanceWarning(Warning): - pass - -class AmbiguousIndexError(KeyError): - pass - + """ + Warnings shown when there is a possible performance + impact. + """ class UnsupportedFunctionCall(ValueError): pass diff --git a/pandas/tests/test_errors.py b/pandas/tests/test_errors.py index ffecd9f0f3faa..aabce7ecb7066 100644 --- a/pandas/tests/test_errors.py +++ b/pandas/tests/test_errors.py @@ -6,8 +6,7 @@ @pytest.mark.parametrize( - "exc", ['AmbiguousIndexError', - 'UnsupportedFunctionCall', 'UnsortedIndexError', + "exc", ['UnsupportedFunctionCall', 'UnsortedIndexError', 'OutOfBoundsDatetime', 'ParserError', 'PerformanceWarning', 'DtypeWarning', 'EmptyDataError', 'ParserWarning']) From 3dc4b9a455c7da621fa6c2850362a26ee4fa8b50 Mon Sep 17 00:00:00 2001 From: Jeff Reback Date: Mon, 27 Mar 2017 17:33:55 -0400 Subject: [PATCH 09/12] more docs for exceptions --- pandas/errors/__init__.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pandas/errors/__init__.py b/pandas/errors/__init__.py index 19bff3d570a0e..f6719e7be421b 100644 --- a/pandas/errors/__init__.py +++ b/pandas/errors/__init__.py @@ -12,8 +12,10 @@ class PerformanceWarning(Warning): """ class UnsupportedFunctionCall(ValueError): - pass - + """ + If attempting to call a numpy function on a pandas + object. For example using ``np.cumsum(groupby_object)``. + """ class UnsortedIndexError(KeyError): """ From d636ef71d8956ea3dd17e5e73f9da8a13faef8ec Mon Sep 17 00:00:00 2001 From: Jeff Reback Date: Mon, 27 Mar 2017 17:37:09 -0400 Subject: [PATCH 10/12] document removed exceptions --- doc/source/whatsnew/v0.20.0.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/source/whatsnew/v0.20.0.txt b/doc/source/whatsnew/v0.20.0.txt index 846a7c6acec51..3f408147501e8 100644 --- a/doc/source/whatsnew/v0.20.0.txt +++ b/doc/source/whatsnew/v0.20.0.txt @@ -884,6 +884,8 @@ Other API Changes 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: From ab4525be39a24564df0e640fd974207220a5eb0d Mon Sep 17 00:00:00 2001 From: Jeff Reback Date: Mon, 27 Mar 2017 17:38:54 -0400 Subject: [PATCH 11/12] typo on pandas.errors in whatsnew --- doc/source/whatsnew/v0.20.0.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/source/whatsnew/v0.20.0.txt b/doc/source/whatsnew/v0.20.0.txt index 3f408147501e8..0533448fed547 100644 --- a/doc/source/whatsnew/v0.20.0.txt +++ b/doc/source/whatsnew/v0.20.0.txt @@ -88,8 +88,7 @@ The following are now part of this API: .. code-block:: python - ['AmbiguousIndexError', - 'DtypeWarning', + ['DtypeWarning', 'EmptyDataError', 'OutOfBoundsDatetime', 'ParserError', From e5fbdc8e00e220eed797d4fb05bcb02b356d2f45 Mon Sep 17 00:00:00 2001 From: Jeff Reback Date: Mon, 3 Apr 2017 14:12:01 -0400 Subject: [PATCH 12/12] give nicer deprecation / message on infer_dtype moving --- pandas/__init__.py | 3 ++- pandas/tests/api/test_api.py | 2 +- pandas/tests/api/test_lib.py | 11 +++++------ pandas/util/depr_module.py | 15 ++++++++++++++- 4 files changed, 22 insertions(+), 9 deletions(-) diff --git a/pandas/__init__.py b/pandas/__init__.py index 5c7c9d44c5d10..1bc85899fb89f 100644 --- a/pandas/__init__.py +++ b/pandas/__init__.py @@ -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 diff --git a/pandas/tests/api/test_api.py b/pandas/tests/api/test_api.py index 7de8fc25f687b..7d1308d67668e 100644 --- a/pandas/tests/api/test_api.py +++ b/pandas/tests/api/test_api.py @@ -187,7 +187,7 @@ class TestLib(tm.TestCase): def test_deprecation_access_func(self): with catch_warnings(record=True): - pd.lib.infer_dtype + pd.lib.infer_dtype('foo') class TestTSLib(tm.TestCase): diff --git a/pandas/tests/api/test_lib.py b/pandas/tests/api/test_lib.py index 4632d551e574e..db2c68c6197d7 100644 --- a/pandas/tests/api/test_lib.py +++ b/pandas/tests/api/test_lib.py @@ -1,11 +1,10 @@ # -*- coding: utf-8 -*- -import pytest +from warnings import catch_warnings import pandas # noqa -@pytest.mark.parametrize('f', ['infer_dtype']) -def test_importable(f): - from pandas.api import lib - e = getattr(lib, f) - assert e is not None +def test_moved_infer_dtype(): + with catch_warnings(record=True): + e = pandas.lib.infer_dtype('foo') + assert e is not None diff --git a/pandas/util/depr_module.py b/pandas/util/depr_module.py index af7faf9dd96c8..0885c81ce2757 100644 --- a/pandas/util/depr_module.py +++ b/pandas/util/depr_module.py @@ -18,14 +18,19 @@ class _DeprecatedModule(object): be used when needed. removals : objects or methods in module that will no longer be accessible once module is removed. + moved : dict, optional + dictionary of function name -> new location for moved + objects """ - def __init__(self, deprmod, deprmodto=None, removals=None): + def __init__(self, deprmod, deprmodto=None, removals=None, + moved=None): self.deprmod = deprmod self.deprmodto = deprmodto self.removals = removals if self.removals is not None: self.removals = frozenset(self.removals) + self.moved = moved # For introspection purposes. self.self_dir = frozenset(dir(self.__class__)) @@ -60,6 +65,14 @@ def __getattr__(self, name): "{deprmod}.{name} is deprecated and will be removed in " "a future version.".format(deprmod=self.deprmod, name=name), FutureWarning, stacklevel=2) + elif self.moved is not None and name in self.moved: + warnings.warn( + "{deprmod} is deprecated and will be removed in " + "a future version.\nYou can access {name} in {moved}".format( + deprmod=self.deprmod, + name=name, + moved=self.moved[name]), + FutureWarning, stacklevel=2) else: deprmodto = self.deprmodto if deprmodto is None: