diff --git a/.travis.yml b/.travis.yml index f8302f4718ef2..529f1221899dc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,7 +41,7 @@ matrix: - dist: trusty env: - - JOB="3.6, coverage" ENV_FILE="ci/deps/travis-36.yaml" PATTERN="((not slow and not network) or (single and db))" PANDAS_TESTING_MODE="deprecate" COVERAGE=true + - JOB="3.6, coverage" ENV_FILE="ci/deps/travis-36-cov.yaml" PATTERN="((not slow and not network) or (single and db))" PANDAS_TESTING_MODE="deprecate" COVERAGE=true # In allow_failures - dist: trusty diff --git a/README.md b/README.md index dcf39864e46e2..e8bfd28cc8208 100644 --- a/README.md +++ b/README.md @@ -164,7 +164,7 @@ pip install pandas ``` ## Dependencies -- [NumPy](https://www.numpy.org): 1.12.0 or higher +- [NumPy](https://www.numpy.org): 1.13.3 or higher - [python-dateutil](https://labix.org/python-dateutil): 2.5.0 or higher - [pytz](https://pythonhosted.org/pytz): 2015.4 or higher diff --git a/ci/azure/windows.yml b/ci/azure/windows.yml index cd5879bf55e4b..1e3390a7f8d9b 100644 --- a/ci/azure/windows.yml +++ b/ci/azure/windows.yml @@ -8,7 +8,7 @@ jobs: vmImage: ${{ parameters.vmImage }} strategy: matrix: - py36_np14: + py36_np15: ENV_FILE: ci/deps/azure-windows-36.yaml CONDA_PY: "36" diff --git a/ci/deps/azure-35-compat.yaml b/ci/deps/azure-35-compat.yaml index adae9bc761a42..708c08239c7c0 100644 --- a/ci/deps/azure-35-compat.yaml +++ b/ci/deps/azure-35-compat.yaml @@ -3,23 +3,23 @@ channels: - defaults - conda-forge dependencies: - - beautifulsoup4==4.4.1 - - bottleneck=1.2.0 - - cython=0.28.2 - - hypothesis>=3.58.0 + - beautifulsoup4=4.4.1 + - bottleneck=1.2.1 - jinja2=2.8 - - numexpr=2.6.1 - - numpy=1.12.0 + - numexpr=2.6.2 + - numpy=1.13.3 - openpyxl=2.4.0 - pytables=3.4.2 - python-dateutil=2.5.0 - - python=3.5* + - python=3.5.* - pytz=2015.4 - - scipy=0.18.1 + - scipy=0.19.0 - xlrd=1.0.0 - xlsxwriter=0.7.7 - xlwt=1.0.0 # universal + - cython=0.28.2 + - hypothesis>=3.58.0 - pytest-xdist - pytest-mock - isort diff --git a/ci/deps/azure-36-locale.yaml b/ci/deps/azure-36-locale.yaml index c74d56443be5d..4209247cd6ce5 100644 --- a/ci/deps/azure-36-locale.yaml +++ b/ci/deps/azure-36-locale.yaml @@ -4,15 +4,15 @@ channels: - conda-forge dependencies: - beautifulsoup4==4.5.1 - - bottleneck=1.2.0 + - bottleneck=1.2.* - cython=0.28.2 - lxml - - matplotlib=2.0.0 - - numpy=1.12.0 + - matplotlib=2.2.2 + - numpy=1.14.* - openpyxl=2.4.0 - python-dateutil - python-blosc - - python=3.6 + - python=3.6.* - pytz=2016.10 - scipy - sqlalchemy=1.1.4 diff --git a/ci/deps/azure-36-locale_slow.yaml b/ci/deps/azure-36-locale_slow.yaml index 3f788e5ddcf39..fa2749017ec07 100644 --- a/ci/deps/azure-36-locale_slow.yaml +++ b/ci/deps/azure-36-locale_slow.yaml @@ -10,14 +10,14 @@ dependencies: - ipython - jinja2 - lxml - - matplotlib + - matplotlib=3.0.* - nomkl - numexpr - - numpy + - numpy=1.15.* - openpyxl - pytables - python-dateutil - - python=3.6* + - python=3.6.* - pytz - s3fs - scipy diff --git a/ci/deps/azure-37-locale.yaml b/ci/deps/azure-37-locale.yaml index 9d598cddce91a..71d69d0ab68c1 100644 --- a/ci/deps/azure-37-locale.yaml +++ b/ci/deps/azure-37-locale.yaml @@ -16,7 +16,7 @@ dependencies: - openpyxl - pytables - python-dateutil - - python=3.7* + - python=3.7.* - pytz - s3fs - scipy diff --git a/ci/deps/azure-37-numpydev.yaml b/ci/deps/azure-37-numpydev.yaml index e58c1f599279c..d940463e2768c 100644 --- a/ci/deps/azure-37-numpydev.yaml +++ b/ci/deps/azure-37-numpydev.yaml @@ -2,7 +2,7 @@ name: pandas-dev channels: - defaults dependencies: - - python=3.7* + - python=3.7.* - pytz - Cython>=0.28.2 # universal diff --git a/ci/deps/azure-macos-35.yaml b/ci/deps/azure-macos-35.yaml index 38625c6563753..591266348a5f1 100644 --- a/ci/deps/azure-macos-35.yaml +++ b/ci/deps/azure-macos-35.yaml @@ -8,14 +8,14 @@ dependencies: - html5lib - jinja2 - lxml - - matplotlib=2.2.0 + - matplotlib=2.2.3 - nomkl - numexpr - - numpy=1.12.0 + - numpy=1.13.3 - openpyxl - pyarrow - pytables - - python=3.5* + - python=3.5.* - pytz - xarray - xlrd diff --git a/ci/deps/azure-windows-36.yaml b/ci/deps/azure-windows-36.yaml index 5ce55a4cb4c0e..7b3ae259fb8dd 100644 --- a/ci/deps/azure-windows-36.yaml +++ b/ci/deps/azure-windows-36.yaml @@ -7,9 +7,9 @@ dependencies: - bottleneck - boost-cpp<1.67 - fastparquet>=0.2.1 - - matplotlib + - matplotlib=3.0.2 - numexpr - - numpy=1.14* + - numpy=1.15.* - openpyxl - parquet-cpp - pyarrow diff --git a/ci/deps/azure-windows-37.yaml b/ci/deps/azure-windows-37.yaml index 96ddc1d6293d8..5384e794d442a 100644 --- a/ci/deps/azure-windows-37.yaml +++ b/ci/deps/azure-windows-37.yaml @@ -9,7 +9,7 @@ dependencies: - html5lib - jinja2 - lxml - - matplotlib=3.0.1 + - matplotlib=2.2.* - numexpr - numpy=1.14.* - openpyxl diff --git a/ci/deps/travis-36.yaml b/ci/deps/travis-36-cov.yaml similarity index 92% rename from ci/deps/travis-36.yaml rename to ci/deps/travis-36-cov.yaml index 06fc0d76a3d16..95914568bea43 100644 --- a/ci/deps/travis-36.yaml +++ b/ci/deps/travis-36-cov.yaml @@ -14,14 +14,15 @@ dependencies: - matplotlib - nomkl - numexpr - - numpy + - numpy=1.15.* - openpyxl + - pandas-gbq - psycopg2 - pyarrow=0.9.0 - pymysql - pytables - python-snappy - - python=3.6.6 + - python=3.6.* - pytz - s3fs - scikit-learn diff --git a/ci/deps/travis-36-doc.yaml b/ci/deps/travis-36-doc.yaml index 8015f7bdc81c6..9d6cbd82fdc05 100644 --- a/ci/deps/travis-36-doc.yaml +++ b/ci/deps/travis-36-doc.yaml @@ -29,7 +29,7 @@ dependencies: - pytables - python-dateutil - python-snappy - - python=3.6* + - python=3.6.* - pytz - scipy - seaborn diff --git a/ci/deps/travis-36-locale.yaml b/ci/deps/travis-36-locale.yaml index fb0401958f05a..71022320da674 100644 --- a/ci/deps/travis-36-locale.yaml +++ b/ci/deps/travis-36-locale.yaml @@ -4,26 +4,33 @@ channels: - conda-forge dependencies: - beautifulsoup4 + - blosc=1.14.3 + - python-blosc - cython>=0.28.2 + - fastparquet=0.2.1 + - gcsfs=0.1.0 - html5lib - ipython - jinja2 - - lxml - - matplotlib + - lxml=3.7.0 + - matplotlib=3.0.0 - nomkl - numexpr - numpy - openpyxl - - psycopg2 + - pandas-gbq=0.8.0 + - psycopg2=2.6.2 - pymysql=0.7.9 - pytables - python-dateutil - - python=3.6* + # cannot go past python=3.6.6 for matplotlib=3.0.0 due to + # https://github.com/matplotlib/matplotlib/issues/12626 + - python=3.6.6 - pytz - - s3fs + - s3fs=0.0.8 - scipy - - sqlalchemy - - xarray + - sqlalchemy=1.1.4 + - xarray=0.8.2 - xlrd - xlsxwriter - xlwt diff --git a/ci/deps/travis-36-slow.yaml b/ci/deps/travis-36-slow.yaml index 46875d59411d9..365c78c02f4d4 100644 --- a/ci/deps/travis-36-slow.yaml +++ b/ci/deps/travis-36-slow.yaml @@ -16,7 +16,7 @@ dependencies: - pymysql - pytables - python-dateutil - - python=3.6* + - python=3.6.* - pytz - s3fs - scipy diff --git a/ci/deps/travis-37.yaml b/ci/deps/travis-37.yaml index f71d29fe13378..3ddd08e640806 100644 --- a/ci/deps/travis-37.yaml +++ b/ci/deps/travis-37.yaml @@ -4,7 +4,7 @@ channels: - conda-forge - c3i_test dependencies: - - python=3.7 + - python=3.7.* - botocore>=1.11 - cython>=0.28.2 - numpy diff --git a/doc/source/install.rst b/doc/source/install.rst index 5df633e8dd984..b3b5945cc515e 100644 --- a/doc/source/install.rst +++ b/doc/source/install.rst @@ -224,7 +224,7 @@ Dependencies ------------ * `setuptools `__: 24.2.0 or higher -* `NumPy `__: 1.12.0 or higher +* `NumPy `__: 1.13.3 or higher * `python-dateutil `__: 2.5.0 or higher * `pytz `__: 2015.4 or higher @@ -235,11 +235,11 @@ Recommended Dependencies * `numexpr `__: for accelerating certain numerical operations. ``numexpr`` uses multiple cores as well as smart chunking and caching to achieve large speedups. - If installed, must be Version 2.6.1 or higher. + If installed, must be Version 2.6.2 or higher. * `bottleneck `__: for accelerating certain types of ``nan`` evaluations. ``bottleneck`` uses specialized cython routines to achieve large speedups. If installed, - must be Version 1.2.0 or higher. + must be Version 1.2.1 or higher. .. note:: @@ -254,27 +254,27 @@ Optional Dependencies * `Cython `__: Only necessary to build development version. Version 0.28.2 or higher. -* `SciPy `__: miscellaneous statistical functions, Version 0.18.1 or higher -* `xarray `__: pandas like handling for > 2 dims. Version 0.7.0 or higher is recommended. +* `SciPy `__: miscellaneous statistical functions, Version 0.19.0 or higher +* `xarray `__: pandas like handling for > 2 dims. Version 0.8.2 or higher is recommended. * `PyTables `__: necessary for HDF5-based storage, Version 3.4.2 or higher * `pyarrow `__ (>= 0.9.0): necessary for feather-based storage. -* `Apache Parquet `__, either `pyarrow `__ (>= 0.7.0) or `fastparquet `__ (>= 0.2.1) for parquet-based storage. The `snappy `__ and `brotli `__ are available for compression support. +* `Apache Parquet `__, either `pyarrow `__ (>= 0.9.0) or `fastparquet `__ (>= 0.2.1) for parquet-based storage. The `snappy `__ and `brotli `__ are available for compression support. * `SQLAlchemy `__: for SQL database support. Version 1.1.4 or higher recommended. Besides SQLAlchemy, you also need a database specific driver. You can find an overview of supported drivers for each SQL dialect in the `SQLAlchemy docs `__. Some common drivers are: * `psycopg2 `__: for PostgreSQL * `pymysql `__: for MySQL. * `SQLite `__: for SQLite, this is included in Python's standard library by default. -* `matplotlib `__: for plotting, Version 2.0.0 or higher. +* `matplotlib `__: for plotting, Version 2.2.2 or higher. * For Excel I/O: * `xlrd/xlwt `__: Excel reading (xlrd), version 1.0.0 or higher required, and writing (xlwt) * `openpyxl `__: openpyxl version 2.4.0 - for writing .xlsx files (xlrd >= 0.9.0) + for writing .xlsx files (xlrd >= 1.0.0) * `XlsxWriter `__: Alternative Excel writer * `Jinja2 `__: Template engine for conditional HTML formatting. -* `s3fs `__: necessary for Amazon S3 access (s3fs >= 0.0.7). +* `s3fs `__: necessary for Amazon S3 access (s3fs >= 0.0.8). * `blosc `__: for msgpack compression using ``blosc`` * `gcsfs `__: necessary for Google Cloud Storage access (gcsfs >= 0.1.0). * One of @@ -289,8 +289,6 @@ Optional Dependencies `__: for Google BigQuery I/O. (pandas-gbq >= 0.8.0) - -* `Backports.lzma `__: Only for Python 2, for writing to and/or reading from an xz compressed DataFrame in CSV; Python 3 support is built into the standard library. * One of the following combinations of libraries is needed to use the top-level :func:`~pandas.read_html` function: diff --git a/doc/source/whatsnew/v0.25.0.rst b/doc/source/whatsnew/v0.25.0.rst index 49b2349851479..c7554a70bea91 100644 --- a/doc/source/whatsnew/v0.25.0.rst +++ b/doc/source/whatsnew/v0.25.0.rst @@ -159,30 +159,54 @@ cause a ``SparseSeries`` or ``SparseDataFrame`` to be returned, as before. Increased minimum versions for dependencies ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Due to dropping support for Python 2.7, a number of optional dependencies have updated minimum versions. -Independently, some minimum supported versions of dependencies were updated (:issue:`23519`, :issue:`24942`). +Due to dropping support for Python 2.7, a number of optional dependencies have updated minimum versions (issue:`25725`, :issue:`24942`, :issue:`25752`). +Independently, some minimum supported versions of dependencies were updated (:issue:`23519`, :issue:`25554`). If installed, we now require: +-----------------+-----------------+----------+ | Package | Minimum Version | Required | +=================+=================+==========+ -| beautifulsoup4 | 4.4.1 | | +| numpy | 1.13.3 | X | +-----------------+-----------------+----------+ -| openpyxl | 2.4.0 | | +| pytz | 2015.4 | X | +-----------------+-----------------+----------+ -| pymysql | 0.7.9 | | +| bottleneck | 1.2.1 | | +-----------------+-----------------+----------+ -| pytz | 2015.4 | | -+-----------------+-----------------+----------+ -| sqlalchemy | 1.1.4 | | -+-----------------+-----------------+----------+ -| xlsxwriter | 0.7.7 | | -+-----------------+-----------------+----------+ -| xlwt | 1.0.0 | | +| numexpr | 2.6.2 | | +-----------------+-----------------+----------+ | pytest (dev) | 4.0.2 | | +-----------------+-----------------+----------+ +For `optional libraries `_ the general recommendation is to use the latest version. +The following table lists the lowest version per library that is currently being tested throughout the development of pandas. +Optional libraries below the lowest tested version may still work, but are not considered supported. + ++-----------------+-----------------+ +| Package | Minimum Version | ++=================+=================+ +| fastparquet | 0.2.1 | ++-----------------+-----------------+ +| matplotlib | 2.2.2 | ++-----------------+-----------------+ +| openpyxl | 2.4.0 | ++-----------------+-----------------+ +| pyarrow | 0.9.0 | ++-----------------+-----------------+ +| pytables | 3.4.2 | ++-----------------+-----------------+ +| scipy | 0.19.0 | ++-----------------+-----------------+ +| sqlalchemy | 1.1.4 | ++-----------------+-----------------+ +| xarray | 0.8.2 | ++-----------------+-----------------+ +| xlrd | 1.0.0 | ++-----------------+-----------------+ +| xlsxwriter | 0.7.7 | ++-----------------+-----------------+ +| xlwt | 1.0.0 | ++-----------------+-----------------+ + .. _whatsnew_0250.api.other: Other API Changes diff --git a/environment.yml b/environment.yml index 1d7c8b96216e3..a1042be48156c 100644 --- a/environment.yml +++ b/environment.yml @@ -31,14 +31,14 @@ dependencies: - blosc - botocore>=1.11 - boto3 - - bottleneck>=1.2.0 + - bottleneck>=1.2.1 - fastparquet>=0.2.1 - html5lib - ipython>=5.6.0 - ipykernel - jinja2 - lxml - - matplotlib>=2.0.0 + - matplotlib>=2.2.2 - nbsphinx - numexpr>=2.6.8 - openpyxl diff --git a/pandas/_libs/tslibs/timestamps.pyx b/pandas/_libs/tslibs/timestamps.pyx index c4d47a3c2384a..ae15fb36169be 100644 --- a/pandas/_libs/tslibs/timestamps.pyx +++ b/pandas/_libs/tslibs/timestamps.pyx @@ -129,18 +129,6 @@ class RoundTo(object): return 4 -cdef inline _npdivmod(x1, x2): - """implement divmod for numpy < 1.13""" - return np.floor_divide(x1, x2), np.remainder(x1, x2) - - -try: - from numpy import divmod as npdivmod -except ImportError: - # numpy < 1.13 - npdivmod = _npdivmod - - cdef inline _floor_int64(values, unit): return values - np.remainder(values, unit) @@ -183,7 +171,7 @@ def round_nsint64(values, mode, freq): # for odd unit there is no need of a tie break if unit % 2: return _rounddown_int64(values, unit) - quotient, remainder = npdivmod(values, unit) + quotient, remainder = np.divmod(values, unit) mask = np.logical_or( remainder > (unit // 2), np.logical_and(remainder == (unit // 2), quotient % 2) diff --git a/pandas/compat/numpy/__init__.py b/pandas/compat/numpy/__init__.py index 6e9f768d8bd68..aed8fd2710e6f 100644 --- a/pandas/compat/numpy/__init__.py +++ b/pandas/compat/numpy/__init__.py @@ -9,18 +9,17 @@ # numpy versioning _np_version = np.__version__ _nlv = LooseVersion(_np_version) -_np_version_under1p13 = _nlv < LooseVersion('1.13') _np_version_under1p14 = _nlv < LooseVersion('1.14') _np_version_under1p15 = _nlv < LooseVersion('1.15') _np_version_under1p16 = _nlv < LooseVersion('1.16') _np_version_under1p17 = _nlv < LooseVersion('1.17') -if _nlv < '1.12': +if _nlv < '1.13.3': raise ImportError('this version of pandas is incompatible with ' - 'numpy < 1.12.0\n' + 'numpy < 1.13.3\n' 'your numpy version is {0}.\n' - 'Please upgrade numpy to >= 1.12.0 to use ' + 'Please upgrade numpy to >= 1.13.3 to use ' 'this pandas version'.format(_np_version)) @@ -64,7 +63,6 @@ def np_array_datetime64_compat(arr, *args, **kwargs): __all__ = ['np', - '_np_version_under1p13', '_np_version_under1p14', '_np_version_under1p15', '_np_version_under1p16', diff --git a/pandas/core/arrays/categorical.py b/pandas/core/arrays/categorical.py index 75b64a06fe8e8..26f42cd13ffe1 100644 --- a/pandas/core/arrays/categorical.py +++ b/pandas/core/arrays/categorical.py @@ -101,13 +101,6 @@ def f(self, other): ret[na_mask] = False return ret - # Numpy < 1.13 may convert a scalar to a zerodim array during - # comparison operation when second arg has higher priority, e.g. - # - # cat[0] < cat - # - # With cat[0], for example, being ``np.int64(1)`` by the time it gets - # into this function would become ``np.array(1)``. if is_scalar(other): if other in self.categories: i = self.categories.get_loc(other) diff --git a/pandas/core/arrays/datetimes.py b/pandas/core/arrays/datetimes.py index 33e6674389e7c..8b14471521a69 100644 --- a/pandas/core/arrays/datetimes.py +++ b/pandas/core/arrays/datetimes.py @@ -197,9 +197,6 @@ def wrapper(self, other): result = com.values_from_object(result) - # Make sure to pass an array to result[...]; indexing with - # Series breaks with older version of numpy - o_mask = np.array(o_mask) if o_mask.any(): result[o_mask] = nat_result diff --git a/pandas/core/arrays/numpy_.py b/pandas/core/arrays/numpy_.py index 8e2ab586cacb6..0deefd2b10b6e 100644 --- a/pandas/core/arrays/numpy_.py +++ b/pandas/core/arrays/numpy_.py @@ -1,6 +1,7 @@ import numbers import numpy as np +from numpy.lib.mixins import NDArrayOperatorsMixin from pandas._libs import lib from pandas.compat.numpy import function as nv @@ -82,20 +83,6 @@ def itemsize(self): return self._dtype.itemsize -# TODO(NumPy1.13): remove this -# Compat for NumPy 1.12, which doesn't provide NDArrayOperatorsMixin -# or __array_ufunc__, so those operations won't be available to people -# on older NumPys. -# -# We would normally write this as bases=(...), then "class Foo(*bases): -# but Python2 doesn't allow unpacking tuples in the class statement. -# So, we fall back to "object", to avoid writing a metaclass. -try: - from numpy.lib.mixins import NDArrayOperatorsMixin -except ImportError: - NDArrayOperatorsMixin = object - - class PandasArray(ExtensionArray, ExtensionOpsMixin, NDArrayOperatorsMixin): """ A pandas ExtensionArray for NumPy data. @@ -111,10 +98,6 @@ class PandasArray(ExtensionArray, ExtensionOpsMixin, NDArrayOperatorsMixin): The NumPy ndarray to wrap. Must be 1-dimensional. copy : bool, default False Whether to copy `values`. - - Notes - ----- - Operations like ``+`` and applying ufuncs requires NumPy>=1.13. """ # If you're wondering why pd.Series(cls) doesn't put the array in an # ExtensionBlock, search for `ABCPandasArray`. We check for diff --git a/pandas/core/arrays/sparse.py b/pandas/core/arrays/sparse.py index 96c89981ff5e9..c414362041627 100644 --- a/pandas/core/arrays/sparse.py +++ b/pandas/core/arrays/sparse.py @@ -1846,9 +1846,7 @@ def make_sparse(arr, kind='block', fill_value=None, dtype=None, copy=False): if isna(fill_value): mask = notna(arr) else: - # For str arrays in NumPy 1.12.0, operator!= below isn't - # element-wise but just returns False if fill_value is not str, - # so cast to object comparison to be safe + # cast to object comparison to be safe if is_string_dtype(arr): arr = arr.astype(object) diff --git a/pandas/core/computation/check.py b/pandas/core/computation/check.py index da89bde56fe18..c9b68661fd596 100644 --- a/pandas/core/computation/check.py +++ b/pandas/core/computation/check.py @@ -2,7 +2,7 @@ import warnings _NUMEXPR_INSTALLED = False -_MIN_NUMEXPR_VERSION = "2.6.1" +_MIN_NUMEXPR_VERSION = "2.6.2" _NUMEXPR_VERSION = None try: diff --git a/pandas/core/groupby/generic.py b/pandas/core/groupby/generic.py index 0604689c6bb2b..3a676fc94dff8 100644 --- a/pandas/core/groupby/generic.py +++ b/pandas/core/groupby/generic.py @@ -17,7 +17,6 @@ from pandas._libs import Timestamp, lib import pandas.compat as compat from pandas.compat import lzip -from pandas.compat.numpy import _np_version_under1p13 from pandas.errors import AbstractMethodError from pandas.util._decorators import Appender, Substitution @@ -1218,7 +1217,7 @@ def count(self): mask = (ids != -1) & ~isna(val) ids = ensure_platform_int(ids) - minlength = ngroups or (None if _np_version_under1p13 else 0) + minlength = ngroups or 0 out = np.bincount(ids[mask], minlength=minlength) return Series(out, diff --git a/pandas/core/missing.py b/pandas/core/missing.py index 6a6ab78ae3554..f029cc75c350a 100644 --- a/pandas/core/missing.py +++ b/pandas/core/missing.py @@ -1,7 +1,6 @@ """ Routines for filling missing data. """ -from distutils.version import LooseVersion import operator import numpy as np @@ -347,17 +346,8 @@ def _from_derivatives(xi, yi, x, order=None, der=0, extrapolate=False): y : scalar or array_like The result, of length R or length M or M by R. """ - import scipy from scipy import interpolate - if LooseVersion(scipy.__version__) < LooseVersion('0.18.0'): - try: - method = interpolate.piecewise_polynomial_interpolate - return method(xi, yi.reshape(-1, 1), x, - orders=order, der=der) - except AttributeError: - pass - # return the method for compat with scipy version & backwards compat method = interpolate.BPoly.from_derivatives m = method(xi, yi.reshape(-1, 1), diff --git a/pandas/core/nanops.py b/pandas/core/nanops.py index 5e762325da192..cfc42d26c5471 100644 --- a/pandas/core/nanops.py +++ b/pandas/core/nanops.py @@ -23,7 +23,7 @@ import pandas.core.common as com _BOTTLENECK_INSTALLED = False -_MIN_BOTTLENECK_VERSION = '1.0.0' +_MIN_BOTTLENECK_VERSION = '1.2.1' try: import bottleneck as bn diff --git a/pandas/io/sql.py b/pandas/io/sql.py index 266535fb6fcbd..09bed9a534f19 100644 --- a/pandas/io/sql.py +++ b/pandas/io/sql.py @@ -45,24 +45,11 @@ def _is_sqlalchemy_connectable(con): try: import sqlalchemy _SQLALCHEMY_INSTALLED = True - - from distutils.version import LooseVersion - ver = sqlalchemy.__version__ - # For sqlalchemy versions < 0.8.2, the BIGINT type is recognized - # for a sqlite engine, which results in a warning when trying to - # read/write a DataFrame with int64 values. (GH7433) - if LooseVersion(ver) < LooseVersion('0.8.2'): - from sqlalchemy import BigInteger - from sqlalchemy.ext.compiler import compiles - - @compiles(BigInteger, 'sqlite') - def compile_big_int_sqlite(type_, compiler, **kw): - return 'INTEGER' except ImportError: _SQLALCHEMY_INSTALLED = False if _SQLALCHEMY_INSTALLED: - import sqlalchemy + import sqlalchemy # noqa: F811 return isinstance(con, sqlalchemy.engine.Connectable) else: return False diff --git a/pandas/plotting/_compat.py b/pandas/plotting/_compat.py index 5c5c4800eef62..67f3d983480f8 100644 --- a/pandas/plotting/_compat.py +++ b/pandas/plotting/_compat.py @@ -16,8 +16,5 @@ def inner(): return inner -_mpl_ge_2_0_1 = _mpl_version('2.0.1', operator.ge) -_mpl_ge_2_1_0 = _mpl_version('2.1.0', operator.ge) -_mpl_ge_2_2_0 = _mpl_version('2.2.0', operator.ge) -_mpl_ge_2_2_2 = _mpl_version('2.2.2', operator.ge) +_mpl_ge_2_2_3 = _mpl_version('2.2.3', operator.ge) _mpl_ge_3_0_0 = _mpl_version('3.0.0', operator.ge) diff --git a/pandas/plotting/_core.py b/pandas/plotting/_core.py index 59d3bb355c1d7..35948ce7c19c9 100644 --- a/pandas/plotting/_core.py +++ b/pandas/plotting/_core.py @@ -1,7 +1,6 @@ # being a bit too dynamic # pylint: disable=E1101 from collections import namedtuple -from distutils.version import LooseVersion import re import warnings @@ -1474,18 +1473,9 @@ def _get_ind(self, y): def _plot(cls, ax, y, style=None, bw_method=None, ind=None, column_num=None, stacking_id=None, **kwds): from scipy.stats import gaussian_kde - from scipy import __version__ as spv y = remove_na_arraylike(y) - - if LooseVersion(spv) >= '0.11.0': - gkde = gaussian_kde(y, bw_method=bw_method) - else: - gkde = gaussian_kde(y) - if bw_method is not None: - msg = ('bw_method was added in Scipy 0.11.0.' + - ' Scipy version in use is {spv}.'.format(spv=spv)) - warnings.warn(msg) + gkde = gaussian_kde(y, bw_method=bw_method) y = gkde.evaluate(ind) lines = MPLPlot._plot(ax, ind, y, style=style, **kwds) diff --git a/pandas/tests/arithmetic/test_numeric.py b/pandas/tests/arithmetic/test_numeric.py index d556101ac2ecb..0df6631a1e9d7 100644 --- a/pandas/tests/arithmetic/test_numeric.py +++ b/pandas/tests/arithmetic/test_numeric.py @@ -963,8 +963,7 @@ def test_binops(self): self.check_binop(ops, scalars, idxs) def test_binops_pow(self): - # later versions of numpy don't allow powers of negative integers - # so test separately + # numpy does not allow powers of negative integers so test separately # https://github.com/numpy/numpy/pull/8127 ops = [pow] scalars = [1, 2] diff --git a/pandas/tests/arrays/test_numpy.py b/pandas/tests/arrays/test_numpy.py index 9cf26dce15d0a..5e4f6e376c1d3 100644 --- a/pandas/tests/arrays/test_numpy.py +++ b/pandas/tests/arrays/test_numpy.py @@ -5,8 +5,6 @@ import numpy as np import pytest -import pandas.util._test_decorators as td - import pandas as pd from pandas.arrays import PandasArray from pandas.core.arrays.numpy_ import PandasDtype @@ -178,7 +176,7 @@ def test_validate_reduction_keyword_args(): # ---------------------------------------------------------------------------- # Ops -@td.skip_if_no("numpy", min_version="1.13.0") + def test_ufunc(): arr = PandasArray(np.array([-1.0, 0.0, 1.0])) result = np.abs(arr) @@ -193,7 +191,6 @@ def test_ufunc(): tm.assert_extension_array_equal(r2, e2) -@td.skip_if_no("numpy", min_version="1.13.0") def test_basic_binop(): # Just a basic smoke test. The EA interface tests exercise this # more thoroughly. diff --git a/pandas/tests/frame/test_missing.py b/pandas/tests/frame/test_missing.py index 2a940daa3a4eb..d097f5e37e6b0 100644 --- a/pandas/tests/frame/test_missing.py +++ b/pandas/tests/frame/test_missing.py @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- import datetime -from distutils.version import LooseVersion import dateutil import numpy as np @@ -16,13 +15,6 @@ import pandas.util.testing as tm from pandas.util.testing import assert_frame_equal, assert_series_equal -try: - import scipy - _is_scipy_ge_0190 = (LooseVersion(scipy.__version__) >= - LooseVersion('0.19.0')) -except ImportError: - _is_scipy_ge_0190 = False - def _skip_if_no_pchip(): try: @@ -716,14 +708,8 @@ def test_interp_various(self): result = df.interpolate(method='cubic') # GH #15662. - # new cubic and quadratic interpolation algorithms from scipy 0.19.0. - # previously `splmake` was used. See scipy/scipy#6710 - if _is_scipy_ge_0190: - expected.A.loc[3] = 2.81547781 - expected.A.loc[13] = 5.52964175 - else: - expected.A.loc[3] = 2.81621174 - expected.A.loc[13] = 5.64146581 + expected.A.loc[3] = 2.81547781 + expected.A.loc[13] = 5.52964175 assert_frame_equal(result, expected) result = df.interpolate(method='nearest') @@ -732,12 +718,8 @@ def test_interp_various(self): assert_frame_equal(result, expected, check_dtype=False) result = df.interpolate(method='quadratic') - if _is_scipy_ge_0190: - expected.A.loc[3] = 2.82150771 - expected.A.loc[13] = 6.12648668 - else: - expected.A.loc[3] = 2.82533638 - expected.A.loc[13] = 6.02817974 + expected.A.loc[3] = 2.82150771 + expected.A.loc[13] = 6.12648668 assert_frame_equal(result, expected) result = df.interpolate(method='slinear') @@ -769,14 +751,10 @@ def test_interp_alt_scipy(self): assert_frame_equal(result, expectedk) _skip_if_no_pchip() - import scipy + result = df.interpolate(method='pchip') expected.loc[2, 'A'] = 3 - - if LooseVersion(scipy.__version__) >= LooseVersion('0.17.0'): - expected.loc[5, 'A'] = 6.0 - else: - expected.loc[5, 'A'] = 6.125 + expected.loc[5, 'A'] = 6.0 assert_frame_equal(result, expected) diff --git a/pandas/tests/frame/test_rank.py b/pandas/tests/frame/test_rank.py index 6bb9dea15d1ce..3af625323118c 100644 --- a/pandas/tests/frame/test_rank.py +++ b/pandas/tests/frame/test_rank.py @@ -1,6 +1,5 @@ # -*- coding: utf-8 -*- from datetime import datetime, timedelta -from distutils.version import LooseVersion import numpy as np import pytest @@ -209,7 +208,6 @@ def test_rank_axis(self): def test_rank_methods_frame(self): pytest.importorskip('scipy.stats.special') rankdata = pytest.importorskip('scipy.stats.rankdata') - import scipy xs = np.random.randint(0, 21, (100, 26)) xs = (xs - 10.0) / 10.0 @@ -225,11 +223,8 @@ def test_rank_methods_frame(self): rankdata, ax, vals, m if m != 'first' else 'ordinal') sprank = sprank.astype(np.float64) - expected = DataFrame(sprank, columns=cols) - - if (LooseVersion(scipy.__version__) >= - LooseVersion('0.17.0')): - expected = expected.astype('float64') + expected = DataFrame(sprank, + columns=cols).astype('float64') tm.assert_frame_equal(result, expected) @pytest.mark.parametrize('dtype', ['O', 'f8', 'i8']) diff --git a/pandas/tests/plotting/common.py b/pandas/tests/plotting/common.py index 9067a724289fe..1eef226749383 100644 --- a/pandas/tests/plotting/common.py +++ b/pandas/tests/plotting/common.py @@ -6,7 +6,6 @@ import numpy as np from numpy import random -import pytest from pandas.compat import iteritems from pandas.util._decorators import cache_readonly @@ -28,23 +27,6 @@ """ -def _skip_if_no_scipy_gaussian_kde(): - try: - from scipy.stats import gaussian_kde # noqa - except ImportError: - pytest.skip("scipy version doesn't support gaussian_kde") - - -def _ok_for_gaussian_kde(kind): - if kind in ['kde', 'density']: - try: - from scipy.stats import gaussian_kde # noqa - except ImportError: - return False - - return True - - @td.skip_if_no_mpl class TestPlotBase(object): @@ -53,10 +35,7 @@ def setup_method(self, method): import matplotlib as mpl mpl.rcdefaults() - self.mpl_ge_2_0_1 = plotting._compat._mpl_ge_2_0_1() - self.mpl_ge_2_1_0 = plotting._compat._mpl_ge_2_1_0() - self.mpl_ge_2_2_0 = plotting._compat._mpl_ge_2_2_0() - self.mpl_ge_2_2_2 = plotting._compat._mpl_ge_2_2_2() + self.mpl_ge_2_2_3 = plotting._compat._mpl_ge_2_2_3() self.mpl_ge_3_0_0 = plotting._compat._mpl_ge_3_0_0() self.bp_n_objects = 7 @@ -470,8 +449,6 @@ def is_grid_on(): spndx = 1 for kind in kinds: - if not _ok_for_gaussian_kde(kind): - continue self.plt.subplot(1, 4 * len(kinds), spndx) spndx += 1 diff --git a/pandas/tests/plotting/test_datetimelike.py b/pandas/tests/plotting/test_datetimelike.py index 8d8330cf5b9a2..c451228b5b319 100644 --- a/pandas/tests/plotting/test_datetimelike.py +++ b/pandas/tests/plotting/test_datetimelike.py @@ -14,8 +14,7 @@ from pandas.core.indexes.period import Period, PeriodIndex, period_range from pandas.core.indexes.timedeltas import timedelta_range from pandas.core.resample import DatetimeIndex -from pandas.tests.plotting.common import ( - TestPlotBase, _skip_if_no_scipy_gaussian_kde) +from pandas.tests.plotting.common import TestPlotBase import pandas.util.testing as tm from pandas.util.testing import assert_series_equal, ensure_clean @@ -406,11 +405,9 @@ def test_get_finder(self): def test_finder_daily(self): day_lst = [10, 40, 252, 400, 950, 2750, 10000] - if (self.mpl_ge_3_0_0 or not self.mpl_ge_2_0_1 - or (self.mpl_ge_2_1_0 and not self.mpl_ge_2_2_2)): - # 2.0.0, 2.2.0 (exactly) or >= 3.0.0 + if self.mpl_ge_3_0_0 or not self.mpl_ge_2_2_3: xpl1 = xpl2 = [Period('1999-1-1', freq='B').ordinal] * len(day_lst) - else: # 2.0.1, 2.1.0, 2.2.2, 2.2.3 + else: # 2.2.3, 2.2.4 xpl1 = [7565, 7564, 7553, 7546, 7518, 7428, 7066] xpl2 = [7566, 7564, 7554, 7546, 7519, 7429, 7066] @@ -436,11 +433,9 @@ def test_finder_daily(self): def test_finder_quarterly(self): yrs = [3.5, 11] - if (self.mpl_ge_3_0_0 or not self.mpl_ge_2_0_1 - or (self.mpl_ge_2_1_0 and not self.mpl_ge_2_2_2)): - # 2.0.0, 2.2.0 (exactly) or >= 3.0.0 + if self.mpl_ge_3_0_0 or not self.mpl_ge_2_2_3: xpl1 = xpl2 = [Period('1988Q1').ordinal] * len(yrs) - else: # 2.0.1, 2.1.0, 2.2.2, 2.2.3 + else: # 2.2.3, 2.2.4 xpl1 = [68, 68] xpl2 = [72, 68] @@ -466,11 +461,9 @@ def test_finder_quarterly(self): def test_finder_monthly(self): yrs = [1.15, 2.5, 4, 11] - if (self.mpl_ge_3_0_0 or not self.mpl_ge_2_0_1 - or (self.mpl_ge_2_1_0 and not self.mpl_ge_2_2_2)): - # 2.0.0, 2.2.0 (exactly) or >= 3.0.0 + if self.mpl_ge_3_0_0 or not self.mpl_ge_2_2_3: xpl1 = xpl2 = [Period('Jan 1988').ordinal] * len(yrs) - else: # 2.0.1, 2.1.0, 2.2.2, 2.2.3 + else: # 2.2.3, 2.2.4 xpl1 = [216, 216, 204, 204] xpl2 = [216, 216, 216, 204] @@ -504,11 +497,9 @@ def test_finder_monthly_long(self): @pytest.mark.slow def test_finder_annual(self): - if (self.mpl_ge_3_0_0 or not self.mpl_ge_2_0_1 - or (self.mpl_ge_2_1_0 and not self.mpl_ge_2_2_2)): - # 2.0.0, 2.2.0 (exactly) or >= 3.0.0 + if self.mpl_ge_3_0_0 or not self.mpl_ge_2_2_3: xp = [1987, 1988, 1990, 1990, 1995, 2020, 2070, 2170] - else: # 2.0.1, 2.1.0, 2.2.2, 2.2.3 + else: # 2.2.3, 2.2.4 xp = [1986, 1986, 1990, 1990, 1995, 2020, 1970, 1970] xp = [Period(x, freq='A').ordinal for x in xp] @@ -545,10 +536,7 @@ def test_finder_hourly(self): ser.plot(ax=ax) xaxis = ax.get_xaxis() rs = xaxis.get_majorticklocs()[0] - if self.mpl_ge_2_0_1: - xp = Period('1/1/1999', freq='H').ordinal - else: # 2.0.0 - xp = Period('1998-12-31 22:00', freq='H').ordinal + xp = Period('1/1/1999', freq='H').ordinal assert rs == xp @@ -563,9 +551,7 @@ def test_gaps(self): line = lines[0] data = line.get_xydata() - if (self.mpl_ge_3_0_0 or not self.mpl_ge_2_0_1 - or (self.mpl_ge_2_1_0 and not self.mpl_ge_2_2_2)): - # 2.0.0, 2.2.0 (exactly) or >= 3.0.0 + if self.mpl_ge_3_0_0 or not self.mpl_ge_2_2_3: data = np.ma.MaskedArray(data, mask=isna(data), fill_value=np.nan) assert isinstance(data, np.ma.core.MaskedArray) @@ -584,9 +570,7 @@ def test_gaps(self): line = lines[0] data = line.get_xydata() - if (self.mpl_ge_3_0_0 or not self.mpl_ge_2_0_1 - or (self.mpl_ge_2_1_0 and not self.mpl_ge_2_2_2)): - # 2.0.0, 2.2.0 (exactly) or >= 3.0.0 + if self.mpl_ge_3_0_0 or not self.mpl_ge_2_2_3: data = np.ma.MaskedArray(data, mask=isna(data), fill_value=np.nan) assert isinstance(data, np.ma.core.MaskedArray) @@ -604,9 +588,7 @@ def test_gaps(self): assert len(lines) == 1 line = lines[0] data = line.get_xydata() - if (self.mpl_ge_3_0_0 or not self.mpl_ge_2_0_1 - or (self.mpl_ge_2_1_0 and not self.mpl_ge_2_2_2)): - # 2.0.0, 2.2.0 (exactly) or >= 3.0.0 + if self.mpl_ge_3_0_0 or not self.mpl_ge_2_2_3: data = np.ma.MaskedArray(data, mask=isna(data), fill_value=np.nan) assert isinstance(data, np.ma.core.MaskedArray) @@ -629,9 +611,7 @@ def test_gap_upsample(self): line = lines[0] data = line.get_xydata() - if (self.mpl_ge_3_0_0 or not self.mpl_ge_2_0_1 - or (self.mpl_ge_2_1_0 and not self.mpl_ge_2_2_2)): - # 2.0.0, 2.2.0 (exactly) or >= 3.0.0 + if self.mpl_ge_3_0_0 or not self.mpl_ge_2_2_3: data = np.ma.MaskedArray(data, mask=isna(data), fill_value=np.nan) assert isinstance(data, np.ma.core.MaskedArray) @@ -698,7 +678,6 @@ def test_secondary_y_ts(self): @pytest.mark.slow @td.skip_if_no_scipy def test_secondary_kde(self): - _skip_if_no_scipy_gaussian_kde() ser = Series(np.random.randn(10)) fig, ax = self.plt.subplots() @@ -1422,13 +1401,8 @@ def test_plot_outofbounds_datetime(self): def test_format_timedelta_ticks_narrow(self): - if self.mpl_ge_2_0_1: - expected_labels = (['00:00:00.0000000{:0>2d}'.format(i) - for i in range(10)]) - else: # 2.0.0 - expected_labels = [''] + [ - '00:00:00.00000000{:d}'.format(2 * i) - for i in range(5)] + [''] + expected_labels = (['00:00:00.0000000{:0>2d}'.format(i) + for i in range(10)]) rng = timedelta_range('0', periods=10, freq='ns') df = DataFrame(np.random.randn(len(rng), 3), rng) @@ -1443,7 +1417,6 @@ def test_format_timedelta_ticks_narrow(self): def test_format_timedelta_ticks_wide(self): expected_labels = [ - '', '00:00:00', '1 days 03:46:40', '2 days 07:33:20', @@ -1453,13 +1426,7 @@ def test_format_timedelta_ticks_wide(self): '6 days 22:40:00', '8 days 02:26:40', '9 days 06:13:20', - '' ] - if self.mpl_ge_2_2_0: - expected_labels = expected_labels[1:-1] - elif self.mpl_ge_2_0_1: - expected_labels = expected_labels[1:-1] - expected_labels[-1] = '' rng = timedelta_range('0', periods=10, freq='1 d') df = DataFrame(np.random.randn(len(rng), 3), rng) diff --git a/pandas/tests/plotting/test_frame.py b/pandas/tests/plotting/test_frame.py index 4c22c3245b788..292c6ea910788 100644 --- a/pandas/tests/plotting/test_frame.py +++ b/pandas/tests/plotting/test_frame.py @@ -19,9 +19,7 @@ from pandas import ( DataFrame, MultiIndex, PeriodIndex, Series, bdate_range, date_range) from pandas.core.arrays import integer_array -from pandas.tests.plotting.common import ( - TestPlotBase, _check_plot_works, _ok_for_gaussian_kde, - _skip_if_no_scipy_gaussian_kde) +from pandas.tests.plotting.common import TestPlotBase, _check_plot_works import pandas.util.testing as tm from pandas.io.formats.printing import pprint_thing @@ -1514,8 +1512,6 @@ def test_boxplot_subplots_return_type(self): @pytest.mark.slow @td.skip_if_no_scipy def test_kde_df(self): - _skip_if_no_scipy_gaussian_kde() - df = DataFrame(randn(100, 4)) ax = _check_plot_works(df.plot, kind='kde') expected = [pprint_thing(c) for c in df.columns] @@ -1536,8 +1532,6 @@ def test_kde_df(self): @pytest.mark.slow @td.skip_if_no_scipy def test_kde_missing_vals(self): - _skip_if_no_scipy_gaussian_kde() - df = DataFrame(np.random.uniform(size=(100, 4))) df.loc[0, 0] = np.nan _check_plot_works(df.plot, kind='kde') @@ -1563,11 +1557,7 @@ def test_hist_df(self): self._check_ticks_props(axes, xrot=40, yrot=0) tm.close() - if plotting._compat._mpl_ge_2_2_0(): - kwargs = {"density": True} - else: - kwargs = {"normed": True} - ax = series.plot.hist(cumulative=True, bins=4, **kwargs) + ax = series.plot.hist(cumulative=True, bins=4, density=True) # height of last bin (index 5) must be 1.0 rects = [x for x in ax.get_children() if isinstance(x, Rectangle)] tm.assert_almost_equal(rects[-1].get_height(), 1.0) @@ -1707,8 +1697,6 @@ def test_df_legend_labels(self): df4 = DataFrame(rand(3, 3), columns=['j', 'k', 'l']) for kind in kinds: - if not _ok_for_gaussian_kde(kind): - continue ax = df.plot(kind=kind, legend=True) self._check_legend_labels(ax, labels=df.columns) @@ -1797,8 +1785,6 @@ def test_no_legend(self): df = DataFrame(rand(3, 3), columns=['a', 'b', 'c']) for kind in kinds: - if not _ok_for_gaussian_kde(kind): - continue ax = df.plot(kind=kind, legend=False) self._check_legend_labels(ax, visible=False) @@ -2044,8 +2030,6 @@ def test_hist_colors(self): @pytest.mark.slow @td.skip_if_no_scipy def test_kde_colors(self): - _skip_if_no_scipy_gaussian_kde() - from matplotlib import cm custom_colors = 'rgcby' @@ -2067,8 +2051,6 @@ def test_kde_colors(self): @pytest.mark.slow @td.skip_if_no_scipy def test_kde_colors_and_styles_subplots(self): - _skip_if_no_scipy_gaussian_kde() - from matplotlib import cm default_colors = self._unpack_cycler(self.plt.rcParams) @@ -2212,11 +2194,11 @@ def test_unordered_ts(self): ydata = ax.lines[0].get_ydata() tm.assert_numpy_array_equal(ydata, np.array([1.0, 2.0, 3.0])) + @td.skip_if_no_scipy def test_kind_both_ways(self): df = DataFrame({'x': [1, 2, 3]}) for kind in plotting._core._common_kinds: - if not _ok_for_gaussian_kde(kind): - continue + df.plot(kind=kind) getattr(df.plot, kind)() for kind in ['scatter', 'hexbin']: @@ -2226,8 +2208,6 @@ def test_kind_both_ways(self): def test_all_invalid_plot_data(self): df = DataFrame(list('abcd')) for kind in plotting._core._common_kinds: - if not _ok_for_gaussian_kde(kind): - continue msg = "no numeric data to plot" with pytest.raises(TypeError, match=msg): @@ -2239,8 +2219,6 @@ def test_partially_invalid_plot_data(self): df = DataFrame(randn(10, 2), dtype=object) df[np.random.rand(df.shape[0]) > 0.5] = 'a' for kind in plotting._core._common_kinds: - if not _ok_for_gaussian_kde(kind): - continue msg = "no numeric data to plot" with pytest.raises(TypeError, match=msg): @@ -2569,8 +2547,6 @@ def test_errorbar_asymmetrical(self): tm.close() - # This XPASSES when tested with mpl == 3.0.1 - @td.xfail_if_mpl_2_2 def test_table(self): df = DataFrame(np.random.rand(10, 3), index=list(string.ascii_letters[:10])) @@ -2727,6 +2703,7 @@ def _check(axes): self._check_visible(ax.get_xticklabels(), visible=True) self._check_visible(ax.get_xticklabels(minor=True), visible=True) + @td.skip_if_no_scipy def test_memory_leak(self): """ Check that every plot type gets properly collected. """ import weakref @@ -2734,8 +2711,7 @@ def test_memory_leak(self): results = {} for kind in plotting._core._plot_klass.keys(): - if not _ok_for_gaussian_kde(kind): - continue + args = {} if kind in ['hexbin', 'scatter', 'pie']: df = self.hexbin_df diff --git a/pandas/tests/plotting/test_hist_method.py b/pandas/tests/plotting/test_hist_method.py index 4f0bef52b5e15..c62ed21c2fb17 100644 --- a/pandas/tests/plotting/test_hist_method.py +++ b/pandas/tests/plotting/test_hist_method.py @@ -12,7 +12,6 @@ from pandas.tests.plotting.common import TestPlotBase, _check_plot_works import pandas.util.testing as tm -from pandas.plotting._compat import _mpl_ge_2_2_0 from pandas.plotting._core import grouped_hist @@ -193,12 +192,8 @@ def test_hist_df_legacy(self): ylabelsize=yf, yrot=yrot) tm.close() - # make sure kwargs to hist are handled - if _mpl_ge_2_2_0(): - kwargs = {"density": True} - else: - kwargs = {"normed": True} - ax = ser.hist(cumulative=True, bins=4, **kwargs) + + ax = ser.hist(cumulative=True, bins=4, density=True) # height of last bin (index 5) must be 1.0 rects = [x for x in ax.get_children() if isinstance(x, Rectangle)] tm.assert_almost_equal(rects[-1].get_height(), 1.0) @@ -248,12 +243,11 @@ def test_hist_layout(self): @pytest.mark.slow # GH 9351 def test_tight_layout(self): - if self.mpl_ge_2_0_1: - df = DataFrame(randn(100, 3)) - _check_plot_works(df.hist) - self.plt.tight_layout() + df = DataFrame(randn(100, 3)) + _check_plot_works(df.hist) + self.plt.tight_layout() - tm.close() + tm.close() @td.skip_if_no_mpl @@ -285,14 +279,9 @@ def test_grouped_hist_legacy(self): xf, yf = 20, 18 xrot, yrot = 30, 40 - if _mpl_ge_2_2_0(): - kwargs = {"density": True} - else: - kwargs = {"normed": True} - axes = grouped_hist(df.A, by=df.C, cumulative=True, bins=4, xlabelsize=xf, xrot=xrot, - ylabelsize=yf, yrot=yrot, **kwargs) + ylabelsize=yf, yrot=yrot, density=True) # height of last bin (index 5) must be 1.0 for ax in axes.ravel(): rects = [x for x in ax.get_children() if isinstance(x, Rectangle)] diff --git a/pandas/tests/plotting/test_misc.py b/pandas/tests/plotting/test_misc.py index 98248586f3d27..a184c024f4459 100644 --- a/pandas/tests/plotting/test_misc.py +++ b/pandas/tests/plotting/test_misc.py @@ -61,8 +61,6 @@ def test_bootstrap_plot(self): @td.skip_if_no_mpl class TestDataFramePlots(TestPlotBase): - # This XPASSES when tested with mpl == 3.0.1 - @td.xfail_if_mpl_2_2 @td.skip_if_no_scipy def test_scatter_matrix_axis(self): scatter_matrix = plotting.scatter_matrix diff --git a/pandas/tests/plotting/test_series.py b/pandas/tests/plotting/test_series.py index e384c578aa446..a2250a8942e22 100644 --- a/pandas/tests/plotting/test_series.py +++ b/pandas/tests/plotting/test_series.py @@ -15,9 +15,7 @@ import pandas as pd from pandas import DataFrame, Series, date_range -from pandas.tests.plotting.common import ( - TestPlotBase, _check_plot_works, _ok_for_gaussian_kde, - _skip_if_no_scipy_gaussian_kde) +from pandas.tests.plotting.common import TestPlotBase, _check_plot_works import pandas.util.testing as tm import pandas.plotting as plotting @@ -61,8 +59,6 @@ def test_plot(self): _check_plot_works(self.iseries.plot) for kind in ['line', 'bar', 'barh', 'kde', 'hist', 'box']: - if not _ok_for_gaussian_kde(kind): - continue _check_plot_works(self.series[:5].plot, kind=kind) _check_plot_works(self.series[:10].plot.barh) @@ -602,7 +598,6 @@ def test_hist_kde(self): ylabels = ax.get_yticklabels() self._check_text_labels(ylabels, [''] * len(ylabels)) - _skip_if_no_scipy_gaussian_kde() _check_plot_works(self.ts.plot.kde) _check_plot_works(self.ts.plot.density) _, ax = self.plt.subplots() @@ -616,8 +611,6 @@ def test_hist_kde(self): @pytest.mark.slow @td.skip_if_no_scipy def test_kde_kwargs(self): - _skip_if_no_scipy_gaussian_kde() - sample_points = np.linspace(-100, 100, 20) _check_plot_works(self.ts.plot.kde, bw_method='scott', ind=20) _check_plot_works(self.ts.plot.kde, bw_method=None, ind=20) @@ -634,8 +627,6 @@ def test_kde_kwargs(self): @pytest.mark.slow @td.skip_if_no_scipy def test_kde_missing_vals(self): - _skip_if_no_scipy_gaussian_kde() - s = Series(np.random.uniform(size=50)) s[0] = np.nan axes = _check_plot_works(s.plot.kde) @@ -669,7 +660,6 @@ def test_hist_kde_color(self): assert len(ax.patches) == 10 self._check_colors(ax.patches, facecolors=['b'] * 10) - _skip_if_no_scipy_gaussian_kde() _, ax = self.plt.subplots() ax = self.ts.plot.kde(logy=True, color='r', ax=ax) self._check_ax_scales(ax, yaxis='log') @@ -694,8 +684,7 @@ def test_kind_both_ways(self): plotting._core._series_kinds) _, ax = self.plt.subplots() for kind in kinds: - if not _ok_for_gaussian_kde(kind): - continue + s.plot(kind=kind, ax=ax) getattr(s.plot, kind)() @@ -704,8 +693,6 @@ def test_invalid_plot_data(self): s = Series(list('abcd')) _, ax = self.plt.subplots() for kind in plotting._core._common_kinds: - if not _ok_for_gaussian_kde(kind): - continue msg = "no numeric data to plot" with pytest.raises(TypeError, match=msg): @@ -715,16 +702,12 @@ def test_invalid_plot_data(self): def test_valid_object_plot(self): s = Series(lrange(10), dtype=object) for kind in plotting._core._common_kinds: - if not _ok_for_gaussian_kde(kind): - continue _check_plot_works(s.plot, kind=kind) def test_partially_invalid_plot_data(self): s = Series(['a', 'b', 1.0, 2]) _, ax = self.plt.subplots() for kind in plotting._core._common_kinds: - if not _ok_for_gaussian_kde(kind): - continue msg = "no numeric data to plot" with pytest.raises(TypeError, match=msg): @@ -783,12 +766,9 @@ def test_errorbar_plot(self): s.plot(yerr=np.arange(11)) s_err = ['zzz'] * 10 - # MPL > 2.0.0 will most likely use TypeError here - with pytest.raises((TypeError, ValueError)): + with pytest.raises(TypeError): s.plot(yerr=s_err) - # This XPASSES when tested with mpl == 3.0.1 - @td.xfail_if_mpl_2_2 def test_table(self): _check_plot_works(self.series.plot, table=True) _check_plot_works(self.series.plot, table=self.series) diff --git a/pandas/tests/series/test_analytics.py b/pandas/tests/series/test_analytics.py index 919f942bfa437..9e44cc32f8f45 100644 --- a/pandas/tests/series/test_analytics.py +++ b/pandas/tests/series/test_analytics.py @@ -1,7 +1,6 @@ # coding=utf-8 # pylint: disable-msg=E1101,W0612 -from distutils.version import LooseVersion from itertools import product import operator @@ -343,7 +342,6 @@ def test_corr(self, datetime_series): @td.skip_if_no_scipy def test_corr_rank(self): - import scipy import scipy.stats as stats # kendall and spearman @@ -358,11 +356,6 @@ def test_corr_rank(self): expected = stats.spearmanr(A, B)[0] tm.assert_almost_equal(result, expected) - # these methods got rewritten in 0.8 - if LooseVersion(scipy.__version__) < LooseVersion('0.9'): - pytest.skip("skipping corr rank because of scipy version " - "{0}".format(scipy.__version__)) - # results from R A = Series( [-0.89926396, 0.94209606, -1.03289164, -0.95445587, 0.76910310, - diff --git a/pandas/tests/series/test_missing.py b/pandas/tests/series/test_missing.py index 403fdb383d81a..7b1df6917e77c 100644 --- a/pandas/tests/series/test_missing.py +++ b/pandas/tests/series/test_missing.py @@ -2,7 +2,6 @@ # pylint: disable-msg=E1101,W0612 from datetime import datetime, timedelta -from distutils.version import LooseVersion import numpy as np from numpy import nan @@ -21,13 +20,6 @@ import pandas.util.testing as tm from pandas.util.testing import assert_frame_equal, assert_series_equal -try: - import scipy - _is_scipy_ge_0190 = (LooseVersion(scipy.__version__) >= - LooseVersion('0.19.0')) -except ImportError: - _is_scipy_ge_0190 = False - def _skip_if_no_pchip(): try: @@ -1069,12 +1061,7 @@ def test_interp_scipy_basic(self): assert_series_equal(result, expected) # quadratic # GH #15662. - # new cubic and quadratic interpolation algorithms from scipy 0.19.0. - # previously `splmake` was used. See scipy/scipy#6710 - if _is_scipy_ge_0190: - expected = Series([1, 3., 6.823529, 12., 18.058824, 25.]) - else: - expected = Series([1, 3., 6.769231, 12., 18.230769, 25.]) + expected = Series([1, 3., 6.823529, 12., 18.058824, 25.]) result = s.interpolate(method='quadratic') assert_series_equal(result, expected) @@ -1342,7 +1329,7 @@ def test_spline(self): expected = Series([1., 2., 3., 4., 5., 6., 7.]) assert_series_equal(result, expected) - @td.skip_if_no('scipy', min_version='0.15') + @td.skip_if_no_scipy def test_spline_extrapolate(self): s = Series([1, 2, 3, 4, np.nan, 6, np.nan]) result3 = s.interpolate(method='spline', order=1, ext=3) diff --git a/pandas/tests/series/test_rank.py b/pandas/tests/series/test_rank.py index c6a149bc0c296..31885077f53c1 100644 --- a/pandas/tests/series/test_rank.py +++ b/pandas/tests/series/test_rank.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- -from distutils.version import LooseVersion from itertools import chain import numpy as np @@ -321,7 +320,6 @@ def test_rank_desc_mix_nans_infs(self): def test_rank_methods_series(self): pytest.importorskip('scipy.stats.special') rankdata = pytest.importorskip('scipy.stats.rankdata') - import scipy xs = np.random.randn(9) xs = np.concatenate([xs[i:] for i in range(0, 9, 2)]) # add duplicates @@ -335,10 +333,7 @@ def test_rank_methods_series(self): for m in ['average', 'min', 'max', 'first', 'dense']: result = ts.rank(method=m) sprank = rankdata(vals, m if m != 'first' else 'ordinal') - expected = Series(sprank, index=index) - - if LooseVersion(scipy.__version__) >= LooseVersion('0.17.0'): - expected = expected.astype('float64') + expected = Series(sprank, index=index).astype('float64') tm.assert_series_equal(result, expected) def test_rank_dense_method(self): diff --git a/pandas/tests/sparse/frame/test_to_from_scipy.py b/pandas/tests/sparse/frame/test_to_from_scipy.py index bdb2cd022b451..a80a51a66017e 100644 --- a/pandas/tests/sparse/frame/test_to_from_scipy.py +++ b/pandas/tests/sparse/frame/test_to_from_scipy.py @@ -1,5 +1,3 @@ -from distutils.version import LooseVersion - import numpy as np import pytest @@ -77,9 +75,8 @@ def test_from_to_scipy_object(spmatrix, fill_value): columns = list('cd') index = list('ab') - if (spmatrix is scipy.sparse.dok_matrix and LooseVersion( - scipy.__version__) >= LooseVersion('0.19.0')): - pytest.skip("dok_matrix from object does not work in SciPy >= 0.19") + if spmatrix is scipy.sparse.dok_matrix: + pytest.skip("dok_matrix from object does not work in SciPy") # Make one ndarray and from it one sparse matrix, both to be used for # constructing frames and comparing results diff --git a/pandas/tests/test_algos.py b/pandas/tests/test_algos.py index b8226bc2f8269..b64786de264cd 100644 --- a/pandas/tests/test_algos.py +++ b/pandas/tests/test_algos.py @@ -228,9 +228,9 @@ 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\(\)") + msg = ("unorderable types: .* [<>] .*" + "|" # the above case happens for numpy < 1.14 + "'[<>]' not supported between instances of .*") with pytest.raises(TypeError, match=msg): algos.factorize(x17[::-1], sort=True) diff --git a/pandas/tests/test_expressions.py b/pandas/tests/test_expressions.py index 62962f20b0786..53d62a492794e 100644 --- a/pandas/tests/test_expressions.py +++ b/pandas/tests/test_expressions.py @@ -6,7 +6,6 @@ from numpy.random import randn import pytest -from pandas import _np_version_under1p13 from pandas.core.api import DataFrame from pandas.core.computation import expressions as expr import pandas.util.testing as tm @@ -357,8 +356,8 @@ def test_bool_ops_warn_on_arithmetic(self): f = getattr(operator, name) fe = getattr(operator, sub_funcs[subs[op]]) - # >= 1.13.0 these are now TypeErrors - if op == '-' and not _np_version_under1p13: + if op == '-': + # raises TypeError continue with tm.use_numexpr(True, min_elements=5): diff --git a/pandas/tests/test_nanops.py b/pandas/tests/test_nanops.py index 21aee7eeaa0f4..5a163e7819fd1 100644 --- a/pandas/tests/test_nanops.py +++ b/pandas/tests/test_nanops.py @@ -5,7 +5,6 @@ import numpy as np import pytest -from pandas.compat.numpy import _np_version_under1p13 import pandas.util._test_decorators as td from pandas.core.dtypes.common import is_integer_dtype @@ -345,7 +344,7 @@ def test_nanstd(self, ddof): allow_str=False, allow_date=False, allow_tdelta=True, allow_obj='convert', ddof=ddof) - @td.skip_if_no('scipy', min_version='0.17.0') + @td.skip_if_no_scipy @pytest.mark.parametrize('ddof', range(3)) def test_nansem(self, ddof): from scipy.stats import sem @@ -414,7 +413,7 @@ def _skew_kurt_wrap(self, values, axis=None, func=None): return 0. return result - @td.skip_if_no('scipy', min_version='0.17.0') + @td.skip_if_no_scipy def test_nanskew(self): from scipy.stats import skew func = partial(self._skew_kurt_wrap, func=skew) @@ -423,7 +422,7 @@ def test_nanskew(self): allow_str=False, allow_date=False, allow_tdelta=False) - @td.skip_if_no('scipy', min_version='0.17.0') + @td.skip_if_no_scipy def test_nankurt(self): from scipy.stats import kurtosis func1 = partial(kurtosis, fisher=True) @@ -1017,6 +1016,8 @@ def test_use_bottleneck(): (np.nanmedian, 2.5), (np.min, 1), (np.max, 4), + (np.nanmin, 1), + (np.nanmax, 4) ]) def test_numpy_ops(numpy_op, expected): # GH8383 @@ -1024,21 +1025,6 @@ def test_numpy_ops(numpy_op, expected): assert result == expected -@pytest.mark.parametrize("numpy_op, expected", [ - (np.nanmin, 1), - (np.nanmax, 4), -]) -def test_numpy_ops_np_version_under1p13(numpy_op, expected): - # GH8383 - result = numpy_op(pd.Series([1, 2, 3, 4])) - if _np_version_under1p13: - # bug for numpy < 1.13, where result is a series, should be a scalar - with pytest.raises(ValueError): - assert result == expected - else: - assert result == expected - - @pytest.mark.parametrize("operation", [ nanops.nanany, nanops.nanall, diff --git a/pandas/tests/test_sorting.py b/pandas/tests/test_sorting.py index c753b5531fde7..04a50cf6facd5 100644 --- a/pandas/tests/test_sorting.py +++ b/pandas/tests/test_sorting.py @@ -413,10 +413,9 @@ def test_mixed_integer_from_list(self): 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 = ("unorderable types: .* [<>] .*" + "|" # the above case happens for numpy < 1.14 + "'[<>]' not supported between instances of .*") with pytest.raises(TypeError, match=msg): safe_sort(arr) diff --git a/pandas/util/_test_decorators.py b/pandas/util/_test_decorators.py index c0a972388d886..7266833f8bbde 100644 --- a/pandas/util/_test_decorators.py +++ b/pandas/util/_test_decorators.py @@ -23,7 +23,6 @@ def test_foo(): For more information, refer to the ``pytest`` documentation on ``skipif``. """ -from distutils.version import LooseVersion import locale import pytest @@ -79,17 +78,6 @@ def _skip_if_no_mpl(): return True -def _skip_if_mpl_2_2(): - mod = safe_import("matplotlib") - - if mod: - v = mod.__version__ - if LooseVersion(v) > LooseVersion('2.1.2'): - return True - else: - mod.use("Agg", warn=False) - - def _skip_if_has_locale(): lang, _ = locale.getlocale() if lang is not None: @@ -149,9 +137,6 @@ def decorated_func(func): reason="NumPy 1.15 or greater required") skip_if_mpl = pytest.mark.skipif(not _skip_if_no_mpl(), reason="matplotlib is present") -xfail_if_mpl_2_2 = pytest.mark.xfail(_skip_if_mpl_2_2(), - reason="matplotlib 2.2", - strict=False) skip_if_32bit = pytest.mark.skipif(is_platform_32bit(), reason="skipping for 32 bit") skip_if_windows = pytest.mark.skipif(is_platform_windows(), diff --git a/requirements-dev.txt b/requirements-dev.txt index e3034cb99ee80..173441489b388 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -20,14 +20,14 @@ beautifulsoup4>=4.2.1 blosc botocore>=1.11 boto3 -bottleneck>=1.2.0 +bottleneck>=1.2.1 fastparquet>=0.2.1 html5lib ipython>=5.6.0 ipykernel jinja2 lxml -matplotlib>=2.0.0 +matplotlib>=2.2.2 nbsphinx numexpr>=2.6.8 openpyxl diff --git a/setup.py b/setup.py index e5ef0d7bd3aea..1dca7fa77219f 100755 --- a/setup.py +++ b/setup.py @@ -30,7 +30,7 @@ def is_platform_mac(): return sys.platform == 'darwin' -min_numpy_ver = '1.12.0' +min_numpy_ver = '1.13.3' setuptools_kwargs = { 'install_requires': [ 'python-dateutil >= 2.5.0',