Python Venv Demo

VERSION a9b38ce
Python Venv Demo

A canvas-local virtualenv for Python, following the same meshfox:var from= pattern SPEC.md's "Computed variables" describes: the venv-setup block below creates .meshfox/python-venv.canvas.md.venv/ (idempotently), installs this demo's one dependency into it, and reports its own interpreter path as the computed PYTHON variable. Every other Python-running fence in this document references it via interpreter="$PYTHON -u" rather than a hardcoded virtualenv path or whatever Python happens to be on $PATH — useful since a system Python is often externally managed (Homebrew, PEP 668) and refuses a bare pip install.

That interpreter= reference is also the only ordering this canvas needs: SPEC.md's "Computed variables" makes a from=-declared variable's source block an implicit dependency of anything that resolves it, exactly like an explicit deps= — so demo below needs no deps= of its own at all, even though it can't actually run before venv-setup has both created the venv and installed everything into it.

Environment setup

interpreter="@python_venv" is meshfox's own built-in interpreter for exactly this — a small, fixed set of macro scripts meshfox carries with it. A text fence is read as requirements.txt; the builtin creates its canvas-local virtualenv (idempotent once created), installs the requirements, and reports the venv's own python3 as the computed PYTHON variable via $MESHFOX_VARS_OUT (SPEC.md's "Computed variables") — the same shell script this node used to spell out by hand, now shipped inside meshfox itself. Anything that needs the venv ready just references $PYTHON (see the root node's note above) rather than also declaring an explicit deps= on this block. Skipped on a later run in the same session once its own code hasn't changed (the usual session-freshness skip).

tabulate==0.9.0
exit code: 0 · 261ms

Requirement already satisfied: tabulate==0.9.0 in ./.meshfox/python-venv.canvas.md.venv/lib/python3.14/site-packages (from -r /var/folders/y2/qq2wc6hd75b06jsjmcvpbmn80000gn/T/meshfox-54304-5a44f457-3d19-49f5-9a5d-90b21f8294c5.tmp (line 1)) (0.9.0)
venv ready: /Users/orofarne/sources/meshfox/examples/.meshfox/python-venv.canvas.md.venv/bin/python3

The same interpreter also accepts a toml fence as pyproject.toml. This alternative installs a temporary project into the same canvas-local venv; use either setup block for a given project. A build backend and project metadata are required because pip installs the project directory.

[build-system]
requires = ["setuptools>=61"]
build-backend = "setuptools.build_meta"

[project]
name = "meshfox-venv-example"
version = "0.1.0"
dependencies = ["tabulate==0.9.0"]

[tool.setuptools]
py-modules = []
Demo

Imports the package installed above and prints a small table with it — proof the venv/install chain actually ran, not just that the files exist.

from tabulate import tabulate

print(tabulate([["meshfox", "canvas"], ["venv", "demo"]], headers=["a", "b"]))
exit code: 0 · 50ms

a        b
-------  ------
meshfox  canvas
venv     demo
A module next to the canvas

$PYTHON isn't the venv's bare python3: interpreter="@python_venv" reports a small launcher, .meshfox/python-venv.canvas.md.venv/bin/python3-mf, which is the venv's Python with the block's working directory added to PYTHONPATH. meshfox runs a block's code from a file that doesn't live in that directory, and Python looks next to the script, not the cwd — so without the launcher a block can't import a module sitting beside its canvas. With it, the block below imports venv_demo_helper.py (which itself uses the venv's tabulate) with no sys.path.insert(0, os.getcwd()). It prints a Markdown table, and output="markdown" (see pandas-dataframe.canvas.md) shows it as a rendered table instead of a block of pipe characters.

import sys

import venv_demo_helper

print(venv_demo_helper.render([
    ["venv_demo_helper", "next to the canvas (PYTHONPATH from the launcher)"],
    ["tabulate", "the canvas's own virtualenv"],
]))
print()
print(f"Python: `{sys.executable}`")
modulefound via
venv_demo_helpernext to the canvas (PYTHONPATH from the launcher)
tabulatethe canvas's own virtualenv

Python: /Users/orofarne/sources/meshfox/examples/.meshfox/python-venv.canvas.md.venv/bin/python3

An independent XLS environment

The default environment above exports PYTHON. A second setup can install spreadsheet dependencies independently, without changing that variable or adding packages to the default environment. name=xls selects .meshfox/python-venv.canvas.md.venv/.named/xls/; var=XLS_PYTHON selects the output key. Both options are optional and independent: changing only var= still uses the default environment. Reusing the same name= shares an environment between setup blocks.

python-calamine

This consumer automatically runs xls-setup through the computed variable. It imports the XLS reader and prints its separate environment path; no spreadsheet fixture is needed. To read a real workbook, use CalamineWorkbook.from_path("report.xls").

import sys
from pathlib import Path

from python_calamine import CalamineWorkbook

assert Path(sys.prefix).name == "xls"
assert Path(sys.prefix).parent.name == ".named"
print(f"XLS environment: {sys.prefix}")
print(f"Reader ready: {CalamineWorkbook.__name__}")

The original consumers keep using interpreter="$PYTHON -u". The two interpreters now point to distinct environments with separate installed packages. @node_env supports the same name= and var= options, with NODE as the default output key.