Tutorial setup

If you have not done the prior sections, you’ll need to start the docker image:

docker run -it ghcr.io/spack/tutorial:hpcic25

and then set Spack up like this:

git clone --depth=2 --branch=releases/v1.0 https://github.com/spack/spack
. spack/share/spack/setup-env.sh
spack repo update builtin --tag v2025.07.0
spack mirror add --unsigned tutorial /mirror
spack compiler find

See the Basic Installation Tutorial for full details on setup. For more help, join us in the #tutorial channel on Slack – get an invitation at slack.spack.io

Warning

The spack tutorial -y command is intended for use in a container or VM. Use with care in other environments since it replaces some configuration files in order to establish suitable settings for the tutorial.

Scripting with Spack

This tutorial introduces advanced scripting features available in Spack, using the spack find and spack python commands. We’ve already seen how to list and search installed packages with spack find. The spack python command allows us to write more complex queries, as it gives access to all of Spack’s internal APIs.

Since Spack has an extensive API, we’ll only scratch the surface here.

Scripting with spack find

The output we’ve seen from spack find has been for human consumption. We can take advantage of the command’s advanced features to generate machine-readable output suitable for piping to a script.

spack find --format

The main function of spack find is to display concrete specs that correspond to installed packages. By default, they are shown with default attributes, like the @version suffix.

The --format argument allows us to display the specs using custom format strings.

Suppose we only want to see the name, version, and first ten (10) characters of the hash for every package installed in the Spack instance. This output can be generated with the following command:

$ spack find --format "{name} {version} {hash:10}"
adept-utils 1.0.1 yjgv7u3uwf		       m4 1.4.20 ypq2dyeslm
autoconf 2.72 5xgjgaemj5		       m4 1.4.20 rpphs4iqga
autoconf 2.72 krgi7jfdrs		       macsio 1.1 jubkwpoou3
autoconf-archive 2023.02.20 u24n5okomp	       macsio 1.1 w4772cduse
automake 1.16.5 vorbe53mrr		       meson 1.7.0 hcseihgy2i
automake 1.16.5 jgeyxwqrov		       meson 1.7.0 tqc2ju3muw
axl 0.9.0 maau75ypfw			       mpc 1.3.1 mkqx7budcw
bc 1.07.1 vbae3vxecf			       mpfr 4.2.1 abjn4yec4c
berkeley-db 18.1.40 k5bepowzfo		       mpich 4.3.0 l2h74uyzoj
berkeley-db 18.1.40 ikx4n4c7ko		       mpich 4.3.0 3bsqfeynbf
bison 3.8.2 ecemgn6zeg			       munge 0.5.15 uwm6hk76ja
bison 3.8.2 acgafisyw7			       ncurses 6.5 u7sn2jtlva
boost 1.72.0 x4ntqhhem4			       ncurses 6.5 56rxnkfzlb
bzip2 1.0.8 vy2ggzhuzo			       netlib-lapack 3.12.1 xx23tbfq7n
bzip2 1.0.8 3kql5yq6uc			       netlib-scalapack 2.2.2 igwbxq4vt5
ca-certificates-mozilla 2025-05-20 s3bxsw4irc  netlib-scalapack 2.2.2 tl5f6ke6ov
callpath 1.0.4 yokxcwu2j5		       netlib-scalapack 2.2.2 hk7ftpc2qc
cmake 3.31.8 usc3vzrzie			       netlib-scalapack 2.2.2 nimjflq6w6
cmake 3.31.8 yxjigtdrlw			       nghttp2 1.65.0 hpkxq4qzia
compiler-wrapper 1.0 rwnqblirwn		       nghttp2 1.65.0 2v5o3rauqq
curl 8.11.1 7xf5wleip2			       ninja 1.12.1 binn5bdm4u
curl 8.11.1 etcxzzkvyw			       ninja 1.12.1 pn35lwakeu
diffutils 3.10 pptkbjbkik		       numactl 2.0.18 74aq3kxwhm
diffutils 3.10 6lfrh36pe3		       numactl 2.0.18 naapp6hxkq
dtcmp 1.1.5 pqglwfz6zw			       openblas 0.3.29 77haeboy74
dyninst 13.0.0 np3n5uf2ba		       openblas 0.3.29 z3ynokzpyv
ed 1.4 iktf6j2v5y			       openmpi 5.0.8 ezkzlw5tyu
elfutils 0.192 bqadq4z3np		       openmpi 5.0.8 qdunbuirtg
er 0.5.0 vmunrpqq4a			       openssh 9.9p1 2s7eddoqit
expat 2.7.1 ut2qx6nkwc			       openssh 9.9p1 sgecnstwdq
expat 2.7.1 lfwqiuwkit			       openssl 3.4.1 kphogwy3wl
findutils 4.10.0 ga3qiejil4		       openssl 3.4.1 osxtmvl4zg
findutils 4.10.0 vhsfohm5zw		       pcre2 10.44 ayrshy3nkp
gawk 5.3.1 jxq6uva54u			       pdsh 2.31 b2w7bpkhnb
gcc 10.5.0 7w652unbwy			       perl 5.40.0 nsqyer7nqs
gcc 11.4.0 j7ykyvm5an			       perl 5.40.0 txcbw3fccp
gcc 12.5.0 fmxnit5ggu			       pigz 2.8 prsofdph5z
gcc-runtime 10.5.0 ekeebbiepo		       pigz 2.8 zia4xj2idu
gcc-runtime 11.4.0 3c5xh7dqud		       pkgconf 2.3.0 xoghzadcbb
gcc-runtime 12.5.0 zubbt4yxn3		       pkgconf 2.3.0 qz3jy42ylz
gdbm 1.23 5yo63cnvgy			       pmix 5.0.5 msnkjumpg7
gdbm 1.23 cxbuzxk4lq			       pmix 5.0.5 wqd5fdu5gl
gettext 0.23.1 soasbhmurz		       py-beniget 0.4.1 yjbwas7zwz
gettext 0.23.1 goyejxw4nh		       py-cython 3.0.12 33ypsy5oip
glib 2.82.5 wpegaowgsf			       py-flit-core 3.12.0 bw467tx7wa
glibc 2.35 epwvtixhox			       py-gast 0.5.4 xwt2et7ii2
gmake 4.4.1 haeogmcedf			       py-meson-python 0.16.0 bi3kygbxso
gmake 4.4.1 5vb6e4beeo			       py-numpy 2.3.1 7cmuxbwfgn
gmake 4.4.1 xvxobm5cq3			       py-packaging 25.0 4edf37ky2o
gmake 4.4.1 4gp5ttded7			       py-pip 25.1.1 tsrheapc75
gmp 6.3.0 zx3x4nm3dj			       py-pip 25.1.1 nne5hgsvom
hdf5 1.14.6 53lfqwufrt			       py-ply 3.11 cg53hr3fds
hdf5 1.14.6 rewh52tlww			       py-pybind11 2.13.6 lgys3shnnr
hdf5 1.14.6 p3ly6asjcv			       py-pyproject-metadata 0.9.1 vlo72hfjof
hwloc 2.11.1 jhcvb6nk7g			       py-pythran 0.16.1 y2j3wh4mr4
hwloc 2.11.1 3e4kpzphqr			       py-scipy 1.16.0 qbiffx7j4v
intel-tbb 2022.0.0 3g2dqp5itv		       py-setuptools 80.9.0 73p4zkrqbb
json-c 0.18 tiufmaxqw6			       py-setuptools 80.9.0 hjettfg7x2
json-cwx 0.12 5roxsj7npl		       py-wheel 0.45.1 daflthkr3y
kokkos 4.5.01 53vnflrbks		       py-wheel 0.45.1 wjtuyuom3i
kokkos-kernels 4.5.01 wudwbac7p6	       python 3.13.5 dcljl7pmhi
krb5 1.21.3 zo73rgnlq3			       python 3.13.5 musqpuq2h6
krb5 1.21.3 nm4trzqdaw			       python-venv 1.0 hzcm35kueh
kvtree 1.5.0 hztyggwuil			       python-venv 1.0 xmpetx7fsz
libbsd 0.12.2 bcrniixykr		       rankstr 0.4.0 khn5kuon4e
libbsd 0.12.2 es3e2le2oe		       re2c 3.1 zpoiduqoui
libdwarf 2.0.0 uirapsmqr5		       re2c 3.1 cjnodvgptr
libedit 3.1-20240808 h766azt27z		       readline 8.2 skysn5ppma
libedit 3.1-20240808 wspzmodxgc		       readline 8.2 lxvqq5ood4
libevent 2.1.12 dvz3n3eojb		       redset 0.4.0 sn64td3ppz
libevent 2.1.12 alldwq4ypk		       scr 2.0.0 qdg5iykctd
libfabric 2.2.0 lublgehlip		       scr 3.1.0 jsy37gt736
libfabric 2.2.0 atjn3er45p		       shuffile 0.4.0 mo3jxy62lc
libffi 3.4.8 4466i2xl4j			       silo 4.11.1 axjmrnblx3
libffi 3.4.8 ddom6iure3			       slurm 23-11-1-1 ycmepbpfi4
libgcrypt 1.11.1 ln55ajiiws		       spath 0.4.0 kmq4tumwh2
libgpg-error 1.55 xxu2l5erii		       sqlite 3.46.0 zjvsjg7we5
libiberty 2.41 cvva4qyqow		       sqlite 3.46.0 brglstmfyn
libiconv 1.18 kgw5nkswdp		       tar 1.35 ye5hcpfjk5
libiconv 1.18 m2sseeiara		       tar 1.35 4do6jx74ch
libmd 1.1.0 7x6ozmzda7			       tcl 8.6.12 gbhibagbyj
libmd 1.1.0 bqguhkf6f3			       tcl 8.6.12 6wkjgx5kzi
libpciaccess 0.17 w5iqeddpn6		       texinfo 7.1 z47kihjvhl
libpciaccess 0.17 j336pb5rrn		       trilinos 16.1.0 5agd4kt5c4
libsigsegv 2.14 vefpsalwx4		       trilinos 16.1.0 s2kwzuhecz
libsigsegv 2.14 ffctxurczj		       unzip 6.0 hvxekp5s26
libtool 2.4.7 l2jtwyuivf		       util-linux-uuid 2.41 o26ozsqsvc
libtool 2.4.7 7z4rzcr3e7		       util-linux-uuid 2.41 v2nef6xnzn
libxcrypt 4.4.38 iundcaqxew		       util-macros 1.20.1 itmqxdmqzx
libxcrypt 4.4.38 qhnn6wrmss		       util-macros 1.20.1 kbleacprn5
libxml2 2.13.5 7mdlpguain		       xz 5.6.3 zeynpnjapl
libxml2 2.13.5 f2wxschdrk		       xz 5.6.3 3kvqodyyfe
libyogrt 1.35 7igkceogx7		       yaksa 0.3 at3giizyfe
llvm 14.0.0 oc4qy2fa3e			       yaksa 0.3 5r6tuoocxu
lmod 8.7.18 gegst44iqq			       zlib-ng 2.0.7 yq5p6pli22
lua 5.4.6 cvp4vnchqf			       zlib-ng 2.2.4 g7ixtqygrf
lua-luafilesystem 1.8.0 clpxqjmecg	       zlib-ng 2.2.4 6xddq3ypcy
lua-luaposix 36.1 xtcb4fb255		       zlib-ng 2.2.4 rdf7ff3uwe
lwgrp 1.0.6 aueg5csxqj			       zstd 1.5.7 bmaw6fn2i5
lz4 1.10.0 6ekevdfw2g			       zstd 1.5.7 2jhx5guzif

Note that name, version, and hash are attributes of Spack’s internal Spec object and enclosing them in braces ensures they are output according to the format string.

spack find --format can be combined with typical command line tools like sort or uniq to retrieve information relevant to specific workflows.

spack find --json

Alternatively, we can get a serialized version of Spec objects in the JSON format using the --json option.

For example, to get attributes for all installations of zlib-ng:

$ spack find --json zlib-ng

This command provides complete information about any spec of interest in a structured format. The output of spack find --json can be piped to JSON filtering tools like jq to extract specific information.

Visit basic usage docs for more examples.

Introducing the spack python command

What if we need to perform more advanced queries?

Spack provides the spack python command to launch an interpreter with Spack’s Python modules available to import. The underlying Python instance is used for all other commands. We can write scripts to:

  • run Spack commands

  • explore abstract and concretized specs

  • directly access other internal components of Spack

Let’s launch a Spack-aware Python interpreter by entering:

$ spack python
exit()
Spack version 1.0.0
Python 3.11.11, Linux x86_64
>>> exit()

As we are in a Python interpreter, use exit() to end the session and return to the terminal.

Accessing the Spec object

Let’s take a look at the internal representation of the Spack Spec. As previously mentioned, specs can be either abstract or concrete. The specs we’ve seen in package.py files (e.g., in the install() method) have been concrete, or fully specified. Specs typed on the command line have been abstract. Understanding the differences between the two types is key to using Spack’s internal API.

Let’s open another Python interpreter with spack python, instantiate the zlib spec, and check a few properties of an abstract spec:

  >>> from spack.spec import Spec
  >>> zlib = Spec('zlib target=x86_64_v3')
  >>> zlib.concrete
  False
  >>> zlib.version
  Traceback (most recent call last):
    File "<console>", line 1, in <module>
    File "/home/spack/spack/lib/spack/spack/spec.py", line 3166, in version
      raise SpecError("Spec version is not concrete: " + str(self))
  SpecError: Spec version is not concrete: zlib arch=None-None-x86_64_v3
  >>> zlib.versions
  [:]
  >>> str(zlib.architecture)
  None-None-x86_64_v3

Notice that there are Spec properties and methods not accessible to abstract specs; specifically:

  • an exception – SpecError – is raised if we try to access its version

  • there are no associated versions

  • the spec’s operating system is None

Without exiting the interpreter, let’s concretize the spec and try again:

  >>> from spack.concretize import concretize_one
  >>> zlib_concrete = spack.concretize.concretize_one(zlib)
  >>> zlib_concrete.concrete
  True
  >>> zlib_concrete.version
  Version('1.3.1')
  >>> zlib_concrete.versions
  [Version('1.3.1')]
  >>> str(zlib_concrete.architecture)
  linux-ubuntu22.04-x86_64_v3

Notice that the concretized spec now:

  • has a version

  • has a single entry in its versions list

  • the operating system is now ubuntu22.04

Querying the Spack database

More powerful queries are available when we look at the information stored in the Spack database. The Database object in Spack is in the spack.store.STORE.db variable. We’ll interact with it mainly through the query() method. Let’s see the documentation available for query() using Python’s built-in help() function:

>>> import spack.store
>>> help(spack.store.STORE.db.query)
Help on method query in module spack.database:

query(query_spec: Union[str, ForwardRef('spack.spec.Spec'), NoneType] = None, *, predicate_fn: Optional[Callable[[spack.database.InstallRecord], bool]] = None, installed: Union[bool, spack.enums.InstallRecordStatus] = True, explicit: Optional[bool] = None, start_date: Optional[datetime.datetime] = None, end_date: Optional[datetime.datetime] = None, in_buildcache: Optional[bool] = None, hashes: Optional[List[str]] = None, origin: Optional[str] = None, install_tree: str = 'all') -> List[ForwardRef('spack.spec.Spec')] method of spack.database.Database instance
    Queries the Spack database including all upstream databases.

    Args:
        query_spec:  if query_spec is ``None``, match all specs in the database.
            If it is a spec, return all specs matching ``spec.satisfies(query_spec)``.

        predicate_fn: optional predicate taking an InstallRecord as argument, and returning
            whether that record is selected for the query. It can be used to craft criteria
            that need some data for selection not provided by the Database itself.

        installed: if ``True``, includes only installed specs in the search. If ``False`` only
            missing specs, and if ``any``, all specs in database. If an InstallStatus or
            iterable of InstallStatus, returns specs whose install status matches at least
            one of the InstallStatus.

        explicit: a spec that was installed following a specific user request is marked as
            explicit. If instead it was pulled-in as a dependency of a user requested spec
            it's considered implicit.

        start_date: if set considers only specs installed from the starting date.

        end_date: if set considers only specs installed until the ending date.

        in_buildcache: specs that are marked in this database as part of an associated binary
            cache are ``in_buildcache``. All other specs are not. This field is used for
            querying mirror indices. By default, it does not check this status.

        hashes: list of hashes used to restrict the search

        install_tree: query 'all' (default), 'local', 'upstream', or upstream path

        origin: origin of the spec
