Description
Several public docstrings in UltraPlot 2.7.1 have malformed indentation or incorrect parameter documentation. I verified this against the official PyPI wheel (ultraplot-2.7.1-py3-none-any.whl, with its SHA256 checked against PyPI metadata), an installed 2.7.1 package, and the v2.7.1 GitHub source.
-
Expanded docstrings have inconsistent indentation in the distributed package. This affects ultraplot.figure, ultraplot.subplot, and ultraplot.subplots; I also observed it in Figure.__init__ and GridSpec.__init__. Section headings and the first parameter retain the surrounding source indentation, while subsequent lines from the inserted snippet are dedented. For example, the first parameter and its description in figure() both have four leading spaces, but the next parameter has none. inspect.getdoc() does not repair this. Passing the installed UI docstrings through Sphinx's NumpyDocstring parser leaves their indented sections unparsed.
-
The projection parameter name and type are split onto separate, equally indented lines. The shared snippet contains projection : followed by str, ... on the next line, instead of one NumPy-style parameter declaration. This is present in the source snippet as well as the installed docstrings for subplots() and Figure.subplots().
-
The order description reverses C/F ordering. The shared subplot snippet describes C as column-major and F as row-major. The implementation and actual subplot positions instead use C for row-major and F for column-major.
The latter two are issues in shared source snippets, separate from the distribution-time indentation problem. Single-line Python string literals with escaped newlines are valid docstrings; the issue is their resulting content and structure.
Steps to reproduce
With UltraPlot 2.7.1 installed:
import inspect
import platform
import matplotlib
matplotlib.use("Agg")
import numpy as np
import ultraplot as uplt
print("Python:", platform.python_version())
print("UltraPlot:", uplt.__version__)
print("Matplotlib:", matplotlib.__version__)
print("NumPy:", np.__version__)
for name in ("figure", "subplot", "subplots"):
doc = inspect.getdoc(getattr(uplt, name)) or ""
print(f"\n{name}:")
for line in doc.splitlines()[:12]:
print(repr(line))
lines = (inspect.getdoc(uplt.subplots) or "").splitlines()
index = lines.index("projection :")
print("\nprojection declaration:", repr("\n".join(lines[index:index + 2])))
for order in ("C", "F"):
fig, axs = uplt.subplots(nrows=2, ncols=2, order=order)
slots: list[tuple[int, int]] = []
for ax in axs:
spec = ax.get_subplotspec()
slots.append((spec.rowspan.start, spec.colspan.start))
print(order, slots)
uplt.close(fig)
Actual behavior includes this excerpt for figure():
' Parameters'
' ----------'
' refnum : int, optional'
' The reference subplot number. The `refwidth`, `refheight`, and `refaspect`'
The following refaspect declaration has zero leading spaces. The projection declaration is:
'projection :\nstr, `cartopy.crs.Projection`, or `~mpl_toolkits.basemap.Basemap`, optional'
The actual subplot positions are:
C [(0, 0), (0, 1), (1, 0), (1, 1)]
F [(0, 0), (1, 0), (0, 1), (1, 1)]
Expected behavior: section headings and parameter declarations should align at column zero after docstring normalization, with descriptions indented beneath them. projection and its type should be on the same declaration line. The order documentation should say row-major for C and column-major for F.
Source investigation
- The UI functions use shared snippet placeholders in the v2.7.1 source. Executing that source with the snippet decorator produces correctly aligned UI docstrings, unlike the installed expanded literals.
- The build-time expander substitutes into raw AST string values before normalization. The runtime snippet manager normalizes with
inspect.getdoc() before substitution. For figure(), expanding the raw source docstring and then applying inspect.cleandoc() reproduces the installed __doc__ exactly. Normalizing before expansion produces the correctly aligned version. This appears to explain the indentation discrepancy.
- The projection snippet contains the split declaration.
- The subplot parameter snippet contains the reversed C/F description; the implementation uses NumPy's
reshape(..., order=order).
It may help to preserve normalize-before-substitute semantics when materializing docstrings, and extend the installed-docstring check to validate section/parameter indentation in addition to checking for unresolved placeholders.
Equivalent steps in matplotlib
Not applicable: this concerns UltraPlot's shared docstrings and package-build expansion, rather than Matplotlib plotting behavior.
Ultra version
Reproduced on macOS arm64 with Python 3.14.7, UltraPlot 2.7.1, Matplotlib 3.11.2, and NumPy 2.5.3.
Description
Several public docstrings in UltraPlot 2.7.1 have malformed indentation or incorrect parameter documentation. I verified this against the official PyPI wheel (
ultraplot-2.7.1-py3-none-any.whl, with its SHA256 checked against PyPI metadata), an installed 2.7.1 package, and thev2.7.1GitHub source.Expanded docstrings have inconsistent indentation in the distributed package. This affects
ultraplot.figure,ultraplot.subplot, andultraplot.subplots; I also observed it inFigure.__init__andGridSpec.__init__. Section headings and the first parameter retain the surrounding source indentation, while subsequent lines from the inserted snippet are dedented. For example, the first parameter and its description infigure()both have four leading spaces, but the next parameter has none.inspect.getdoc()does not repair this. Passing the installed UI docstrings through Sphinx'sNumpyDocstringparser leaves their indented sections unparsed.The
projectionparameter name and type are split onto separate, equally indented lines. The shared snippet containsprojection :followed bystr, ...on the next line, instead of one NumPy-style parameter declaration. This is present in the source snippet as well as the installed docstrings forsubplots()andFigure.subplots().The
orderdescription reverses C/F ordering. The shared subplot snippet describesCas column-major andFas row-major. The implementation and actual subplot positions instead useCfor row-major andFfor column-major.The latter two are issues in shared source snippets, separate from the distribution-time indentation problem. Single-line Python string literals with escaped newlines are valid docstrings; the issue is their resulting content and structure.
Steps to reproduce
With UltraPlot 2.7.1 installed:
Actual behavior includes this excerpt for
figure():The following
refaspectdeclaration has zero leading spaces. The projection declaration is:The actual subplot positions are:
Expected behavior: section headings and parameter declarations should align at column zero after docstring normalization, with descriptions indented beneath them.
projectionand its type should be on the same declaration line. Theorderdocumentation should say row-major forCand column-major forF.Source investigation
inspect.getdoc()before substitution. Forfigure(), expanding the raw source docstring and then applyinginspect.cleandoc()reproduces the installed__doc__exactly. Normalizing before expansion produces the correctly aligned version. This appears to explain the indentation discrepancy.reshape(..., order=order).It may help to preserve normalize-before-substitute semantics when materializing docstrings, and extend the installed-docstring check to validate section/parameter indentation in addition to checking for unresolved placeholders.
Equivalent steps in matplotlib
Not applicable: this concerns UltraPlot's shared docstrings and package-build expansion, rather than Matplotlib plotting behavior.
Ultra version
Reproduced on macOS arm64 with Python 3.14.7, UltraPlot 2.7.1, Matplotlib 3.11.2, and NumPy 2.5.3.