Skip to content

Split+Parametrize Timedelta tests #19736

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 9 commits into from
Feb 20, 2018
217 changes: 217 additions & 0 deletions pandas/tests/scalar/timedelta/test_construction.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
# -*- coding: utf-8 -*-
from datetime import timedelta

import pytest
import numpy as np

import pandas as pd
import pandas.util.testing as tm
from pandas import Timedelta


class TestTimedeltaConstructor(object):
Copy link
Contributor

Choose a reason for hiding this comment

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

can you de-class these

Copy link
Member Author

Choose a reason for hiding this comment

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

Sure.

def test_construction(self):
expected = np.timedelta64(10, 'D').astype('m8[ns]').view('i8')
assert Timedelta(10, unit='d').value == expected
assert Timedelta(10.0, unit='d').value == expected
assert Timedelta('10 days').value == expected
assert Timedelta(days=10).value == expected
assert Timedelta(days=10.0).value == expected

expected += np.timedelta64(10, 's').astype('m8[ns]').view('i8')
assert Timedelta('10 days 00:00:10').value == expected
assert Timedelta(days=10, seconds=10).value == expected
assert Timedelta(days=10, milliseconds=10 * 1000).value == expected
assert Timedelta(days=10,
microseconds=10 * 1000 * 1000).value == expected

# rounding cases
assert Timedelta(82739999850000).value == 82739999850000
assert ('0 days 22:58:59.999850' in str(Timedelta(82739999850000)))
assert Timedelta(123072001000000).value == 123072001000000
assert ('1 days 10:11:12.001' in str(Timedelta(123072001000000)))

# string conversion with/without leading zero
# GH#9570
assert Timedelta('0:00:00') == timedelta(hours=0)
assert Timedelta('00:00:00') == timedelta(hours=0)
assert Timedelta('-1:00:00') == -timedelta(hours=1)
assert Timedelta('-01:00:00') == -timedelta(hours=1)

# more strings & abbrevs
# GH#8190
assert Timedelta('1 h') == timedelta(hours=1)
assert Timedelta('1 hour') == timedelta(hours=1)
assert Timedelta('1 hr') == timedelta(hours=1)
assert Timedelta('1 hours') == timedelta(hours=1)
assert Timedelta('-1 hours') == -timedelta(hours=1)
assert Timedelta('1 m') == timedelta(minutes=1)
assert Timedelta('1.5 m') == timedelta(seconds=90)
assert Timedelta('1 minute') == timedelta(minutes=1)
assert Timedelta('1 minutes') == timedelta(minutes=1)
assert Timedelta('1 s') == timedelta(seconds=1)
assert Timedelta('1 second') == timedelta(seconds=1)
assert Timedelta('1 seconds') == timedelta(seconds=1)
assert Timedelta('1 ms') == timedelta(milliseconds=1)
assert Timedelta('1 milli') == timedelta(milliseconds=1)
assert Timedelta('1 millisecond') == timedelta(milliseconds=1)
assert Timedelta('1 us') == timedelta(microseconds=1)
assert Timedelta('1 micros') == timedelta(microseconds=1)
assert Timedelta('1 microsecond') == timedelta(microseconds=1)
assert Timedelta('1.5 microsecond') == Timedelta('00:00:00.000001500')
assert Timedelta('1 ns') == Timedelta('00:00:00.000000001')
assert Timedelta('1 nano') == Timedelta('00:00:00.000000001')
assert Timedelta('1 nanosecond') == Timedelta('00:00:00.000000001')

# combos
assert Timedelta('10 days 1 hour') == timedelta(days=10, hours=1)
assert Timedelta('10 days 1 h') == timedelta(days=10, hours=1)
assert Timedelta('10 days 1 h 1m 1s') == timedelta(
days=10, hours=1, minutes=1, seconds=1)
assert Timedelta('-10 days 1 h 1m 1s') == -timedelta(
days=10, hours=1, minutes=1, seconds=1)
assert Timedelta('-10 days 1 h 1m 1s') == -timedelta(
days=10, hours=1, minutes=1, seconds=1)
assert Timedelta('-10 days 1 h 1m 1s 3us') == -timedelta(
days=10, hours=1, minutes=1, seconds=1, microseconds=3)
assert Timedelta('-10 days 1 h 1.5m 1s 3us') == -timedelta(
days=10, hours=1, minutes=1, seconds=31, microseconds=3)

