Skip to content

v1.1.1: Examples That Actually Run

Choose a tag to compare

@HugoFara HugoFara released this 04 Sep 15:26
· 57 commits to main since this release
f2d6086

No behaviour changes. This release exists because the library's front door was broken: the example on the PyPI landing page had never run, seven of the fifteen tutorial notebooks raised on execution, two-thirds of the package had no API reference at all, and the annotations shipped invisible to downstream type checkers. Thanks to @the-moog for reporting #25, which started this.

Every documentation figure below was measured against a sphinx-build, and every example was verified by installing the built wheel into a clean virtualenv and running it.

Fixed

  • The examples on the PyPI landing page. Both README visualization snippets called plot_kinematic_linkage(linkage), but that function takes (linkage, fig, axis, loci) and always has — the signature is identical in 1.0.0, so these examples never ran, on any release. They now call show_linkage(), which builds the figure and runs the simulation itself. The PSO snippet separately used get_num_constraints() / set_num_constraints(), removed earlier in the 1.x line; it now uses get_constraints() / set_constraints().

  • The front-page example did not say what to install. The first snippet in the README calls path_generation() and show_linkage(), which live behind the scipy and viz extras. Every other example needing an extra said so; this one did not, so after a plain pip install pylinkage it raised ModuleNotFoundError before reaching any pylinkage code. It now names the install line it needs.

  • Type information was not exposed to users. The package is fully annotated and passes mypy --strict on all 133 source files, but shipped no PEP 561 py.typed marker, so type checkers and editors in downstream projects silently ignored every annotation and treated pylinkage as untyped. The marker is now in the wheel.

  • Tutorial notebooks failing to execute. Seven of the fifteen raised against removed API: get_num_constraints() / set_num_constraints() (notebooks 02, 03, 09, 10, 11, 13), SymbolicLinkage.components in place of .joints (05), and mechanism_to_linkage() (10). Notebook 10 additionally described the component/dyad Linkage as a "legacy" API throughout; the legacy API was pylinkage.joints, which no longer exists. A Notebooks CI workflow now executes every notebook on push and pull request, so this cannot silently return.

  • Stale API reference. docs/source/api/ was checked-in sphinx-apidoc output not regenerated since before 1.0. It documented three modules that no longer exist — the legacy pylinkage.joints package, pylinkage.collections, and pylinkage.linkage.linkage — which failed to import on every docs build. More importantly it covered only 6 of the package's 18 subpackages: synthesis, mechanism, hypergraph, cam, symbolic, solver, components, actuators, dyads, simulation, assur, bridge, population and topology had no API reference at all.

  • Docstrings rendered wrongly in the API reference. The codebase writes Google-style docstrings, but the docs never enabled sphinx.ext.napoleon, so every one was parsed as a definition list: parameter descriptions were swallowed as stray indentation, and *args / **kwargs were read as emphasis markup. Napoleon is now enabled, with napoleon_use_ivar so a documented attribute does not collide with the entry autodoc already generates for the same dataclass field, and :no-index: on package-level automodule directives so each object is indexed once rather than once per re-export. Nine genuinely malformed docstrings were fixed by hand.

  • Documentation links that pointed at the wrong class. pylinkage.dyads exports Dyad as a plain alias of Component, and the package annotated its anchors with that alias. Two unrelated classes are also named Dyad (pylinkage.assur.Dyad, an Assur group, and pylinkage.synthesis.Dyad, a Burmester construct), so Sphinx resolved those annotations to one of them and sent readers to a class the code never referred to. The annotations now name Component directly; the aliases remain exported and unchanged, so no import breaks.

  • Broken README links, on three surfaces at once. The links to the 15 tutorial notebooks, CONTRIBUTING.md and CODE_OF_CONDUCT.md were repository-relative, so they resolved only on GitHub and were dead on PyPI and in the rendered documentation. They are now absolute URLs. The README was also rendered twice in the docs — listed in the toctree and pulled in again with .. include::.

Together these take the documentation build from 496 warnings to 8, the remaining 8 being the genuine assur.Dyad / synthesis.Dyad name collision, which is deferred to 1.2.0 under the deprecation policy in #22.

Added

  • Public benchmarks, at docs/source/benchmarks.md: figures for the numba solver, PSO throughput, and the three synthesis entry points, with the hardware they came from and the command that reproduces them. The harness measures the public API only, takes the median of repeated runs, and discards warmup so numba's one-off JIT compilation is not charged to steady-state figures. Headline numbers: step_fast() is 6.4x step(), PSO sustains ~16,000 fitness evaluations per second on a four-bar, and path_generation() costs well over a second because it searches 36 coupler orientations — worth knowing before calling it in a loop.

  • pylinkage.dyads.to_mechanism() is now public. It converts a component Linkage into a Mechanism, and previously existed only as pylinkage.dyads._conversion.to_mechanism, so it could not be used or documented without reaching into a private module. The conversion remains one-way.

Changed

  • One docstring style across the codebase. Docstrings were split between two conventions: 85 files used Google style while 16 used reST field lists, and linkage/transmission.py used both at once. The 16 — concentrated in symbolic/, optimization/ and geometry/, the oldest code in the package — are converted to Google style. This is presentation only: 393 fields were rewritten with no change to wording.

  • The full extra now includes pymoo, so pip install pylinkage[full] covers multi-objective optimization as the README's "all optional backends" description promises. moo remains available on its own, and is now listed in the README's extras table.

Full changelog: v1.1.0...v1.1.1