Skip to content

v2.7.1: malformed expanded docstrings and incorrect subplots parameter documentation #835

Description

@munechika-koyo

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.

  1. 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.

  2. 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().

  3. 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.

No activity

Activity on this issue will appear here.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions