Skip to content

Commit 7fe8ac2

Browse files
Merge remote-tracking branch 'upstream/master' into doc-build-single-docstring
2 parents 2766dde + abc4ef9 commit 7fe8ac2

File tree

9 files changed

+77
-47
lines changed

9 files changed

+77
-47
lines changed

.pep8speaks.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,7 @@ scanner:
66
pycodestyle:
77
max-line-length: 79
88
ignore: # Errors and warnings to ignore
9-
- E731
10-
- E402
9+
- E402, # module level import not at top of file
10+
- E731, # do not assign a lambda expression, use a def
11+
- E741, # do not use variables named 'l', 'O', or 'I'
12+
- W503 # line break before binary operator

ci/lint.sh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,12 @@ if [ "$LINT" ]; then
3737
fi
3838
echo "Linting scripts/*.py DONE"
3939

40-
echo "Linting doc script"
41-
flake8 doc/make.py
40+
echo "Linting doc scripts"
41+
flake8 doc/make.py doc/source/conf.py
4242
if [ $? -ne "0" ]; then
4343
RET=1
4444
fi
45-
echo "Linting doc script DONE"
45+
echo "Linting doc scripts DONE"
4646

4747
echo "Linting *.pyx"
4848
flake8 pandas --filename=*.pyx --select=E501,E302,E203,E111,E114,E221,E303,E128,E231,E126,E265,E305,E301,E127,E261,E271,E129,W291,E222,E241,E123,F403

doc/source/conf.py

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
#
33
# pandas documentation build configuration file, created by
44
#
5-
# This file is execfile()d with the current directory set to its containing dir.
5+
# This file is execfile()d with the current directory set to its containing
6+
# dir.
67
#
78
# Note that not all possible configuration values are present in this
89
# autogenerated file.
@@ -49,8 +50,9 @@
4950

5051
# -- General configuration -----------------------------------------------
5152

52-
# Add any Sphinx extension module names here, as strings. They can be extensions
53-
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. sphinxext.
53+
# Add any Sphinx extension module names here, as strings. They can be
54+
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
55+
# sphinxext.
5456

