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 …