From eed5b94d71c1063af3b8a052ef08f45b6eb6fd2f Mon Sep 17 00:00:00 2001 From: hannah Date: Thu, 30 Apr 2020 23:22:46 -0400 Subject: [PATCH 01/11] FuncFormatter can take func(x) and func(x,pos), and FuncFormatter tests --- lib/matplotlib/tests/test_ticker.py | 21 +++++++++++++++++++++ lib/matplotlib/ticker.py | 24 ++++++++++++++++++++---- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/lib/matplotlib/tests/test_ticker.py b/lib/matplotlib/tests/test_ticker.py index 263df149de5d..3c01c5bd7756 100644 --- a/lib/matplotlib/tests/test_ticker.py +++ b/lib/matplotlib/tests/test_ticker.py @@ -1041,6 +1041,27 @@ def test_basic(self): assert '00002' == tmp_form(2) +class TestFuncFormatter: + def test_input_x_pos(self): + func = lambda x, pos : f"{x}+{pos}" + funcform = mticker.FuncFormatter(func) + assert "1+2" == funcform(1,2) + + def text_input_x(self): + func = lambda x: f"hello {x}" + funcform = mticker.FuncFormatter(func) + assert "hello 0" == funcform(0) + + def test_error(self): + with pytest.raises(TypeError, match=r"FuncFormatter*"): + func = lambda x, y, z: " ".join([x, y, z]) + funcform = mticker.FuncFormatter(func) + funcform(1,2,3) + + def test_built_in(self): + funcform = mticker.FuncFormatter("{} hi!".format) + assert "42 hi!" == funcform(42) + class TestStrMethodFormatter: test_data = [ ('{x:05d}', (2,), '00002'), diff --git a/lib/matplotlib/ticker.py b/lib/matplotlib/ticker.py index 277f55a1afab..ae103348b297 100644 --- a/lib/matplotlib/ticker.py +++ b/lib/matplotlib/ticker.py @@ -168,6 +168,7 @@ import logging import locale import math +import inspect from numbers import Integral import numpy as np @@ -377,12 +378,26 @@ class FuncFormatter(Formatter): """ Use a user-defined function for formatting. - The function should take in two inputs (a tick value ``x`` and a - position ``pos``), and return a string containing the corresponding - tick label. + The function can take in at most two inputs (a required tick value ``x`` and + an optional position ``pos``), and must return a string containing the + corresponding tick label. """ def __init__(self, func): - self.func = func + try: + self.nargs = len(inspect.signature(func).parameters) + if self.nargs == 2: + self.func = func + elif self.nargs == 1: + def func_pos(x, pos): + return func(x) + self.func = func_pos + else: + raise TypeError("""FuncFormatter functions take at most + 2 parameters: x (required), pos (optional)""") + except ValueError as e: + #built ins like str.format don't have signatures + self.func = func + def __call__(self, x, pos=None): """ @@ -390,6 +405,7 @@ def __call__(self, x, pos=None): *x* and *pos* are passed through as-is. """ + return self.func(x, pos) From 103314bfbd7885e3bb760f7f13457066e198517e Mon Sep 17 00:00:00 2001 From: hannah Date: Fri, 1 May 2020 11:06:24 -0400 Subject: [PATCH 02/11] flake errors --- lib/matplotlib/tests/test_ticker.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/matplotlib/tests/test_ticker.py b/lib/matplotlib/tests/test_ticker.py index 3c01c5bd7756..a56752553213 100644 --- a/lib/matplotlib/tests/test_ticker.py +++ b/lib/matplotlib/tests/test_ticker.py @@ -1043,25 +1043,29 @@ def test_basic(self): class TestFuncFormatter: def test_input_x_pos(self): - func = lambda x, pos : f"{x}+{pos}" + def func(x, pos): + return f"{x}+{pos}" funcform = mticker.FuncFormatter(func) - assert "1+2" == funcform(1,2) + assert "1+2" == funcform(1, 2) def text_input_x(self): - func = lambda x: f"hello {x}" + def func(x): + f"hello {x}" funcform = mticker.FuncFormatter(func) assert "hello 0" == funcform(0) def test_error(self): with pytest.raises(TypeError, match=r"FuncFormatter*"): - func = lambda x, y, z: " ".join([x, y, z]) + def func(x, y, z): + " ".join([x, y, z]) funcform = mticker.FuncFormatter(func) - funcform(1,2,3) + funcform(1, 2, 3) def test_built_in(self): funcform = mticker.FuncFormatter("{} hi!".format) assert "42 hi!" == funcform(42) + class TestStrMethodFormatter: test_data = [ ('{x:05d}', (2,), '00002'), From 14f0106793c6c38c1f7b54ce7ca85432ce4d0d56 Mon Sep 17 00:00:00 2001 From: hannah Date: Fri, 1 May 2020 14:22:56 -0400 Subject: [PATCH 03/11] added in @anntzer's suggestion for parsing strings --- lib/matplotlib/tests/test_ticker.py | 46 ++++++++++++++-------------- lib/matplotlib/ticker.py | 47 +++++++++++++++++------------ 2 files changed, 52 insertions(+), 41 deletions(-) diff --git a/lib/matplotlib/tests/test_ticker.py b/lib/matplotlib/tests/test_ticker.py index a56752553213..efe99cf83239 100644 --- a/lib/matplotlib/tests/test_ticker.py +++ b/lib/matplotlib/tests/test_ticker.py @@ -1042,28 +1042,30 @@ def test_basic(self): class TestFuncFormatter: - def test_input_x_pos(self): - def func(x, pos): - return f"{x}+{pos}" - funcform = mticker.FuncFormatter(func) - assert "1+2" == funcform(1, 2) - - def text_input_x(self): - def func(x): - f"hello {x}" - funcform = mticker.FuncFormatter(func) - assert "hello 0" == funcform(0) - - def test_error(self): - with pytest.raises(TypeError, match=r"FuncFormatter*"): - def func(x, y, z): - " ".join([x, y, z]) - funcform = mticker.FuncFormatter(func) - funcform(1, 2, 3) - - def test_built_in(self): - funcform = mticker.FuncFormatter("{} hi!".format) - assert "42 hi!" == funcform(42) + tests = [("function, 1 input", + (lambda x: f"{x}!", [2], "2!")), + ("function 2 inputs", + (lambda x, pos: f"{x}+{pos}!", [2, 3], "2+3!")), + ("format, 1 input", + ("{}!".format, [2], "2!")), + ("format 2 inputs", + ("{}+{}!".format, [2, 3], "2+3!"))] + ids, data = zip(*tests) + + @pytest.mark.parametrize("func, args, expected", data, ids=ids) + def test_arguments(self, func, args, expected): + assert expected == mticker.FuncFormatter(func)(*args) + + @pytest.mark.parametrize("func", [(lambda x, y, z: ""), + ("{}+{}+{}".format)], + ids=["function", "format"]) + def test_typerror(self, func): + with pytest.raises(TypeError, match=r'function: 3'): + mticker.FuncFormatter(func) + + def test_other_builtins(self): + with pytest.raises(UserWarning, match=r'max is not'): + mticker.FuncFormatter(max) class TestStrMethodFormatter: diff --git a/lib/matplotlib/ticker.py b/lib/matplotlib/ticker.py index ae103348b297..29629a5e28bb 100644 --- a/lib/matplotlib/ticker.py +++ b/lib/matplotlib/ticker.py @@ -165,10 +165,13 @@ """ import itertools +import inspect import logging import locale import math -import inspect +import string +import types +import warnings from numbers import Integral import numpy as np @@ -378,26 +381,33 @@ class FuncFormatter(Formatter): """ Use a user-defined function for formatting. - The function can take in at most two inputs (a required tick value ``x`` and - an optional position ``pos``), and must return a string containing the - corresponding tick label. + The function can take in at most two inputs (a required tick value ``x`` + and an optional position ``pos``), and must return a string containing + the corresponding tick label. """ def __init__(self, func): - try: - self.nargs = len(inspect.signature(func).parameters) - if self.nargs == 2: - self.func = func - elif self.nargs == 1: - def func_pos(x, pos): - return func(x) - self.func = func_pos - else: - raise TypeError("""FuncFormatter functions take at most - 2 parameters: x (required), pos (optional)""") - except ValueError as e: - #built ins like str.format don't have signatures + if not isinstance(func, types.BuiltinFunctionType): + nargs = len(inspect.signature(func).parameters) + elif (func.__name__ == 'format'): + #check if there's a format spec + nargs = len([(_, _, fs, _) for (_, _, fs, _) + in string.Formatter().parse(func.__self__) + if fs is not None]) + else: + #finding argcount for other builtins is a mess + nargs = 2 + raise warnings.warn(f"""{func.__name__} is not supported + and may not work as expected""") + if nargs == 2: self.func = func - + elif nargs == 1: + def func_pos(x, pos): + return func(x) + self.func = func_pos + else: + raise TypeError(f"""Number of parameters in function: {nargs}. + FuncFormatter functions take at most 2: + x (required), pos (optional).""") def __call__(self, x, pos=None): """ @@ -405,7 +415,6 @@ def __call__(self, x, pos=None): *x* and *pos* are passed through as-is. """ - return self.func(x, pos) From 0ed733c306d9d73824cec37b5af29e87cdc58067 Mon Sep 17 00:00:00 2001 From: hannah Date: Fri, 1 May 2020 14:40:58 -0400 Subject: [PATCH 04/11] added @timhoffm's suggestion about changing wrap to lambda and implicit concat on message --- lib/matplotlib/tests/test_ticker.py | 2 +- lib/matplotlib/ticker.py | 19 +++++++++---------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/lib/matplotlib/tests/test_ticker.py b/lib/matplotlib/tests/test_ticker.py index efe99cf83239..696c5082e9c8 100644 --- a/lib/matplotlib/tests/test_ticker.py +++ b/lib/matplotlib/tests/test_ticker.py @@ -1060,7 +1060,7 @@ def test_arguments(self, func, args, expected): ("{}+{}+{}".format)], ids=["function", "format"]) def test_typerror(self, func): - with pytest.raises(TypeError, match=r'function: 3'): + with pytest.raises(TypeError, match=r'3 arguments'): mticker.FuncFormatter(func) def test_other_builtins(self): diff --git a/lib/matplotlib/ticker.py b/lib/matplotlib/ticker.py index 29629a5e28bb..12ca704cfe51 100644 --- a/lib/matplotlib/ticker.py +++ b/lib/matplotlib/ticker.py @@ -396,18 +396,17 @@ def __init__(self, func): else: #finding argcount for other builtins is a mess nargs = 2 - raise warnings.warn(f"""{func.__name__} is not supported - and may not work as expected""") - if nargs == 2: + raise warnings.warn(f"{func.__name__} is not supported " + "and may not work as expected") + + if nargs == 1: + self.func = lambda x, pos: func(x) + elif nargs == 2: self.func = func - elif nargs == 1: - def func_pos(x, pos): - return func(x) - self.func = func_pos else: - raise TypeError(f"""Number of parameters in function: {nargs}. - FuncFormatter functions take at most 2: - x (required), pos (optional).""") + raise TypeError(f"{func.__name__} takes {nargs} arguments. " + "FuncFormatter functions take at most 2: " + "x (required), pos (optional).") def __call__(self, x, pos=None): """ From 394d73a46989b36970a0d40291f8693286f1e3e6 Mon Sep 17 00:00:00 2001 From: hannah Date: Fri, 1 May 2020 17:12:36 -0400 Subject: [PATCH 05/11] @anntzer suggestions - gettattr, cbook.warn, switch in __call__ flake errors --- lib/matplotlib/tests/test_ticker.py | 27 ++++++++++++++++++++++++- lib/matplotlib/ticker.py | 31 ++++++++++++++--------------- 2 files changed, 41 insertions(+), 17 deletions(-) diff --git a/lib/matplotlib/tests/test_ticker.py b/lib/matplotlib/tests/test_ticker.py index 696c5082e9c8..ce8d0ac70744 100644 --- a/lib/matplotlib/tests/test_ticker.py +++ b/lib/matplotlib/tests/test_ticker.py @@ -1042,6 +1042,7 @@ def test_basic(self): class TestFuncFormatter: +<<<<<<< HEAD tests = [("function, 1 input", (lambda x: f"{x}!", [2], "2!")), ("function 2 inputs", @@ -1051,7 +1052,6 @@ class TestFuncFormatter: ("format 2 inputs", ("{}+{}!".format, [2, 3], "2+3!"))] ids, data = zip(*tests) - @pytest.mark.parametrize("func, args, expected", data, ids=ids) def test_arguments(self, func, args, expected): assert expected == mticker.FuncFormatter(func)(*args) @@ -1067,6 +1067,31 @@ def test_other_builtins(self): with pytest.raises(UserWarning, match=r'max is not'): mticker.FuncFormatter(max) +======= + def test_input_x_pos(self): + def func(x, pos): + return f"{x}+{pos}" + funcform = mticker.FuncFormatter(func) + assert "1+2" == funcform(1, 2) + + def text_input_x(self): + def func(x): + f"hello {x}" + funcform = mticker.FuncFormatter(func) + assert "hello 0" == funcform(0) + + def test_error(self): + with pytest.raises(TypeError, match=r"FuncFormatter*"): + def func(x, y, z): + " ".join([x, y, z]) + funcform = mticker.FuncFormatter(func) + funcform(1, 2, 3) + + def test_built_in(self): + funcform = mticker.FuncFormatter("{} hi!".format) + assert "42 hi!" == funcform(42) +>>>>>>> 103314bfb... flake errors + class TestStrMethodFormatter: test_data = [ diff --git a/lib/matplotlib/ticker.py b/lib/matplotlib/ticker.py index 12ca704cfe51..76494ecdc213 100644 --- a/lib/matplotlib/ticker.py +++ b/lib/matplotlib/ticker.py @@ -171,7 +171,6 @@ import math import string import types -import warnings from numbers import Integral import numpy as np @@ -386,25 +385,23 @@ class FuncFormatter(Formatter): the corresponding tick label. """ def __init__(self, func): + self.func = func + if not isinstance(func, types.BuiltinFunctionType): - nargs = len(inspect.signature(func).parameters) - elif (func.__name__ == 'format'): + self.nargs = len(inspect.signature(func).parameters) + elif (isinstance(getattr(func, "__self__"), str) and + (getattr(func, "__name__", "") == "format")): #check if there's a format spec - nargs = len([(_, _, fs, _) for (_, _, fs, _) - in string.Formatter().parse(func.__self__) - if fs is not None]) + self.nargs = len([(_, _, fs, _) for (_, _, fs, _) + in string.Formatter().parse(func.__self__) + if fs is not None]) else: #finding argcount for other builtins is a mess - nargs = 2 - raise warnings.warn(f"{func.__name__} is not supported " - "and may not work as expected") - - if nargs == 1: - self.func = lambda x, pos: func(x) - elif nargs == 2: - self.func = func - else: - raise TypeError(f"{func.__name__} takes {nargs} arguments. " + self.nargs = 2 + cbook._warn_external(f"{func.__name__} is not supported " + "and may not work as expected") + if self.nargs not in [1, 2]: + raise TypeError(f"{func.__name__} takes {self.nargs} arguments. " "FuncFormatter functions take at most 2: " "x (required), pos (optional).") @@ -414,6 +411,8 @@ def __call__(self, x, pos=None): *x* and *pos* are passed through as-is. """ + if self.nargs == 1: + return self.func(x) return self.func(x, pos) From a21c4a87e09d00ff7a56f991117bbc838eb6695e Mon Sep 17 00:00:00 2001 From: hannah Date: Fri, 1 May 2020 19:33:28 -0400 Subject: [PATCH 06/11] why are all the git checks failing? --- lib/matplotlib/tests/test_ticker.py | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/lib/matplotlib/tests/test_ticker.py b/lib/matplotlib/tests/test_ticker.py index ce8d0ac70744..f4d26a7b234c 100644 --- a/lib/matplotlib/tests/test_ticker.py +++ b/lib/matplotlib/tests/test_ticker.py @@ -1042,7 +1042,6 @@ def test_basic(self): class TestFuncFormatter: -<<<<<<< HEAD tests = [("function, 1 input", (lambda x: f"{x}!", [2], "2!")), ("function 2 inputs", @@ -1067,31 +1066,6 @@ def test_other_builtins(self): with pytest.raises(UserWarning, match=r'max is not'): mticker.FuncFormatter(max) -======= - def test_input_x_pos(self): - def func(x, pos): - return f"{x}+{pos}" - funcform = mticker.FuncFormatter(func) - assert "1+2" == funcform(1, 2) - - def text_input_x(self): - def func(x): - f"hello {x}" - funcform = mticker.FuncFormatter(func) - assert "hello 0" == funcform(0) - - def test_error(self): - with pytest.raises(TypeError, match=r"FuncFormatter*"): - def func(x, y, z): - " ".join([x, y, z]) - funcform = mticker.FuncFormatter(func) - funcform(1, 2, 3) - - def test_built_in(self): - funcform = mticker.FuncFormatter("{} hi!".format) - assert "42 hi!" == funcform(42) ->>>>>>> 103314bfb... flake errors - class TestStrMethodFormatter: test_data = [ From e2d51818906cfbbb3e577288d3672d488eaffd8c Mon Sep 17 00:00:00 2001 From: hannah Date: Sun, 3 May 2020 00:00:27 -0400 Subject: [PATCH 07/11] turned func into a property --- lib/matplotlib/tests/test_ticker.py | 5 ++++ lib/matplotlib/ticker.py | 37 ++++++++++++++++++----------- 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/lib/matplotlib/tests/test_ticker.py b/lib/matplotlib/tests/test_ticker.py index f4d26a7b234c..2546336ff017 100644 --- a/lib/matplotlib/tests/test_ticker.py +++ b/lib/matplotlib/tests/test_ticker.py @@ -1066,6 +1066,11 @@ def test_other_builtins(self): with pytest.raises(UserWarning, match=r'max is not'): mticker.FuncFormatter(max) + def test_update(self): + formatter = mticker.FuncFormatter(lambda x, pos: f"{x}+{pos}") + assert "1+2" == formatter(1,2) + with pytest.raises(TypeError, match='3 arguments'): + formatter.func = lambda x, pos, error: "!" class TestStrMethodFormatter: test_data = [ diff --git a/lib/matplotlib/ticker.py b/lib/matplotlib/ticker.py index 76494ecdc213..62749161ccb5 100644 --- a/lib/matplotlib/ticker.py +++ b/lib/matplotlib/ticker.py @@ -387,33 +387,42 @@ class FuncFormatter(Formatter): def __init__(self, func): self.func = func + def __call__(self, x, pos=None): + """ + Return the value of the user defined function. + + *x* and *pos* are passed through as-is. + """ + if self._nargs == 1: + return self._func(x) + return self._func(x, pos) + + @property + def func(self): + return self._func + + @func.setter + def func(self, func): + self._func = func if not isinstance(func, types.BuiltinFunctionType): - self.nargs = len(inspect.signature(func).parameters) + self._nargs = len(inspect.signature(func).parameters) elif (isinstance(getattr(func, "__self__"), str) and (getattr(func, "__name__", "") == "format")): #check if there's a format spec - self.nargs = len([(_, _, fs, _) for (_, _, fs, _) + self._nargs = len([(_, _, fs, _) for (_, _, fs, _) in string.Formatter().parse(func.__self__) if fs is not None]) else: #finding argcount for other builtins is a mess - self.nargs = 2 + self._nargs = 2 cbook._warn_external(f"{func.__name__} is not supported " "and may not work as expected") - if self.nargs not in [1, 2]: - raise TypeError(f"{func.__name__} takes {self.nargs} arguments. " + if self._nargs not in [1, 2]: + raise TypeError(f"{func.__name__} takes {self._nargs} arguments. " "FuncFormatter functions take at most 2: " "x (required), pos (optional).") + - def __call__(self, x, pos=None): - """ - Return the value of the user defined function. - - *x* and *pos* are passed through as-is. - """ - if self.nargs == 1: - return self.func(x) - return self.func(x, pos) class FormatStrFormatter(Formatter): From 74df2a99fe55d55a442d2ea185bde008ad32e2cb Mon Sep 17 00:00:00 2001 From: hannah Date: Sun, 3 May 2020 00:14:09 -0400 Subject: [PATCH 08/11] flake errors --- lib/matplotlib/tests/test_ticker.py | 5 +++-- lib/matplotlib/ticker.py | 4 +--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/matplotlib/tests/test_ticker.py b/lib/matplotlib/tests/test_ticker.py index 2546336ff017..c6e2ce7be146 100644 --- a/lib/matplotlib/tests/test_ticker.py +++ b/lib/matplotlib/tests/test_ticker.py @@ -1068,9 +1068,10 @@ def test_other_builtins(self): def test_update(self): formatter = mticker.FuncFormatter(lambda x, pos: f"{x}+{pos}") - assert "1+2" == formatter(1,2) + assert "1+2" == formatter(1, 2) with pytest.raises(TypeError, match='3 arguments'): - formatter.func = lambda x, pos, error: "!" + formatter.func = lambda x, pos, error: "!" + class TestStrMethodFormatter: test_data = [ diff --git a/lib/matplotlib/ticker.py b/lib/matplotlib/ticker.py index 62749161ccb5..1bb380149788 100644 --- a/lib/matplotlib/ticker.py +++ b/lib/matplotlib/ticker.py @@ -420,9 +420,7 @@ def func(self, func): if self._nargs not in [1, 2]: raise TypeError(f"{func.__name__} takes {self._nargs} arguments. " "FuncFormatter functions take at most 2: " - "x (required), pos (optional).") - - + "x (required), pos (optional). class FormatStrFormatter(Formatter): From 1232f7a4bcfd603dfa551d30b68f51c63b413466 Mon Sep 17 00:00:00 2001 From: hannah Date: Sun, 3 May 2020 14:45:00 -0400 Subject: [PATCH 09/11] fixed tests by putting in left out closing ')' --- lib/matplotlib/ticker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/ticker.py b/lib/matplotlib/ticker.py index 1bb380149788..7319717f568e 100644 --- a/lib/matplotlib/ticker.py +++ b/lib/matplotlib/ticker.py @@ -420,7 +420,7 @@ def func(self, func): if self._nargs not in [1, 2]: raise TypeError(f"{func.__name__} takes {self._nargs} arguments. " "FuncFormatter functions take at most 2: " - "x (required), pos (optional). + "x (required), pos (optional).") class FormatStrFormatter(Formatter): From 79e90631833d58f8858bca210dd3dd675a588d54 Mon Sep 17 00:00:00 2001 From: hannah Date: Thu, 14 May 2020 01:19:03 -0400 Subject: [PATCH 10/11] updated to try/catch, changed the str tests, and switched polar test to use strmethodformatter --- lib/matplotlib/tests/test_polar.py | 2 +- lib/matplotlib/tests/test_ticker.py | 33 ++++++++++--------------- lib/matplotlib/ticker.py | 38 ++++++++++++++--------------- 3 files changed, 33 insertions(+), 40 deletions(-) diff --git a/lib/matplotlib/tests/test_polar.py b/lib/matplotlib/tests/test_polar.py index 12f03fd6c6bd..c785d9b97817 100644 --- a/lib/matplotlib/tests/test_polar.py +++ b/lib/matplotlib/tests/test_polar.py @@ -139,7 +139,7 @@ def test_polar_units_2(fig_test, fig_ref): ax = fig_ref.add_subplot(projection="polar") ax.plot(np.deg2rad(xs), ys) - ax.xaxis.set_major_formatter(mpl.ticker.FuncFormatter("{:.12}".format)) + ax.xaxis.set_major_formatter(mpl.ticker.StrMethodFormatter("{x:.12}")) ax.set(xlabel="rad", ylabel="km") diff --git a/lib/matplotlib/tests/test_ticker.py b/lib/matplotlib/tests/test_ticker.py index c6e2ce7be146..e6659d943d40 100644 --- a/lib/matplotlib/tests/test_ticker.py +++ b/lib/matplotlib/tests/test_ticker.py @@ -1042,34 +1042,27 @@ def test_basic(self): class TestFuncFormatter: - tests = [("function, 1 input", - (lambda x: f"{x}!", [2], "2!")), - ("function 2 inputs", - (lambda x, pos: f"{x}+{pos}!", [2, 3], "2+3!")), - ("format, 1 input", - ("{}!".format, [2], "2!")), - ("format 2 inputs", - ("{}+{}!".format, [2, 3], "2+3!"))] - ids, data = zip(*tests) - @pytest.mark.parametrize("func, args, expected", data, ids=ids) + @pytest.mark.parametrize("func, args, expected", + [(lambda x: f"{x}!", [2], "2!"), + (lambda x, pos: f"{x}+{pos}!", [2, 3], "2+3!")]) def test_arguments(self, func, args, expected): assert expected == mticker.FuncFormatter(func)(*args) - @pytest.mark.parametrize("func", [(lambda x, y, z: ""), - ("{}+{}+{}".format)], - ids=["function", "format"]) - def test_typerror(self, func): - with pytest.raises(TypeError, match=r'3 arguments'): - mticker.FuncFormatter(func) + @pytest.mark.parametrize("func, args, expected", + [("{}!".format, [2], "2!"), + ("{}+{}!".format, [2, 3], "2+3!")]) + def test_builtins(self, func, args, expected): + with pytest.raises(UserWarning, match=r'not support format'): + assert expected == mticker.FuncFormatter(func)(*args) - def test_other_builtins(self): - with pytest.raises(UserWarning, match=r'max is not'): - mticker.FuncFormatter(max) + def test_typerror(self): + with pytest.raises(TypeError, match=r'must take at most'): + mticker.FuncFormatter((lambda x, y, z: " ")) def test_update(self): formatter = mticker.FuncFormatter(lambda x, pos: f"{x}+{pos}") assert "1+2" == formatter(1, 2) - with pytest.raises(TypeError, match='3 arguments'): + with pytest.raises(TypeError, match=r'must take at most'): formatter.func = lambda x, pos, error: "!" diff --git a/lib/matplotlib/ticker.py b/lib/matplotlib/ticker.py index 7319717f568e..06932d71682d 100644 --- a/lib/matplotlib/ticker.py +++ b/lib/matplotlib/ticker.py @@ -169,8 +169,6 @@ import logging import locale import math -import string -import types from numbers import Integral import numpy as np @@ -403,24 +401,26 @@ def func(self): @func.setter def func(self, func): - self._func = func - if not isinstance(func, types.BuiltinFunctionType): - self._nargs = len(inspect.signature(func).parameters) - elif (isinstance(getattr(func, "__self__"), str) and - (getattr(func, "__name__", "") == "format")): - #check if there's a format spec - self._nargs = len([(_, _, fs, _) for (_, _, fs, _) - in string.Formatter().parse(func.__self__) - if fs is not None]) - else: - #finding argcount for other builtins is a mess + try: + sig = inspect.signature(func) + except ValueError: self._nargs = 2 - cbook._warn_external(f"{func.__name__} is not supported " - "and may not work as expected") - if self._nargs not in [1, 2]: - raise TypeError(f"{func.__name__} takes {self._nargs} arguments. " - "FuncFormatter functions take at most 2: " - "x (required), pos (optional).") + cbook._warn_external("FuncFormatter may not support " + f"{func.__name__}. Please look the " + "other formatters in `matplotlib.ticker`.") + else: + try: + sig.bind(None, None) + self._nargs = 2 + except TypeError: + try: + sig.bind(None) + self._nargs = 1 + except TypeError: + raise TypeError(f"{func.__name__} must take " + "at most 2 arguments: " + "x (required), pos (optional).") + self._func = func class FormatStrFormatter(Formatter): From bb7280ea3e6ea09826a66a93f88e401fdc650bae Mon Sep 17 00:00:00 2001 From: hannah Date: Thu, 14 May 2020 01:23:16 -0400 Subject: [PATCH 11/11] lost a word --- lib/matplotlib/ticker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/ticker.py b/lib/matplotlib/ticker.py index 06932d71682d..f35fc554f115 100644 --- a/lib/matplotlib/ticker.py +++ b/lib/matplotlib/ticker.py @@ -406,7 +406,7 @@ def func(self, func): except ValueError: self._nargs = 2 cbook._warn_external("FuncFormatter may not support " - f"{func.__name__}. Please look the " + f"{func.__name__}. Please look at the " "other formatters in `matplotlib.ticker`.") else: try: