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

Skip to content

Missing return type hints for Figure #25607

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions lib/matplotlib/artist.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ from .axes._base import _AxesBase
from .backend_bases import RendererBase, MouseEvent
from .cm import ScalarMappable
from .colors import BoundaryNorm
from .figure import Figure, FigureBase
from .figure import Figure, SubFigure
from .path import Path
from .patches import Patch
from .patheffects import AbstractPathEffect
Expand Down Expand Up @@ -35,7 +35,7 @@ class Artist:
zorder: float
def __init_subclass__(cls): ...
stale_callback: Callable[[Artist, bool], None] | None
figure: FigureBase | None
figure: Figure | SubFigure | None
clipbox: Bbox | None
def __init__(self) -> None: ...
def remove(self) -> None: ...
Expand Down
2 changes: 1 addition & 1 deletion lib/matplotlib/backend_bases.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def get_registered_canvas_class(format: str) -> type[FigureCanvasBase]: ...

class RendererBase:
def __init__(self) -> None: ...
def open_group(self, s: str, gid: int | None = ...) -> None: ...
def open_group(self, s: str, gid: str | None = ...) -> None: ...
def close_group(self, s: str) -> None: ...
def draw_path(
self,
Expand Down
2 changes: 1 addition & 1 deletion lib/matplotlib/figure.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,6 @@ def __init__(self, **kwargs):
# axis._get_tick_boxes_siblings
self._align_label_groups = {"x": cbook.Grouper(), "y": cbook.Grouper()}

self.figure = self
self._localaxes = [] # track all axes
self.artists = []
self.lines = []
Expand Down Expand Up @@ -2458,6 +2457,7 @@ def __init__(self,
%(Figure:kwdoc)s
"""
super().__init__(**kwargs)
self.figure = self
self._layout_engine = None

if layout is not None:
Expand Down
20 changes: 10 additions & 10 deletions lib/matplotlib/figure.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ from matplotlib.colors import Colormap, Normalize
from matplotlib.colorbar import Colorbar
from matplotlib.cm import ScalarMappable
from matplotlib.gridspec import GridSpec, SubplotSpec
from matplotlib.image import _ImageBase
from matplotlib.image import _ImageBase, FigureImage
from matplotlib.layout_engine import (
ConstrainedLayoutEngine,
LayoutEngine,
Expand Down Expand Up @@ -69,7 +69,6 @@ class SubplotParams:
) -> None: ...

class FigureBase(Artist):
figure: FigureBase | None
artists: list[Artist]
lines: list[Line2D]
patches: list[Patch]
Expand Down Expand Up @@ -154,15 +153,15 @@ class FigureBase(Artist):
*,
sharex: bool | Literal["none", "all", "row", "col"] = ...,
sharey: bool | Literal["none", "all", "row", "col"] = ...,
squeeze: Literal[True] = ...,
squeeze: bool = ...,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did this change?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a particular case of a potentially more general issue, which was closely related enough to this change that I decided to make the change for this one here.

Essentially while it seems like Literal[True] and Literal[False] should actually span bool, they technically do not, as they only handle the case of literals being passed, not a variable with type bool.

That said, in many cases it doesn't really make sense to pass anything other than a literal there, so the "passed an unknown bool" case is pretty unexpected.
e.g. the cbook.load_data method has a couple booleans that we would never expect to be passed as an unknown bool (in part because that is a largely for internal use method).

In this particular case a more complete answer would be to try and do our best with overloads to mete out the case which is passed sqeeze=True with Literal[1] for nrows/ncols and then have a fallback for this version which can't necessarily differentiate what the return will be.

In fact, unions in returns are generally discouraged and the prevailing wisdom is to just use Any (if overloads cannot properly distinguish the return type). This is actually what I've already done with pyplot.subplots, which calls this method.

Removing such unions is a change I've been leaning towards doing at some point, but made a minimal change here as the return union actually encompasses all possible returns regardless of the value of squeeze here.

width_ratios: ArrayLike | None = ...,
height_ratios: ArrayLike | None = ...,
subplot_kw: dict[str, Any] | None = ...,
gridspec_kw: dict[str, Any] | None = ...
) -> np.ndarray | SubplotBase | Axes: ...
def delaxes(self, ax: Axes) -> None: ...
def clear(self, keep_observers: bool = ...) -> None: ...
def clf(self, keep_observers: bool = ...): ...
def clf(self, keep_observers: bool = ...) -> None: ...

@overload
def legend(self) -> Legend: ...
Expand Down Expand Up @@ -203,7 +202,7 @@ class FigureBase(Artist):
def align_xlabels(self, axs: Iterable[Axes] | None = ...) -> None: ...
def align_ylabels(self, axs: Iterable[Axes] | None = ...) -> None: ...
def align_labels(self, axs: Iterable[Axes] | None = ...) -> None: ...
def add_gridspec(self, nrows: int = ..., ncols: int = ..., **kwargs): ...
def add_gridspec(self, nrows: int = ..., ncols: int = ..., **kwargs) -> GridSpec: ...
@overload
def subfigures(
self,
Expand Down Expand Up @@ -234,7 +233,7 @@ class FigureBase(Artist):
def _gci(self) -> ScalarMappable | None: ...
def _process_projection_requirements(
self, *args, axes_class=None, polar=False, projection=None, **kwargs
): ...
) -> tuple[type[Axes], dict[str, Any]]: ...
def get_default_bbox_extra_artists(self) -> list[Artist]: ...
def get_tightbbox(
self,
Expand All @@ -258,7 +257,7 @@ class FigureBase(Artist):
) -> dict[Any, Axes]: ...

class SubFigure(FigureBase):
figure: FigureBase
figure: Figure
subplotpars: SubplotParams
dpi_scale_trans: Affine2D
canvas: FigureCanvasBase
Expand Down Expand Up @@ -295,6 +294,7 @@ class SubFigure(FigureBase):
def get_axes(self) -> list[Axes]: ...

class Figure(FigureBase):
figure: Figure
bbox_inches: Bbox
dpi_scale_trans: Affine2D
bbox: Bbox
Expand Down Expand Up @@ -357,7 +357,7 @@ class Figure(FigureBase):
origin: Literal["upper", "lower"] | None = ...,
resize: bool = ...,
**kwargs
): ...
) -> FigureImage: ...
def set_size_inches(
self, w: float | tuple[float, float], h: float | None = ..., forward: bool = ...
) -> None: ...
Expand All @@ -371,7 +371,7 @@ class Figure(FigureBase):
def clear(self, keep_observers: bool = ...) -> None: ...
def draw_without_rendering(self) -> None: ...
def draw_artist(self, a: Artist) -> None: ...
def add_axobserver(self, func: Callable[[Figure], Any]): ...
def add_axobserver(self, func: Callable[[Figure], Any]) -> None: ...
def savefig(
self,
fname: str | os.PathLike | IO,
Expand All @@ -388,7 +388,7 @@ class Figure(FigureBase):
mouse_pop: MouseButton = ...,
mouse_stop: MouseButton = ...,
) -> list[tuple[int, int]]: ...
def waitforbuttonpress(self, timeout: float = ...): ...
def waitforbuttonpress(self, timeout: float = ...) -> None | bool: ...
def tight_layout(
self,
*,
Expand Down
11 changes: 6 additions & 5 deletions lib/matplotlib/pyplot.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@
from matplotlib.figure import SubFigure
from matplotlib.legend import Legend
from matplotlib.mlab import GaussianKDE
from matplotlib.image import AxesImage
from matplotlib.image import AxesImage, FigureImage
from matplotlib.patches import FancyArrow, StepPatch
from matplotlib.quiver import Barbs, Quiver, QuiverKey
from matplotlib.scale import ScaleBase
Expand Down Expand Up @@ -754,7 +754,7 @@ def figure(
FigureClass: Type[Figure] = Figure,
clear: bool = False,
**kwargs
):
) -> Figure:
"""
Create a new figure, or activate an existing figure.

Expand Down Expand Up @@ -857,6 +857,7 @@ def figure(
in the matplotlibrc file.
"""
if isinstance(num, FigureBase):
# type narrowed to `Figure | SubFigure` by combination of input and isinstance
if num.canvas.manager is None:
raise ValueError("The passed figure is not managed by pyplot")
_pylab_helpers.Gcf.set_active(num.canvas.manager)
Expand Down Expand Up @@ -2347,7 +2348,7 @@ def matshow(A: ArrayLike, fignum: None | int = None, **kwargs) -> AxesImage:
# Extract actual aspect ratio of array and make appropriately sized
# figure.
fig = figure(fignum, figsize=figaspect(A))
ax = fig.add_axes([0.15, 0.09, 0.775, 0.775])
ax = fig.add_axes((0.15, 0.09, 0.775, 0.775))
im = ax.matshow(A, **kwargs)
sci(im)
return im
Expand Down Expand Up @@ -2403,7 +2404,7 @@ def figimage(
origin: Literal["upper", "lower"] | None = None,
resize: bool = False,
**kwargs,
):
) -> FigureImage:
return gcf().figimage(
X,
xo=xo,
Expand Down Expand Up @@ -2494,7 +2495,7 @@ def tight_layout(

# Autogenerated by boilerplate.py. Do not edit as changes will be lost.
@_copy_docstring_and_deprecators(Figure.waitforbuttonpress)
def waitforbuttonpress(timeout: float = -1):
def waitforbuttonpress(timeout: float = -1) -> None | bool:
return gcf().waitforbuttonpress(timeout=timeout)


Expand Down