(END)

We’ll primarily make use of the query_spec argument.

Recall that spack find is limited to queries of attributes with matching values. It cannot be used to find packages that do not meet a specific condition.

We can use the Python interface to write these types of queries. For example, let’s find all packages that were compiled with gcc but do not depend on mpich. We can do this by using custom Python code and Spack database queries. We will use the spack.cmd.display_specs for output to achieve the same printing functionality as the spack find command:

  >>> gcc_query_spec = Spec('%gcc')
  >>> gcc_specs = spack.store.STORE.db.query(gcc_query_spec)
  >>> result = [spec for spec in gcc_specs if not spec.satisfies('^mpich')]
  >>> import spack.cmd
  >>> spack.cmd.display_specs(result)
  -- linux-ubuntu22.04-x86_64_v3 / gcc@11.4.0 -------------------------
autoconf@2.72                       gdbm@1.23             libsigsegv@2.14   perl@5.38.0
automake@1.16.5                     gettext@0.22.5        libtool@2.4.7     pigz@2.8
berkeley-db@18.1.40                 glibc@2.35            libxcrypt@4.4.35  pkgconf@2.2.0
bison@3.8.2                         gmake@4.4.1           libxml2@2.10.3    pmix@5.0.1
bzip2@1.0.8                         hdf5@1.14.3           m4@1.4.19         readline@8.2
ca-certificates-mozilla@2023-05-30  hwloc@2.9.1           ncurses@6.5       tar@1.34
cmake@3.27.9                        krb5@1.20.1           nghttp2@1.57.0    util-macros@1.19.3
curl@8.7.1                          libedit@3.1-20230828  numactl@2.0.14    xz@5.4.6
diffutils@3.10                      libevent@2.1.12       openmpi@5.0.3     zlib-ng@2.1.6
findutils@4.9.0                     libiconv@1.17         openssh@9.7p1     zstd@1.5.6
gcc-runtime@11.4.0                  libpciaccess@0.17     openssl@3.3.0

Now we have a powerful query not available through spack find.

Exit the interpreter to return to the command line:

>>> exit()

before generalizing the functionality for reuse.

Using scripts

Next, the script can be updated to accept arguments from the command line. By generalizing the script to take include and exclude specs as arguments, it becomes a flexible, general-purpose query tool.

Open a file called find_exclude.py in a text editor and add the following code:

from spack.spec import Spec
import spack.store
import spack.cmd
import sys

include_spec = Spec(sys.argv[1])
exclude_spec = Spec(sys.argv[2])

all_included = spack.store.STORE.db.query(include_spec)
result = [spec for spec in all_included if not spec.satisfies(exclude_spec)]

spack.cmd.display_specs(result)

We added importing and using the system package (sys) to access the first and second command line arguments.

Now we can run our new script by entering the following:

$ spack python find_exclude.py %gcc ^mpich
-- linux-ubuntu22.04-x86_64_v3 / %c,cxx,fortran=gcc@11.4.0 ------
mpich@4.3.0  openblas@0.3.29  openmpi@5.0.8  scr@2.0.0	silo@4.11.1  trilinos@16.1.0

-- linux-ubuntu22.04-x86_64_v3 / %c,cxx,fortran=gcc@12.5.0 ------
mpich@4.3.0  openblas@0.3.29  openmpi@5.0.8  py-scipy@1.16.0  scr@3.1.0