5557
extensions = ['sphinx.ext.autodoc',
5658
'sphinx.ext.autosummary',
@@ -60,7 +62,8 @@
6062
'numpydoc',
6163
'ipython_sphinxext.ipython_directive',
6264
'ipython_sphinxext.ipython_console_highlighting',
63-
'IPython.sphinxext.ipython_console_highlighting', # lowercase didn't work
65+
# lowercase didn't work
66+
'IPython.sphinxext.ipython_console_highlighting',
6467
'sphinx.ext.intersphinx',
6568
'sphinx.ext.coverage',
6669
'sphinx.ext.mathjax',
@@ -107,7 +110,7 @@
107110
import pandas
108111

109112
# version = '%s r%s' % (pandas.__version__, svn_version())
110-
version = '%s' % (pandas.__version__)
113+
version = str(pandas.__version__)
111114

112115
# The full version, including alpha/beta/rc tags.
113116
release = version
@@ -129,8 +132,8 @@
129132
# for source files.
130133
exclude_trees = []
131134

132-
# The reST default role (used for this markup: `text`) to use for all documents.
133-
# default_role = None
135+
# The reST default role (used for this markup: `text`) to use for all
136+
# documents. default_role = None
134137

135138
# If true, '()' will be appended to :func: etc. cross-reference text.
136139
# add_function_parentheses = True
@@ -304,8 +307,8 @@
304307
# The font size ('10pt', '11pt' or '12pt').
305308
# latex_font_size = '10pt'
306309

307-
# Grouping the document tree into LaTeX files. List of tuples
308-
# (source start file, target name, title, author, documentclass [howto/manual]).
310+
# Grouping the document tree into LaTeX files. List of tuples (source start
311+
# file, target name, title, author, documentclass [howto/manual]).
309312
latex_documents = [
310313
('index', 'pandas.tex',
311314
u('pandas: powerful Python data analysis toolkit'),
@@ -362,23 +365,23 @@
362365
# wherever the docs are built. The docs' target is the browser, not
363366
# the console, so this is fine.
364367
'pd.options.display.encoding="utf8"'
365-
]
368+
]
366369

367370

368371
# Add custom Documenter to handle attributes/methods of an AccessorProperty
369372
# eg pandas.Series.str and pandas.Series.dt (see GH9322)
370373

371374
import sphinx
372375
from sphinx.util import rpartition
373-
from sphinx.ext.autodoc import Documenter, MethodDocumenter, AttributeDocumenter
376+
from sphinx.ext.autodoc import (
377+
Documenter, MethodDocumenter, AttributeDocumenter)
374378
from sphinx.ext.autosummary import Autosummary
375379

376380

377381
class AccessorDocumenter(MethodDocumenter):
378382
"""
379383
Specialized Documenter subclass for accessors.
380384
"""
381-
382385
objtype = 'accessor'
383386
directivetype = 'method'
384387

@@ -396,7 +399,6 @@ class AccessorLevelDocumenter(Documenter):
396399
Specialized Documenter subclass for objects on accessor level (methods,
397400
attributes).
398401
"""
399-
400402
# This is the simple straightforward version
401403
# modname is None, base the last elements (eg 'hour')
402404
# and path the part before (eg 'Series.dt')
@@ -406,7 +408,6 @@ class AccessorLevelDocumenter(Documenter):
406408
# mod_cls = mod_cls.split('.')
407409
#
408410
# return modname, mod_cls + [base]
409-
410411
def resolve_name(self, modname, parents, path, base):
411412
if modname is None:
412413
if path:
@@ -441,16 +442,17 @@ def resolve_name(self, modname, parents, path, base):
441442
return modname, parents + [base]
442443

443444

444-
class AccessorAttributeDocumenter(AccessorLevelDocumenter, AttributeDocumenter):
445-
445+
class AccessorAttributeDocumenter(AccessorLevelDocumenter,
446+
AttributeDocumenter):
446447
objtype = 'accessorattribute'
447448
directivetype = 'attribute'
448449

449-
# lower than AttributeDocumenter so this is not chosen for normal attributes
450+
# lower than AttributeDocumenter so this is not chosen for normal
451+
# attributes
450452
priority = 0.6
451453

452-
class AccessorMethodDocumenter(AccessorLevelDocumenter, MethodDocumenter):
453454

455+
class AccessorMethodDocumenter(AccessorLevelDocumenter, MethodDocumenter):
454456
objtype = 'accessormethod'
455457
directivetype = 'method'
456458

@@ -478,7 +480,6 @@ class PandasAutosummary(Autosummary):
478480
This alternative autosummary class lets us override the table summary for
479481
Series.plot and DataFrame.plot in the API docs.
480482
"""
481-
482483
def _replace_pandas_items(self, display_name, sig, summary, real_name):
483484
# this a hack: ideally we should extract the signature from the
484485
# .__call__ method instead of hard coding this
@@ -531,18 +532,18 @@ def linkcode_resolve(domain, info):
531532
lineno = None
532533

533534
if lineno:
534-
linespec = "#L%d-L%d" % (lineno, lineno + len(source) - 1)
535+
linespec = "#L{:d}-L{:d}".format(lineno, lineno + len(source) - 1)
535536
else:
536537
linespec = ""
537538

538539
fn = os.path.relpath(fn, start=os.path.dirname(pandas.__file__))
539540

540541
if '+' in pandas.__version__:
541-
return "http://github.com/pandas-dev/pandas/blob/master/pandas/%s%s" % (
542-
fn, linespec)
542+
return ("http://github.com/pandas-dev/pandas/blob/master/pandas/"
543+
"{}{}".format(fn, linespec))
543544
else:
544-
return "http://github.com/pandas-dev/pandas/blob/v%s/pandas/%s%s" % (
545-
pandas.__version__, fn, linespec)
545+
return ("http://github.com/pandas-dev/pandas/blob/"
546+
"v{}/pandas/{}{}".format(pandas.__version__, fn, linespec))
546547

547548

548549
# remove the docstring of the flags attribute (inherited from numpy ndarray)

doc/source/whatsnew/v0.23.0.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -757,6 +757,7 @@ Datetimelike
757757
Timedelta
758758
^^^^^^^^^
759759

760+
- Bug in :func:`Timedelta.__mul__` where multiplying by ``NaT`` returned ``NaT`` instead of raising a ``TypeError`` (:issue:`19819`)
760761
- Bug in :class:`Series` with ``dtype='timedelta64[ns]`` where addition or subtraction of ``TimedeltaIndex`` had results cast to ``dtype='int64'`` (:issue:`17250`)
761762
- Bug in :class:`Series` with ``dtype='timedelta64[ns]`` where addition or subtraction of ``TimedeltaIndex`` could return a ``Series`` with an incorrect name (:issue:`19043`)
762763
- Bug in :func:`Timedelta.__floordiv__` and :func:`Timedelta.__rfloordiv__` dividing by many incompatible numpy objects was incorrectly allowed (:issue:`18846`)
@@ -766,6 +767,7 @@ Timedelta
766767
- Bug in :func:`Timedelta.__floordiv__`, :func:`Timedelta.__rfloordiv__` where operating with a ``Tick`` object would raise a ``TypeError`` instead of returning a numeric value (:issue:`19738`)
767768
- Bug in :func:`Period.asfreq` where periods near ``datetime(1, 1, 1)`` could be converted incorrectly (:issue:`19643`)
768769
- Bug in :func:`Timedelta.total_seconds()` causing precision errors i.e. ``Timedelta('30S').total_seconds()==30.000000000000004`` (:issue:`19458`)
770+
- Bug in :func: `Timedelta.__rmod__` where operating with a ``numpy.timedelta64`` returned a ``timedelta64`` object instead of a ``Timedelta`` (:issue:`19820`)
769771
- Multiplication of :class:`TimedeltaIndex` by ``TimedeltaIndex`` will now raise ``TypeError`` instead of raising ``ValueError`` in cases of length mis-match (:issue`19333`)
770772
-
771773

@@ -899,6 +901,7 @@ Reshaping
899901
- Bug in :func:`DataFrame.join` which does an ``outer`` instead of a ``left`` join when being called with multiple DataFrames and some have non-unique indices (:issue:`19624`)
900902
- :func:`Series.rename` now accepts ``axis`` as a kwarg (:issue:`18589`)
901903
- Comparisons between :class:`Series` and :class:`Index` would return a ``Series`` with an incorrect name, ignoring the ``Index``'s name attribute (:issue:`19582`)
904+
- Bug in :func:`qcut` where datetime and timedelta data with ``NaT`` present raised a ``ValueError`` (:issue:`19768`)
902905

903906
Other
904907
^^^^^

pandas/_libs/tslibs/timedeltas.pyx

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1057,7 +1057,7 @@ class Timedelta(_Timedelta):
10571057
return other * self.to_timedelta64()
10581058

10591059
elif other is NaT:
1060-
return NaT
1060+
raise TypeError('Cannot multiply Timedelta with NaT')
10611061

10621062
elif not (is_integer_object(other) or is_float_object(other)):
10631063
# only integers and floats allowed
@@ -1109,7 +1109,11 @@ class Timedelta(_Timedelta):
11091109
return self // other.delta
11101110
return NotImplemented
11111111

1112-
if hasattr(other, 'dtype'):
1112+
elif is_timedelta64_object(other):
1113+
# convert to Timedelta below
1114+
pass
1115+
1116+
elif hasattr(other, 'dtype'):
11131117
if other.dtype.kind == 'm':
11141118
# also timedelta-like
11151119
return _broadcast_floordiv_td64(self.value, other, _floordiv)
@@ -1144,7 +1148,11 @@ class Timedelta(_Timedelta):
11441148
return other.delta // self
11451149
return NotImplemented
11461150

1147-
if hasattr(other, 'dtype'):
1151+
elif is_timedelta64_object(other):
1152+
# convert to Timedelta below
1153+
pass
1154+
1155+
elif hasattr(other, 'dtype'):
11481156
if other.dtype.kind == 'm':
11491157
# also timedelta-like
11501158
return _broadcast_floordiv_td64(self.value, other, _rfloordiv)

pandas/core/reshape/tile.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -279,18 +279,22 @@ def _trim_zeros(x):
279279
def _coerce_to_type(x):
280280
"""
281281
if the passed data is of datetime/timedelta type,
282-
this method converts it to integer so that cut method can
282+
this method converts it to numeric so that cut method can
283283
handle it
284284
"""
285285
dtype = None
286286

287287
if is_timedelta64_dtype(x):
288-
x = to_timedelta(x).view(np.int64)
288+
x = to_timedelta(x)
289289
dtype = np.timedelta64
290290
elif is_datetime64_dtype(x):
291-
x = to_datetime(x).view(np.int64)
291+
x = to_datetime(x)
292292
dtype = np.datetime64
293293

294+
if dtype is not None:
295+
# GH 19768: force NaT to NaN during integer conversion
296+
x = np.where(x.notna(), x.view(np.int64), np.nan)
297+
294298
return x, dtype
295299

296300

pandas/tests/reshape/test_tile.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66

77
from pandas import (Series, isna, to_datetime, DatetimeIndex,
88
Timestamp, Interval, IntervalIndex, Categorical,
9-
cut, qcut, date_range)
9+
cut, qcut, date_range, NaT, TimedeltaIndex)
10+
from pandas.tseries.offsets import Nano, Day
1011
import pandas.util.testing as tm
1112
from pandas.api.types import CategoricalDtype as CDT
1213