# Currently invalid as it has a - on the hh:mm:dd part
# (only allowed on the days)
with pytest.raises(ValueError):
Timedelta('-10 days -1 h 1.5m 1s 3us')

# only leading neg signs are allowed
with pytest.raises(ValueError):
Timedelta('10 days -1 h 1.5m 1s 3us')

# no units specified
with pytest.raises(ValueError):
Timedelta('3.1415')

# invalid construction
tm.assert_raises_regex(ValueError, "cannot construct a Timedelta",
lambda: Timedelta())
tm.assert_raises_regex(ValueError,
"unit abbreviation w/o a number",
lambda: Timedelta('foo'))
tm.assert_raises_regex(ValueError,
"cannot construct a Timedelta from the "
"passed arguments, allowed keywords are ",
lambda: Timedelta(day=10))

# floats
expected = np.timedelta64(
10, 's').astype('m8[ns]').view('i8') + np.timedelta64(
500, 'ms').astype('m8[ns]').view('i8')
assert Timedelta(10.5, unit='s').value == expected

# offset
assert pd.to_timedelta(pd.offsets.Hour(2)) == Timedelta(hours=2)
assert Timedelta(pd.offsets.Hour(2)) == Timedelta(hours=2)
assert Timedelta(pd.offsets.Second(2)) == Timedelta(seconds=2)

# GH#11995: unicode
expected = Timedelta('1H')
result = pd.Timedelta(u'1H')
assert result == expected
assert (pd.to_timedelta(pd.offsets.Hour(2)) ==
Timedelta(u'0 days, 02:00:00'))

with pytest.raises(ValueError):
Timedelta(u'foo bar')

@pytest.mark.parametrize('item', list({'days': 'D',
'seconds': 's',
'microseconds': 'us',
'milliseconds': 'ms',
'minutes': 'm',
'hours': 'h',
'weeks': 'W'}.items()))
@pytest.mark.parametrize('npdtype', [np.int64, np.int32, np.int16,
np.float64, np.float32, np.float16])
def test_td_construction_with_np_dtypes(self, npdtype, item):
# GH#8757: test construction with np dtypes
pykwarg, npkwarg = item
expected = np.timedelta64(1, npkwarg).astype('m8[ns]').view('i8')
assert Timedelta(**{pykwarg: npdtype(1)}).value == expected

@pytest.mark.parametrize('val', [
'1s', '-1s', '1us', '-1us', '1 day', '-1 day',
'-23:59:59.999999', '-1 days +23:59:59.999999', '-1ns',
'1ns', '-23:59:59.999999999'])
def test_td_from_repr_roundtrip(self, val):
# round-trip both for string and value
td = Timedelta(val)
assert Timedelta(td.value) == td

# str does not normally display nanos
if not td.nanoseconds:
assert Timedelta(str(td)) == td
assert Timedelta(td._repr_base(format='all')) == td

def test_overflow_on_construction(self):
# xref https://github.com/statsmodels/statsmodels/issues/3374
value = pd.Timedelta('1day').value * 20169940
with pytest.raises(OverflowError):
pd.Timedelta(value)

# xref GH#17637
with pytest.raises(OverflowError):
pd.Timedelta(7 * 19999, unit='D')

with pytest.raises(OverflowError):
pd.Timedelta(timedelta(days=13 * 19999))

@pytest.mark.parametrize('fmt,exp', [
('P6DT0H50M3.010010012S', Timedelta(days=6, minutes=50, seconds=3,
milliseconds=10, microseconds=10,
nanoseconds=12)),
('P-6DT0H50M3.010010012S', Timedelta(days=-6, minutes=50, seconds=3,
milliseconds=10, microseconds=10,
nanoseconds=12)),
('P4DT12H30M5S', Timedelta(days=4, hours=12, minutes=30, seconds=5)),
('P0DT0H0M0.000000123S', Timedelta(nanoseconds=123)),
('P0DT0H0M0.00001S', Timedelta(microseconds=10)),
('P0DT0H0M0.001S', Timedelta(milliseconds=1)),
('P0DT0H1M0S', Timedelta(minutes=1)),
('P1DT25H61M61S', Timedelta(days=1, hours=25, minutes=61, seconds=61))
])
def test_iso_constructor(self, fmt, exp):
assert Timedelta(fmt) == exp