-- linux-ubuntu22.04-x86_64_v3 / %c,cxx=gcc@11.4.0 --------------
adept-utils@1.0.1    elfutils@0.192	 kokkos@4.5.01	 macsio@1.1	 tcl@8.6.12
berkeley-db@18.1.40  expat@2.7.1	 krb5@1.21.3	 ncurses@6.5	 tcl@8.6.12
bison@3.8.2	     gcc@12.5.0		 libdwarf@2.0.0	 nghttp2@1.65.0	 texinfo@7.1
boost@1.72.0	     gettext@0.23.1	 libffi@3.4.8	 ninja@1.12.1	 unzip@6.0
callpath@1.0.4	     glib@2.82.5	 libiberty@2.41	 openssh@9.9p1	 zlib-ng@2.0.7
cmake@3.31.8	     gmp@6.3.0		 lua@5.4.6	 openssl@3.4.1	 zlib-ng@2.2.4
curl@8.11.1	     hwloc@2.11.1	 lz4@1.10.0	 python@3.13.5	 zstd@1.5.7
dyninst@13.0.0	     intel-tbb@2022.0.0	 m4@1.4.20	 re2c@3.1

-- linux-ubuntu22.04-x86_64_v3 / %c,cxx=gcc@12.5.0 --------------
axl@0.9.0	     expat@2.7.1     m4@1.4.20	     openssl@3.4.1     redset@0.4.0
berkeley-db@18.1.40  gettext@0.23.1  macsio@1.1	     py-cython@3.0.12  shuffile@0.4.0
bison@3.8.2	     hwloc@2.11.1    ncurses@6.5     py-numpy@2.3.1    spath@0.4.0
cmake@3.31.8	     krb5@1.21.3     nghttp2@1.65.0  python@3.13.5     zlib-ng@2.2.4
curl@8.11.1	     kvtree@1.5.0    ninja@1.12.1    rankstr@0.4.0     zstd@1.5.7
er@0.5.0	     libffi@3.4.8    openssh@9.9p1   re2c@3.1

-- linux-ubuntu22.04-x86_64_v3 / %c,fortran=gcc@11.4.0 ----------
libyogrt@1.35

-- linux-ubuntu22.04-x86_64_v3 / %c,fortran=gcc@12.5.0 ----------
netlib-lapack@3.12.1  netlib-scalapack@2.2.2  netlib-scalapack@2.2.2

-- linux-ubuntu22.04-x86_64_v3 / %c=gcc@10.5.0 ------------------
gmake@4.4.1

-- linux-ubuntu22.04-x86_64_v3 / %c=gcc@11.4.0 ------------------
automake@1.16.5	  json-c@0.18		libtool@2.4.7		 pdsh@2.31
bc@1.07.1	  json-cwx@0.12		libxcrypt@4.4.38	 perl@5.40.0
bzip2@1.0.8	  libbsd@0.12.2		libxml2@2.13.5		 pigz@2.8
diffutils@3.10	  libedit@3.1-20240808	lmod@8.7.18		 pkgconf@2.3.0
dtcmp@1.1.5	  libevent@2.1.12	lua-luafilesystem@1.8.0	 pmix@5.0.5
ed@1.4		  libfabric@2.2.0	lua-luaposix@36.1	 readline@8.2
findutils@4.10.0  libgcrypt@1.11.1	lwgrp@1.0.6		 slurm@23-11-1-1
gawk@5.3.1	  libgpg-error@1.55	mpc@1.3.1		 sqlite@3.46.0
gdbm@1.23	  libiconv@1.18		mpfr@4.2.1		 tar@1.35
gmake@4.4.1	  libmd@1.1.0		munge@0.5.15		 util-linux-uuid@2.41
hdf5@1.14.6	  libpciaccess@0.17	numactl@2.0.18		 xz@5.6.3
hdf5@1.14.6	  libsigsegv@2.14	pcre2@10.44		 yaksa@0.3

-- linux-ubuntu22.04-x86_64_v3 / %c=gcc@12.5.0 ------------------
automake@1.16.5	      libevent@2.1.12	 libxml2@2.13.5		 sqlite@3.46.0
bzip2@1.0.8	      libfabric@2.2.0	 numactl@2.0.18		 tar@1.35
diffutils@3.10	      libiconv@1.18	 perl@5.40.0		 util-linux-uuid@2.41
findutils@4.10.0      libmd@1.1.0	 pigz@2.8		 xz@5.6.3
gdbm@1.23	      libpciaccess@0.17	 pkgconf@2.3.0		 yaksa@0.3
gmake@4.4.1	      libsigsegv@2.14	 pmix@5.0.5
libbsd@0.12.2	      libtool@2.4.7	 py-meson-python@0.16.0
libedit@3.1-20240808  libxcrypt@4.4.38	 readline@8.2