@@ -250,6 +251,18 @@ def test_qcut_nas(self):
250251
result = qcut(arr, 4)
251252
assert isna(result[:20]).all()
252253

254+
@pytest.mark.parametrize('s', [
255+
Series(DatetimeIndex(['20180101', NaT, '20180103'])),
256+
Series(TimedeltaIndex(['0 days', NaT, '2 days']))],
257+
ids=lambda x: str(x.dtype))
258+
def test_qcut_nat(self, s):
259+
# GH 19768
260+
intervals = IntervalIndex.from_tuples(
261+
[(s[0] - Nano(), s[2] - Day()), np.nan, (s[2] - Day(), s[2])])
262+
expected = Series(Categorical(intervals, ordered=True))
263+
result = qcut(s, 2)
264+
tm.assert_series_equal(result, expected)
265+
253266
def test_qcut_index(self):
254267
result = qcut([0, 2], 2)
255268
intervals = [Interval(-0.001, 1), Interval(1, 2)]

pandas/tests/scalar/timedelta/test_arithmetic.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,16 @@ class TestTimedeltaMultiplicationDivision(object):
216216
# ---------------------------------------------------------------
217217
# Timedelta.__mul__, __rmul__
218218

219+
@pytest.mark.parametrize('td_nat', [pd.NaT,
220+
np.timedelta64('NaT', 'ns'),
221+
np.timedelta64('NaT')])
222+
@pytest.mark.parametrize('op', [operator.mul, ops.rmul])
223+
def test_td_mul_nat(self, op, td_nat):
224+
# GH#19819
225+
td = Timedelta(10, unit='d')
226+
with pytest.raises(TypeError):
227+
op(td, td_nat)
228+
219229
@pytest.mark.parametrize('op', [operator.mul, ops.rmul])
220230
def test_td_mul_scalar(self, op):
221231
# GH#19738
@@ -441,15 +451,13 @@ def test_mod_timedeltalike(self):
441451
result = td % NaT
442452
assert result is NaT
443453

