Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e57b321

Browse files
committed
Add xlim / ylim autogeneration
- Create get_signature method - Create AXES_GETTER_SETTER_TEMPLATE - Create call_param method on generate_function
1 parent f6b77d2 commit e57b321

2 files changed

Lines changed: 151 additions & 35 deletions

File tree

lib/matplotlib/pyplot.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4457,6 +4457,72 @@ def yscale(value: str | ScaleBase, **kwargs) -> None:
44574457
gca().set_yscale(value, **kwargs)
44584458

44594459

4460+
# Autogenerated by boilerplate.py. Do not edit as changes will be lost.
4461+
@overload
4462+
@_copy_docstring_and_deprecators(Axes.get_xlim)
4463+
def xlim() -> tuple[float, float]:
4464+
...
4465+
4466+
4467+
# Autogenerated by boilerplate.py. Do not edit as changes will be lost.
4468+
@overload
4469+
@_copy_docstring_and_deprecators(Axes.set_xlim)
4470+
def xlim(
4471+
left: float | tuple[float, float] | None = None,
4472+
right: float | None = None,
4473+
*,
4474+
emit: bool = True,
4475+
auto: bool | None = False,
4476+
xmin: float | None = None,
4477+
xmax: float | None = None,
4478+
) -> tuple[float, float]:
4479+
...
4480+
4481+
4482+
# Autogenerated by boilerplate.py. Do not edit as changes will be lost.
4483+
@_copy_docstring_and_deprecators(Axes.get_xlim)
4484+
def xlim(*args, **kwargs):
4485+
ax = gca()
4486+
if not args and not kwargs:
4487+
return ax.get_xlim()
4488+
4489+
ret = ax.set_xlim(*args, **kwargs)
4490+
return ret
4491+
4492+
4493+
# Autogenerated by boilerplate.py. Do not edit as changes will be lost.
4494+
@overload
4495+
@_copy_docstring_and_deprecators(Axes.get_ylim)
4496+
def ylim() -> tuple[float, float]:
4497+
...
4498+
4499+
4500+
# Autogenerated by boilerplate.py. Do not edit as changes will be lost.
4501+
@overload
4502+
@_copy_docstring_and_deprecators(Axes.set_ylim)
4503+
def ylim(
4504+
bottom: float | tuple[float, float] | None = None,
4505+
top: float | None = None,
4506+
*,
4507+
emit: bool = True,
4508+
auto: bool | None = False,
4509+
ymin: float | None = None,
4510+
ymax: float | None = None,
4511+
) -> tuple[float, float]:
4512+
...
4513+
4514+
4515+
# Autogenerated by boilerplate.py. Do not edit as changes will be lost.
4516+
@_copy_docstring_and_deprecators(Axes.get_ylim)
4517+
def ylim(*args, **kwargs):
4518+
ax = gca()
4519+
if not args and not kwargs:
4520+
return ax.get_ylim()
4521+
4522+
ret = ax.set_ylim(*args, **kwargs)
4523+
return ret
4524+
4525+
44604526
# Autogenerated by boilerplate.py. Do not edit as changes will be lost.
44614527
def autumn() -> None:
44624528
"""

tools/boilerplate.py

Lines changed: 85 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,25 @@ def {name}{signature}:
5454
{return_statement}gca().{called_name}{call}
5555
"""
5656

