Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 4adf436

Browse filesBrowse files
authored
Merge pull request #13744 from timhoffm/restructure-boilerplate
Restructure boilerplate.py
2 parents cce3ef4 + 235cd4d commit 4adf436
Copy full SHA for 4adf436

File tree

Expand file treeCollapse file tree

1 file changed

+115
-90
lines changed
Filter options
Expand file treeCollapse file tree

1 file changed

+115
-90
lines changed

‎tools/boilerplate.py

Copy file name to clipboardExpand all lines: tools/boilerplate.py
+115-90Lines changed: 115 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -35,17 +35,17 @@
3535
# Autogenerated by boilerplate.py. Do not edit as changes will be lost."""
3636

3737
CMAPPABLE_TEMPLATE = AUTOGEN_MSG + """
38-
@docstring.copy(Axes.%(real_name)s)
39-
def %(func)s%(sig)s:
40-
__ret = gca().%(real_name)s%(call)s
41-
%(mappable)s
38+
@docstring.copy(Axes.{called_name})
39+
def {name}{signature}:
40+
__ret = gca().{called_name}{call}
41+
{sci_command}
4242
return __ret
4343
"""
4444

4545
NON_CMAPPABLE_TEMPLATE = AUTOGEN_MSG + """
46-
@docstring.copy(Axes.%(real_name)s)
47-
def %(func)s%(sig)s:
48-
return gca().%(real_name)s%(call)s
46+
@docstring.copy(Axes.{called_name})
47+
def {name}{signature}:
48+
return gca().{called_name}{call}
4949
"""
5050

