I have this use case when during one script I want to use one .pyd library but generally I want to use another version of the same .pyd.
To accomplish this I switch .pyd files when python script starts and then import lib imports correct version.
At the end of python script (using atexit) I've attached script that will presumably switch the library. The catch is that you cannot change .pyd if it's used by some process (which is current python instance) and it cannot be unloaded (I've found notion that it's impossible to unload loaded .dlls or .pyds at runtime). So I need to kill the python.exe and then run my script.
When I kill python.exe it seems to terminate os.system
I've tried at first and it never comes to running .bat file that will perform the library switch. And I'm trying to work around that.
LONG STORY SHORT - I want to kill python process and run some code after.
Example code is below - it never prints process id to test_my_case.txt
. If I remove && timeout 3
it works fine - so I think the problem is that subprocess.call
process is killed as python process gets killed and it's not able to print if there is any delay before the echo.
What I've tried - os.startfile
, os.system
, subprocess.Popen
, subprocess.call
.
import os
import subprocess
import atexit
# never prints PID to the test_my_case.txt
def switch_library():
command = f"taskkill /F /PID {os.getpid()} && timeout 3 && echo {os.getpid()} > test_my_case.txt"
subprocess.run(command, shell=True)
atexit.register(switch_library)
exit()
Well, this is fairly hacky but I've found a way to do it through task scheduler (on Windows). First I've tried to do it with schtasks but it doesn't allow settings start time in seconds when I want the script to be executed very shortly after it's scheduled, therefore I moved to Powershell script...
import os
import sys
import tempfile
import subprocess
import atexit
from pathlib import Path
@atexit.register
def switch_library():
temp_folder = Path(tempfile.gettempdir())
pid = os.getpid()
def write_to_file(filepath, string):
with open(filepath, "w") as fi:
fi.write(string)
cmd_script = f"taskkill /F /PID {pid} & timeout 3"
ps_script = f"""Unregister-ScheduledTask -TaskName "library_switch" -Confirm:$false
$taskAction = New-ScheduledTaskAction -Execute "cmd.exe" -Argument '/c "{cmd_script}"'
Register-ScheduledTask 'library_switch' -Action $taskAction
Start-ScheduledTask -TaskName "library_switch"
"""
ps_script_file = temp_folder / "terminator.ps1"
write_to_file(ps_script_file, ps_script)
# requires: Set-ExecutionPolicy RemoteSigned
show_ps_output = False
stdout = sys.stdout if show_ps_output else subprocess.DEVNULL
p = subprocess.Popen(["powershell.exe", ps_script], stdout=stdout)
p.communicate()