Skip to content

Pytzectomy #11360

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Jul 9, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ exclude =
versioneer.py
tools/gh_api.py
tools/github_stats.py
.tox
.eggs

per-file-ignores =
setup.py: E402
Expand Down
4 changes: 4 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -158,14 +158,18 @@ before_script: |
fi

script:
# each script we want to run need to go in it's own section and the program you want
# to fail travis need to be the last thing called
- |
echo "Calling pytest with the following arguments: $PYTEST_ADDOPTS"
python -mpytest
- tox -e pytz
- |
if [[ $RUN_FLAKE8 == 1 ]]; then
flake8 --statistics && echo "Flake8 passed without any issues!"
fi


before_cache: |
rm -rf $HOME/.cache/matplotlib/tex.cache
rm -rf $HOME/.cache/matplotlib/test_cache
Expand Down
1 change: 0 additions & 1 deletion INSTALL.rst
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,6 @@ Matplotlib requires the following dependencies:
* `dateutil <https://pypi.python.org/pypi/python-dateutil>`_ (>= 2.1)
* `kiwisolver <https://github.com/nucleic/kiwi>`_ (>= 1.0.0)
* `pyparsing <https://pyparsing.wikispaces.com/>`_
* `pytz <http://pytz.sourceforge.net/>`_

Optionally, you can also install a number of packages to enable better user
interface toolkits. See :ref:`what-is-a-backend` for more details on the
Expand Down
2 changes: 1 addition & 1 deletion build_alllocal.cmd
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
:: This assumes you have installed all the dependencies via conda packages:
:: # create a new environment with the required packages
:: conda create -n "matplotlib_build" python=3.5 numpy python-dateutil pyparsing pytz tornado cycler tk libpng zlib freetype
:: conda create -n "matplotlib_build" python=3.5 numpy python-dateutil pyparsing tornado cycler tk libpng zlib freetype
:: activate matplotlib_build
:: if you want qt backend, you also have to install pyqt
:: conda install pyqt
Expand Down
4 changes: 4 additions & 0 deletions doc/api/next_api_changes/2018-06-01-PG-pytz-ectomy.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Removed ``pytz`` as a dependency
--------------------------------

Since ``dateutil`` and ``pytz`` both provide time zones, and matplotlib already depends on ``dateutil``, matplotlib will now use ``dateutil`` time zones internally and drop the redundant dependency on ``pytz``. While ``dateutil`` time zones are preferred (and currently recommended in the Python documentation), the explicit use of ``pytz`` zones is still supported.
6 changes: 0 additions & 6 deletions doc/glossary/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,6 @@ Glossary
language widely used for scripting, application development, web
application servers, scientific computing and more.

pytz
`pytz <http://pythonhosted.org/pytz/>`_ provides the Olson tz
database in Python. it allows accurate and cross platform
timezone calculations and solves the issue of ambiguous times at
the end of daylight savings

Qt
`Qt <https://www.qt.io/>`__ is a cross-platform
application framework for desktop and embedded development.
Expand Down
4 changes: 2 additions & 2 deletions lib/matplotlib/axis.py
Original file line number Diff line number Diff line change
Expand Up @@ -1747,8 +1747,8 @@ def axis_date(self, tz=None):
# the registered converter can be selected, and the "units" attribute,
# which is the timezone, can be set.
if isinstance(tz, str):
import pytz
tz = pytz.timezone(tz)
import dateutil.tz
tz = dateutil.tz.gettz(tz)
self.update_units(datetime.datetime(2009, 1, 1, 0, 0, 0, 0, tz))

def get_tick_space(self):
Expand Down
33 changes: 7 additions & 26 deletions lib/matplotlib/dates.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
"""
Matplotlib provides sophisticated date plotting capabilities, standing on the
shoulders of python :mod:`datetime`, the add-on modules :mod:`pytz` and
:mod:`dateutil`.
shoulders of python :mod:`datetime` and the add-on module :mod:`dateutil`.


.. _date-format:
Expand Down Expand Up @@ -46,19 +45,17 @@

All the Matplotlib date converters, tickers and formatters are timezone aware.
If no explicit timezone is provided, the rcParam ``timezone`` is assumend. If
you want to use a custom time zone, pass a :class:`pytz.timezone` instance
you want to use a custom time zone, pass a :class:`datetime.tzinfo` instance
with the tz keyword argument to :func:`num2date`, :func:`.plot_date`, and any
custom date tickers or locators you create.
See `pytz <http://pythonhosted.org/pytz/>`_ for information on :mod:`pytz` and
timezone handling.

A wide range of specific and general purpose date tick locators and
formatters are provided in this module. See
:mod:`matplotlib.ticker` for general information on tick locators
and formatters. These are described below.


The `dateutil module <https://dateutil.readthedocs.io/en/stable/>`_ provides
The `dateutil module <https://dateutil.readthedocs.io>`_ provides
additional code to handle date ticking, making it easy to place ticks
on any kinds of dates. See examples below.

Expand Down Expand Up @@ -110,7 +107,7 @@
:class:`matplotlib.dates.rrulewrapper`. The
:class:`rrulewrapper` is a simple wrapper around a
:class:`dateutil.rrule` (`dateutil
<https://dateutil.readthedocs.io/en/stable/>`_) which allow almost
<https://dateutil.readthedocs.io>`_) which allow almost
arbitrary date tick specifications. See `rrule example
<../gallery/ticks_and_spines/date_demo_rrule.html>`_.

Expand Down Expand Up @@ -149,6 +146,7 @@
SECONDLY)
from dateutil.relativedelta import relativedelta
import dateutil.parser
import dateutil.tz
import numpy as np

import matplotlib
Expand All @@ -175,23 +173,7 @@
_log = logging.getLogger(__name__)


# Make a simple UTC instance so we don't always have to import
# pytz. From the python datetime library docs:

class _UTC(datetime.tzinfo):
"""UTC"""

def utcoffset(self, dt):
return datetime.timedelta(0)

def tzname(self, dt):
return "UTC"

def dst(self, dt):
return datetime.timedelta(0)


UTC = _UTC()
UTC = datetime.timezone.utc


def _get_rc_timezone():
Expand All @@ -201,8 +183,7 @@ def _get_rc_timezone():
s = matplotlib.rcParams['timezone']
if s == 'UTC':
return UTC
import pytz
return pytz.timezone(s)
return dateutil.tz.gettz(s)


"""
Expand Down
1 change: 1 addition & 0 deletions lib/matplotlib/sphinxext/tests/test_tinypages.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@


def test_tinypages(tmpdir):
pytest.importorskip('sphinx')
html_dir = pjoin(str(tmpdir), 'html')
doctree_dir = pjoin(str(tmpdir), 'doctrees')
# Build the pages with warnings turned into errors
Expand Down
17 changes: 10 additions & 7 deletions lib/matplotlib/tests/test_axes.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import datetime

import pytz
import dateutil.tz as dutz

import numpy as np
from numpy import ma
Expand Down Expand Up @@ -5331,8 +5331,9 @@ def test_bar_uint8():
@image_comparison(baseline_images=['date_timezone_x'], extensions=['png'])
def test_date_timezone_x():
# Tests issue 5575
time_index = [pytz.timezone('Canada/Eastern').localize(datetime.datetime(
year=2016, month=2, day=22, hour=x)) for x in range(3)]
time_index = [datetime.datetime(2016, 2, 22, hour=x,
tzinfo=dutz.gettz('Canada/Eastern'))
for x in range(3)]

# Same Timezone
fig = plt.figure(figsize=(20, 12))
Expand All @@ -5348,8 +5349,9 @@ def test_date_timezone_x():
extensions=['png'])
def test_date_timezone_y():
# Tests issue 5575
time_index = [pytz.timezone('Canada/Eastern').localize(datetime.datetime(
year=2016, month=2, day=22, hour=x)) for x in range(3)]
time_index = [datetime.datetime(2016, 2, 22, hour=x,
tzinfo=dutz.gettz('Canada/Eastern'))
for x in range(3)]

# Same Timezone
fig = plt.figure(figsize=(20, 12))
Expand All @@ -5366,8 +5368,9 @@ def test_date_timezone_y():
extensions=['png'])
def test_date_timezone_x_and_y():
# Tests issue 5575
time_index = [pytz.timezone('UTC').localize(datetime.datetime(
year=2016, month=2, day=22, hour=x)) for x in range(3)]
UTC = datetime.timezone.utc
time_index = [datetime.datetime(2016, 2, 22, hour=x, tzinfo=UTC)
for x in range(3)]

# Same Timezone
fig = plt.figure(figsize=(20, 12))
Expand Down
44 changes: 34 additions & 10 deletions lib/matplotlib/tests/test_dates.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,25 @@
import tempfile
from unittest.mock import Mock

import dateutil
import dateutil.tz
import dateutil.rrule
import numpy as np
import pytest
import pytz

from matplotlib.testing.decorators import image_comparison
import matplotlib.pyplot as plt
from matplotlib.cbook import MatplotlibDeprecationWarning
import matplotlib.dates as mdates


def __has_pytz():
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

double underscore seems a bit overkill

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have no strong preference here. I think I used double underscore because I intended it to be ephemeral. I think maybe I should switch it to:

def __has_pytz():
    ...
HAS_PYTZ = __has_pytz()
del __has_pytz()

We can drop the del line and switch to a single underscore if that's preferred style.

try:
import pytz
return True
except ImportError:
return False
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, disturbing that this line isn't being hit. Something is indirectly pulling in a pytz dependency in the main test suite.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the problem is pandas. I was under the impression that the pandas integration tests were being run separately from the main test suite. If that's no longer the case, then this is a bit of a problem, since you could have implicit dependencies on any of the pandas dependencies.



def test_date_numpyx():
# test that numpy dates work properly...
base = datetime.datetime(2017, 1, 1)
Expand Down Expand Up @@ -180,8 +188,8 @@ def test_RRuleLocator():

def test_RRuleLocator_dayrange():
loc = mdates.DayLocator()
x1 = datetime.datetime(year=1, month=1, day=1, tzinfo=pytz.UTC)
y1 = datetime.datetime(year=1, month=1, day=16, tzinfo=pytz.UTC)
x1 = datetime.datetime(year=1, month=1, day=1, tzinfo=mdates.UTC)
y1 = datetime.datetime(year=1, month=1, day=16, tzinfo=mdates.UTC)
loc.tick_values(x1, y1)
# On success, no overflow error shall be thrown

Expand Down Expand Up @@ -482,8 +490,8 @@ def test_date_inverted_limit():

def _test_date2num_dst(date_range, tz_convert):
# Timezones
BRUSSELS = pytz.timezone('Europe/Brussels')
UTC = pytz.UTC
BRUSSELS = dateutil.tz.gettz('Europe/Brussels')
UTC = mdates.UTC

# Create a list of timezone-aware datetime objects in UTC
# Interval is 0b0.0000011 days, to prevent float rounding issues
Expand Down Expand Up @@ -575,10 +583,7 @@ def tz_convert(*args):
_test_date2num_dst(pd.date_range, tz_convert)


@pytest.mark.parametrize("attach_tz, get_tz", [
(lambda dt, zi: zi.localize(dt), lambda n: pytz.timezone(n)),
(lambda dt, zi: dt.replace(tzinfo=zi), lambda n: dateutil.tz.gettz(n))])
def test_rrulewrapper(attach_tz, get_tz):
def _test_rrulewrapper(attach_tz, get_tz):
SYD = get_tz('Australia/Sydney')

dtstart = attach_tz(datetime.datetime(2017, 4, 1, 0), SYD)
Expand All @@ -593,6 +598,25 @@ def test_rrulewrapper(attach_tz, get_tz):
assert act == exp


def test_rrulewrapper():
def attach_tz(dt, zi):
return dt.replace(tzinfo=zi)

_test_rrulewrapper(attach_tz, dateutil.tz.gettz)


@pytest.mark.pytz
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's this mark?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All otherwise unspecified marks are used to register a test with the mark of that name. This indicates that the decorated test uses pytz, so that you can filter out tests that require pytz (or that don't require pytz).

@pytest.mark.skipif(not __has_pytz(), reason="Requires pytz")
def test_rrulewrapper_pytz():
# Test to make sure pytz zones are supported in rrules
import pytz

def attach_tz(dt, zi):
return zi.localize(dt)

_test_rrulewrapper(attach_tz, pytz.timezone)


def test_DayLocator():
with pytest.raises(ValueError):
mdates.DayLocator(interval=-1)
Expand Down
2 changes: 1 addition & 1 deletion requirements/testing/travis_all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@ pytest-rerunfailures
pytest-timeout
pytest-xdist
python-dateutil
sphinx
tornado
tox
1 change: 0 additions & 1 deletion setupext.py
Original file line number Diff line number Diff line change
Expand Up @@ -1341,7 +1341,6 @@ def get_install_requires(self):
"kiwisolver>=1.0.1",
"pyparsing>=2.0.1,!=2.0.4,!=2.1.2,!=2.1.6",
"python-dateutil>=2.1",
"pytz",
]


Expand Down
8 changes: 8 additions & 0 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,11 @@ commands =
pytest --pyargs matplotlib
deps =
pytest

[testenv:pytz]
changedir = /tmp
commands =
pytest -m pytz {toxinidir}
deps =
pytest
pytz