Creating self-contained executable Python scripts for rendering Quarto documents using the Jupyter engine
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
Introduction
In previous posts I have covered creating
effectively multi-engine Quarto documents and also how to use
uv virtual environments for the nbstata Jupyter kernel to run Quarto documents with Stata code. Hence by trivial extension we can use uv
to manage the virutal environments for running Quarto documents using the jupyter: python3
engine.
The slight inconvenience about this approach when you are working on a collaborative project with new Python users is that you end up leaving a README or shell script with the required commands to activate the environment, install the nbstata kernel, and run Quarto. I sense this management of the virutal environment is a pain point for new Python users – who are likely wondering what on earth a virtual environment is. So I have been looking for a way to simplify this process for them.
A recent post by Matt Dray about using uv to run self-contained executable Python scripts got me thinking. Could I produce a similar self-contained executable Python script to perform the rendering for Quarto documents using the Jupyter engine. Then my colleagues would only need to call the script as an executable at the command line. This would avoid them the trouble of managing the virtual environment.
The self-contained executable Python script
I came up with the following Python script.
#!/usr/bin/env -S uv run --script # /// script # requires-python = ">=3.9" # dependencies = [ # "jupyterlab>=4.4.3", # "jupyterlab-stata-highlight2>=0.1.2", # "nbstata>=0.8.3", # ] # /// import subprocess cmd0 = "python -m nbstata.install --sys-prefix" retval0 = subprocess.call(cmd0, shell=True) print('returned value:', retval0) cmd1 = "quarto render --profile stata-questions" retval1 = subprocess.call(cmd1, shell=True) print('returned value:', retval1) cmd2 = "quarto render --profile stata-solutions" retval2 = subprocess.call(cmd2, shell=True) print('returned value:', retval2)
-
The first line, the shebang ensures it is run by
uv run
-
The metadata defining the Python environment is declared between the
# /// script # ... # ///
- If you don’t use Stata, say you are using the
jupyter: python3
engine then you can delete thejupyterlab-stata-highlight2
andnbstata
entries and the first group of 3 lines forcmd0
. - If you use additional Python packages in your code then you need to add them to the list.
- If you don’t use Stata, say you are using the
-
Then comes the actual code. These are simply system calls using the subprocess module. You can amend the number of calls and the calls themselves inside the string quotes as required. I am recreating some of the rendering commands in my recent post about using Quarto profiles for tutorial documents. It’s worth pointing out that I haven’t used the Python quarto package here as it’s currently slightly too limited for my use (I’m not sure it can render profiles).
Save the script in a file, say render, then make it executable with
chmod +x render
Then all my colleagues need to do is run it with
./render
Of course uv and Quarto need to be installed and be on their PATH
, and Stata needs to be installed locally when using that. For my colleagues using Windows, they need to run this from a Git Bash shell rather than from Powershell or CMD shell (for the shebang line to work).
If you are only using the Quarto knitr engine then you don’t need this script because you don’t need Jupyter.
And for more information about uv Python scripts, the full documentation is here.
Summary
I have shown how to make a self-contained executable Python script to render Quarto documents using the Jupyter engine which automatically manage their own virtual environment. This means users don’t have to manage the virtual environment themselves, which can be a pain point for new Python users.
R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.