From 840eec8d53e4f64287e7b7f07480512f3fc6920f Mon Sep 17 00:00:00 2001 From: Will Ayd Date: Wed, 16 May 2018 14:22:13 -0700 Subject: [PATCH 01/17] Added test case --- pandas/tests/test_downstream.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/pandas/tests/test_downstream.py b/pandas/tests/test_downstream.py index a595d9f18d6b8..8845f8cfac6b4 100644 --- a/pandas/tests/test_downstream.py +++ b/pandas/tests/test_downstream.py @@ -2,6 +2,8 @@ """ Testing that we work in the downstream packages """ +import subprocess + import pytest import numpy as np # noqa from pandas import DataFrame @@ -53,6 +55,15 @@ def test_xarray(df): assert df.to_xarray() is not None +def test_xarray_oo_optimizable(): + # GH 21071 + ret = subprocess.run(["python", "-OO", "-c", "import pandas"]) + result = ret.returncode + expected = 0 + + assert result == expected + + @tm.network def test_statsmodels(): From 19e71e396363b648cf5f5b9c458886470665c1bd Mon Sep 17 00:00:00 2001 From: Will Ayd Date: Wed, 16 May 2018 14:24:50 -0700 Subject: [PATCH 02/17] Conditionals for -OO optimization support --- pandas/tseries/offsets.py | 7 +++++-- pandas/util/_decorators.py | 9 +++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/pandas/tseries/offsets.py b/pandas/tseries/offsets.py index 749165f894819..eb1f43a50909f 100644 --- a/pandas/tseries/offsets.py +++ b/pandas/tseries/offsets.py @@ -1090,12 +1090,15 @@ def apply(self, other): class CustomBusinessMonthEnd(_CustomBusinessMonth): - __doc__ = _CustomBusinessMonth.__doc__.replace('[BEGIN/END]', 'end') + if _CustomBusinessMonth.__doc__: + __doc__ = _CustomBusinessMonth.__doc__.replace('[BEGIN/END]', 'end') _prefix = 'CBM' class CustomBusinessMonthBegin(_CustomBusinessMonth): - __doc__ = _CustomBusinessMonth.__doc__.replace('[BEGIN/END]', 'beginning') + if _CustomBusinessMonth.__doc__: + __doc__ = _CustomBusinessMonth.__doc__.replace('[BEGIN/END]', + 'beginning') _prefix = 'CBMS' diff --git a/pandas/util/_decorators.py b/pandas/util/_decorators.py index 624fbbbd4f05e..9f4d99856f539 100644 --- a/pandas/util/_decorators.py +++ b/pandas/util/_decorators.py @@ -54,10 +54,11 @@ def wrapper(*args, **kwargs): {rest} """) rest = getattr(wrapper, '__doc__', '') - docstring = tpl.format(version=version, - msg='\n '.join(wrap(msg, 70)), - rest=dedent(rest)) - wrapper.__doc__ = docstring + if rest: + docstring = tpl.format(version=version, + msg='\n '.join(wrap(msg, 70)), + rest=dedent(rest)) + wrapper.__doc__ = docstring return wrapper From 95826d3aac57caa4bf040a2873947ad6693a8b03 Mon Sep 17 00:00:00 2001 From: Will Ayd Date: Wed, 16 May 2018 15:11:14 -0700 Subject: [PATCH 03/17] Updated test name --- pandas/tests/test_downstream.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/tests/test_downstream.py b/pandas/tests/test_downstream.py index 8845f8cfac6b4..cca49803c1250 100644 --- a/pandas/tests/test_downstream.py +++ b/pandas/tests/test_downstream.py @@ -55,7 +55,7 @@ def test_xarray(df): assert df.to_xarray() is not None -def test_xarray_oo_optimizable(): +def test_oo_optimizable(): # GH 21071 ret = subprocess.run(["python", "-OO", "-c", "import pandas"]) result = ret.returncode From 0e48c18f6d82c3124463c8678e5d4c6f95b0863f Mon Sep 17 00:00:00 2001 From: Will Ayd Date: Wed, 16 May 2018 16:15:27 -0700 Subject: [PATCH 04/17] Py27 Compat --- pandas/tests/test_downstream.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/pandas/tests/test_downstream.py b/pandas/tests/test_downstream.py index cca49803c1250..7386f8e639f62 100644 --- a/pandas/tests/test_downstream.py +++ b/pandas/tests/test_downstream.py @@ -57,11 +57,7 @@ def test_xarray(df): def test_oo_optimizable(): # GH 21071 - ret = subprocess.run(["python", "-OO", "-c", "import pandas"]) - result = ret.returncode - expected = 0 - - assert result == expected + subprocess.check_call(["python", "-OO", "-c", "import pandas"]) @tm.network From abdc5f29cb027548bc4be4d2986f9fc9db9ce30f Mon Sep 17 00:00:00 2001 From: Will Ayd Date: Sun, 20 May 2018 13:22:49 -0700 Subject: [PATCH 05/17] Leveraged docstring substitution --- pandas/tseries/offsets.py | 13 ++++++------- pandas/util/_decorators.py | 29 ++++++++++++----------------- 2 files changed, 18 insertions(+), 24 deletions(-) diff --git a/pandas/tseries/offsets.py b/pandas/tseries/offsets.py index eb1f43a50909f..71ec1fcf1d0fe 100644 --- a/pandas/tseries/offsets.py +++ b/pandas/tseries/offsets.py @@ -14,7 +14,7 @@ # import after tools, dateutil check from dateutil.easter import easter from pandas._libs import tslib, Timestamp, OutOfBoundsDatetime, Timedelta -from pandas.util._decorators import cache_readonly +from pandas.util._decorators import cache_readonly, Appender, Substitution from pandas._libs.tslibs import ccalendar, frequencies as libfrequencies from pandas._libs.tslibs.timedeltas import delta_to_nanoseconds @@ -1011,7 +1011,7 @@ class BusinessMonthBegin(MonthOffset): class _CustomBusinessMonth(_CustomMixin, BusinessMixin, MonthOffset): """ DateOffset subclass representing one custom business month, incrementing - between [BEGIN/END] of month dates + between %(increment)s of month dates Parameters ---------- @@ -1089,16 +1089,15 @@ def apply(self, other): return result +@Substitution(increment='end') +@Appender(_CustomBusinessMonth.__doc__) class CustomBusinessMonthEnd(_CustomBusinessMonth): - if _CustomBusinessMonth.__doc__: - __doc__ = _CustomBusinessMonth.__doc__.replace('[BEGIN/END]', 'end') _prefix = 'CBM' +@Substitution(increment='beginning') +@Appender(_CustomBusinessMonth.__doc__) class CustomBusinessMonthBegin(_CustomBusinessMonth): - if _CustomBusinessMonth.__doc__: - __doc__ = _CustomBusinessMonth.__doc__.replace('[BEGIN/END]', - 'beginning') _prefix = 'CBMS' diff --git a/pandas/util/_decorators.py b/pandas/util/_decorators.py index 9f4d99856f539..67aa3e0e9f4ac 100644 --- a/pandas/util/_decorators.py +++ b/pandas/util/_decorators.py @@ -3,7 +3,7 @@ import inspect import types import warnings -from textwrap import dedent, wrap +from textwrap import dedent from functools import wraps, update_wrapper @@ -39,27 +39,22 @@ def deprecate(name, alternative, version, alt_name=None, warning_msg = msg or '{} is deprecated, use {} instead'.format(name, alt_name) + # adding deprecated directive to the docstring + msg = msg or 'Use `{alt_name}` instead.'.format(alt_name=alt_name) + + @Substitution(version=version, msg=msg) + @Appender(name.__doc__) @wraps(alternative) def wrapper(*args, **kwargs): + """ + .. deprecated:: %(version)s + + %(msg)s + + """ warnings.warn(warning_msg, klass, stacklevel=stacklevel) return alternative(*args, **kwargs) - # adding deprecated directive to the docstring - msg = msg or 'Use `{alt_name}` instead.'.format(alt_name=alt_name) - tpl = dedent(""" - .. deprecated:: {version} - - {msg} - - {rest} - """) - rest = getattr(wrapper, '__doc__', '') - if rest: - docstring = tpl.format(version=version, - msg='\n '.join(wrap(msg, 70)), - rest=dedent(rest)) - wrapper.__doc__ = docstring - return wrapper From e4ba94840c62f3a593f26b87d54bbae860109807 Mon Sep 17 00:00:00 2001 From: Will Ayd Date: Sun, 20 May 2018 13:27:29 -0700 Subject: [PATCH 06/17] Updated docstring for deprecate wrapper --- pandas/util/_decorators.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pandas/util/_decorators.py b/pandas/util/_decorators.py index 67aa3e0e9f4ac..f23abac4360a7 100644 --- a/pandas/util/_decorators.py +++ b/pandas/util/_decorators.py @@ -19,19 +19,19 @@ def deprecate(name, alternative, version, alt_name=None, Parameters ---------- - name : str - Name of function to deprecate - alternative : str - Name of function to use instead + name : func + Function to deprecate. + alternative : func + Function to use instead. version : str - Version of pandas in which the method has been deprecated + Version of pandas in which the method has been deprecated. alt_name : str, optional - Name to use in preference of alternative.__name__ + Name to use in preference of alternative.__name__. klass : Warning, default FutureWarning stacklevel : int, default 2 msg : str - The message to display in the warning. - Default is '{name} is deprecated. Use {alt_name} instead.' + The message to display in the warning. + Default is '{name} is deprecated. Use {alt_name} instead.' """ alt_name = alt_name or alternative.__name__ From 021786bf71372dabeb94e9019da3cfaee3bd2671 Mon Sep 17 00:00:00 2001 From: Will Ayd Date: Sun, 20 May 2018 13:34:08 -0700 Subject: [PATCH 07/17] Whatsnew note --- doc/source/whatsnew/v0.23.1.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/source/whatsnew/v0.23.1.txt b/doc/source/whatsnew/v0.23.1.txt index 5a553264e828b..465610873df52 100644 --- a/doc/source/whatsnew/v0.23.1.txt +++ b/doc/source/whatsnew/v0.23.1.txt @@ -94,3 +94,8 @@ Categorical ^^^^^^^^^^^ - + +Other +^^^^^ + +- Bug preventing pandas from being importable with -OO optimization (:issue:`21071`) From a1b409d69bf80c7d8e7f7600ba4a401b6d31c46f Mon Sep 17 00:00:00 2001 From: Will Ayd Date: Thu, 24 May 2018 09:51:44 -0700 Subject: [PATCH 08/17] Reverted class Substitution in offsets.py --- pandas/tseries/offsets.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/pandas/tseries/offsets.py b/pandas/tseries/offsets.py index 71ec1fcf1d0fe..0678f135cc659 100644 --- a/pandas/tseries/offsets.py +++ b/pandas/tseries/offsets.py @@ -1011,7 +1011,7 @@ class BusinessMonthBegin(MonthOffset): class _CustomBusinessMonth(_CustomMixin, BusinessMixin, MonthOffset): """ DateOffset subclass representing one custom business month, incrementing - between %(increment)s of month dates + between [BEGIN/END] of month dates Parameters ---------- @@ -1089,15 +1089,18 @@ def apply(self, other): return result -@Substitution(increment='end') -@Appender(_CustomBusinessMonth.__doc__) class CustomBusinessMonthEnd(_CustomBusinessMonth): + # TODO: Replace condition with Subsitution after dropping Py27 support + if _CustomBusinessMonth.__doc__: + __doc__ = _CustomBusinessMonth.__doc__.replace('[BEGIN/END]', 'end') _prefix = 'CBM' -@Substitution(increment='beginning') -@Appender(_CustomBusinessMonth.__doc__) class CustomBusinessMonthBegin(_CustomBusinessMonth): + # TODO: Replace condition with Subsitution after dropping Py27 support + if _CustomBusinessMonth.__doc__: + __doc__ = _CustomBusinessMonth.__doc__.replace('[BEGIN/END]', + 'beginning') _prefix = 'CBMS' From a89c4f4695597f9d75292474c0e5e2f2a3cbe2e4 Mon Sep 17 00:00:00 2001 From: Will Ayd Date: Thu, 24 May 2018 11:47:52 -0700 Subject: [PATCH 09/17] Recursive OO support --- pandas/conftest.py | 9 +++++---- pandas/tests/test_downstream.py | 12 +++++++++++- pandas/util/_test_decorators.py | 25 ------------------------- 3 files changed, 16 insertions(+), 30 deletions(-) diff --git a/pandas/conftest.py b/pandas/conftest.py index b09cb872a12fb..1fe7d02308e6a 100644 --- a/pandas/conftest.py +++ b/pandas/conftest.py @@ -4,6 +4,7 @@ import pandas as pd from pandas.compat import PY3 import pandas.util._test_decorators as td +from pandas.util._decorators import Substitution def pytest_addoption(parser): @@ -133,19 +134,19 @@ def nulls_fixture(request): TIMEZONES = [None, 'UTC', 'US/Eastern', 'Asia/Tokyo', 'dateutil/US/Pacific'] -@td.parametrize_fixture_doc(str(TIMEZONES)) +@Substitution(params=TIMEZONES) @pytest.fixture(params=TIMEZONES) def tz_naive_fixture(request): """ - Fixture for trying timezones including default (None): {0} + Fixture for trying timezones including default (None): %(params)s """ return request.param -@td.parametrize_fixture_doc(str(TIMEZONES[1:])) +@Substitution(params=TIMEZONES[1:]) @pytest.fixture(params=TIMEZONES[1:]) def tz_aware_fixture(request): """ - Fixture for trying explicit timezones: {0} + Fixture for trying explicit timezones: %(params)s """ return request.param diff --git a/pandas/tests/test_downstream.py b/pandas/tests/test_downstream.py index 7386f8e639f62..989a266599b70 100644 --- a/pandas/tests/test_downstream.py +++ b/pandas/tests/test_downstream.py @@ -2,7 +2,9 @@ """ Testing that we work in the downstream packages """ +import pkgutil import subprocess +import warnings import pytest import numpy as np # noqa @@ -57,7 +59,15 @@ def test_xarray(df): def test_oo_optimizable(): # GH 21071 - subprocess.check_call(["python", "-OO", "-c", "import pandas"]) + pkg_gen = pkgutil.walk_packages('.') + + # Ignore items at the top of the package like setup and versioneer + packages = [x for x in pkg_gen if x[0].path != '.'] + statement = ";".join("import {name}".format(name=package.name) + for package in packages) + + with warnings.catch_warnings(record=True): + subprocess.check_call(["python", "-OO", "-c", statement]) @tm.network diff --git a/pandas/util/_test_decorators.py b/pandas/util/_test_decorators.py index 89d90258f58e0..ab6dfee9c862c 100644 --- a/pandas/util/_test_decorators.py +++ b/pandas/util/_test_decorators.py @@ -189,28 +189,3 @@ def decorated_func(func): "installed->{installed}".format( enabled=_USE_NUMEXPR, installed=_NUMEXPR_INSTALLED)) - - -def parametrize_fixture_doc(*args): - """ - Intended for use as a decorator for parametrized fixture, - this function will wrap the decorated function with a pytest - ``parametrize_fixture_doc`` mark. That mark will format - initial fixture docstring by replacing placeholders {0}, {1} etc - with parameters passed as arguments. - - Parameters: - ---------- - args: iterable - Positional arguments for docstring. - - Returns: - ------- - documented_fixture: function - The decorated function wrapped within a pytest - ``parametrize_fixture_doc`` mark - """ - def documented_fixture(fixture): - fixture.__doc__ = fixture.__doc__.format(*args) - return fixture - return documented_fixture From 078610a435debc8bdc288aaf6a68429ba72784c6 Mon Sep 17 00:00:00 2001 From: Will Ayd Date: Thu, 24 May 2018 11:48:44 -0700 Subject: [PATCH 10/17] LINT fixup --- pandas/tseries/offsets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/tseries/offsets.py b/pandas/tseries/offsets.py index 0678f135cc659..54670c0e652e0 100644 --- a/pandas/tseries/offsets.py +++ b/pandas/tseries/offsets.py @@ -14,7 +14,7 @@ # import after tools, dateutil check from dateutil.easter import easter from pandas._libs import tslib, Timestamp, OutOfBoundsDatetime, Timedelta -from pandas.util._decorators import cache_readonly, Appender, Substitution +from pandas.util._decorators import cache_readonly from pandas._libs.tslibs import ccalendar, frequencies as libfrequencies from pandas._libs.tslibs.timedeltas import delta_to_nanoseconds From c697dae7f337e3240f9a451b4bdb09c2ef80ae65 Mon Sep 17 00:00:00 2001 From: Will Ayd Date: Thu, 24 May 2018 11:50:49 -0700 Subject: [PATCH 11/17] Updated whatsnew --- doc/source/whatsnew/v0.23.1.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/source/whatsnew/v0.23.1.txt b/doc/source/whatsnew/v0.23.1.txt index 266d0659ebead..470609f469b8e 100644 --- a/doc/source/whatsnew/v0.23.1.txt +++ b/doc/source/whatsnew/v0.23.1.txt @@ -46,8 +46,6 @@ Documentation Changes Bug Fixes ~~~~~~~~~ -- tab completion on :class:`Index` in IPython no longer outputs deprecation warnings (:issue:`21125`) - Groupby/Resample/Rolling ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -106,4 +104,5 @@ Categorical Other ^^^^^ +- Tab completion on :class:`Index` in IPython no longer outputs deprecation warnings (:issue:`21125`) - Bug preventing pandas from being importable with -OO optimization (:issue:`21071`) From d6c66ece0fffecf6c67c0287bcb0c28b994d6224 Mon Sep 17 00:00:00 2001 From: Will Ayd Date: Fri, 25 May 2018 13:36:42 -0700 Subject: [PATCH 12/17] Reverted recursive import test --- pandas/tests/test_downstream.py | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/pandas/tests/test_downstream.py b/pandas/tests/test_downstream.py index 989a266599b70..05d47ea752aa9 100644 --- a/pandas/tests/test_downstream.py +++ b/pandas/tests/test_downstream.py @@ -59,15 +59,7 @@ def test_xarray(df): def test_oo_optimizable(): # GH 21071 - pkg_gen = pkgutil.walk_packages('.') - - # Ignore items at the top of the package like setup and versioneer - packages = [x for x in pkg_gen if x[0].path != '.'] - statement = ";".join("import {name}".format(name=package.name) - for package in packages) - - with warnings.catch_warnings(record=True): - subprocess.check_call(["python", "-OO", "-c", statement]) + subprocess.check_call(["python", "-OO", "-c", "import pandas"]) @tm.network From c825636cf904a8b1c13a3a85b6606fe0f85bfb8a Mon Sep 17 00:00:00 2001 From: Will Ayd Date: Fri, 25 May 2018 13:39:20 -0700 Subject: [PATCH 13/17] Reverted conftest / decorators to master --- pandas/conftest.py | 9 ++++----- pandas/util/_test_decorators.py | 25 +++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/pandas/conftest.py b/pandas/conftest.py index 1fe7d02308e6a..b09cb872a12fb 100644 --- a/pandas/conftest.py +++ b/pandas/conftest.py @@ -4,7 +4,6 @@ import pandas as pd from pandas.compat import PY3 import pandas.util._test_decorators as td -from pandas.util._decorators import Substitution def pytest_addoption(parser): @@ -134,19 +133,19 @@ def nulls_fixture(request): TIMEZONES = [None, 'UTC', 'US/Eastern', 'Asia/Tokyo', 'dateutil/US/Pacific'] -@Substitution(params=TIMEZONES) +@td.parametrize_fixture_doc(str(TIMEZONES)) @pytest.fixture(params=TIMEZONES) def tz_naive_fixture(request): """ - Fixture for trying timezones including default (None): %(params)s + Fixture for trying timezones including default (None): {0} """ return request.param -@Substitution(params=TIMEZONES[1:]) +@td.parametrize_fixture_doc(str(TIMEZONES[1:])) @pytest.fixture(params=TIMEZONES[1:]) def tz_aware_fixture(request): """ - Fixture for trying explicit timezones: %(params)s + Fixture for trying explicit timezones: {0} """ return request.param diff --git a/pandas/util/_test_decorators.py b/pandas/util/_test_decorators.py index ab6dfee9c862c..89d90258f58e0 100644 --- a/pandas/util/_test_decorators.py +++ b/pandas/util/_test_decorators.py @@ -189,3 +189,28 @@ def decorated_func(func): "installed->{installed}".format( enabled=_USE_NUMEXPR, installed=_NUMEXPR_INSTALLED)) + + +def parametrize_fixture_doc(*args): + """ + Intended for use as a decorator for parametrized fixture, + this function will wrap the decorated function with a pytest + ``parametrize_fixture_doc`` mark. That mark will format + initial fixture docstring by replacing placeholders {0}, {1} etc + with parameters passed as arguments. + + Parameters: + ---------- + args: iterable + Positional arguments for docstring. + + Returns: + ------- + documented_fixture: function + The decorated function wrapped within a pytest + ``parametrize_fixture_doc`` mark + """ + def documented_fixture(fixture): + fixture.__doc__ = fixture.__doc__.format(*args) + return fixture + return documented_fixture From f8ccfa02cee501083f31fe952a24a0fb33d6d836 Mon Sep 17 00:00:00 2001 From: Will Ayd Date: Fri, 25 May 2018 13:41:09 -0700 Subject: [PATCH 14/17] Removed errant Categorical section in whatsnew --- doc/source/whatsnew/v0.23.1.txt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/doc/source/whatsnew/v0.23.1.txt b/doc/source/whatsnew/v0.23.1.txt index a659f88062047..9eedca36703d4 100644 --- a/doc/source/whatsnew/v0.23.1.txt +++ b/doc/source/whatsnew/v0.23.1.txt @@ -96,11 +96,6 @@ Reshaping - Bug in :func:`concat` where error was raised in concatenating :class:`Series` with numpy scalar and tuple names (:issue:`21015`) - -Categorical -^^^^^^^^^^^ - -- - Other ^^^^^ From e427f4b14a9a3bb9e2b930fdb09ac6ff35e7e88a Mon Sep 17 00:00:00 2001 From: Will Ayd Date: Fri, 25 May 2018 13:41:43 -0700 Subject: [PATCH 15/17] LINT fixup --- pandas/tests/test_downstream.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/pandas/tests/test_downstream.py b/pandas/tests/test_downstream.py index 56bf19e525d84..c2d09c6d49e86 100644 --- a/pandas/tests/test_downstream.py +++ b/pandas/tests/test_downstream.py @@ -2,9 +2,7 @@ """ Testing that we work in the downstream packages """ -import pkgutil import subprocess -import warnings import pytest import numpy as np # noqa From a2e748aa0f0ae41ff5c70630f8c86fc1a318dea5 Mon Sep 17 00:00:00 2001 From: Will Ayd Date: Tue, 29 May 2018 13:29:26 -0700 Subject: [PATCH 16/17] Updated TODO comments --- pandas/tseries/offsets.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas/tseries/offsets.py b/pandas/tseries/offsets.py index 54670c0e652e0..c294110d89ec5 100644 --- a/pandas/tseries/offsets.py +++ b/pandas/tseries/offsets.py @@ -1090,14 +1090,14 @@ def apply(self, other): class CustomBusinessMonthEnd(_CustomBusinessMonth): - # TODO: Replace condition with Subsitution after dropping Py27 support + # TODO(py27): Replace condition with Subsitution after dropping Py27 if _CustomBusinessMonth.__doc__: __doc__ = _CustomBusinessMonth.__doc__.replace('[BEGIN/END]', 'end') _prefix = 'CBM' class CustomBusinessMonthBegin(_CustomBusinessMonth): - # TODO: Replace condition with Subsitution after dropping Py27 support + # TODO(py27): Replace condition with Subsitution after dropping Py27 if _CustomBusinessMonth.__doc__: __doc__ = _CustomBusinessMonth.__doc__.replace('[BEGIN/END]', 'beginning') From 75dbaad4cf7b33b8b6ba709e3bd527e4d970cb5d Mon Sep 17 00:00:00 2001 From: Will Ayd Date: Tue, 29 May 2018 13:40:55 -0700 Subject: [PATCH 17/17] Fixed decorate docstring wrapper --- pandas/util/_decorators.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/pandas/util/_decorators.py b/pandas/util/_decorators.py index f23abac4360a7..6b55554cdc941 100644 --- a/pandas/util/_decorators.py +++ b/pandas/util/_decorators.py @@ -3,8 +3,8 @@ import inspect import types import warnings -from textwrap import dedent -from functools import wraps, update_wrapper +from textwrap import dedent, wrap +from functools import wraps, update_wrapper, WRAPPER_ASSIGNMENTS def deprecate(name, alternative, version, alt_name=None, @@ -19,8 +19,8 @@ def deprecate(name, alternative, version, alt_name=None, Parameters ---------- - name : func - Function to deprecate. + name : str + Name of function to deprecate. alternative : func Function to use instead. version : str @@ -41,10 +41,10 @@ def deprecate(name, alternative, version, alt_name=None, # adding deprecated directive to the docstring msg = msg or 'Use `{alt_name}` instead.'.format(alt_name=alt_name) + msg = '\n '.join(wrap(msg, 70)) @Substitution(version=version, msg=msg) - @Appender(name.__doc__) - @wraps(alternative) + @Appender(alternative.__doc__) def wrapper(*args, **kwargs): """ .. deprecated:: %(version)s @@ -55,6 +55,11 @@ def wrapper(*args, **kwargs): warnings.warn(warning_msg, klass, stacklevel=stacklevel) return alternative(*args, **kwargs) + # Since we are using Substitution to create the required docstring, + # remove that from the attributes that should be assigned to the wrapper + assignments = tuple(x for x in WRAPPER_ASSIGNMENTS if x != '__doc__') + update_wrapper(wrapper, alternative, assigned=assignments) + return wrapper