Hi Tutors! I have a problem that I've solved using Python, and I want to know if I've done a good job :-)
Here's the problem: At my work we have a Windows network. On a network drive lives a program that a couple people need to access (there's a shortcut on each user's Desktop to the executable). The problem is, only *one* person at a time should run the program. For various reasons, it's possible for information to get corrupted if two people are using the program at the same time. Here's the old solution to the problem: Pick-up the phone. Dial Dave's extension. Dave this is Bill, I'm going to use the program. Use the program. Call Dave again and tell him I'm done using the program. And Dave does the same for me. Putting it mildly - this is a less than ideal way to run software ;-) Now here's my solution: 1. Create a program let's call it 'myProg' that spawns 'otherProg'. 2. 'myProg' will utilize a config file. 3. When 'myProg' is started it looks in the config file to see if 'otherProg' is running. 4. If 'otherProg' is not running, start it and write to the config file that 'otherProg' is running (also write who is running it). 5. 'myProg' continues to run on the user's computer, continuously checking the PID (of 'otherProg') to see if the process is still alive. 6. When we don't find the PID anymore, write to the config file that 'otherProg' isn't running. 7. Shutdown 'myProg'. Now in step #3 above - if 'myProg' reads the config file and finds that the 'otherProg' is currently running, the user is warned that 'The program is currently in use by <insert username from config file>!' And 'otherProg' is not started. Couple of other things..... 1. I'm taking 'myProg' and creating a single-file executable using py2exe. 2. 'myProg.exe' and the config file live on the network in the same directory as 'otherProg'. 3. User's have a shortcut on the Desktop to 'myProg.exe' instead of 'otherProg'. BTW, I've never stopped to consider if there was a simple 'Windows networking / permissions' type solution to the problem. I just went straight to Python :-) Here's my code. I'd appreciate any critiques! Thanks, Bill <code> import time import os import sys import getpass from ConfigParser import ConfigParser import win32pdhutil import win32con import win32api CONFIG_FILE = 'WatchProc.ini' # Is there a better way to deal with this # default config file data? defaultConfigData = \ """ [Process] proc = [Current User] user = [Executable] exe = [Process Status] running = [Shutdown Status] ok = """ class WatchProc: def __init__(self): self.config = Config() self.user = getpass.getuser() self.checkConfig() def checkConfig(self): """ Check the config file and see if a process is listed. If nothing is listed throw an error, else do checkStatus(). """ proc = self.config.getConfig('Process', 'proc') if proc == '': self.configFileError() else: self.checkStatus() def checkStatus(self): """ Check the config file to see if the process is running or not. If running throw an error, else start the app. """ status = self.config.getConfig('Process Status', 'running') if status == 'True': # App is in use. self.usageError() elif status == 'False': # App not in use. self.startApp() else: # Config file is not setup properly. self.configFileError() def startApp(self): """ Write the user's name to the config file. Start the executable. Then monitor the process. """ self.config.setConfig('Current User', 'user', self.user) self.startExe() time.sleep(1) self.monitorProcess() def monitorProcess(self): """ Get the process name from the config file then continuously check to see if the process is running. When the process dies, call cleanup(). """ procname = self.config.getConfig('Process', 'proc') self.config.setConfig('Shutdown Status', 'ok', False) CHECK = True while CHECK: try: pid = \ win32pdhutil.FindPerformanceAttributesByName(procname) time.sleep(.5) except: # App has stopped running. CHECK = False self.cleanup() def startExe(self): """ Grab the name of the executable to start. Write to the config file that we're running. Spawn. """ exe = self.config.getConfig('Executable', 'exe') self.config.setConfig('Process Status', 'running', True) os.spawnv(os.P_NOWAIT, exe, []) def cleanup(self): """ Set the config file to the proper values (for a clean shutdown) and then exit. """ self.config.setConfig('Shutdown Status', 'ok', True) self.config.setConfig('Process Status', 'running', False) self.config.setConfig('Current User', 'user', '') sys.exit() def configFileError(self): """ Error message that gets called when a value in the config file is missing. """ errMsg = 'The configuration file is not setup properly!' win32api.MessageBox(0, errMsg, 'Config File Error', win32con.MB_ICONEXCLAMATION) def usageError(self): """ Error message that gets called when somebody else is currently running the "watched" program. """ user = self.config.getConfig('Current User', 'user') errMsg = 'The program is currently in use by %s!' % (user) win32api.MessageBox(0, errMsg, 'Start Program Error', win32con.MB_ICONEXCLAMATION) class Config: def __init__(self): # Check to see if the config file exists, # if not create one. if not os.path.exists(CONFIG_FILE): self.writeDefaultConfig() self.cp = ConfigParser() self.cp.read(CONFIG_FILE) def setConfig(self, section, option, value): """ Method used to set config options and values in the ini file. """ self.cp.set(section, option, value) f = open(CONFIG_FILE, 'w') self.cp.write(f) f.close() def getConfig(self, section, option): """ Returns a value from the config file. """ return self.cp.get(section, option) def writeDefaultConfig(self): """ Writes the 'default' config file. Will only get called if one does not exist. """ f = open(CONFIG_FILE, "w") f.write(defaultConfigData) f.close() if __name__ == '__main__': watcher = WatchProc() </code> _______________________________________________ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor