-
-
Save JavaScriptDude/b436bfda31e765ef7a9916890c786138 to your computer and use it in GitHub Desktop.
| import time, sys, os | |
| class SingleInstanceChecker: | |
| def __init__(self, id): | |
| if isWin(): | |
| ensure_win32api() | |
| self.mutexname = id | |
| self.lock = win32event.CreateMutex(None, False, self.mutexname) | |
| self.running = (win32api.GetLastError() == winerror.ERROR_ALREADY_EXISTS) | |
| else: | |
| ensure_fcntl() | |
| self.lock = open(f"/tmp/isnstance_{id}.lock", 'wb') | |
| try: | |
| fcntl.lockf(self.lock, fcntl.LOCK_EX | fcntl.LOCK_NB) | |
| self.running = False | |
| except IOError: | |
| self.running = True | |
| def already_running(self): | |
| return self.running | |
| def __del__(self): | |
| if self.lock: | |
| try: | |
| if isWin(): | |
| win32api.CloseHandle(self.lock) | |
| else: | |
| os.close(self.lock) | |
| except Exception as ex: | |
| pass | |
| # --------------------------------------- | |
| # Utility Functions | |
| # Dynamically load win32api on demand | |
| # Install with: pip install pywin32 | |
| win32api=winerror=win32event=None | |
| def ensure_win32api(): | |
| global win32api,winerror,win32event | |
| if win32api is None: | |
| import win32api | |
| import winerror | |
| import win32event | |
| # Dynamically load fcntl on demand (python stdlib) | |
| fcntl=None | |
| def ensure_fcntl(): | |
| global fcntl | |
| if fcntl is None: | |
| import fcntl | |
| def isWin(): | |
| return (os.name == 'nt') | |
| # --------------------------------------- | |
| def main(argv): | |
| _timeout = 10 | |
| print("main() called. sleeping for %s seconds" % _timeout) | |
| time.sleep(_timeout) | |
| print("DONE") | |
| if __name__ == '__main__': | |
| SCR_NAME = "my_script" | |
| sic = SingleInstanceChecker(SCR_NAME) | |
| if sic.already_running(): | |
| print("An instance of {} is already running.".format(SCR_NAME)) | |
| sys.exit(1) | |
| else: | |
| main(sys.argv[1:]) |
@dineshbvadhia Was a typo. fcntl is built into the python stdlib. Thanks for letting me know.
Hi. Typed the code but mypy generates a bunch of 'has no attribute' errors which I'm not sure how to resolve:
from typing import Any
import time, sys, os
class SingleInstanceChecker:
def __init__(self, id: str) -> None:
if isWin():
ensure_win32api()
self.mutexname = id
self.lock = win32event.CreateMutex(None, False, self.mutexname)
self.running = (win32api.GetLastError() == winerror.ERROR_ALREADY_EXISTS)
else:
ensure_fcntl()
self.lock = open(f"/tmp/isnstance_{id}.lock", 'wb')
try:
fcntl.lockf(self.lock, fcntl.LOCK_EX | fcntl.LOCK_NB)
self.running = False
except IOError:
self.running = True
def already_running(self) -> Any:
return self.running
def __del__(self) -> None:
if self.lock:
try:
if isWin():
win32api.CloseHandle(self.lock)
else:
os.close(self.lock)
except Exception as ex:
pass
# ---------------------------------------
# Utility Functions
# Dynamically load win32api on demand
# Install with: pip install pywin32
win32api=winerror=win32event=None
def ensure_win32api() -> None:
global win32api,winerror,win32event
if win32api is None:
import win32api
import winerror
import win32event
# Dynamically load fcntl on demand (python stdlib)
fcntl=None
def ensure_fcntl() -> None:
global fcntl
if fcntl is None:
import fcntl
def isWin() -> bool:
return (os.name == 'nt')
# ---------------------------------------
def main(argv: list[str]) -> None:
_timeout: int = 10
print("main() called. sleeping for %s seconds" % _timeout)
time.sleep(_timeout)
print("DONE")
if __name__ == '__main__':
SCR_NAME: str = "my_script"
sic = SingleInstanceChecker(SCR_NAME)
if sic.already_running():
print("An instance of {} is already running.".format(SCR_NAME))
sys.exit(1)
else:
main(sys.argv[1:])
> mypy SingleInstanceChecker.py
py:9: error: "None" has no attribute "CreateMutex" [attr-defined]
py:10: error: "None" has no attribute "GetLastError" [attr-defined]
py:10: error: "None" has no attribute "ERROR_ALREADY_EXISTS" [attr-defined]
py:16: error: "None" has no attribute "lockf" [attr-defined]
py:16: error: "None" has no attribute "LOCK_EX" [attr-defined]
py:16: error: "None" has no attribute "LOCK_NB" [attr-defined]
py:28: error: "None" has no attribute "CloseHandle" [attr-defined]
Found 7 errors in 1 file (checked 1 source file)
Although I've never used mypy. I suspect that mypy is getting confused by the dynamic loading of the platform specific library via ensure_win32api and ensure_fcntl. I'm sure if you made a linux and windows specific versions and explicitly load the respective library, mypy will not have issues.
There may be a more pythonic way to do this type of platform specific dynamic loading that would make mypy happy but I don't have the bandwidth to investigate. Suggestions would be appreciated.
The code definitely works and I've used it in dozens of usecases where I develop the code in linux and deploy in windows in some cases. I use this code for my scheduled task / cron based jobs.
@JavaScriptDude Apologies if I gave the impression the code doesn't work - it does work. My code base is typed and so wanted to type this. I'll investigate further.
No problem at all. Glad to have my open source code being helpful.
Where is the fcntl package from because get these errors?: