0

In my code I have a temporary file that I want to have removed either at the program end or if there is an abort via a click exception. I can't use tempfile.TemporaryFile because the file could either be local or on a remote machine. Hence I thought registering a cleanup function via click.call_on_close would be an elegant solution.

My problem now is: how do I get the filename into that cleanup callback?

This is what I got:

import click
import os
import tempfile

def remove_tmp_file(**kwargs):
    # ??? somehow get the file name
    if host == "localhost":
        os.remove(tmp_file)
    else:
        delete_tmp_file_remote(tmp_file)

@click.command()
@click.pass_context
def main(...):
    tmp_file = tempfile.mktemp(prefix="my_prefix_", dir="/tmp")
    ctx.call_on_close(remove_tmp_file)
    # do something with tmp_file

How can I pass information (stored in variables) from my main function into this callback?

Matthias
  • 141
  • 9
  • 1
    Seems like using argument binding: https://stackoverflow.com/questions/277922/python-argument-binders would be the way to go here. – Fantastic Mr Fox Apr 04 '23 at 23:18

2 Answers2

0

The simplest solution would be a global variable.

import click
import os
import tempfile

tmp_file = None

def remove_tmp_file(**kwargs):
    global tmp_file
    if not tmp_file:
        return
    if host == "localhost":
        os.remove(tmp_file)
    else:
        delete_tmp_file_remote(tmp_file)

@click.command()
@click.pass_context
def main(...):
    global tmp_file_to_delete
    tmp_file = tempfile.mktemp(prefix="my_prefix_", dir="/tmp")
    ctx.call_on_close(remove_tmp_file)
    # do something with tmp_file
kichik
  • 33,220
  • 7
  • 94
  • 114
  • I thought about that too. I'm rather leaning against it as I will need connection parameters for remote site removal as well and I don't like putting all of that in global variables. – Matthias Apr 05 '23 at 08:59
0

I found 2 working solutions.

1.) Store the information you need into the click context:

import click
import os
import tempfile

def remove_tmp_file(**kwargs):
    ctx = click.get_current_context()
    tmp_file = ctx.params["tmp_file"]
    ...
    if host == "localhost":
        os.remove(tmp_file)
    else:
        delete_tmp_file_remote(tmp_file)

@click.command()
@click.pass_context
def main(...):
    tmp_file = tempfile.mktemp(prefix="my_prefix_", dir="/tmp")
    ctx.params["tmp_file"] = tmp_file
    ctx.call_on_close(remove_tmp_file)
    # do something with tmp_file

2.) Use a lambda for the callback as suggested by @Fantastic Mr Fox

import click
import os
import tempfile

def remove_tmp_file(*args):
    tmp_file, other_parameter = args
    
    if host == "localhost":
        os.remove(tmp_file)
    else:
        delete_tmp_file_remote(tmp_file)

@click.command()
@click.pass_context
def main(...):
    tmp_file = tempfile.mktemp(prefix="my_prefix_", dir="/tmp")
    ctx.call_on_close(lambda: remove_tmp_file(tmp_file, other_parameter))
    # do something with tmp_file

I found 2.) to be more elegant so I chose it.

Matthias
  • 141
  • 9