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',