57+
AXES_GETTER_SETTER_TEMPLATE = AUTOGEN_MSG + """
58+
@overload
59+
@_copy_docstring_and_deprecators(Axes.get_{called_name})
60+
def {name}() -> {get_return_type}: ...
61+
""" + AUTOGEN_MSG + """
62+
@overload
63+
@_copy_docstring_and_deprecators(Axes.set_{called_name})
64+
def {name}{signature}: ...
65+
""" + AUTOGEN_MSG + """
66+
@_copy_docstring_and_deprecators(Axes.get_{called_name})
67+
def {name}(*args, **kwargs):
68+
ax = gca()
69+
if not args and not kwargs:
70+
return ax.get_{called_name}()
71+
72+
ret = ax.set_{called_name}(*args, **kwargs)
73+
return ret
74+
"""
75+
5776
FIGURE_METHOD_TEMPLATE = AUTOGEN_MSG + """
5877
@_copy_docstring_and_deprecators(Figure.{called_name})
5978
def {name}{signature}:
@@ -102,14 +121,15 @@ class direct_repr:
102121
"""
103122
A placeholder class to destringify annotations from ast
104123
"""
124+
105125
def __init__(self, value):
106126
self._repr = value
107127

108128
def __repr__(self):
109129
return self._repr
110130

111131

112-
def generate_function(name, called_fullname, template, **kwargs):
132+
def generate_function(name, called_fullname, template, gettersetter=False, **kwargs):
113133
"""
114134
Create a wrapper function *pyplot_name* calling *call_name*.
115135
@@ -127,6 +147,11 @@ def generate_function(name, called_fullname, template, **kwargs):
127147
- signature: The function signature (including parentheses).
128148
- called_name: The name of the called function.
129149
- call: Parameters passed to *called_name* (including parentheses).
150+
gettersetter : bool
151+
Indicate if the method to be wrapped is correponding to a getter and setter. A new placeholdr is filled :
152+
153+
- get_return_type: The type returned by the getter
154+
- set_return_type: The type returned by the setter
130155
131156
**kwargs
132157
Additional parameters are passed to ``template.format()``.
@@ -135,15 +160,14 @@ def generate_function(name, called_fullname, template, **kwargs):
135160
class_name, called_name = called_fullname.split('.')
136161
class_ = {'Axes': Axes, 'Figure': Figure}[class_name]
137162

138-
meth = getattr(class_, called_name)
139-
decorator = _api.deprecation.DECORATORS.get(meth)
140-
# Generate the wrapper with the non-kwonly signature, as it will get
141-
# redecorated with make_keyword_only by _copy_docstring_and_deprecators.
142-
if decorator and decorator.func is _api.make_keyword_only:
143-
meth = meth.__wrapped__
163+
if not gettersetter:
164+
signature = get_signature(class_, called_name)
165+
else:
166+
getter_signature = get_signature(class_, f"get_{called_name}")
167+
kwargs.setdefault("get_return_type", str(getter_signature.return_annotation))
144168

145-
annotated_trees = get_ast_mro_trees(class_)
146-
signature = get_matching_signature(meth, annotated_trees)
169+
signature = get_signature(class_, f"set_{called_name}")
170+
kwargs.setdefault('return_type', str(signature.return_annotation))
147171

