Where should I create temporary files intended to be used by programs which may be packaged as snaps?

I am writing a python program which programmatically creates a temporary file and then runs a command on it. By default, the Python tempfile module creates temporary files in /tmp. Unfortunately this path is not available to snaps.

What is a suitable, standardized temporary location to create my temporary file in order to retain compatibility with both snap-packaged and non-snap-packaged versions of the command?

  • Dropping files in a random subdirectory of the user’s home directory is not suitable. The user’s home directory is not a temporary directory and should not be treated as such.
  • Dropping the file anywhere in ~/snap is also not suitable, as this is not compatible if the software is not packaged with snap.
  • ~/.cache is not suitable, as the contents of this directory is also not available to snaps.

I ran into this exact same issue: I’m writing a Python library that wraps the Juju CLI. But juju is now packaged as a confined snap, and I was using tempfile.NamedTemporaryFile to create a file to pass to juju run with something like --params /tmp/tmp123458.yaml. However, tempfile puts its files in /tmp, so Juju wasn’t able to read them, as you point out.

I ended up solving it with code like this:

    @functools.cached_property
    def _juju_is_snap(self) -> bool:
        which = shutil.which(self.cli_binary)
        return which is not None and '/snap/' in which

    @functools.cached_property
    def _temp_dir(self) -> str:
        if self._juju_is_snap:
            # If Juju is running as a snap, we can't use /tmp, so put temp files here instead.
            temp_dir = os.path.expanduser('~/snap/juju/common')
            os.makedirs(temp_dir, exist_ok=True)
            return temp_dir
        else:
            return tempfile.gettempdir()

And then inside Juju.run:

        params_file = None
        if params is not None:
            with tempfile.NamedTemporaryFile(
                'w+', delete=False, dir=self._temp_dir
            ) as params_file:
                _yaml.safe_dump(params, params_file)
            args.extend(['--params', params_file.name])

Using ~/snap/juju/common seemed the correct choice. And as you can see, I’m doing a rough test to see “is the application running as a snap?”

What makes you think this ? There is definitely /tmp for snaps and many use it … that specific /tmp is inside confinement though and not accessible to anything outside of the snap but it is nontheless fully usable inside the snap … does the tempfile module throw any errors when you use it (it should definitely just work) ?

If you need something usable across other snaps I’d take a look at $XDG_RUNTIME_DIR …