-- linux-ubuntu22.04-x86_64_v3 / %cxx=gcc@11.4.0 ----------------
kokkos-kernels@4.5.01

-- linux-ubuntu22.04-x86_64_v3 / %cxx=gcc@12.5.0 ----------------
py-pybind11@2.13.6  py-pythran@0.16.1

-- linux-ubuntu22.04-x86_64_v3 / no compilers -------------------
gcc-runtime@10.5.0  gcc-runtime@11.4.0	gcc-runtime@12.5.0

This works well, as long as we remember to use Spack’s python command to run it.

Using the spack-python executable

What if the script needs to be shared with others, without requiring them to remember to use spack python?

This can be done by adding a shebang line as the first line of the Python script, which allows it to be run as an executable. However, there is an important limitation to be aware of, as shown in the next example.

Open the find_exclude.py script we created above and add the shebang line with spack python as the arguments to env:

#!/usr/bin/env spack python
from spack.spec import Spec
import spack.store
import spack.cmd
import sys

include_spec = Spec(sys.argv[1])
exclude_spec = Spec(sys.argv[2])

all_included = spack.store.STORE.db.query(include_spec)
result = [spec for spec in all_included if not spec.satisfies(exclude_spec)]

spack.cmd.display_specs(result)

Exit the editor and add execute permissions to the script before running it as follows:

$ chmod u+x find_exclude.py
$ ./find_exclude.py %gcc ^mpich
/usr/bin/env: ‘spack python’: Permission denied

If we’re lucky, it ran successfully, but there’s no guarantee this will work for every system. Some systems only support a single argument on the shebang line (see here). spack-python, which is a wrapper script for spack python, solves this issue.

Bring up the file in the editor again and change the env argument to spack-python as follows:

#!/usr/bin/env spack-python
from spack.spec import Spec
import spack.store
import spack.cmd
import sys

include_spec = Spec(sys.argv[1])
exclude_spec = Spec(sys.argv[2])

all_included = spack.store.STORE.db.query(include_spec)
result = [spec for spec in all_included if not spec.satisfies(exclude_spec)]

spack.cmd.display_specs(result)

Exit the editor and run the script again:

$ ./find_exclude.py %gcc ^mpich
-- linux-ubuntu22.04-x86_64_v3 / %c,cxx,fortran=gcc@11.4.0 ------
mpich@4.3.0  openblas@0.3.29  openmpi@5.0.8  scr@2.0.0	silo@4.11.1  trilinos@16.1.0

-- linux-ubuntu22.04-x86_64_v3 / %c,cxx,fortran=gcc@12.5.0 ------
mpich@4.3.0  openblas@0.3.29  openmpi@5.0.8  py-scipy@1.16.0  scr@3.1.0

-- linux-ubuntu22.04-x86_64_v3 / %c,cxx=gcc@11.4.0 --------------
adept-utils@1.0.1    elfutils@0.192	 kokkos@4.5.01	 macsio@1.1	 tcl@8.6.12
berkeley-db@18.1.40  expat@2.7.1	 krb5@1.21.3	 ncurses@6.5	 tcl@8.6.12
bison@3.8.2	     gcc@12.5.0		 libdwarf@2.0.0	 nghttp2@1.65.0	 texinfo@7.1
boost@1.72.0	     gettext@0.23.1	 libffi@3.4.8	 ninja@1.12.1	 unzip@6.0
callpath@1.0.4	     glib@2.82.5	 libiberty@2.41	 openssh@9.9p1	 zlib-ng@2.0.7
cmake@3.31.8	     gmp@6.3.0		 lua@5.4.6	 openssl@3.4.1	 zlib-ng@2.2.4
curl@8.11.1	     hwloc@2.11.1	 lz4@1.10.0	 python@3.13.5	 zstd@1.5.7
dyninst@13.0.0	     intel-tbb@2022.0.0	 m4@1.4.20	 re2c@3.1