148172
# Replace self argument.
149173
params = list(signature.parameters.values())[1:]
@@ -152,30 +176,30 @@ def generate_function(name, called_fullname, template, **kwargs):
152176
param.replace(default=value_formatter(param.default))
153177
if param.default is not param.empty else param
154178
for param in params]))
179+
155180
# How to call the wrapped function.
156-
call = '(' + ', '.join((
157-
# Pass "intended-as-positional" parameters positionally to avoid
158-
# forcing third-party subclasses to reproduce the parameter names.
159-
'{0}'
160-
if param.kind in [
161-
Parameter.POSITIONAL_OR_KEYWORD]
162-
and param.default is Parameter.empty else
163-
# Only pass the data kwarg if it is actually set, to avoid forcing
164-
# third-party subclasses to support it.
165-
'**({{"data": data}} if data is not None else {{}})'
166-
if param.name == "data" else
167-
'{0}={0}'
168-
if param.kind in [
169-
Parameter.POSITIONAL_OR_KEYWORD,
170-
Parameter.KEYWORD_ONLY] else
171-
'{0}'
172-
if param.kind is Parameter.POSITIONAL_ONLY else
173-
'*{0}'
174-
if param.kind is Parameter.VAR_POSITIONAL else
175-
'**{0}'
176-
if param.kind is Parameter.VAR_KEYWORD else
177-
None).format(param.name)
178-
for param in params) + ')'
181+
182+
def call_param(param: Parameter):
183+
match param.kind:
184+
# Pass "intended-as-positional" parameters positionally to avoid
185+
# forcing third-party subclasses to reproduce the parameter names.
186+
case Parameter.POSITIONAL_OR_KEYWORD if param.default is Parameter.empty:
187+
return '{0}'
188+
# Only pass the data kwarg if it is actually set, to avoid forcing
189+
# third-party subclasses to support it.
190+
case _ if param.name == "data":
191+
return '**({{"data": data}} if data is not None else {{}})'
192+
case Parameter.POSITIONAL_OR_KEYWORD | Parameter.KEYWORD_ONLY:
193+
return '{0}={0}'
194+
case Parameter.POSITIONAL_ONLY:
195+
return '{0}'
196+
case Parameter.VAR_POSITIONAL:
197+
return '*{0}'
198+
case Parameter.VAR_KEYWORD:
199+
return '**{0}'
200+
return None
201+
202+
call = '(' + ', '.join((call_param(param)).format(param.name) for param in params) + ')'
179203
return_statement = 'return ' if has_return_value else ''
180204
# Bail out in case of name collision.
181205
for reserved in ('gca', 'gci', 'gcf', '__ret'):
@@ -286,7 +310,12 @@ def boilerplate_gen():
286310
'xlabel:set_xlabel',
287311
'ylabel:set_ylabel',
288312
'xscale:set_xscale',
289-
'yscale:set_yscale',
313+
'yscale:set_yscale'
314+
)
315+
316+
_axes_getter_setters = (
317+
'xlim',
318+
'ylim',
290319
)
291320

292321
cmappable = {
@@ -341,6 +370,14 @@ def boilerplate_gen():
341370
yield generate_function(name, f'Axes.{called_name}', template,
342371
sci_command=cmappable.get(name))
343372

373+
for spec in _axes_getter_setters:
374+
if ':' in spec:
375+
name, called_name = spec.split(':')
376+
else:
377+
name = called_name = spec
378+
yield generate_function(name, f'Axes.{called_name}',
379+
AXES_GETTER_SETTER_TEMPLATE, True)
380+
344381
cmaps = (
345382
'autumn',
346383
'bone',
@@ -405,6 +442,19 @@ def get_ast_mro_trees(cls):
405442
return [get_ast_tree(c) for c in cls.__mro__ if c.__module__ != "builtins"]
406443

407444

445+
def get_signature(class_, name):
446+
meth = getattr(class_, name)
447+
448+
decorator = _api.deprecation.DECORATORS.get(meth)
449+
# Generate the wrapper with the non-kwonly signature, as it will get
450+
# redecorated with make_keyword_only by _copy_docstring_and_deprecators.
451+
if decorator and decorator.func is _api.make_keyword_only:
452+
meth = meth.__wrapped__
453+
454+
annotated_trees = get_ast_mro_trees(class_)
455+
return get_matching_signature(meth, annotated_trees)
456+
457+
408458
def get_matching_signature(method, trees):
409459
sig = inspect.signature(method)
410460
for tree in trees:
@@ -460,10 +510,10 @@ def update_sig_from_node(node, sig):
460510
if len(sys.argv) > 1:
461511
pyplot_path = Path(sys.argv[1])
462512
else:
463-
mpl_path = (Path(__file__).parent / ".." /"lib"/"matplotlib").resolve()
513+
mpl_path = (Path(__file__).parent / ".." / "lib" / "matplotlib").resolve()
464514
pyplot_path = mpl_path / "pyplot.py"
465515
for cls in [Axes, Figure]:
466-
if mpl_path not in Path(inspect.getfile(cls)).parents:
516+
if mpl_path not in Path(inspect.getfile(cls)).parents:
467517
raise RuntimeError(
468518
f"{cls.__name__} import path is not {mpl_path}.\n"
469519
"Please make sure your Matplotlib installation "

0 commit comments

Comments
 (0)