5151
# Used for colormap functions
@@ -61,11 +61,111 @@ def {name}():
6161
'''
6262

6363

64+
class value_formatter:
65+
"""
66+
Format function default values as needed for inspect.formatargspec.
67+
The interesting part is a hard-coded list of functions used
68+
as defaults in pyplot methods.
69+
"""
70+
71+
def __init__(self, value):
72+
if value is mlab.detrend_none:
73+
self._repr = "mlab.detrend_none"
74+
elif value is mlab.window_hanning:
75+
self._repr = "mlab.window_hanning"
76+
elif value is np.mean:
77+
self._repr = "np.mean"
78+
elif value is cbook.deprecation._deprecated_parameter:
79+
self._repr = "cbook.deprecation._deprecated_parameter"
80+
else:
81+
self._repr = repr(value)
82+
83+
def __repr__(self):
84+
return self._repr
85+
86+
87+
def generate_function(name, called_name, template, **kwargs):
88+
"""
89+
Create a wrapper function *pyplot_name* calling *call_name*.
90+
91+
Parameters
92+
----------
93+
name : str
94+
The function to be created.
95+
called_name : str
96+
The function to be wrapped.
97+
template : str
98+
The template to be used. The template must contain {}-style format
99+
placeholders. The following placeholders are filled in:
100+
101+
- name: The function name.
102+
- signature: The function signature (including parentheses).
103+
- called_name: The name of the called function.
104+
- call: Parameters passed to *called_name* (including parentheses).
105+
106+
**kwargs
107+
Additional parameters are passed to ``template.format()``.
108+
"""
109+
text_wrapper = textwrap.TextWrapper(
110+
break_long_words=False, width=70,
111+
initial_indent=' ' * 8, subsequent_indent=' ' * 8)
112+
113+
# Get signature of wrapped function.
114+
signature = inspect.signature(getattr(Axes, called_name))
115+
# Replace self argument.
116+
params = list(signature.parameters.values())[1:]
117+
signature = str(signature.replace(parameters=[
118+
param.replace(default=value_formatter(param.default))
119+
if param.default is not param.empty else param
120+
for param in params]))
121+
if len('def ' + name + signature) >= 80:
122+
# Move opening parenthesis before newline.
123+
signature = '(\n' + text_wrapper.fill(signature).replace('(', '', 1)
124+
# How to call the wrapped function.
125+
call = '(' + ', '.join((
126+
# Pass "intended-as-positional" parameters positionally to avoid
127+
# forcing third-party subclasses to reproduce the parameter names.
128+
'{0}'
129+
if param.kind in [
130+
Parameter.POSITIONAL_OR_KEYWORD]
131+
and param.default is Parameter.empty else
132+
# Only pass the data kwarg if it is actually set, to avoid forcing
133+
# third-party subclasses to support it.
134+
'**({{"data": data}} if data is not None else {{}})'
135+
if param.name == "data" else
136+
'{0}={0}'
137+
if param.kind in [
138+
Parameter.POSITIONAL_OR_KEYWORD,
139+
Parameter.KEYWORD_ONLY] else
140+
'*{0}'
141+
if param.kind is Parameter.VAR_POSITIONAL else
142+
'**{0}'
143+
if param.kind is Parameter.VAR_KEYWORD else
144+
# Intentionally crash for Parameter.POSITIONAL_ONLY.
145+
None).format(param.name)
146+
for param in params) + ')'
147+
MAX_CALL_PREFIX = 18 # len(' __ret = gca().')
148+
if MAX_CALL_PREFIX + max(len(name), len(called_name)) + len(call) >= 80:
149+
call = '(\n' + text_wrapper.fill(call[1:])
150+
# Bail out in case of name collision.
151+
for reserved in ('gca', 'gci', '__ret'):
152+
if reserved in params:
153+
raise ValueError(
154+
f'Axes method {called_name} has kwarg named {reserved}')
155+
156+
return template.format(
157+
name=name,
158+
called_name=called_name,
159+
signature=signature,
160+
call=call,
161+
**kwargs)
162+
163+
64164
def boilerplate_gen():
65165
"""Generator of lines for the automated part of pyplot."""
66166

67167
# These methods are all simple wrappers of Axes methods by the same name.
68-
_commands = (
168+
_axes_commands = (
69169
'acorr',
70170
'angle_spectrum',
71171
'annotate',
@@ -161,91 +261,16 @@ def boilerplate_gen():
161261
'tripcolor': 'sci(__ret)',
162262
}
163263

164-
class value_formatter:
165-
"""
166-
Format function default values as needed for inspect.formatargspec.
167-
The interesting part is a hard-coded list of functions used
168-
as defaults in pyplot methods.
169-
"""
170-
171-
def __init__(self, value):
172-
if value is mlab.detrend_none:
173-
self._repr = "mlab.detrend_none"
174-
elif value is mlab.window_hanning:
175-
self._repr = "mlab.window_hanning"
176-
elif value is np.mean:
177-
self._repr = "np.mean"
178-
elif value is cbook.deprecation._deprecated_parameter:
179-
self._repr = "cbook.deprecation._deprecated_parameter"
180-
else:
181-
self._repr = repr(value)
182-
183-
def __repr__(self):
184-
return self._repr
185-
186-
text_wrapper = textwrap.TextWrapper(
187-
break_long_words=False, width=70,
188-
initial_indent=' ' * 8, subsequent_indent=' ' * 8)
189-
190-
for spec in _commands:
264+
for spec in _axes_commands:
191265
if ':' in spec:
192-
func, real_name = spec.split(':')
266+
name, called_name = spec.split(':')
193267
else:
194-
func = real_name = spec
268+
name = called_name = spec
195269

196-
# For some commands, an additional line is needed to set the color map.
197-
if func in cmappable:
198-
fmt = CMAPPABLE_TEMPLATE
199-
mappable = ' ' + cmappable[func]
200-
else:
201-
fmt = NON_CMAPPABLE_TEMPLATE
202-
203-
# Get signature of wrapped function.
204-
sig = inspect.signature(getattr(Axes, real_name))
205-
206-
# Replace self argument.
207-
params = list(sig.parameters.values())[1:]
208-
209-
sig = str(sig.replace(parameters=[
210-
param.replace(default=value_formatter(param.default))
211-
if param.default is not param.empty else param
212-
for param in params]))
213-
if len('def ' + func + sig) >= 80:
214-
# Move opening parenthesis before newline.
215-
sig = '(\n' + text_wrapper.fill(sig).replace('(', '', 1)
216-
217-
# How to call the wrapped function.
218-
call = '(' + ', '.join((
219-
# Pass "intended-as-positional" parameters positionally to avoid
220-
# forcing third-party subclasses to reproduce the parameter names.
221-
'{0}'
222-
if param.kind in [Parameter.POSITIONAL_OR_KEYWORD]
223-
and param.default is Parameter.empty else
224-
# Only pass the data kwarg if it is actually set, to avoid forcing
225-
# third-party subclasses to support it.
226-
'**({{"data": data}} if data is not None else {{}})'
227-
if param.name == "data" else
228-
'{0}={0}'
229-
if param.kind in [Parameter.POSITIONAL_OR_KEYWORD,
230-
Parameter.KEYWORD_ONLY] else
231-
'*{0}'
232-
if param.kind is Parameter.VAR_POSITIONAL else
233-
'**{0}'
234-
if param.kind is Parameter.VAR_KEYWORD else
235-
# Intentionally crash for Parameter.POSITIONAL_ONLY.
236-
None).format(param.name)
237-
for param in params) + ')'
238-
MAX_CALL_PREFIX = 18 # len(' __ret = gca().')
239-
if MAX_CALL_PREFIX + max(len(func), len(real_name)) + len(call) >= 80:
240-
call = '(\n' + text_wrapper.fill(call[1:])
241-
242-
# Bail out in case of name collision.
243-
for reserved in ('gca', 'gci', '__ret'):
244-
if reserved in params:
245-
raise ValueError(
246-
'Axes method {} has kwarg named {}'.format(func, reserved))
247-
248-
yield fmt % locals()
270+
template = (CMAPPABLE_TEMPLATE if name in cmappable else
271+
NON_CMAPPABLE_TEMPLATE)
272+
yield generate_function(name, called_name, template,
273+
sci_command=cmappable.get(name))
249274

250275
cmaps = (
251276
'autumn',

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.