444-
@pytest.mark.xfail(reason='GH#19378 floordiv td64 returns td64')
445454
def test_mod_timedelta64_nat(self):
446455
# GH#19365
447456
td = Timedelta(hours=37)
448457

449458
result = td % np.timedelta64('NaT', 'ns')
450459
assert result is NaT
451460

452-
@pytest.mark.xfail(reason='GH#19378 floordiv td64 returns td64')
453461
def test_mod_timedelta64(self):
454462
# GH#19365
455463
td = Timedelta(hours=37)
@@ -458,7 +466,6 @@ def test_mod_timedelta64(self):
458466
assert isinstance(result, Timedelta)
459467
assert result == Timedelta(hours=1)
460468

461-
@pytest.mark.xfail(reason='GH#19378 floordiv by Tick not implemented')
462469
def test_mod_offset(self):
463470
# GH#19365
464471
td = Timedelta(hours=37)
@@ -505,7 +512,6 @@ def test_rmod_pytimedelta(self):
505512
assert isinstance(result, Timedelta)
506513
assert result == Timedelta(minutes=1)
507514

508-
@pytest.mark.xfail(reason='GH#19378 floordiv by Tick not implemented')
509515
def test_rmod_timedelta64(self):
510516
# GH#19365
511517
td = Timedelta(minutes=3)
@@ -564,7 +570,6 @@ def test_divmod(self):
564570
assert np.isnan(result[0])
565571
assert result[1] is pd.NaT
566572

567-
@pytest.mark.xfail(reason='GH#19378 floordiv by Tick not implemented')
568573
def test_divmod_offset(self):
569574
# GH#19365
570575
td = Timedelta(days=2, hours=6)
@@ -588,7 +593,6 @@ def test_rdivmod_pytimedelta(self):
588593
assert isinstance(result[1], Timedelta)
589594
assert result[1] == Timedelta(hours=6)
590595

591-
@pytest.mark.xfail(reason='GH#19378 floordiv by Tick not implemented')
592596
def test_rdivmod_offset(self):
593597
result = divmod(pd.offsets.Hour(54), Timedelta(hours=-4))
594598
assert result[0] == -14

pandas/tests/scalar/timedelta/test_timedelta.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,6 @@ def test_unary_ops(self):
6262
assert abs(-td) == td
6363
assert abs(-td) == Timedelta('10d')
6464

65-
def test_binary_ops_nat(self):
66-
td = Timedelta(10, unit='d')
67-
# FIXME: The next test is wrong: td * NaT should raise
68-
assert (td * pd.NaT) is pd.NaT
69-
7065

7166
class TestTimedeltaComparison(object):
7267
def test_comparison_object_array(self):

0 commit comments

Comments
 (0)