From 371a257de6e484a97859573a01d46506f17f6b38 Mon Sep 17 00:00:00 2001 From: Jeff Reback Date: Wed, 8 Nov 2017 16:48:29 -0500 Subject: [PATCH 1/7] BLD: require python-dateutil>=2.5.0 --- ci/requirements-2.7.build | 2 +- ci/requirements-2.7.run | 2 +- ci/requirements-2.7_COMPAT.build | 2 +- ci/requirements-2.7_COMPAT.run | 2 +- conda.recipe/meta.yaml | 2 +- doc/source/install.rst | 2 +- doc/source/whatsnew/v0.22.0.txt | 14 +++++++++++++- pandas/compat/__init__.py | 20 ++++---------------- pandas/tests/indexes/datetimes/test_tools.py | 4 ++-- pandas/tests/scalar/test_timestamp.py | 10 ++++------ 10 files changed, 29 insertions(+), 31 deletions(-) diff --git a/ci/requirements-2.7.build b/ci/requirements-2.7.build index 415df13179fcf..d1cc61df0a77c 100644 --- a/ci/requirements-2.7.build +++ b/ci/requirements-2.7.build @@ -1,5 +1,5 @@ python=2.7* -python-dateutil=2.4.1 +python-dateutil=2.5.0 pytz=2013b nomkl numpy diff --git a/ci/requirements-2.7.run b/ci/requirements-2.7.run index a68e1d256058d..3a1e91e4246b5 100644 --- a/ci/requirements-2.7.run +++ b/ci/requirements-2.7.run @@ -1,4 +1,4 @@ -python-dateutil=2.4.1 +python-dateutil=2.5.0 pytz=2013b numpy xlwt=0.7.5 diff --git a/ci/requirements-2.7_COMPAT.build b/ci/requirements-2.7_COMPAT.build index d9c932daa110b..aa767c1001196 100644 --- a/ci/requirements-2.7_COMPAT.build +++ b/ci/requirements-2.7_COMPAT.build @@ -1,5 +1,5 @@ python=2.7* numpy=1.9.2 cython=0.23 -dateutil=1.5 +python-dateutil=2.5.0 pytz=2013b diff --git a/ci/requirements-2.7_COMPAT.run b/ci/requirements-2.7_COMPAT.run index 39bf720140733..c3daed6e6e1da 100644 --- a/ci/requirements-2.7_COMPAT.run +++ b/ci/requirements-2.7_COMPAT.run @@ -1,5 +1,5 @@ numpy=1.9.2 -dateutil=1.5 +python-dateutil=2.5.0 pytz=2013b scipy=0.14.0 xlwt=0.7.5 diff --git a/conda.recipe/meta.yaml b/conda.recipe/meta.yaml index 2aee11772896f..584f23e22a146 100644 --- a/conda.recipe/meta.yaml +++ b/conda.recipe/meta.yaml @@ -22,7 +22,7 @@ requirements: run: - python - numpy x.x - - python-dateutil + - python-dateutil >=2.5.0 - pytz test: diff --git a/doc/source/install.rst b/doc/source/install.rst index 7c1fde119ceaa..3b095c4b9d755 100644 --- a/doc/source/install.rst +++ b/doc/source/install.rst @@ -200,7 +200,7 @@ Dependencies * `setuptools `__ * `NumPy `__: 1.9.0 or higher -* `python-dateutil `__: 1.5 or higher +* `python-dateutil `__: 2.5 or higher * `pytz `__: Needed for time zone support .. _install.recommended_dependencies: diff --git a/doc/source/whatsnew/v0.22.0.txt b/doc/source/whatsnew/v0.22.0.txt index e8f2823f32edd..1ae48a316dc05 100644 --- a/doc/source/whatsnew/v0.22.0.txt +++ b/doc/source/whatsnew/v0.22.0.txt @@ -86,8 +86,20 @@ Backwards incompatible API changes - :func:`Series.fillna` now raises a ``TypeError`` instead of a ``ValueError`` when passed a list, tuple or DataFrame as a ``value`` (:issue:`18293`) - :func:`pandas.DataFrame.merge` no longer casts a ``float`` column to ``object`` when merging on ``int`` and ``float`` columns (:issue:`16572`) - The default NA value for :class:`UInt64Index` has changed from 0 to ``NaN``, which impacts methods that mask with NA, such as ``UInt64Index.where()`` (:issue:`18398`) -- +Dependencies have increased minimum versions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +We have updated our minimum supported versions of dependencies (). +If installed, we now require: + + +-----------------+-----------------+----------+ + | Package | Minimum Version | Required | + +=================+=================+==========+ + | python-dateutil | 2.5.0 | X | + +-----------------+-----------------+----------+ + +- :func:`Series.fillna` now raises a ``TypeError`` instead of a ``ValueError`` when passed a list, tuple or DataFrame as a ``value`` (:issue:`18293`) diff --git a/pandas/compat/__init__.py b/pandas/compat/__init__.py index a615e098135a9..2deb29dabe764 100644 --- a/pandas/compat/__init__.py +++ b/pandas/compat/__init__.py @@ -396,25 +396,13 @@ def raise_with_traceback(exc, traceback=Ellipsis): If traceback is not passed, uses sys.exc_info() to get traceback.""" -# http://stackoverflow.com/questions/4126348 -# Thanks to @martineau at SO - +# dateutil minimum version import dateutil -if PY2 and LooseVersion(dateutil.__version__) == '2.0': - # dateutil brokenness - raise Exception('dateutil 2.0 incompatible with Python 2.x, you must ' - 'install version 1.5 or 2.1+!') - +if LooseVersion(dateutil.__version__) < '2.5': + raise ImportError('dateutil 2.5.0 is the minimum required version') from dateutil import parser as _date_parser -if LooseVersion(dateutil.__version__) < '2.0': - - @functools.wraps(_date_parser.parse) - def parse_date(timestr, *args, **kwargs): - timestr = bytes(timestr) - return _date_parser.parse(timestr, *args, **kwargs) -else: - parse_date = _date_parser.parse +parse_date = _date_parser.parse # https://github.com/pandas-dev/pandas/pull/9123 diff --git a/pandas/tests/indexes/datetimes/test_tools.py b/pandas/tests/indexes/datetimes/test_tools.py index a1287c3102b77..6c72e65b1021c 100644 --- a/pandas/tests/indexes/datetimes/test_tools.py +++ b/pandas/tests/indexes/datetimes/test_tools.py @@ -1160,9 +1160,9 @@ class TestDatetimeParsingWrappers(object): @pytest.mark.parametrize('cache', [True, False]) def test_parsers(self, cache): + # dateutil >= 2.5.0 defaults to yearfirst=True # https://github.com/dateutil/dateutil/issues/217 - import dateutil - yearfirst = dateutil.__version__ >= LooseVersion('2.5.0') + yearfirst = True cases = {'2011-01-01': datetime(2011, 1, 1), '2Q2005': datetime(2005, 4, 1), diff --git a/pandas/tests/scalar/test_timestamp.py b/pandas/tests/scalar/test_timestamp.py index dab508de335c4..f4706db48b5b8 100644 --- a/pandas/tests/scalar/test_timestamp.py +++ b/pandas/tests/scalar/test_timestamp.py @@ -16,8 +16,9 @@ import pandas.util.testing as tm from pandas.tseries import offsets, frequencies -from pandas._libs.tslibs.timezones import get_timezone -from pandas._libs.tslibs import conversion, period +from pandas._libs import period +from pandas._libs.tslibs.timezones import get_timezone, dateutil_gettz as gettz +from pandas._libs.tslibs import conversion from pandas.compat import long, PY3 from pandas.util.testing import assert_series_equal @@ -359,9 +360,7 @@ def test_conversion(self): '2014-01-01 00:00:00.000000001']) def test_repr(self, date, freq): # dateutil zone change (only matters for repr) - if (dateutil.__version__ >= LooseVersion('2.3') and - (dateutil.__version__ <= LooseVersion('2.4.0') or - dateutil.__version__ >= LooseVersion('2.6.0'))): + if dateutil.__version__ >= LooseVersion('2.6.0'): timezones = ['UTC', 'Asia/Tokyo', 'US/Eastern', 'dateutil/US/Pacific'] else: @@ -1381,7 +1380,6 @@ def test_timestamp_to_datetime_explicit_pytz(self): def test_timestamp_to_datetime_explicit_dateutil(self): tm._skip_if_windows_python_3() - from pandas._libs.tslibs.timezones import dateutil_gettz as gettz stamp = Timestamp('20090415', tz=gettz('US/Eastern'), freq='D') dtval = stamp.to_pydatetime() assert stamp == dtval From 3fad66823cff90efe644e20993290c031f9fe238 Mon Sep 17 00:00:00 2001 From: Jeff Reback Date: Wed, 8 Nov 2017 16:53:41 -0500 Subject: [PATCH 2/7] DEPS: require openpyxl >= 2.3.2 closes #15184 --- ci/requirements-2.7.run | 2 +- ci/requirements-2.7_LOCALE.run | 2 +- doc/source/install.rst | 4 +- doc/source/whatsnew/v0.22.0.txt | 7 +- pandas/compat/openpyxl_compat.py | 35 ----- pandas/io/excel.py | 197 +------------------------- pandas/tests/io/test_excel.py | 231 ++----------------------------- 7 files changed, 25 insertions(+), 453 deletions(-) delete mode 100644 pandas/compat/openpyxl_compat.py diff --git a/ci/requirements-2.7.run b/ci/requirements-2.7.run index 3a1e91e4246b5..7c10b98fb6e14 100644 --- a/ci/requirements-2.7.run +++ b/ci/requirements-2.7.run @@ -5,7 +5,7 @@ xlwt=0.7.5 numexpr pytables matplotlib -openpyxl=1.6.2 +openpyxl=2.4.0 xlrd=0.9.2 sqlalchemy=0.9.6 lxml diff --git a/ci/requirements-2.7_LOCALE.run b/ci/requirements-2.7_LOCALE.run index 978bbf6a051c5..5a65271ad4fd8 100644 --- a/ci/requirements-2.7_LOCALE.run +++ b/ci/requirements-2.7_LOCALE.run @@ -2,7 +2,7 @@ python-dateutil pytz=2013b numpy=1.9.2 xlwt=0.7.5 -openpyxl=1.6.2 +openpyxl=2.4.0 xlsxwriter=0.5.2 xlrd=0.9.2 bottleneck=1.0.0 diff --git a/doc/source/install.rst b/doc/source/install.rst index 3b095c4b9d755..957d01747cf62 100644 --- a/doc/source/install.rst +++ b/doc/source/install.rst @@ -244,8 +244,8 @@ Optional Dependencies * For Excel I/O: * `xlrd/xlwt `__: Excel reading (xlrd) and writing (xlwt) - * `openpyxl `__: openpyxl version 1.6.1 - or higher (but lower than 2.0.0), or version 2.2 or higher, for writing .xlsx files (xlrd >= 0.9.0) + * `openpyxl `__: openpyxl version 2.4.0 + for writing .xlsx files (xlrd >= 0.9.0) * `XlsxWriter `__: Alternative Excel writer * `Jinja2 `__: Template engine for conditional HTML formatting. diff --git a/doc/source/whatsnew/v0.22.0.txt b/doc/source/whatsnew/v0.22.0.txt index 1ae48a316dc05..c4348a230b5cd 100644 --- a/doc/source/whatsnew/v0.22.0.txt +++ b/doc/source/whatsnew/v0.22.0.txt @@ -83,14 +83,17 @@ Other Enhancements Backwards incompatible API changes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +<<<<<<< 93855ed7385e8a4a3550332bb706821633b97c03 - :func:`Series.fillna` now raises a ``TypeError`` instead of a ``ValueError`` when passed a list, tuple or DataFrame as a ``value`` (:issue:`18293`) - :func:`pandas.DataFrame.merge` no longer casts a ``float`` column to ``object`` when merging on ``int`` and ``float`` columns (:issue:`16572`) - The default NA value for :class:`UInt64Index` has changed from 0 to ``NaN``, which impacts methods that mask with NA, such as ``UInt64Index.where()`` (:issue:`18398`) +.. _whatsnew_0220.api_breaking.deps: + Dependencies have increased minimum versions ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -We have updated our minimum supported versions of dependencies (). +We have updated our minimum supported versions of dependencies (:issue:`15184`). If installed, we now require: +-----------------+-----------------+----------+ @@ -98,6 +101,8 @@ If installed, we now require: +=================+=================+==========+ | python-dateutil | 2.5.0 | X | +-----------------+-----------------+----------+ + | openpyxl | 2.4.0 | | + +-----------------+-----------------+----------+ - :func:`Series.fillna` now raises a ``TypeError`` instead of a ``ValueError`` when passed a list, tuple or DataFrame as a ``value`` (:issue:`18293`) diff --git a/pandas/compat/openpyxl_compat.py b/pandas/compat/openpyxl_compat.py deleted file mode 100644 index 87cf52cf00fef..0000000000000 --- a/pandas/compat/openpyxl_compat.py +++ /dev/null @@ -1,35 +0,0 @@ -""" -Detect incompatible version of OpenPyXL - -GH7169 -""" - -from distutils.version import LooseVersion - -start_ver = '1.6.1' -stop_ver = '2.0.0' - - -def is_compat(major_ver=1): - """Detect whether the installed version of openpyxl is supported - - Parameters - ---------- - ver : int - 1 requests compatibility status among the 1.x.y series - 2 requests compatibility status of 2.0.0 and later - Returns - ------- - compat : bool - ``True`` if openpyxl is installed and is a compatible version. - ``False`` otherwise. - """ - import openpyxl - ver = LooseVersion(openpyxl.__version__) - if major_ver == 1: - return LooseVersion(start_ver) <= ver < LooseVersion(stop_ver) - elif major_ver == 2: - return LooseVersion(stop_ver) <= ver - else: - raise ValueError('cannot test for openpyxl compatibility with ver {0}' - .format(major_ver)) diff --git a/pandas/io/excel.py b/pandas/io/excel.py index fec916dc52d20..882130bedcbf0 100644 --- a/pandas/io/excel.py +++ b/pandas/io/excel.py @@ -28,7 +28,6 @@ from pandas.core import config from pandas.io.formats.printing import pprint_thing import pandas.compat as compat -import pandas.compat.openpyxl_compat as openpyxl_compat from warnings import warn from distutils.version import LooseVersion from pandas.util._decorators import Appender, deprecate_kwarg @@ -185,22 +184,6 @@ def _get_default_writer(ext): def get_writer(engine_name): - if engine_name == 'openpyxl': - try: - import openpyxl - - # with version-less openpyxl engine - # make sure we make the intelligent choice for the user - if LooseVersion(openpyxl.__version__) < '2.0.0': - return _writers['openpyxl1'] - elif LooseVersion(openpyxl.__version__) < '2.2.0': - return _writers['openpyxl20'] - else: - return _writers['openpyxl22'] - except ImportError: - # fall through to normal exception handling below - pass - try: return _writers[engine_name] except KeyError: @@ -828,20 +811,15 @@ def close(self): return self.save() -class _Openpyxl1Writer(ExcelWriter): - engine = 'openpyxl1' +class _OpenpyxlWriter(ExcelWriter): + engine = 'openpyxl' supported_extensions = ('.xlsx', '.xlsm') - openpyxl_majorver = 1 def __init__(self, path, engine=None, **engine_kwargs): - if not openpyxl_compat.is_compat(major_ver=self.openpyxl_majorver): - raise ValueError('Installed openpyxl is not supported at this ' - 'time. Use {majorver}.x.y.' - .format(majorver=self.openpyxl_majorver)) # Use the openpyxl module as the Excel writer. from openpyxl.workbook import Workbook - super(_Openpyxl1Writer, self).__init__(path, **engine_kwargs) + super(_OpenpyxlWriter, self).__init__(path, **engine_kwargs) # Create workbook object with default optimized_write=True. self.book = Workbook() @@ -861,72 +839,6 @@ def save(self): """ return self.book.save(self.path) - def write_cells(self, cells, sheet_name=None, startrow=0, startcol=0, - freeze_panes=None): - # Write the frame cells using openpyxl. - from openpyxl.cell import get_column_letter - - sheet_name = self._get_sheet_name(sheet_name) - - if sheet_name in self.sheets: - wks = self.sheets[sheet_name] - else: - wks = self.book.create_sheet() - wks.title = sheet_name - self.sheets[sheet_name] = wks - - for cell in cells: - colletter = get_column_letter(startcol + cell.col + 1) - xcell = wks.cell("{col}{row}".format(col=colletter, - row=startrow + cell.row + 1)) - if (isinstance(cell.val, compat.string_types) and - xcell.data_type_for_value(cell.val) != xcell.TYPE_STRING): - xcell.set_value_explicit(cell.val) - else: - xcell.value = _conv_value(cell.val) - style = None - if cell.style: - style = self._convert_to_style(cell.style) - for field in style.__fields__: - xcell.style.__setattr__(field, - style.__getattribute__(field)) - - if isinstance(cell.val, datetime): - xcell.style.number_format.format_code = self.datetime_format - elif isinstance(cell.val, date): - xcell.style.number_format.format_code = self.date_format - - if cell.mergestart is not None and cell.mergeend is not None: - cletterstart = get_column_letter(startcol + cell.col + 1) - cletterend = get_column_letter(startcol + cell.mergeend + 1) - - wks.merge_cells('{start}{row}:{end}{mergestart}' - .format(start=cletterstart, - row=startrow + cell.row + 1, - end=cletterend, - mergestart=startrow + - cell.mergestart + 1)) - - # Excel requires that the format of the first cell in a merged - # range is repeated in the rest of the merged range. - if style: - first_row = startrow + cell.row + 1 - last_row = startrow + cell.mergestart + 1 - first_col = startcol + cell.col + 1 - last_col = startcol + cell.mergeend + 1 - - for row in range(first_row, last_row + 1): - for col in range(first_col, last_col + 1): - if row == first_row and col == first_col: - # Ignore first cell. It is already handled. - continue - colletter = get_column_letter(col) - xcell = wks.cell("{col}{row}" - .format(col=colletter, row=row)) - for field in style.__fields__: - xcell.style.__setattr__( - field, style.__getattribute__(field)) - @classmethod def _convert_to_style(cls, style_dict): """ @@ -948,88 +860,6 @@ def _convert_to_style(cls, style_dict): return xls_style - -register_writer(_Openpyxl1Writer) - - -class _OpenpyxlWriter(_Openpyxl1Writer): - engine = 'openpyxl' - - -register_writer(_OpenpyxlWriter) - - -class _Openpyxl20Writer(_Openpyxl1Writer): - """ - Note: Support for OpenPyxl v2 is currently EXPERIMENTAL (GH7565). - """ - engine = 'openpyxl20' - openpyxl_majorver = 2 - - def write_cells(self, cells, sheet_name=None, startrow=0, startcol=0, - freeze_panes=None): - # Write the frame cells using openpyxl. - from openpyxl.cell import get_column_letter - - sheet_name = self._get_sheet_name(sheet_name) - - if sheet_name in self.sheets: - wks = self.sheets[sheet_name] - else: - wks = self.book.create_sheet() - wks.title = sheet_name - self.sheets[sheet_name] = wks - - for cell in cells: - colletter = get_column_letter(startcol + cell.col + 1) - xcell = wks["{col}{row}" - .format(col=colletter, row=startrow + cell.row + 1)] - xcell.value = _conv_value(cell.val) - style_kwargs = {} - - # Apply format codes before cell.style to allow override - if isinstance(cell.val, datetime): - style_kwargs.update(self._convert_to_style_kwargs({ - 'number_format': {'format_code': self.datetime_format}})) - elif isinstance(cell.val, date): - style_kwargs.update(self._convert_to_style_kwargs({ - 'number_format': {'format_code': self.date_format}})) - - if cell.style: - style_kwargs.update(self._convert_to_style_kwargs(cell.style)) - - if style_kwargs: - xcell.style = xcell.style.copy(**style_kwargs) - - if cell.mergestart is not None and cell.mergeend is not None: - cletterstart = get_column_letter(startcol + cell.col + 1) - cletterend = get_column_letter(startcol + cell.mergeend + 1) - - wks.merge_cells('{start}{row}:{end}{mergestart}' - .format(start=cletterstart, - row=startrow + cell.row + 1, - end=cletterend, - mergestart=startrow + - cell.mergestart + 1)) - - # Excel requires that the format of the first cell in a merged - # range is repeated in the rest of the merged range. - if style_kwargs: - first_row = startrow + cell.row + 1 - last_row = startrow + cell.mergestart + 1 - first_col = startcol + cell.col + 1 - last_col = startcol + cell.mergeend + 1 - - for row in range(first_row, last_row + 1): - for col in range(first_col, last_col + 1): - if row == first_row and col == first_col: - # Ignore first cell. It is already handled. - continue - colletter = get_column_letter(col) - xcell = wks["{col}{row}" - .format(col=colletter, row=row)] - xcell.style = xcell.style.copy(**style_kwargs) - @classmethod def _convert_to_style_kwargs(cls, style_dict): """ @@ -1341,13 +1171,7 @@ def _convert_to_number_format(cls, number_format_dict): ------- number_format : str """ - try: - # >= 2.0.0 < 2.1.0 - from openpyxl.styles import NumberFormat - return NumberFormat(**number_format_dict) - except: - # >= 2.1.0 - return number_format_dict['format_code'] + return number_format_dict['format_code'] @classmethod def _convert_to_protection(cls, protection_dict): @@ -1367,17 +1191,6 @@ def _convert_to_protection(cls, protection_dict): return Protection(**protection_dict) - -register_writer(_Openpyxl20Writer) - - -class _Openpyxl22Writer(_Openpyxl20Writer): - """ - Note: Support for OpenPyxl v2.2 is currently EXPERIMENTAL (GH7565). - """ - engine = 'openpyxl22' - openpyxl_majorver = 2 - def write_cells(self, cells, sheet_name=None, startrow=0, startcol=0, freeze_panes=None): # Write the frame cells using openpyxl. @@ -1443,7 +1256,7 @@ def write_cells(self, cells, sheet_name=None, startrow=0, startcol=0, setattr(xcell, k, v) -register_writer(_Openpyxl22Writer) +register_writer(_OpenpyxlWriter) class _XlwtWriter(ExcelWriter): diff --git a/pandas/tests/io/test_excel.py b/pandas/tests/io/test_excel.py index d33136a86faad..96117b3c21a9b 100644 --- a/pandas/tests/io/test_excel.py +++ b/pandas/tests/io/test_excel.py @@ -1,6 +1,4 @@ # pylint: disable=E1101 -import functools -import operator import os import sys import warnings @@ -17,12 +15,12 @@ import pandas as pd import pandas.util.testing as tm from pandas import DataFrame, Index, MultiIndex -from pandas.compat import u, range, map, openpyxl_compat, BytesIO, iteritems +from pandas.compat import u, range, map, BytesIO, iteritems from pandas.core.config import set_option, get_option from pandas.io.common import URLError from pandas.io.excel import ( - ExcelFile, ExcelWriter, read_excel, _XlwtWriter, _Openpyxl1Writer, - _Openpyxl20Writer, _Openpyxl22Writer, register_writer, _XlsxWriter + ExcelFile, ExcelWriter, read_excel, _XlwtWriter, _OpenpyxlWriter, + register_writer, _XlsxWriter ) from pandas.io.formats.excel import ExcelFormatter from pandas.io.parsers import read_csv @@ -1926,207 +1924,10 @@ def test_path_localpath(self): tm.assert_frame_equal(df, result) -def raise_wrapper(major_ver): - def versioned_raise_wrapper(orig_method): - @functools.wraps(orig_method) - def wrapped(self, *args, **kwargs): - _skip_if_no_openpyxl() - if openpyxl_compat.is_compat(major_ver=major_ver): - orig_method(self, *args, **kwargs) - else: - msg = (r'Installed openpyxl is not supported at this ' - r'time\. Use.+') - with tm.assert_raises_regex(ValueError, msg): - orig_method(self, *args, **kwargs) - return wrapped - return versioned_raise_wrapper - - -def raise_on_incompat_version(major_ver): - def versioned_raise_on_incompat_version(cls): - methods = filter(operator.methodcaller( - 'startswith', 'test_'), dir(cls)) - for method in methods: - setattr(cls, method, raise_wrapper( - major_ver)(getattr(cls, method))) - return cls - return versioned_raise_on_incompat_version - - -@raise_on_incompat_version(1) class TestOpenpyxlTests(ExcelWriterBase): + engine_name = 'openpyxl' ext = '.xlsx' - engine_name = 'openpyxl1' - check_skip = staticmethod(lambda *args, **kwargs: None) - - def test_to_excel_styleconverter(self): - _skip_if_no_openpyxl() - if not openpyxl_compat.is_compat(major_ver=1): - pytest.skip('incompatible openpyxl version') - - import openpyxl - - hstyle = {"font": {"bold": True}, - "borders": {"top": "thin", - "right": "thin", - "bottom": "thin", - "left": "thin"}, - "alignment": {"horizontal": "center", "vertical": "top"}} - - xlsx_style = _Openpyxl1Writer._convert_to_style(hstyle) - assert xlsx_style.font.bold - assert (openpyxl.style.Border.BORDER_THIN == - xlsx_style.borders.top.border_style) - assert (openpyxl.style.Border.BORDER_THIN == - xlsx_style.borders.right.border_style) - assert (openpyxl.style.Border.BORDER_THIN == - xlsx_style.borders.bottom.border_style) - assert (openpyxl.style.Border.BORDER_THIN == - xlsx_style.borders.left.border_style) - assert (openpyxl.style.Alignment.HORIZONTAL_CENTER == - xlsx_style.alignment.horizontal) - assert (openpyxl.style.Alignment.VERTICAL_TOP == - xlsx_style.alignment.vertical) - - -def skip_openpyxl_gt21(cls): - """Skip test case if openpyxl >= 2.2""" - - @classmethod - def setup_class(cls): - _skip_if_no_openpyxl() - import openpyxl - ver = openpyxl.__version__ - if (not (LooseVersion(ver) >= LooseVersion('2.0.0') and - LooseVersion(ver) < LooseVersion('2.2.0'))): - pytest.skip("openpyxl %s >= 2.2" % str(ver)) - - cls.setup_class = setup_class - return cls - - -@raise_on_incompat_version(2) -@skip_openpyxl_gt21 -class TestOpenpyxl20Tests(ExcelWriterBase): - ext = '.xlsx' - engine_name = 'openpyxl20' - check_skip = staticmethod(lambda *args, **kwargs: None) - - def test_to_excel_styleconverter(self): - import openpyxl - from openpyxl import styles - - hstyle = { - "font": { - "color": '00FF0000', - "bold": True, - }, - "borders": { - "top": "thin", - "right": "thin", - "bottom": "thin", - "left": "thin", - }, - "alignment": { - "horizontal": "center", - "vertical": "top", - }, - "fill": { - "patternType": 'solid', - 'fgColor': { - 'rgb': '006666FF', - 'tint': 0.3, - }, - }, - "number_format": { - "format_code": "0.00" - }, - "protection": { - "locked": True, - "hidden": False, - }, - } - - font_color = styles.Color('00FF0000') - font = styles.Font(bold=True, color=font_color) - side = styles.Side(style=styles.borders.BORDER_THIN) - border = styles.Border(top=side, right=side, bottom=side, left=side) - alignment = styles.Alignment(horizontal='center', vertical='top') - fill_color = styles.Color(rgb='006666FF', tint=0.3) - fill = styles.PatternFill(patternType='solid', fgColor=fill_color) - - # ahh openpyxl API changes - ver = openpyxl.__version__ - if ver >= LooseVersion('2.0.0') and ver < LooseVersion('2.1.0'): - number_format = styles.NumberFormat(format_code='0.00') - else: - number_format = '0.00' # XXX: Only works with openpyxl-2.1.0 - - protection = styles.Protection(locked=True, hidden=False) - - kw = _Openpyxl20Writer._convert_to_style_kwargs(hstyle) - assert kw['font'] == font - assert kw['border'] == border - assert kw['alignment'] == alignment - assert kw['fill'] == fill - assert kw['number_format'] == number_format - assert kw['protection'] == protection - - def test_write_cells_merge_styled(self): - from pandas.io.formats.excel import ExcelCell - from openpyxl import styles - - sheet_name = 'merge_styled' - - sty_b1 = {'font': {'color': '00FF0000'}} - sty_a2 = {'font': {'color': '0000FF00'}} - - initial_cells = [ - ExcelCell(col=1, row=0, val=42, style=sty_b1), - ExcelCell(col=0, row=1, val=99, style=sty_a2), - ] - - sty_merged = {'font': {'color': '000000FF', 'bold': True}} - sty_kwargs = _Openpyxl20Writer._convert_to_style_kwargs(sty_merged) - openpyxl_sty_merged = styles.Style(**sty_kwargs) - merge_cells = [ - ExcelCell(col=0, row=0, val='pandas', - mergestart=1, mergeend=1, style=sty_merged), - ] - - with ensure_clean('.xlsx') as path: - writer = _Openpyxl20Writer(path) - writer.write_cells(initial_cells, sheet_name=sheet_name) - writer.write_cells(merge_cells, sheet_name=sheet_name) - - wks = writer.sheets[sheet_name] - xcell_b1 = wks['B1'] - xcell_a2 = wks['A2'] - assert xcell_b1.style == openpyxl_sty_merged - assert xcell_a2.style == openpyxl_sty_merged - - -def skip_openpyxl_lt22(cls): - """Skip test case if openpyxl < 2.2""" - - @classmethod - def setup_class(cls): - _skip_if_no_openpyxl() - import openpyxl - ver = openpyxl.__version__ - if LooseVersion(ver) < LooseVersion('2.2.0'): - pytest.skip("openpyxl %s < 2.2" % str(ver)) - - cls.setup_class = setup_class - return cls - - -@raise_on_incompat_version(2) -@skip_openpyxl_lt22 -class TestOpenpyxl22Tests(ExcelWriterBase): - ext = '.xlsx' - engine_name = 'openpyxl22' - check_skip = staticmethod(lambda *args, **kwargs: None) + check_skip = staticmethod(_skip_if_no_openpyxl) def test_to_excel_styleconverter(self): from openpyxl import styles @@ -2174,7 +1975,7 @@ def test_to_excel_styleconverter(self): protection = styles.Protection(locked=True, hidden=False) - kw = _Openpyxl22Writer._convert_to_style_kwargs(hstyle) + kw = _OpenpyxlWriter._convert_to_style_kwargs(hstyle) assert kw['font'] == font assert kw['border'] == border assert kw['alignment'] == alignment @@ -2183,9 +1984,6 @@ def test_to_excel_styleconverter(self): assert kw['protection'] == protection def test_write_cells_merge_styled(self): - if not openpyxl_compat.is_compat(major_ver=2): - pytest.skip('incompatible openpyxl version') - from pandas.io.formats.excel import ExcelCell sheet_name = 'merge_styled' @@ -2199,7 +1997,7 @@ def test_write_cells_merge_styled(self): ] sty_merged = {'font': {'color': '000000FF', 'bold': True}} - sty_kwargs = _Openpyxl22Writer._convert_to_style_kwargs(sty_merged) + sty_kwargs = _OpenpyxlWriter._convert_to_style_kwargs(sty_merged) openpyxl_sty_merged = sty_kwargs['font'] merge_cells = [ ExcelCell(col=0, row=0, val='pandas', @@ -2207,7 +2005,7 @@ def test_write_cells_merge_styled(self): ] with ensure_clean('.xlsx') as path: - writer = _Openpyxl22Writer(path) + writer = _OpenpyxlWriter(path) writer.write_cells(initial_cells, sheet_name=sheet_name) writer.write_cells(merge_cells, sheet_name=sheet_name) @@ -2322,7 +2120,7 @@ def test_column_format(self): try: read_num_format = cell.number_format - except: + except Exception: read_num_format = cell.style.number_format._format_code assert read_num_format == num_format @@ -2366,9 +2164,7 @@ def test_ExcelWriter_dispatch(self): writer_klass = _XlsxWriter except ImportError: _skip_if_no_openpyxl() - if not openpyxl_compat.is_compat(major_ver=1): - pytest.skip('incompatible openpyxl version') - writer_klass = _Openpyxl1Writer + writer_klass = _OpenpyxlWriter with ensure_clean('.xlsx') as path: writer = ExcelWriter(path) @@ -2461,10 +2257,6 @@ def custom_converter(css): pytest.importorskip('jinja2') pytest.importorskip(engine) - if engine == 'openpyxl' and openpyxl_compat.is_compat(major_ver=1): - pytest.xfail('openpyxl1 does not support some openpyxl2-compatible ' - 'style dicts') - # Prepare spreadsheets df = DataFrame(np.random.randn(10, 3)) @@ -2482,9 +2274,6 @@ def custom_converter(css): # For other engines, we only smoke test return openpyxl = pytest.importorskip('openpyxl') - if not openpyxl_compat.is_compat(major_ver=2): - pytest.skip('incompatible openpyxl version') - wb = openpyxl.load_workbook(path) # (1) compare DataFrame.to_excel and Styler.to_excel when unstyled From c8d18a330fe6786bf2bd2a1c6a5f01e0e3186194 Mon Sep 17 00:00:00 2001 From: Jeff Reback Date: Sat, 25 Nov 2017 20:11:30 -0500 Subject: [PATCH 3/7] require pytz >= 2016.1 --- ci/requirements-2.7.build | 2 +- ci/requirements-2.7.run | 2 +- ci/requirements-2.7_COMPAT.build | 2 +- ci/requirements-2.7_COMPAT.run | 2 +- ci/requirements-2.7_LOCALE.build | 2 +- ci/requirements-2.7_LOCALE.run | 2 +- doc/source/install.rst | 2 +- doc/source/whatsnew/v0.22.0.txt | 2 ++ 8 files changed, 9 insertions(+), 7 deletions(-) diff --git a/ci/requirements-2.7.build b/ci/requirements-2.7.build index d1cc61df0a77c..55aa1de60fa33 100644 --- a/ci/requirements-2.7.build +++ b/ci/requirements-2.7.build @@ -1,6 +1,6 @@ python=2.7* python-dateutil=2.5.0 -pytz=2013b +pytz=2016.1 nomkl numpy cython=0.23 diff --git a/ci/requirements-2.7.run b/ci/requirements-2.7.run index 7c10b98fb6e14..8377474554578 100644 --- a/ci/requirements-2.7.run +++ b/ci/requirements-2.7.run @@ -1,5 +1,5 @@ python-dateutil=2.5.0 -pytz=2013b +pytz=2016.1 numpy xlwt=0.7.5 numexpr diff --git a/ci/requirements-2.7_COMPAT.build b/ci/requirements-2.7_COMPAT.build index aa767c1001196..279868d7da1a3 100644 --- a/ci/requirements-2.7_COMPAT.build +++ b/ci/requirements-2.7_COMPAT.build @@ -2,4 +2,4 @@ python=2.7* numpy=1.9.2 cython=0.23 python-dateutil=2.5.0 -pytz=2013b +pytz=2016.1 diff --git a/ci/requirements-2.7_COMPAT.run b/ci/requirements-2.7_COMPAT.run index c3daed6e6e1da..8f56a3d27ad2b 100644 --- a/ci/requirements-2.7_COMPAT.run +++ b/ci/requirements-2.7_COMPAT.run @@ -1,6 +1,6 @@ numpy=1.9.2 python-dateutil=2.5.0 -pytz=2013b +pytz=2016.1 scipy=0.14.0 xlwt=0.7.5 xlrd=0.9.2 diff --git a/ci/requirements-2.7_LOCALE.build b/ci/requirements-2.7_LOCALE.build index 96cb184ec2665..e83c493439b38 100644 --- a/ci/requirements-2.7_LOCALE.build +++ b/ci/requirements-2.7_LOCALE.build @@ -1,5 +1,5 @@ python=2.7* python-dateutil -pytz=2013b +pytz=2016.1 numpy=1.9.2 cython=0.23 diff --git a/ci/requirements-2.7_LOCALE.run b/ci/requirements-2.7_LOCALE.run index 5a65271ad4fd8..0a809a7dd6e5d 100644 --- a/ci/requirements-2.7_LOCALE.run +++ b/ci/requirements-2.7_LOCALE.run @@ -1,5 +1,5 @@ python-dateutil -pytz=2013b +pytz numpy=1.9.2 xlwt=0.7.5 openpyxl=2.4.0 diff --git a/doc/source/install.rst b/doc/source/install.rst index 957d01747cf62..395354cae6d30 100644 --- a/doc/source/install.rst +++ b/doc/source/install.rst @@ -201,7 +201,7 @@ Dependencies * `setuptools `__ * `NumPy `__: 1.9.0 or higher * `python-dateutil `__: 2.5 or higher -* `pytz `__: Needed for time zone support +* `pytz `__: 2016.1 or higher. .. _install.recommended_dependencies: diff --git a/doc/source/whatsnew/v0.22.0.txt b/doc/source/whatsnew/v0.22.0.txt index c4348a230b5cd..461310d7cb168 100644 --- a/doc/source/whatsnew/v0.22.0.txt +++ b/doc/source/whatsnew/v0.22.0.txt @@ -101,6 +101,8 @@ If installed, we now require: +=================+=================+==========+ | python-dateutil | 2.5.0 | X | +-----------------+-----------------+----------+ + | pytz | 2016.1 | X | + +-----------------+-----------------+----------+ | openpyxl | 2.4.0 | | +-----------------+-----------------+----------+ From d2f2e48a8a7b3f3c265df44de7aba99583e41b37 Mon Sep 17 00:00:00 2001 From: Jeff Reback Date: Sat, 25 Nov 2017 20:18:17 -0500 Subject: [PATCH 4/7] more build deps --- ci/environment-dev.yaml | 6 +++--- ci/requirements-optional-pip.txt | 4 +++- ci/requirements_dev.txt | 6 +++--- conda.recipe/meta.yaml | 4 +--- doc/source/whatsnew/v0.22.0.txt | 1 - pandas/compat/__init__.py | 5 +++++ 6 files changed, 15 insertions(+), 11 deletions(-) diff --git a/ci/environment-dev.yaml b/ci/environment-dev.yaml index c3d3d59f895c6..56023d2a71a79 100644 --- a/ci/environment-dev.yaml +++ b/ci/environment-dev.yaml @@ -6,9 +6,9 @@ dependencies: - Cython - NumPy - moto - - pytest - - python-dateutil + - pytest>=3.1 + - python-dateutil>=2.5.0 - python=3 - - pytz + - pytz>=2016.1 - setuptools - sphinx diff --git a/ci/requirements-optional-pip.txt b/ci/requirements-optional-pip.txt index 06b22bd8f2c63..8d4421ba2b681 100644 --- a/ci/requirements-optional-pip.txt +++ b/ci/requirements-optional-pip.txt @@ -1,11 +1,13 @@ # This file was autogenerated by scripts/convert_deps.py -# Do not modify directlybeautifulsoup4 +# Do not modify directly +beautifulsoup4 blosc bottleneck fastparquet feather-format html5lib ipython +ipykernel jinja2 lxml matplotlib diff --git a/ci/requirements_dev.txt b/ci/requirements_dev.txt index 2fb36b7cd70d8..553290b594d71 100644 --- a/ci/requirements_dev.txt +++ b/ci/requirements_dev.txt @@ -3,8 +3,8 @@ Cython NumPy moto -pytest -python-dateutil -pytz +pytest>=3.1 +python-dateutil>=2.5.0 +pytz>=2016.1 setuptools sphinx \ No newline at end of file diff --git a/conda.recipe/meta.yaml b/conda.recipe/meta.yaml index 584f23e22a146..753a2c5b2aa98 100644 --- a/conda.recipe/meta.yaml +++ b/conda.recipe/meta.yaml @@ -16,14 +16,12 @@ requirements: - cython - numpy x.x - setuptools - - pytz - - python-dateutil run: - python - numpy x.x - python-dateutil >=2.5.0 - - pytz + - pytz >=2016.1 test: imports: diff --git a/doc/source/whatsnew/v0.22.0.txt b/doc/source/whatsnew/v0.22.0.txt index 461310d7cb168..bde61d1909eb8 100644 --- a/doc/source/whatsnew/v0.22.0.txt +++ b/doc/source/whatsnew/v0.22.0.txt @@ -83,7 +83,6 @@ Other Enhancements Backwards incompatible API changes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -<<<<<<< 93855ed7385e8a4a3550332bb706821633b97c03 - :func:`Series.fillna` now raises a ``TypeError`` instead of a ``ValueError`` when passed a list, tuple or DataFrame as a ``value`` (:issue:`18293`) - :func:`pandas.DataFrame.merge` no longer casts a ``float`` column to ``object`` when merging on ``int`` and ``float`` columns (:issue:`16572`) - The default NA value for :class:`UInt64Index` has changed from 0 to ``NaN``, which impacts methods that mask with NA, such as ``UInt64Index.where()`` (:issue:`18398`) diff --git a/pandas/compat/__init__.py b/pandas/compat/__init__.py index 2deb29dabe764..6eb600109d5ab 100644 --- a/pandas/compat/__init__.py +++ b/pandas/compat/__init__.py @@ -404,6 +404,11 @@ def raise_with_traceback(exc, traceback=Ellipsis): from dateutil import parser as _date_parser parse_date = _date_parser.parse +# pytz minimum version +import pytz + +if LooseVersion(pytz.__version__) < '2016.1': + raise ImportError('pytz 2016.1 is the minimum required version') # https://github.com/pandas-dev/pandas/pull/9123 def is_platform_little_endian(): From 07b4895e36ecad21f1173f0d67591688026d9931 Mon Sep 17 00:00:00 2001 From: Jeff Reback Date: Tue, 28 Nov 2017 07:10:37 -0500 Subject: [PATCH 5/7] revert pytz --- ci/environment-dev.yaml | 2 +- ci/requirements-2.7.build | 2 +- ci/requirements-2.7.run | 2 +- ci/requirements-2.7_COMPAT.build | 2 +- ci/requirements-2.7_COMPAT.run | 2 +- ci/requirements-2.7_LOCALE.build | 2 +- ci/requirements_dev.txt | 2 +- conda.recipe/meta.yaml | 2 +- doc/source/install.rst | 2 +- doc/source/io.rst | 6 ++---- doc/source/whatsnew/v0.22.0.txt | 2 -- pandas/compat/__init__.py | 5 ----- pandas/tests/scalar/test_timestamp.py | 3 +-- 13 files changed, 12 insertions(+), 22 deletions(-) diff --git a/ci/environment-dev.yaml b/ci/environment-dev.yaml index 56023d2a71a79..57748fef1a2e5 100644 --- a/ci/environment-dev.yaml +++ b/ci/environment-dev.yaml @@ -9,6 +9,6 @@ dependencies: - pytest>=3.1 - python-dateutil>=2.5.0 - python=3 - - pytz>=2016.1 + - pytz - setuptools - sphinx diff --git a/ci/requirements-2.7.build b/ci/requirements-2.7.build index 55aa1de60fa33..d1cc61df0a77c 100644 --- a/ci/requirements-2.7.build +++ b/ci/requirements-2.7.build @@ -1,6 +1,6 @@ python=2.7* python-dateutil=2.5.0 -pytz=2016.1 +pytz=2013b nomkl numpy cython=0.23 diff --git a/ci/requirements-2.7.run b/ci/requirements-2.7.run index 8377474554578..7c10b98fb6e14 100644 --- a/ci/requirements-2.7.run +++ b/ci/requirements-2.7.run @@ -1,5 +1,5 @@ python-dateutil=2.5.0 -pytz=2016.1 +pytz=2013b numpy xlwt=0.7.5 numexpr diff --git a/ci/requirements-2.7_COMPAT.build b/ci/requirements-2.7_COMPAT.build index 279868d7da1a3..aa767c1001196 100644 --- a/ci/requirements-2.7_COMPAT.build +++ b/ci/requirements-2.7_COMPAT.build @@ -2,4 +2,4 @@ python=2.7* numpy=1.9.2 cython=0.23 python-dateutil=2.5.0 -pytz=2016.1 +pytz=2013b diff --git a/ci/requirements-2.7_COMPAT.run b/ci/requirements-2.7_COMPAT.run index 8f56a3d27ad2b..c3daed6e6e1da 100644 --- a/ci/requirements-2.7_COMPAT.run +++ b/ci/requirements-2.7_COMPAT.run @@ -1,6 +1,6 @@ numpy=1.9.2 python-dateutil=2.5.0 -pytz=2016.1 +pytz=2013b scipy=0.14.0 xlwt=0.7.5 xlrd=0.9.2 diff --git a/ci/requirements-2.7_LOCALE.build b/ci/requirements-2.7_LOCALE.build index e83c493439b38..96cb184ec2665 100644 --- a/ci/requirements-2.7_LOCALE.build +++ b/ci/requirements-2.7_LOCALE.build @@ -1,5 +1,5 @@ python=2.7* python-dateutil -pytz=2016.1 +pytz=2013b numpy=1.9.2 cython=0.23 diff --git a/ci/requirements_dev.txt b/ci/requirements_dev.txt index 553290b594d71..e9840388203b1 100644 --- a/ci/requirements_dev.txt +++ b/ci/requirements_dev.txt @@ -5,6 +5,6 @@ NumPy moto pytest>=3.1 python-dateutil>=2.5.0 -pytz>=2016.1 +pytz setuptools sphinx \ No newline at end of file diff --git a/conda.recipe/meta.yaml b/conda.recipe/meta.yaml index 753a2c5b2aa98..8152af84228b8 100644 --- a/conda.recipe/meta.yaml +++ b/conda.recipe/meta.yaml @@ -21,7 +21,7 @@ requirements: - python - numpy x.x - python-dateutil >=2.5.0 - - pytz >=2016.1 + - pytz test: imports: diff --git a/doc/source/install.rst b/doc/source/install.rst index 395354cae6d30..6b460423f24db 100644 --- a/doc/source/install.rst +++ b/doc/source/install.rst @@ -201,7 +201,7 @@ Dependencies * `setuptools `__ * `NumPy `__: 1.9.0 or higher * `python-dateutil `__: 2.5 or higher -* `pytz `__: 2016.1 or higher. +* `pytz `__ .. _install.recommended_dependencies: diff --git a/doc/source/io.rst b/doc/source/io.rst index 2aeafd99f6e72..f96e33dbf9882 100644 --- a/doc/source/io.rst +++ b/doc/source/io.rst @@ -2935,7 +2935,7 @@ Writing Excel Files to Memory +++++++++++++++++++++++++++++ Pandas supports writing Excel files to buffer-like objects such as ``StringIO`` or -``BytesIO`` using :class:`~pandas.io.excel.ExcelWriter`. Pandas also supports Openpyxl >= 2.2. +``BytesIO`` using :class:`~pandas.io.excel.ExcelWriter`. .. code-block:: python @@ -2991,9 +2991,7 @@ files if `Xlsxwriter`_ is not available. To specify which writer you want to use, you can pass an engine keyword argument to ``to_excel`` and to ``ExcelWriter``. The built-in engines are: -- ``openpyxl``: This includes stable support for Openpyxl from 1.6.1. However, - it is advised to use version 2.2 and higher, especially when working with - styles. +- ``openpyxl``: version 2.4 or higher is required - ``xlsxwriter`` - ``xlwt`` diff --git a/doc/source/whatsnew/v0.22.0.txt b/doc/source/whatsnew/v0.22.0.txt index bde61d1909eb8..97aff73e8e5fc 100644 --- a/doc/source/whatsnew/v0.22.0.txt +++ b/doc/source/whatsnew/v0.22.0.txt @@ -100,8 +100,6 @@ If installed, we now require: +=================+=================+==========+ | python-dateutil | 2.5.0 | X | +-----------------+-----------------+----------+ - | pytz | 2016.1 | X | - +-----------------+-----------------+----------+ | openpyxl | 2.4.0 | | +-----------------+-----------------+----------+ diff --git a/pandas/compat/__init__.py b/pandas/compat/__init__.py index 6eb600109d5ab..2deb29dabe764 100644 --- a/pandas/compat/__init__.py +++ b/pandas/compat/__init__.py @@ -404,11 +404,6 @@ def raise_with_traceback(exc, traceback=Ellipsis): from dateutil import parser as _date_parser parse_date = _date_parser.parse -# pytz minimum version -import pytz - -if LooseVersion(pytz.__version__) < '2016.1': - raise ImportError('pytz 2016.1 is the minimum required version') # https://github.com/pandas-dev/pandas/pull/9123 def is_platform_little_endian(): diff --git a/pandas/tests/scalar/test_timestamp.py b/pandas/tests/scalar/test_timestamp.py index f4706db48b5b8..e23911e8d2003 100644 --- a/pandas/tests/scalar/test_timestamp.py +++ b/pandas/tests/scalar/test_timestamp.py @@ -16,9 +16,8 @@ import pandas.util.testing as tm from pandas.tseries import offsets, frequencies -from pandas._libs import period from pandas._libs.tslibs.timezones import get_timezone, dateutil_gettz as gettz -from pandas._libs.tslibs import conversion +from pandas._libs.tslibs import conversion, period from pandas.compat import long, PY3 from pandas.util.testing import assert_series_equal From 468b028f6baaf171919e1508f20886d61721b01e Mon Sep 17 00:00:00 2001 From: Jeff Reback Date: Sun, 3 Dec 2017 17:54:09 -0500 Subject: [PATCH 6/7] update setup.py --- doc/source/install.rst | 2 +- setup.py | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/doc/source/install.rst b/doc/source/install.rst index 6b460423f24db..ae89c64b6e91e 100644 --- a/doc/source/install.rst +++ b/doc/source/install.rst @@ -200,7 +200,7 @@ Dependencies * `setuptools `__ * `NumPy `__: 1.9.0 or higher -* `python-dateutil `__: 2.5 or higher +* `python-dateutil `__: 2.5.0 or higher * `pytz `__ .. _install.recommended_dependencies: diff --git a/setup.py b/setup.py index ba948abf4302b..57131255884de 100755 --- a/setup.py +++ b/setup.py @@ -19,8 +19,6 @@ import versioneer cmdclass = versioneer.get_cmdclass() -PY3 = sys.version_info[0] >= 3 - def is_platform_windows(): return sys.platform == 'win32' or sys.platform == 'cygwin' @@ -46,7 +44,7 @@ def is_platform_mac(): min_numpy_ver = '1.9.0' setuptools_kwargs = { 'install_requires': [ - 'python-dateutil >= 2' if PY3 else 'python-dateutil', + 'python-dateutil >= 2.5.0', 'pytz >= 2011k', 'numpy >= {numpy_ver}'.format(numpy_ver=min_numpy_ver), ], From a0730b567cf5ed2de7f9550bf88c3e163d6b8a6d Mon Sep 17 00:00:00 2001 From: Jeff Reback Date: Mon, 4 Dec 2017 06:34:56 -0500 Subject: [PATCH 7/7] edit whatsnew --- doc/source/whatsnew/v0.22.0.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/doc/source/whatsnew/v0.22.0.txt b/doc/source/whatsnew/v0.22.0.txt index 97aff73e8e5fc..5e605ecb7d8d5 100644 --- a/doc/source/whatsnew/v0.22.0.txt +++ b/doc/source/whatsnew/v0.22.0.txt @@ -103,9 +103,6 @@ If installed, we now require: | openpyxl | 2.4.0 | | +-----------------+-----------------+----------+ -- :func:`Series.fillna` now raises a ``TypeError`` instead of a ``ValueError`` when passed a list, tuple or DataFrame as a ``value`` (:issue:`18293`) - -