Cython quickstart: compile_and_load#

This example shows the minimal workflow:

  1. Compile a small Cython snippet at runtime.

  2. Call the compiled function immediately.

  3. Inspect build/cache metadata (key, build dir, artifact path).

  4. Demonstrate profiles, pin/alias, and restart-safe re-import by key.

Notes#

Runtime compilation requires:

  • a working C/C++ compiler toolchain

  • Python development headers (Python.h)

  • the Cython package

  • (optional) NumPy if numpy_support=True and your code uses NumPy C-API

If prerequisites are not available (common on doc builders), this example prints a short diagnostic and exits gracefully.

# Authors: The scikit-plots developers
# SPDX-License-Identifier: BSD-3-Clause
from __future__ import annotations

from scikitplot import cython
def _print_prereq_summary(report: dict) -> None:
    """Print a stable, user/dev friendly prereq summary."""
    print("Prereq ok:", report.get("ok", False))
    for k in ("cython", "setuptools", "numpy", "compiler", "python_headers"):
        if k in report:
            item = report.get(k, {})
            if isinstance(item, dict):
                ok = item.get("ok", False)
                ver = item.get("version", None)
                msg = item.get("message", None)
                s = f"  - {k}: ok={ok}"
                if ver:
                    s += f", version={ver}"
                if msg:
                    s += f", message={msg}"
                print(s)

Basic environment diagnostic (safe to run on doc builders)

report = cython.check_build_prereqs()
_print_prereq_summary(report)
Prereq ok: False
  - cython: ok=True, version=3.2.4
  - setuptools: ok=True, version=79.0.1

Generate python Module from python#

if not report.get('cython', {}).get('ok'):
    print("\nCython runtime compilation prerequisites are missing.")
    # If your implementation provides a formatted string, prefer it.
    fmt = getattr(report, "format", None)
    if callable(fmt):
        print(fmt())
    else:
        problems = report.get("problems", [])
        if problems:
            print("Problems:", problems)
else:
    # ------------------------------------------------------------
    # 1) Compile a tiny Cython function and call it immediately.
    # ------------------------------------------------------------
    code_f = "def f(int n):\n    return n*n\n"

    try:
        m = cython.compile_and_load(code_f, profile="fast-debug")
    except Exception as e:
        # Docs-safe: show error without crashing the whole gallery build.
        print("\nCompilation failed (showing exception and exiting gracefully):")
        print(type(e).__name__ + ":", e)
    else:
        print("\nCompiled module name:", getattr(m, "__name__", "<unknown>"))
        print("f(10) =", m.f(10))

        # ------------------------------------------------------------
        # 2) If you need build metadata, use *_result API.
        # ------------------------------------------------------------
        code_g = "def g(int n):\n    return n+1\n"
        r = cython.compile_and_load_result(
            code_g,
            profile="fast-debug",
            numpy_support=True,
            numpy_required=False,
        )

        print("\nBuildResult (metadata):")
        print("  module_name :", r.module_name)
        print("  cache key   :", r.key)
        print("  build dir   :", r.build_dir)
        print("  artifact    :", r.artifact_path)
        print("  used_cache  :", r.used_cache)
        print("  created_utc :", r.created_utc)

        # Call g to prove the compiled module is live.
        print("g(10) =", r.module.g(10))

        # ------------------------------------------------------------
        # 3) Restart-safe workflow: import again by cache key.
        # ------------------------------------------------------------
        # This simulates "after kernel restart" behavior.
        try:
            m2 = cython.import_cached(r.key)
        except Exception as e:
            print("\nCould not re-import from cache by key:")
            print(type(e).__name__ + ":", e)
        else:
            print("\nRe-imported from cache key:")
            print("  module:", m2.__name__)
            print("  g(10) :", m2.g(10))

        # ------------------------------------------------------------
        # 4) Pin/Alias for friendly reuse.
        # ------------------------------------------------------------
        alias = "quickstart_g"
        try:
            cython.pin(r.key, alias=alias, overwrite=True)
            m3 = cython.import_pinned(alias)
        except Exception as e:
            print("\nPin/import by alias failed:")
            print(type(e).__name__ + ":", e)
        else:
            print("\nImported via alias:", alias)
            print("  module:", m3.__name__)
            print("  g(10) :", m3.g(10))

        # ------------------------------------------------------------
        # 5) Profile demonstration: release build gets a different key.
        # ------------------------------------------------------------
        r_rel = cython.compile_and_load_result(code_g, profile="release", numpy_support=True, numpy_required=False)
        print("\nProfile comparison (keys):")
        print("  fast-debug:", r.key)
        print("  release   :", r_rel.key)
        print("  keys differ:", r.key != r_rel.key)

        # Optional: print cache stats snapshot, if available.
        if hasattr(cython, "cache_stats"):
            print("\nCache stats snapshot:")
            print(cython.cache_stats())
Compiled module name: scikitplot_cython_c71820fcbdd3d3be
f(10) = 100

BuildResult (metadata):
  module_name : scikitplot_cython_093729e666d9308a
  cache key   : 093729e666d9308a2ee01f667576da3e7022aaf802855405f2fe6727629b9a2a
  build dir   : /home/circleci/.cache/scikitplot/cython/093729e666d9308a2ee01f667576da3e7022aaf802855405f2fe6727629b9a2a
  artifact    : /home/circleci/.cache/scikitplot/cython/093729e666d9308a2ee01f667576da3e7022aaf802855405f2fe6727629b9a2a/scikitplot_cython_093729e666d9308a.cpython-311-x86_64-linux-gnu.so
  used_cache  : False
  created_utc : 2026-02-01T06:33:52Z
g(10) = 11

Re-imported from cache key:
  module: scikitplot_cython_093729e666d9308a
  g(10) : 11

Imported via alias: quickstart_g
  module: scikitplot_cython_093729e666d9308a
  g(10) : 11

Profile comparison (keys):
  fast-debug: 093729e666d9308a2ee01f667576da3e7022aaf802855405f2fe6727629b9a2a
  release   : 106892295832cfc7f01dbb65bd06b364352040aef37075f2634c508019b279d1
  keys differ: True

Cache stats snapshot:
CacheStats(cache_root=PosixPath('/home/circleci/.cache/scikitplot/cython'), n_modules=5, n_packages=0, total_bytes=2935681, pinned_aliases=1, pinned_keys=1, newest_mtime_utc='2026-02-01T06:33:53Z', oldest_mtime_utc='2026-02-01T06:33:52Z')

Tags: domain: cython plot-type: cython purpose: showcase

Total running time of the script: (0 minutes 2.544 seconds)

Related examples

Multi-module package builds (5 package examples)

Multi-module package builds (5 package examples)

Pin/Alias: stable handles for cached builds

Pin/Alias: stable handles for cached builds

Cache and restart reuse

Cache and restart reuse

Browse and compile templates

Browse and compile templates

Gallery generated by Sphinx-Gallery