The most up-to-date version of this README is on GitHub.
pygal-stubs
What is this?
- pygal-stubs is a package that provides external type stubs (PEP 561) for pygal.
- Install it to get static analyisis, type-checking and autocompletion in your favorite IDE, so that you no longer have to pollute your
"strict"codebase with# pyright: ignore[reportUnknownMemberType]. Be sure to read Usage as well.
What this isn't
- This package is not affiliated with pygal.
- It is almost certainly not perfect or 100% accurate. If you spot a mistake (any mistake) and know how to fix it, submit a PR; If you don't, open an issue.
- (Per the LICENSE, this package comes with no warranty whatsoever, however there is one thing we know for a fact will not work at all) This package is not suitable for contributing to pygal itself. If you try to open pygal's source with pygal-stubs installed and your type checker on
"strict", you will almost certainly get type-checking errors and could potentially be misled as to the real types of the objects you're dealing with.- This package is aimed at the end users of pygal and as such reflects the types that appear in the public API, which might differ from implementation details.
- These stubs are not intended for use with any particular type checker, however, they were written while using basedpyright and were tested more thoroughly with it than with any other type checker. As such, it is this package's primary target type checker (it's extremely similar to Pylance so vanilla VS Code users should have no issues). If you have a specific issue with another type checker, please submit a PR or open an issue.
- (obviously) This isn't replacement for pygal's documentation, which should always be considered the source of truth when using pygal.
Installation
pygal-stubs is available on PyPI. Install it with pip install pygal-stubs, uv add pygal-stubs, or however you usually install PyPI packages.
This will also install the following type dependencies automatically:
typing-extensions: Backports modern typing features to all supported Python versions.types-lxml&django-types: Stubs for pygal's optional dependencies to preventAny/Unknownfrom leaking into your codebase.- You might still get
Unknownfrom other pygal dependencies that don't have type stubs available such as cairosvg and pyquery, as well as the map modules (see below).
- You might still get
Note that this package only installs the type stubs, not the optional runtime libraries themselves. If your code uses pygal features that rely on lxml or django, ensure you install those packages separately to avoid runtime ImportErrors.
This package does not include stubs for the separately packaged map modules. You'll need to download those separately. I have created type stubs for my active fork of the world map module. You can find them here: fork, stubs. 1
Usage
Reading and writing Graph attributes
If you already use a strict type checker, existing pygal code will continue to work. However, there is one key detail you must know: Graph attributes (used to configure graphs) are set dynamically at runtime via __setattr__, not defined explicitly on __init__. This means that if you try to access a Graph attribute you haven't set explicitly, you'll get an AttributeError at runtime that type checkers (and these stubs) have no way of knowing about.
For example:
line = pygal.Line()
title = line.title
# Your type checker will say this is str | None,
# when in reality this line will cause an AttributeError!
This isn't an issue if you never read these attributes.
We have also added the more popular (the ones found in the docs + a couple of others) attributes to the __init__ method stubs, so you can assign them directly at instantiation:
import pygal
# Instead of:
line = pygal.Line()
line.title = "My Title"
# or:
config = pygal.Config()
config.title = "My Title"
line = pygal.Line(config)
# You can do:
line = pygal.Line(title="My Title")
Values that aren't in the __init__ signature will be assigned just fine, but they won't be type checked as you'll be falling back to the untyped **kwargs. If you believe that more attributes should be added to an __init__ method signature, please submit a PR. This paragraph also applies to some other methods (e.g. add)
Note that some values passed via constructor kwargs (including the ones typed by these stubs) and Config instances might not actually be assigned until the graph is rendered, so if you must read a value, your safest option is to assign it directly: line.title = "My Title" and, as mentioned above, always use a try-except block to handle potential AttributeErrors.
Why is this?
pygal does not define which attributes each specific Graph type requires, instead providing all attributes, for all graphs, in the massive CommonConfig and Config classes for documentation purposes. Then, at runtime, all attributes are assigned arbitrarily (via __setattr__ from either explicit instance.attr = val asignment from the user or at instantiation time from the constructor **kwargs) to the graph instances.
This means that if we wanted type-checking for these values (instead of accepting anything for any key like __setattr__ normally does), we had to basically hardcode all config attributes for all graphs as properties of BaseGraph, the class that all graphs inherit from. If you know a better way to do this without erasing type checking for these attributes, please submit a PR
Graphs are now generic
Graph, the base class that all pygal graphs inherit from directly or indirectly, is now generic in ValueT, XLabelT, and YLabelT (with defaults Iterable[float], str and str respectively). For most usages this information is not relevant (the values you try to add will be checked for satisfaction of your specific chart class' _ValueT), but this pattern could cause unexpected behaviour in code that can deal with multiple graph types.
For example, say that you want to create a function that takes any pygal graph and renders it in the browser. Since all pygal graphs inherit from Graph, you might think of hinting it like this:
import pygal
def render_any_graph(g: pygal.Graph) -> None:
g.render_in_browser()
But this is wrong. If you try to pass a graph instance whose values and labels types aren't exactly the same as Graph's defaults (see above), you will get a type checking error. An instance of Pie, for example, defines its _ValueT as Sequence[float] | float, which is not Iterable[float] and will therefore be rejected by the type checker.
Your options for typing code that needs to accept multiple graph types are:
- Narrow down the accepted types to only the graphs you need to handle, e.g.
def render_bar_or_line(g: pygal.Bar | pygal.Line) -> None:
g.render_in_browser()
- If you truly need to accept all pygal graphs, you can use
AnyGraph, a type alias (union of Graph and all its subclasses provided by pygal-stubs for convenience, but does not exist at runtime) to represent all graph types:
from pygal import AnyGraph
def render_any_graph(g: AnyGraph) -> None:
g.render_in_browser()
Versioning
{pygal major}.{pygal minor}.{pygal patch}.{stubs revision (incremental)}
For example, the current version number 3.1.3.4 should be interpreted as "the fourth revision of the stubs for pygal version 3.1.3"
-
I cannot currently work on stubs for other map modules (both the documented France and Switzerland maps nor the various non-Kozea ones you can find on PyPI). If you want to make your own type stubs for those, you're more than welcome to do so using pygal-stubs and my world map stubs as a base. If you'd like those stubs to be compatible with pygal-stubs and a mistake in the definition of BaseMap is causing problems, please submit a PR. Once you're done making your type stubs, make an issue so I can add your wonderful contribution to this README for all pygal-stubs users to see. ↩
Metadata
Release files for pygal-stubs 3.1.3.4
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pygal_stubs-3.1.3.4.tar.gz | 18.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pygal_stubs-3.1.3.4-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 53.8 kB
Release files / pygal_stubs-3.1.3.4.tar.gz
| Download URL | pygal_stubs-3.1.3.4.tar.gz |
|---|---|
| Size | 18.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3f586444c2704d8e79078fd2c5ba48370088a53469424783a9e548d25373f2f4
|
|
BLAKE2b-256 checksum How to use checksums |
faee1b860f454477a7958a0219e50bccf2b192f75059b3ccdc7408680af15377
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.23 {"installer":{"name":"uv","version":"0.12.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Linux Mint","version":"22.3","id":"zena","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / pygal_stubs-3.1.3.4-py3-none-any.whl
| Download URL | pygal_stubs-3.1.3.4-py3-none-any.whl |
|---|---|
| Size | 35.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
6392fe45811b03f5f99915a3a2a90b10a052ff3f45949187ab5b5b5aff87507f
|
|
BLAKE2b-256 checksum How to use checksums |
ab72774b4c1cf858e16f788bccc4107efee247ab18b0133ab678bd7b9a2166f3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.23 {"installer":{"name":"uv","version":"0.12.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Linux Mint","version":"22.3","id":"zena","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|