github deeplook/svglib v2.1.0
svglib 2.1.0

4 hours ago

Added

  • Declared support for Python 3.14 (added the classifier and CI matrix
    entry across Ubuntu, macOS, and Windows, alongside the existing 3.9–3.13).
  • Clipping paths now support <circle>, <ellipse>, and <polygon> clip
    shapes, in addition to paths and rectangles, and clipping masks referenced
    from within a <use> element.
  • Transforms are now applied to clipping-path shapes, fixing clip paths that
    relied on previously unsupported transforms (issue #366).
  • The gradient shape classes now implement getBounds(), so drawings that
    contain gradient fills can be measured — for example when used as a flowable
    by rst2pdf (issue #466).

Changed

  • Renamed the gradient shape classes _LinearGradientShape and
    _RadialGradientShape to LinearGradientShape and RadialGradientShape.
    They appear in the rendered Drawing tree and were never meant to be
    private, so the leading underscore was misleading.

Removed

  • Removed the deprecated _LinearGradientShape and _RadialGradientShape
    aliases. Use LinearGradientShape and RadialGradientShape instead.

Fixed

  • The visibility property is now respected on shapes. Elements with
    visibility="hidden" (or collapse), set directly or inherited from an
    ancestor, were still rendered (issue #359).

  • display: none set through a style attribute is now respected. Only the
    display presentation attribute was read, so <g style="display:none"> and
    <rect style="display:none"/> were still rendered (issue #401).

  • Embedded <image> geometry is no longer truncated to whole points. The
    x, y, width, and height of an SVG <image> were each passed through
    int(), so a raster placed at fractional coordinates landed up to ~1pt away
    from a vector element with identical coordinates. Because width/height were
    truncated too, the error grew across the image rather than being a constant
    shift (issue #490).

  • font-family values are now split per CSS instead of on whitespace. An
    unquoted multi-word name such as font-family: Cascadia Code was split into
    Cascadia and Code, so a font registered under its full name was never
    found (issue #374). Commas inside a quoted name (font-family: "Foo, Bar", Arial) no longer split the list either; that previously handed shlex an
    unbalanced quote and raised ValueError: No closing quotation, aborting the
    conversion of a valid value.

  • Replaced locale.getdefaultlocale() (used for <switch> systemLanguage
    matching) with a small environment-variable lookup. getdefaultlocale() is
    deprecated and is removed in Python 3.15; the replacement keeps the same
    behaviour, emits no deprecation warning on 3.12–3.14, and adds unit tests for
    the language-matching path.

  • Clipping paths now support the clip-rule attribute instead of incorrectly
    using fill-rule (issue #485).

  • fill="url(...)" and gradient xlink:href values are now matched correctly
    when the referenced id is quoted (url('#name'), url("#name")) or
    contains a right parenthesis; the previous regex rejected or truncated
    these forms.

  • Rendering to reportlab.graphics.renderSVG.SVGCanvas (as used by
    easy-thumbnails[svg]) no longer raises
    AttributeError: 'SVGCanvas' object has no attribute 'beginPath' when
    drawing a clipped gradient; that canvas doesn't implement beginPath(),
    so the gradient's clip path is now skipped on it instead of erroring.

Type safety and internal quality (no behavior change)

  • Completed static type annotations for svglib.py; the package now passes
    mypy --strict on its own source, with a single documented per-module
    override for the untyped reportlab/cssselect2 base classes it subclasses.
  • Pinned a [tool.mypy] configuration in pyproject.toml and now enforce mypy
    in CI (new type-check.yml workflow) and via a local pre-commit hook, so type
    regressions fail before merge.
  • Tightened internal gradient handling types: parsed gradient definitions now
    use a TypedDict instead of an opaque Dict[str, Any], and the internal
    group/parent parameters are typed as Optional[Group].
  • Added docstrings to the remaining undocumented functions in svglib.py,
    bringing documentation coverage to 100%.

Tooling and housekeeping

  • Removed the DeepSource configuration. Its checks were redundant with ruff,
    mypy --strict, CodeQL, and the pytest matrix, and only produced recurring
    noise on pull requests.
  • Removed the long-defunct uniconv sample tests. They contained no assertions
    and shelled out to UniConvertor, an abandoned Python 2 tool, so they had been
    permanently skipped.
  • Fixed and revived the Windows CI workflow. It was a disabled placeholder that
    compiled GTK/Cairo from source (a ~20–40 minute step); it now runs a real
    CPython 3.9/3.13 matrix in well under a minute by dropping the source build
    and skipping the network-heavy sample tests on Windows (they already run on
    Ubuntu and macOS). The redundant manual Windows workflow was removed.

Don't miss a new svglib release

NewReleases is sending notifications on new releases.