diff --git a/pandas/_libs/index.pyx b/pandas/_libs/index.pyx index 42ba0c1cadaec..7e48c7d94ccf0 100644 --- a/pandas/_libs/index.pyx +++ b/pandas/_libs/index.pyx @@ -24,6 +24,8 @@ from datetime import datetime, timedelta from datetime cimport (get_datetime64_value, _pydatetime_to_dts, pandas_datetimestruct) +from tslibs.timezones cimport _get_utcoffset, _is_utc + from cpython cimport PyTuple_Check, PyList_Check cdef extern from "datetime.h": @@ -554,14 +556,11 @@ cdef inline _to_i8(object val): # Save the original date value so we can get the utcoffset from it. ival = _pydatetime_to_dts(val, &dts) if tzinfo is not None and not _is_utc(tzinfo): - offset = tslib._get_utcoffset(tzinfo, val) + offset = _get_utcoffset(tzinfo, val) ival -= tslib._delta_to_nanoseconds(offset) return ival return val -cdef inline bint _is_utc(object tz): - return tz is UTC or isinstance(tz, _du_utc) - cdef class MultiIndexObjectEngine(ObjectEngine): """ diff --git a/pandas/_libs/period.pyx b/pandas/_libs/period.pyx index 816b7ebfff86d..114d43cbab5e4 100644 --- a/pandas/_libs/period.pyx +++ b/pandas/_libs/period.pyx @@ -31,14 +31,15 @@ cimport util, lib from lib cimport is_null_datetimelike, is_period from pandas._libs import tslib, lib -from pandas._libs.tslib import (Timedelta, Timestamp, iNaT, - NaT, _get_utcoffset) -from tslib cimport ( - maybe_get_tz, - _is_utc, - _is_tzlocal, +from pandas._libs.tslib import Timedelta, Timestamp, iNaT, NaT +from tslib cimport _nat_scalar_rules + +from tslibs.timezones cimport ( + _get_utcoffset, _get_dst_info, - _nat_scalar_rules) + _is_tzlocal, + _is_utc, + maybe_get_tz) from pandas.tseries import offsets from pandas.core.tools.datetimes import parse_time_string @@ -116,6 +117,7 @@ cdef extern from "period_helper.h": initialize_daytime_conversion_factor_matrix() + # Period logic #---------------------------------------------------------------------- diff --git a/pandas/_libs/tslib.pxd b/pandas/_libs/tslib.pxd index aa8cbcb2cedc7..ee8adfe67bb5e 100644 --- a/pandas/_libs/tslib.pxd +++ b/pandas/_libs/tslib.pxd @@ -2,9 +2,5 @@ from numpy cimport ndarray, int64_t cdef convert_to_tsobject(object, object, object, bint, bint) cpdef convert_to_timedelta64(object, object) -cpdef object maybe_get_tz(object) -cdef bint _is_utc(object) -cdef bint _is_tzlocal(object) -cdef object _get_dst_info(object) cdef bint _nat_scalar_rules[6] cdef bint _check_all_nulls(obj) diff --git a/pandas/_libs/tslib.pyx b/pandas/_libs/tslib.pyx index b5aca2e3ec309..1f72ccbee6568 100644 --- a/pandas/_libs/tslib.pyx +++ b/pandas/_libs/tslib.pyx @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # cython: profile=False import warnings @@ -33,6 +34,13 @@ from util cimport (is_integer_object, is_float_object, is_datetime64_object, is_timedelta64_object, INT64_MAX) cimport util +cdef extern from "datetime.h": + bint PyDateTime_Check(object o) + bint PyDate_Check(object o) + void PyDateTime_IMPORT() + +from datetime cimport datetime, timedelta + # this is our datetime.pxd from datetime cimport ( pandas_datetimestruct, @@ -50,12 +58,34 @@ from datetime cimport ( npy_datetime, is_leapyear, dayofweek, - PANDAS_FR_ns, - PyDateTime_Check, PyDate_Check, - PyDateTime_IMPORT, - timedelta, datetime + PANDAS_FR_ns ) +from tslibs.timezones import ( + tzoffset, + _dateutil_gettz, + _dateutil_tzlocal, + _dateutil_tzfile, + _dateutil_tzutc, + maybe_get_tz, + _get_utcoffset, + _unbox_utcoffsets, + get_timezone, + _p_tz_cache_key) +from tslibs.timezones cimport ( + _is_utc, + maybe_get_tz, + _is_tzlocal, + _get_dst_info, + _get_utcoffset, + _unbox_utcoffsets, + _is_fixed_offset, + _get_zone, + _get_utc_trans_times_from_dateutil_tz, + _tz_cache_key, + _treat_tz_as_pytz, + _treat_tz_as_dateutil) + # stdlib datetime imports from datetime import timedelta, datetime from datetime import time as datetime_time @@ -71,26 +101,16 @@ cimport cython import re # dateutil compat -from dateutil.tz import (tzoffset, tzlocal as _dateutil_tzlocal, - tzfile as _dateutil_tzfile, - tzutc as _dateutil_tzutc, - tzstr as _dateutil_tzstr) - -from pandas.compat import is_platform_windows -if is_platform_windows(): - from dateutil.zoneinfo import gettz as _dateutil_gettz -else: - from dateutil.tz import gettz as _dateutil_gettz +from dateutil.tz import tzstr as _dateutil_tzstr + from dateutil.relativedelta import relativedelta from dateutil.parser import DEFAULTPARSER -from pytz.tzinfo import BaseTzInfo as _pytz_BaseTzInfo from pandas.compat import (parse_date, string_types, iteritems, StringIO, callable) import operator import collections -import warnings # initialize numpy import_array() @@ -232,24 +252,6 @@ def ints_to_pytimedelta(ndarray[int64_t] arr, box=False): return result -cdef inline bint _is_tzlocal(object tz): - return isinstance(tz, _dateutil_tzlocal) - - -cdef inline bint _is_fixed_offset(object tz): - if _treat_tz_as_dateutil(tz): - if len(tz._trans_idx) == 0 and len(tz._trans_list) == 0: - return 1 - else: - return 0 - elif _treat_tz_as_pytz(tz): - if (len(tz._transition_info) == 0 - and len(tz._utc_transition_times) == 0): - return 1 - else: - return 0 - return 1 - _zero_time = datetime_time(0, 0) _no_input = object() @@ -1429,11 +1431,6 @@ cdef class _TSObject: def __get__(self): return self.value -cpdef _get_utcoffset(tzinfo, obj): - try: - return tzinfo._utcoffset - except AttributeError: - return tzinfo.utcoffset(obj) # helper to extract datetime and int64 from several different possibilities cdef convert_to_tsobject(object ts, object tz, object unit, @@ -1698,71 +1695,6 @@ def _localize_pydatetime(object dt, object tz): return dt.replace(tzinfo=tz) -def get_timezone(tz): - return _get_zone(tz) - -cdef inline bint _is_utc(object tz): - return tz is UTC or isinstance(tz, _dateutil_tzutc) - -cdef inline object _get_zone(object tz): - """ - We need to do several things here: - 1) Distinguish between pytz and dateutil timezones - 2) Not be over-specific (e.g. US/Eastern with/without DST is same *zone* - but a different tz object) - 3) Provide something to serialize when we're storing a datetime object - in pytables. - - We return a string prefaced with dateutil if it's a dateutil tz, else just - the tz name. It needs to be a string so that we can serialize it with - UJSON/pytables. maybe_get_tz (below) is the inverse of this process. - """ - if _is_utc(tz): - return 'UTC' - else: - if _treat_tz_as_dateutil(tz): - if '.tar.gz' in tz._filename: - raise ValueError( - 'Bad tz filename. Dateutil on python 3 on windows has a ' - 'bug which causes tzfile._filename to be the same for all ' - 'timezone files. Please construct dateutil timezones ' - 'implicitly by passing a string like "dateutil/Europe' - '/London" when you construct your pandas objects instead ' - 'of passing a timezone object. See ' - 'https://github.com/pandas-dev/pandas/pull/7362') - return 'dateutil/' + tz._filename - else: - # tz is a pytz timezone or unknown. - try: - zone = tz.zone - if zone is None: - return tz - return zone - except AttributeError: - return tz - - -cpdef inline object maybe_get_tz(object tz): - """ - (Maybe) Construct a timezone object from a string. If tz is a string, use - it to construct a timezone object. Otherwise, just return tz. - """ - if isinstance(tz, string_types): - if tz == 'tzlocal()': - tz = _dateutil_tzlocal() - elif tz.startswith('dateutil/'): - zone = tz[9:] - tz = _dateutil_gettz(zone) - # On Python 3 on Windows, the filename is not always set correctly. - if isinstance(tz, _dateutil_tzfile) and '.tar.gz' in tz._filename: - tz._filename = zone - else: - tz = pytz.timezone(tz) - elif is_integer_object(tz): - tz = pytz.FixedOffset(tz / 60) - return tz - - class OutOfBoundsDatetime(ValueError): pass @@ -4081,6 +4013,7 @@ def pydt_to_i8(object pydt): return ts.value +# TODO: Never used? def i8_to_pydt(int64_t i8, object tzinfo = None): """ Inverse of pydt_to_i8 @@ -4271,148 +4204,6 @@ def tz_convert_single(int64_t val, object tz1, object tz2): offset = deltas[pos] return utc_date + offset -# Timezone data caches, key is the pytz string or dateutil file name. -dst_cache = {} - -cdef inline bint _treat_tz_as_pytz(object tz): - return hasattr(tz, '_utc_transition_times') and hasattr( - tz, '_transition_info') - -cdef inline bint _treat_tz_as_dateutil(object tz): - return hasattr(tz, '_trans_list') and hasattr(tz, '_trans_idx') - - -def _p_tz_cache_key(tz): - """ Python interface for cache function to facilitate testing.""" - return _tz_cache_key(tz) - - -cdef inline object _tz_cache_key(object tz): - """ - Return the key in the cache for the timezone info object or None - if unknown. - - The key is currently the tz string for pytz timezones, the filename for - dateutil timezones. - - Notes - ===== - This cannot just be the hash of a timezone object. Unfortunately, the - hashes of two dateutil tz objects which represent the same timezone are - not equal (even though the tz objects will compare equal and represent - the same tz file). Also, pytz objects are not always hashable so we use - str(tz) instead. - """ - if isinstance(tz, _pytz_BaseTzInfo): - return tz.zone - elif isinstance(tz, _dateutil_tzfile): - if '.tar.gz' in tz._filename: - raise ValueError('Bad tz filename. Dateutil on python 3 on ' - 'windows has a bug which causes tzfile._filename ' - 'to be the same for all timezone files. Please ' - 'construct dateutil timezones implicitly by ' - 'passing a string like "dateutil/Europe/London" ' - 'when you construct your pandas objects instead ' - 'of passing a timezone object. See ' - 'https://github.com/pandas-dev/pandas/pull/7362') - return 'dateutil' + tz._filename - else: - return None - - -cdef object _get_dst_info(object tz): - """ - return a tuple of : - (UTC times of DST transitions, - UTC offsets in microseconds corresponding to DST transitions, - string of type of transitions) - - """ - cache_key = _tz_cache_key(tz) - if cache_key is None: - num = int(_get_utcoffset(tz, None).total_seconds()) * 1000000000 - return (np.array([NPY_NAT + 1], dtype=np.int64), - np.array([num], dtype=np.int64), - None) - - if cache_key not in dst_cache: - if _treat_tz_as_pytz(tz): - trans = np.array(tz._utc_transition_times, dtype='M8[ns]') - trans = trans.view('i8') - try: - if tz._utc_transition_times[0].year == 1: - trans[0] = NPY_NAT + 1 - except Exception: - pass - deltas = _unbox_utcoffsets(tz._transition_info) - typ = 'pytz' - - elif _treat_tz_as_dateutil(tz): - if len(tz._trans_list): - # get utc trans times - trans_list = _get_utc_trans_times_from_dateutil_tz(tz) - trans = np.hstack([ - np.array([0], dtype='M8[s]'), # place holder for first item - np.array(trans_list, dtype='M8[s]')]).astype( - 'M8[ns]') # all trans listed - trans = trans.view('i8') - trans[0] = NPY_NAT + 1 - - # deltas - deltas = np.array([v.offset for v in ( - tz._ttinfo_before,) + tz._trans_idx], dtype='i8') - deltas *= 1000000000 - typ = 'dateutil' - - elif _is_fixed_offset(tz): - trans = np.array([NPY_NAT + 1], dtype=np.int64) - deltas = np.array([tz._ttinfo_std.offset], - dtype='i8') * 1000000000 - typ = 'fixed' - else: - trans = np.array([], dtype='M8[ns]') - deltas = np.array([], dtype='i8') - typ = None - - else: - # static tzinfo - trans = np.array([NPY_NAT + 1], dtype=np.int64) - num = int(_get_utcoffset(tz, None).total_seconds()) * 1000000000 - deltas = np.array([num], dtype=np.int64) - typ = 'static' - - dst_cache[cache_key] = (trans, deltas, typ) - - return dst_cache[cache_key] - -cdef object _get_utc_trans_times_from_dateutil_tz(object tz): - """ - Transition times in dateutil timezones are stored in local non-dst - time. This code converts them to UTC. It's the reverse of the code - in dateutil.tz.tzfile.__init__. - """ - new_trans = list(tz._trans_list) - last_std_offset = 0 - for i, (trans, tti) in enumerate(zip(tz._trans_list, tz._trans_idx)): - if not tti.isdst: - last_std_offset = tti.offset - new_trans[i] = trans - last_std_offset - return new_trans - - -cpdef ndarray _unbox_utcoffsets(object transinfo): - cdef: - Py_ssize_t i, sz - ndarray[int64_t] arr - - sz = len(transinfo) - arr = np.empty(sz, dtype='i8') - - for i in range(sz): - arr[i] = int(transinfo[i][0].total_seconds()) * 1000000000 - - return arr - @cython.boundscheck(False) @cython.wraparound(False) diff --git a/pandas/_libs/tslibs/__init__.py b/pandas/_libs/tslibs/__init__.py new file mode 100644 index 0000000000000..6ffc2a84242e8 --- /dev/null +++ b/pandas/_libs/tslibs/__init__.py @@ -0,0 +1,3 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# cython: profile=False diff --git a/pandas/_libs/tslibs/timezones.pxd b/pandas/_libs/tslibs/timezones.pxd new file mode 100644 index 0000000000000..59efb24600966 --- /dev/null +++ b/pandas/_libs/tslibs/timezones.pxd @@ -0,0 +1,20 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# cython: profile=False + +from numpy cimport ndarray, float64_t + +cdef object _get_zone(object tz) +cdef object _tz_cache_key(object tz) +cdef bint _is_utc(object tz) +cdef bint _is_tzlocal(object tz) +cdef bint _treat_tz_as_pytz(object tz) +cdef bint _treat_tz_as_dateutil(object tz) +cpdef object maybe_get_tz(object tz) + +cpdef _get_utcoffset(tzinfo, obj) +cpdef ndarray _unbox_utcoffsets(object transinfo) +cdef bint _is_fixed_offset(object tz) +cdef object _get_utc_trans_times_from_dateutil_tz(object tz) + +cpdef object _get_dst_info(object tz) diff --git a/pandas/_libs/tslibs/timezones.pyx b/pandas/_libs/tslibs/timezones.pyx new file mode 100644 index 0000000000000..4d78e83e31101 --- /dev/null +++ b/pandas/_libs/tslibs/timezones.pyx @@ -0,0 +1,301 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# cython: profile=False + +from pandas.compat import string_types, is_platform_windows + + +cdef extern from "Python.h": + Py_ssize_t PY_SSIZE_T_MAX + +cdef extern from "datetime.h": + void PyDateTime_IMPORT() + +# import datetime C API +PyDateTime_IMPORT + + +import numpy as np +cimport numpy as np +from numpy cimport ndarray, int64_t, float64_t +np.import_array() + + +# dateutil compat +from dateutil.tz import (tzoffset, + tzlocal as _dateutil_tzlocal, + tzfile as _dateutil_tzfile, + tzutc as _dateutil_tzutc, + tzstr as _dateutil_tzstr) + +if is_platform_windows(): + from dateutil.zoneinfo import gettz as _dateutil_gettz +else: + from dateutil.tz import gettz as _dateutil_gettz + + +from pytz.tzinfo import BaseTzInfo as _pytz_BaseTzInfo +import pytz +UTC = pytz.utc + + +from cpython cimport PyBool_Check +cdef extern from "numpy/ndarrayobject.h": + bint PyArray_IsIntegerScalar(object) + +cdef inline bint is_integer_object(object obj): + # Ported from util (which gets it from numpy_helper) to avoid + # direct dependency + return (not PyBool_Check(obj)) and PyArray_IsIntegerScalar(obj) + + +cdef int64_t NPY_NAT = np.datetime64('nat').astype(np.int64) + + +#---------------------------------------------------------------------- +# time zone conversion helpers + +def get_timezone(tz): + return _get_zone(tz) + + +cdef bint _is_utc(object tz): + return tz is UTC or isinstance(tz, _dateutil_tzutc) + + +cdef bint _is_tzlocal(object tz): + return isinstance(tz, _dateutil_tzlocal) + + +cdef bint _treat_tz_as_pytz(object tz): + return (hasattr(tz, '_utc_transition_times') and + hasattr(tz, '_transition_info')) + + +cdef bint _treat_tz_as_dateutil(object tz): + return hasattr(tz, '_trans_list') and hasattr(tz, '_trans_idx') + + +cdef object _get_zone(object tz): + """ + We need to do several things here: + 1) Distinguish between pytz and dateutil timezones + 2) Not be over-specific (e.g. US/Eastern with/without DST is same *zone* + but a different tz object) + 3) Provide something to serialize when we're storing a datetime object + in pytables. + + We return a string prefaced with dateutil if it's a dateutil tz, else just + the tz name. It needs to be a string so that we can serialize it with + UJSON/pytables. maybe_get_tz (below) is the inverse of this process. + """ + if _is_utc(tz): + return 'UTC' + else: + if _treat_tz_as_dateutil(tz): + if '.tar.gz' in tz._filename: + raise ValueError( + 'Bad tz filename. Dateutil on python 3 on windows has a ' + 'bug which causes tzfile._filename to be the same for all ' + 'timezone files. Please construct dateutil timezones ' + 'implicitly by passing a string like "dateutil/Europe' + '/London" when you construct your pandas objects instead ' + 'of passing a timezone object. See ' + 'https://github.com/pandas-dev/pandas/pull/7362') + return 'dateutil/' + tz._filename + # TODO: use os.path.join? + else: + # tz is a pytz timezone or unknown. + try: + zone = tz.zone + if zone is None: + return tz + return zone + except AttributeError: + return tz + + +cpdef object maybe_get_tz(object tz): + """ + (Maybe) Construct a timezone object from a string. If tz is a string, use + it to construct a timezone object. Otherwise, just return tz. + """ + if isinstance(tz, string_types): + if tz == 'tzlocal()': + tz = _dateutil_tzlocal() + elif tz.startswith('dateutil/'): + zone = tz[9:] + tz = _dateutil_gettz(zone) + # On Python 3 on Windows, the filename is not always set correctly. + if isinstance(tz, _dateutil_tzfile) and '.tar.gz' in tz._filename: + tz._filename = zone + else: + tz = pytz.timezone(tz) + elif is_integer_object(tz): + tz = pytz.FixedOffset(tz / 60) + return tz + + +def _p_tz_cache_key(tz): + """ Python interface for cache function to facilitate testing.""" + return _tz_cache_key(tz) + + +cdef object _tz_cache_key(object tz): + """ + Return the key in the cache for the timezone info object or None + if unknown. + + The key is currently the tz string for pytz timezones, the filename for + dateutil timezones. + + Notes + ===== + This cannot just be the hash of a timezone object. Unfortunately, the + hashes of two dateutil tz objects which represent the same timezone are + not equal (even though the tz objects will compare equal and represent + the same tz file). Also, pytz objects are not always hashable so we use + str(tz) instead. + """ + if isinstance(tz, _pytz_BaseTzInfo): + return tz.zone + elif isinstance(tz, _dateutil_tzfile): + if '.tar.gz' in tz._filename: + raise ValueError('Bad tz filename. Dateutil on python 3 on ' + 'windows has a bug which causes tzfile._filename ' + 'to be the same for all timezone files. Please ' + 'construct dateutil timezones implicitly by ' + 'passing a string like "dateutil/Europe/London" ' + 'when you construct your pandas objects instead ' + 'of passing a timezone object. See ' + 'https://github.com/pandas-dev/pandas/pull/7362') + return 'dateutil' + tz._filename + else: + return None + + +#---------------------------------------------------------------------- +# UTC Offsets + +cpdef _get_utcoffset(tzinfo, obj): + try: + return tzinfo._utcoffset + except AttributeError: + return tzinfo.utcoffset(obj) + + +cpdef ndarray _unbox_utcoffsets(object transinfo): + cdef: + Py_ssize_t i, sz + ndarray[int64_t] arr + + sz = len(transinfo) + arr = np.empty(sz, dtype='i8') + + for i in range(sz): + arr[i] = int(transinfo[i][0].total_seconds()) * 1000000000 + + return arr + + +cdef bint _is_fixed_offset(object tz): + if _treat_tz_as_dateutil(tz): + if len(tz._trans_idx) == 0 and len(tz._trans_list) == 0: + return 1 + else: + return 0 + elif _treat_tz_as_pytz(tz): + if (len(tz._transition_info) == 0 + and len(tz._utc_transition_times) == 0): + return 1 + else: + return 0 + return 1 + + +cdef object _get_utc_trans_times_from_dateutil_tz(object tz): + """ + Transition times in dateutil timezones are stored in local non-dst + time. This code converts them to UTC. It's the reverse of the code + in dateutil.tz.tzfile.__init__. + """ + new_trans = list(tz._trans_list) + last_std_offset = 0 + for i, (trans, tti) in enumerate(zip(tz._trans_list, tz._trans_idx)): + if not tti.isdst: + last_std_offset = tti.offset + new_trans[i] = trans - last_std_offset + return new_trans + + +#---------------------------------------------------------------------- +# Daylight Savings + +# Timezone data caches, key is the pytz string or dateutil file name. +dst_cache = {} + +# TODO: go back to just cdef +cpdef object _get_dst_info(object tz): + """ + return a tuple of : + (UTC times of DST transitions, + UTC offsets in microseconds corresponding to DST transitions, + string of type of transitions) + + """ + cache_key = _tz_cache_key(tz) + if cache_key is None: + num = int(_get_utcoffset(tz, None).total_seconds()) * 1000000000 + return (np.array([NPY_NAT + 1], dtype=np.int64), + np.array([num], dtype=np.int64), + None) + + if cache_key not in dst_cache: + if _treat_tz_as_pytz(tz): + trans = np.array(tz._utc_transition_times, dtype='M8[ns]') + trans = trans.view('i8') + try: + if tz._utc_transition_times[0].year == 1: + trans[0] = NPY_NAT + 1 + except Exception: + pass + deltas = _unbox_utcoffsets(tz._transition_info) + typ = 'pytz' + + elif _treat_tz_as_dateutil(tz): + if len(tz._trans_list): + # get utc trans times + trans_list = _get_utc_trans_times_from_dateutil_tz(tz) + trans = np.hstack([ + np.array([0], dtype='M8[s]'), # place holder for first item + np.array(trans_list, dtype='M8[s]')]).astype( + 'M8[ns]') # all trans listed + trans = trans.view('i8') + trans[0] = NPY_NAT + 1 + + # deltas + deltas = np.array([v.offset for v in ( + tz._ttinfo_before,) + tz._trans_idx], dtype='i8') + deltas *= 1000000000 + typ = 'dateutil' + + elif _is_fixed_offset(tz): + trans = np.array([NPY_NAT + 1], dtype=np.int64) + deltas = np.array([tz._ttinfo_std.offset], + dtype='i8') * 1000000000 + typ = 'fixed' + else: + trans = np.array([], dtype='M8[ns]') + deltas = np.array([], dtype='i8') + typ = None + + else: + # static tzinfo + trans = np.array([NPY_NAT + 1], dtype=np.int64) + num = int(_get_utcoffset(tz, None).total_seconds()) * 1000000000 + deltas = np.array([num], dtype=np.int64) + typ = 'static' + + dst_cache[cache_key] = (trans, deltas, typ) + + return dst_cache[cache_key] diff --git a/setup.py b/setup.py index 444db5bc4d275..d21df49fe065f 100755 --- a/setup.py +++ b/setup.py @@ -341,6 +341,7 @@ class CheckSDist(sdist_class): 'pandas/_libs/window.pyx', 'pandas/_libs/sparse.pyx', 'pandas/_libs/parsers.pyx', + 'pandas/_libs/tslibs/timezones.pyx', 'pandas/io/sas/sas.pyx'] def initialize_options(self): @@ -483,12 +484,14 @@ def pxd(name): + _pxi_dep['hashtable'])}, '_libs.tslib': {'pyxfile': '_libs/tslib', 'pxdfiles': ['_libs/src/util', '_libs/lib'], - 'depends': tseries_depends, + 'depends': tseries_depends + \ + ['pandas/_libs/tslibs/timezones.pyx'], 'sources': ['pandas/_libs/src/datetime/np_datetime.c', 'pandas/_libs/src/datetime/np_datetime_strings.c', 'pandas/_libs/src/period_helper.c']}, '_libs.period': {'pyxfile': '_libs/period', - 'depends': tseries_depends, + 'depends': tseries_depends + \ + ['pandas/_libs/tslibs/timezones.pyx'], 'sources': ['pandas/_libs/src/datetime/np_datetime.c', 'pandas/_libs/src/datetime/np_datetime_strings.c', 'pandas/_libs/src/period_helper.c']}, @@ -496,7 +499,8 @@ def pxd(name): 'sources': ['pandas/_libs/src/datetime/np_datetime.c', 'pandas/_libs/src/datetime/np_datetime_strings.c'], 'pxdfiles': ['_libs/src/util', '_libs/hashtable'], - 'depends': _pxi_dep['index']}, + 'depends': _pxi_dep['index'] + \ + ['pandas/_libs/tslibs/timezones.pyx']}, '_libs.algos': {'pyxfile': '_libs/algos', 'pxdfiles': ['_libs/src/util', '_libs/algos', '_libs/hashtable'], 'depends': _pxi_dep['algos']}, @@ -528,6 +532,7 @@ def pxd(name): 'depends': ['pandas/_libs/testing.pyx']}, '_libs.hashing': {'pyxfile': '_libs/hashing', 'depends': ['pandas/_libs/hashing.pyx']}, + '_libs.tslibs.timezones': {'pyxfile': '_libs/tslibs/timezones'}, 'io.sas._sas': {'pyxfile': 'io/sas/sas'}, }