-- linux-ubuntu22.04-x86_64_v3 / %c,cxx=gcc@12.5.0 --------------
axl@0.9.0	     expat@2.7.1     m4@1.4.20	     openssl@3.4.1     redset@0.4.0
berkeley-db@18.1.40  gettext@0.23.1  macsio@1.1	     py-cython@3.0.12  shuffile@0.4.0
bison@3.8.2	     hwloc@2.11.1    ncurses@6.5     py-numpy@2.3.1    spath@0.4.0
cmake@3.31.8	     krb5@1.21.3     nghttp2@1.65.0  python@3.13.5     zlib-ng@2.2.4
curl@8.11.1	     kvtree@1.5.0    ninja@1.12.1    rankstr@0.4.0     zstd@1.5.7
er@0.5.0	     libffi@3.4.8    openssh@9.9p1   re2c@3.1

-- linux-ubuntu22.04-x86_64_v3 / %c,fortran=gcc@11.4.0 ----------
libyogrt@1.35

-- linux-ubuntu22.04-x86_64_v3 / %c,fortran=gcc@12.5.0 ----------
netlib-lapack@3.12.1  netlib-scalapack@2.2.2  netlib-scalapack@2.2.2

-- linux-ubuntu22.04-x86_64_v3 / %c=gcc@10.5.0 ------------------
gmake@4.4.1

-- linux-ubuntu22.04-x86_64_v3 / %c=gcc@11.4.0 ------------------
automake@1.16.5	  json-c@0.18		libtool@2.4.7		 pdsh@2.31
bc@1.07.1	  json-cwx@0.12		libxcrypt@4.4.38	 perl@5.40.0
bzip2@1.0.8	  libbsd@0.12.2		libxml2@2.13.5		 pigz@2.8
diffutils@3.10	  libedit@3.1-20240808	lmod@8.7.18		 pkgconf@2.3.0
dtcmp@1.1.5	  libevent@2.1.12	lua-luafilesystem@1.8.0	 pmix@5.0.5
ed@1.4		  libfabric@2.2.0	lua-luaposix@36.1	 readline@8.2
findutils@4.10.0  libgcrypt@1.11.1	lwgrp@1.0.6		 slurm@23-11-1-1
gawk@5.3.1	  libgpg-error@1.55	mpc@1.3.1		 sqlite@3.46.0
gdbm@1.23	  libiconv@1.18		mpfr@4.2.1		 tar@1.35
gmake@4.4.1	  libmd@1.1.0		munge@0.5.15		 util-linux-uuid@2.41
hdf5@1.14.6	  libpciaccess@0.17	numactl@2.0.18		 xz@5.6.3
hdf5@1.14.6	  libsigsegv@2.14	pcre2@10.44		 yaksa@0.3

-- linux-ubuntu22.04-x86_64_v3 / %c=gcc@12.5.0 ------------------
automake@1.16.5	      libevent@2.1.12	 libxml2@2.13.5		 sqlite@3.46.0
bzip2@1.0.8	      libfabric@2.2.0	 numactl@2.0.18		 tar@1.35
diffutils@3.10	      libiconv@1.18	 perl@5.40.0		 util-linux-uuid@2.41
findutils@4.10.0      libmd@1.1.0	 pigz@2.8		 xz@5.6.3
gdbm@1.23	      libpciaccess@0.17	 pkgconf@2.3.0		 yaksa@0.3
gmake@4.4.1	      libsigsegv@2.14	 pmix@5.0.5
libbsd@0.12.2	      libtool@2.4.7	 py-meson-python@0.16.0
libedit@3.1-20240808  libxcrypt@4.4.38	 readline@8.2

-- linux-ubuntu22.04-x86_64_v3 / %cxx=gcc@11.4.0 ----------------
kokkos-kernels@4.5.01

-- linux-ubuntu22.04-x86_64_v3 / %cxx=gcc@12.5.0 ----------------
py-pybind11@2.13.6  py-pythran@0.16.1

-- linux-ubuntu22.04-x86_64_v3 / no compilers -------------------
gcc-runtime@10.5.0  gcc-runtime@11.4.0	gcc-runtime@12.5.0

It will now work on any system with Spack installed.

With these tools, we can create custom Spack queries and prototype new ideas. Contributions that improve or extend common Spack workflows are always welcome in the community.