flexmeasures.ui.utils.vendor_assets

Third-party libraries which the UI loads, and where it loads them from.

Each library is served by FlexMeasures from static/vendor/<key>/<version>/ when its files were fetched there, and loaded from its CDN otherwise, with the hash recorded below as the tag’s integrity attribute. The Docker image comes with the files fetched. A pip-installed FlexMeasures fetches them in the background once it serves its first request, unless the FLEXMEASURES_FETCH_UI_LIBRARIES setting is switched off; then fetch them with:

python -m flexmeasures.ui.utils.fetch_vendor_assets

Fetching also stores each library’s licence next to its files, with any notice file the licence requires to be shipped along, and fails on any file whose hash does not match. Templates load these libraries through the macros in templates/includes/vendor.html.

To bump a library, change its version below, then print the hashes of its files at that version, and paste them in:

python -m flexmeasures.ui.utils.fetch_vendor_assets –print-hashes <key>

Hosts can load other versions through the FLEXMEASURES_JS_VERSIONS setting, see libraries_with_overrides.

Every week, .github/workflows/ui-library-advisories.yml looks up these versions in the OSV database of security advisories.

This is a leaf module, so flexmeasures/ui/__init__.py can import it without an import cycle.

Functions

flexmeasures.ui.utils.vendor_assets.active_libraries() → dict[str, VendorLibrary]

The libraries which the current app loads, or the recorded ones outside an app.

flexmeasures.ui.utils.vendor_assets.download(url: str) → bytes
flexmeasures.ui.utils.vendor_assets.fetch(keys: list[str] | None = None, download: ~typing.Callable[[str], bytes] = <function download>, libraries: dict[str, ~flexmeasures.ui.utils.vendor_assets.VendorLibrary] | None = None) → int

Download the libraries’ files, licences and notices into static/vendor/, checking each against its hash.

Files that are already there with the right hash are skipped, and so are libraries without hashes. Returns the number of files written.

flexmeasures.ui.utils.vendor_assets.fetch_unless_fetching(libraries: dict[str, ~flexmeasures.ui.utils.vendor_assets.VendorLibrary], download: ~typing.Callable[[str], bytes] = <function download>) → int | None

Fetch the libraries’ missing files, unless another process on this host is fetching them.

Returns the number of files written, or None if another process holds the lock.

flexmeasures.ui.utils.vendor_assets.fetched_before() → bool

Whether any library files were fetched into static/vendor/, for example before an upgrade bumped some versions.

flexmeasures.ui.utils.vendor_assets.libraries_with_overrides(setting: dict | None) → dict[str, VendorLibrary]

The libraries to load, with the versions that the FLEXMEASURES_JS_VERSIONS setting sets in place of the recorded ones.

The setting maps a library’s key to its version, in one of three forms:

  • "5.33.1": browsers load the library from its CDN without checking it, and it is not fetched.

  • ("5.33.1", "<sha256>"): the hash of the library’s one file.

  • ("1.9.5", {"dist/leaflet.css": "<sha256>", ...}): the hash of each of the library’s files.

With hashes, the library is handled like the recorded ones: browsers check its files, and it can be fetched. The new version is expected to have the same files as the recorded one, as the templates name them. python -m flexmeasures.ui.utils.fetch_vendor_assets --print-hashes <key> --version <version> prints the setting for a version.

flexmeasures.ui.utils.vendor_assets.local_file(key: str, path: str, libraries: dict[str, VendorLibrary] | None = None) → Path

Where a library’s file is stored when it was fetched.

flexmeasures.ui.utils.vendor_assets.missing_files(libraries: dict[str, VendorLibrary] | None = None) → list[Path]

Files of the libraries which were not fetched, so browsers load them from CDNs.

Files without a hash are left out, as they are never fetched.

flexmeasures.ui.utils.vendor_assets.print_hashes(key: str, download: ~typing.Callable[[str], bytes] = <function download>, version: str | None = None)

Print the hashes of a library’s files.

At its recorded version, they are printed ready to paste into VENDOR_LIBRARIES. At another version, they are printed as an entry of the FLEXMEASURES_JS_VERSIONS setting.

flexmeasures.ui.utils.vendor_assets.unhashed_libraries(libraries: dict[str, VendorLibrary] | None = None) → list[str]

Libraries which FLEXMEASURES_JS_VERSIONS sets to a version without hashes, so browsers load them unchecked.

flexmeasures.ui.utils.vendor_assets.vendor_attrs(key: str, path: str, attribute: str = 'src') → Markup

Attributes for a <script> or <link> tag that loads a library’s file.

When the file comes from a CDN, the browser checks it against its hash, unless FLEXMEASURES_JS_VERSIONS sets a version without one.

flexmeasures.ui.utils.vendor_assets.vendor_url(key: str, path: str) → str

URL of a library’s file: served by FlexMeasures if it was fetched, or else from the library’s CDN.

Classes

class flexmeasures.ui.utils.vendor_assets.VendorLibrary(name: str, version: str, files: dict[str, str | None], license: str, license_sha256: str | None, base_url: str = 'https://cdn.jsdelivr.net/npm/{name}@{version}/', notices: dict[str, str | None] = <factory>, npm_package: str | None = None)

A library’s version, its files with their SHA-256 hashes, and where to download them.

__init__(name: str, version: str, files: dict[str, str | None], license: str, license_sha256: str | None, base_url: str = 'https://cdn.jsdelivr.net/npm/{name}@{version}/', notices: dict[str, str | None] = <factory>, npm_package: str | None = None) → None
licence_files() → list[tuple[str, str, str | None]]

The licence and notices to store next to the library’s files, each as its local path, URL and SHA-256 hash.

property license_path: str

Where the licence is stored, relative to the library’s local directory.

property npm_name: str | None

The npm package which this library is published as, if any, which advisory databases know it by.