@pytest.mark.parametrize('fmt', [
'PPPPPPPPPPPP', 'PDTHMS', 'P0DT999H999M999S',
'P1DT0H0M0.0000000000000S', 'P1DT0H0M00000000000S',
'P1DT0H0M0.S'])
def test_iso_constructor_raises(self, fmt):
with tm.assert_raises_regex(ValueError, 'Invalid ISO 8601 Duration '
'format - {}'.format(fmt)):
Timedelta(fmt)

def test_td_constructor_on_nanoseconds(self):
# GH#9273
result = Timedelta(nanoseconds=100)
expected = Timedelta('100ns')
assert result == expected

result = Timedelta(days=1, hours=1, minutes=1, weeks=1, seconds=1,
milliseconds=1, microseconds=1, nanoseconds=1)
expected = Timedelta(694861001001001)
assert result == expected

result = Timedelta(microseconds=1) + Timedelta(nanoseconds=1)
expected = Timedelta('1us1ns')
assert result == expected

result = Timedelta(microseconds=1) - Timedelta(nanoseconds=1)
expected = Timedelta('999ns')
assert result == expected

result = Timedelta(microseconds=1) + 5 * Timedelta(nanoseconds=-2)
expected = Timedelta('990ns')
assert result == expected

with pytest.raises(TypeError):
Timedelta(nanoseconds='abc')
48 changes: 48 additions & 0 deletions pandas/tests/scalar/timedelta/test_rendering.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# -*- coding: utf-8 -*-
from pandas import Timedelta
Copy link
Contributor

Choose a reason for hiding this comment

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

can you de-class these. I think we are calling this test_formats.py elsewhere?

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 we are calling this test_formats.py elsewhere?

In scalar.timestamps we're calling it test_rendering. In tests.indexes we recently moved a bunch of thematically related tests to pre-existing test_formats.py files (that each only had one test in them, so seemed lonely).

I have a mild preference for "test_rendering" since it is pretty specifically about __repr__ variants, whereas "test_formats" could reasonably refer to e.g. to_csv.

Copy link
Contributor

Choose a reason for hiding this comment

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

just use test_formats for now.



class TestTimedeltaRendering(object):
def test_repr(self):
assert (repr(Timedelta(10, unit='d')) ==
"Timedelta('10 days 00:00:00')")
assert (repr(Timedelta(10, unit='s')) ==
"Timedelta('0 days 00:00:10')")
assert (repr(Timedelta(10, unit='ms')) ==
"Timedelta('0 days 00:00:00.010000')")
assert (repr(Timedelta(-10, unit='ms')) ==
"Timedelta('-1 days +23:59:59.990000')")

def test_isoformat(self):
td = Timedelta(days=6, minutes=50, seconds=3,
milliseconds=10, microseconds=10, nanoseconds=12)
expected = 'P6DT0H50M3.010010012S'
result = td.isoformat()
assert result == expected

td = Timedelta(days=4, hours=12, minutes=30, seconds=5)
result = td.isoformat()
expected = 'P4DT12H30M5S'
assert result == expected

td = Timedelta(nanoseconds=123)
result = td.isoformat()
expected = 'P0DT0H0M0.000000123S'
assert result == expected

# trim nano
td = Timedelta(microseconds=10)
result = td.isoformat()
expected = 'P0DT0H0M0.00001S'
assert result == expected

# trim micro
td = Timedelta(milliseconds=1)
result = td.isoformat()
expected = 'P0DT0H0M0.001S'
assert result == expected

# don't strip every 0
result = Timedelta(minutes=1).isoformat()
expected = 'P0DT0H1M0S'
assert result == expected
Loading