Python Skeleton Scripts
Revision as of 09:37, 1 May 2008 by PeterHarding (talk | contribs)
Get CLI Arguments and Read a Config File - Based on a server
#!/usr/bin/env python # # Purpose: # # $Id:$ # #------------------------------------------------------------------------------- """ Skeleton Python script ... """ #------------------------------------------------------------------------------- import os import sys import getopt import logging #------------------------------------------------------------------------------- from datetime import datetime #------------------------------------------------------------------------------- __version__ = "1.0.0" __id__ = "@(#) skel.py [%s] 05/03/2008" verbose_flg = False debug_level = 0 LOGFILE = "xxxx.log" PIDFILE = "xxxx.pid" tables = [] log = None pid = None #=============================================================================== def INFO(msg): if log: log.info(' ' + msg) if verbose_flg: print "[xxxx] %s" % msg #------------------------------------------------------------------------------- def ERROR(msg): if log: log.error(msg) sys.stderr.write('[xxxx] %s\n' % msg) #------------------------------------------------------------------------------- def WARNING(msg): if log: log.warning('*****' + msg + '*****') if verbose_flg: print "[xxxx] %s" % msg #=============================================================================== def init(): global log global pid pid = os.getpid() log = logging.getLogger('xxx') hdlr = logging.FileHandler(LOGFILE) fmtr = logging.Formatter('%(asctime)s %(levelname)s %(message)s') hdlr.setFormatter(fmtr) log.addHandler(hdlr) log.setLevel(logging.INFO) INFO("Started processing") if (not verbose_flg): INFO("PID is %d" % pid) #=============================================================================== def main(): global verbose_flg global debug_level try: opts, args = getopt.getopt(sys.argv[1:], "dD:vVw?") except getopt.error, msg: print __doc__ return 1 try: terminal_type = os.environ["TERM"] except KeyError, e: print "[xxxx] Set TERM environment variable and rerun!" return 1 wrk_path = os.getcwd() wrk_dir = os.path.basename(wrk_path) data_dir = wrk_dir + '/DATA/' pid_path = data_dir + PIDFILE # os.chdir(data_dir) for o, a in opts: if o == '-d': debug_level += 1 elif o == '-D': debug_level = int(a) elif o == '-v': verbose_flg = True elif o == '-V': print "[xxxx] Version: %s" % __version__ return 1 elif o == '-?': print __doc__ return 1 print "[xxxx] Working directory is %s" % os.getcwd() if (debug_level > 0): print "[xxxx] Debugging level set to %d" % debug_level if args: for arg in args: print arg init() return 0 #------------------------------------------------------------------------------- if __name__ == '__main__' or __name__ == sys.argv[0]: try: sys.exit(main()) except KeyboardInterrupt, e: print "[xxxx] Interrupted!" #------------------------------------------------------------------------------- """ Revision History: Date Who Description -------- --- ------------------------------------------------------------ 20031014 plh Initial implementation Problems to fix: To Do: Issues: """
Reading CSV Files
Daemonized Server
#!/usr/bin/env python # # Purpose: Threaded data server implementation # # $Id:$ # #--------------------------------------------------------------------- """ Uses threaded server model Server side: open a socket on a port, listen for a message from a client, and accept a request and service it. The server spawns a thread to handle each client connection. Threads share global memory space with main thread; This is more portable than fork -- not yet on Windows; This version has been extended to use the standard Python logging module. Add the delimiter to the INI file to allow use of alternate delimiters in transmitted data - so data with embedded commas can be used. """ #--------------------------------------------------------------------- import os import csv import sys import getopt import thread import time import signal import logging #--------------------------------------------------------------------- from socket import * # get socket constructor and constants from datetime import datetime #--------------------------------------------------------------------- __version__ = "1.1.1" __id__ = "@(#) server.py [%s] 05/03/2008" check_flg = False daemon_flg = False silent_flg = False terminate_flg = False verbose_flg = False wait_flg = False debug_level = 0 HOST = '' # Host server - '' means localhost PORT = 9999 # Listen on a non-reserved port number sockobj = None dserver_dir = None data_dir = None pid_path = None CONFIGFILE = "server.ini" LOGFILE = "server.log" PIDFILE = "server.pid" tables = [] INVALID = "INVALID" log = None #===================================================================== class Group: Name = None Idx = None Data = None def __init__(self, name): self.Name = name self.Idx = 0 self.Data = [] def __str__(self): s = "Grp %s Len %d" % (self.Name, len(self.Data)) return s def append(self, s): self.Data.append(s) def set(self): if len(self.Data) > 0: self.Idx = 0 else: self.Idx = -1 #--------------------------------------------------------------------- ... #===================================================================== def INFO(msg): if log: log.info(' ' + msg) if verbose_flg: print "[server] %s" % msg #--------------------------------------------------------------------- def ERROR(msg): if log: log.error(msg) sys.stderr.write('[server] %s\n' % msg) #--------------------------------------------------------------------- def WARNING(msg): if log: log.warning('*****' + msg + '*****') if verbose_flg: print "[server] %s" % msg #===================================================================== def read_config(): config_file = data_dir + CONFIGFILE try: f = open(config_file, 'r') except IOError, e: ERROR('Open failed: ' + str(e)) sys.exit(1) definition_flg = False while True: line = f.readline() if not line: break line = line[:-1] line = line.replace('\r','') line = line.strip() if (line.find("#") != -1): continue if (line.find("[Data]") != -1): definition_flg = True elif (line.find("Description=") != -1): description = line.split("=") (name, type, delimiter) = description[1].split(":") t = Table(name, type, delimiter) INFO(str(t)) tables.append(t) f.close() #--------------------------------------------------------------------- def process(str): if debug_level > 1: INFO("[server::process] len %d msg %s" % (l, msg)) ts = datetime.now().strftime('%Y%m%d%H%M%S') reply = 'XXXX' return reply #--------------------------------------------------------------------- def sig_term(signum, frame): "SIGTERM handler" shutdown() #--------------------------------------------------------------------- def shutdown(): INFO("Server shutdown at %s" % datetime.now()) for i in range(len(tables)): tables[i].flush() try: os.unlink(pid_path) except IOError, e: ERROR('Unlink failed: ' + str(e)) sys.exit(1) sys.exit(0) #--------------------------------------------------------------------- def check_running(): try: pfp = open(pid_path, 'r') except IOError, (errno, strerror): pfp = None # ERROR("I/O error(%s): %s" % (errno, strerror)) except: ERROR("Unexpected error:", sys.exc_info()[0]) raise if pfp: line = pfp.readline() line = line.strip() dserver_pid = int(line) noProcess = 0 try: os.kill(dserver_pid, 0) except OSError, e: if e.errno == 3: noProcess = 1 else: ERROR("kill() failed:" + str(e)) sys.exit(0) if noProcess: INFO("[server] Stale dserver pid file!") pfp.close() os.unlink(pid_path) return None else: pfp.close() return dserver_pid return dserver_pid else: return None #--------------------------------------------------------------------- def create_pidfile(): pid = os.getpid() try: pfp = open(pid_path, 'w') except IOError, e: ERROR("Open failed - " + str(e)) sys.exit(0) pfp.write("%d" % pid) pfp.close() INFO("Running server with PID -> %d" % pid) return pid #--------------------------------------------------------------------- def become_daemon(): pid = os.fork() if pid == 0: # In child pid = create_pidfile() time.sleep(1) elif pid == -1: # Should not happen! ERROR("fork() failed!") time.sleep(1) sys.exit(0) else: # In Parent time.sleep(1) sys.exit(0) time.sleep(2) os.setsid() return pid #--------------------------------------------------------------------- def init(): pid = check_running() if pid: print "[server] Server already running! (pid = %d)" % pid sys.exit(0) if daemon_flg: pid = become_daemon() else: pid = create_pidfile() global log log = logging.getLogger('dserver') hdlr = logging.FileHandler(LOGFILE) fmtr = logging.Formatter('%(asctime)s %(levelname)s %(message)s') hdlr.setFormatter(fmtr) log.addHandler(hdlr) log.setLevel(logging.INFO) INFO("Started processing") read_config() if (not silent_flg): INFO("Server PID is %d" % pid) #--------------------------------------------------------------------- def terminate(): server_pid = check_running() if server_pid: if (not silent_flg): INFO("Terminating server with pid, %d" % server_pid) os.kill(server_pid, signal.SIGTERM) if (wait_flg): while True: try: kill(server_pid, 0) except OSError, e: if e.errno == 3: break else: ERROR("kill() failed:" + str(e)) sys.exit(0) time.sleep(1) return 0 #--------------------------------------------------------------------- def check(): pid = check_running() if pid: print "[server] Server already running! (pid = %d)" % pid sys.exit(0) else: print "[server] Server not running" #==== Socket Server ================================================== def init_connection(): global sockobj sockobj = socket(AF_INET, SOCK_STREAM) # make a TCP socket object sockobj.bind((HOST, PORT)) # bind it to server port number sockobj.listen(10) # allow upto 10 pending connects #--------------------------------------------------------------------- def handle_client(connection): # in spawned thread: reply while True: # read, write a client socket try: request = connection.recv(1024) except: break if debug_level > 0: INFO('[server] Request -> "%s"' % request) if not request: break reply = process(request) if debug_level > 0: INFO('[server] Reply -> "%s..."' % reply[0:30]) connection.send(reply) connection.close() #--------------------------------------------------------------------- def dispatcher(): while True: # Wait for next connection, connection, address = sockobj.accept() INFO('Host (%s) - Connected at %s' % (address[0], datetime.now())) thread.start_new(handle_client, (connection,)) #===================================================================== def main(): global check_flg global daemon_flg global terminate_flg global verbose_flg global wait_flg global debug_level global dserver_dir global data_dir global pid_path try: opts, args = getopt.getopt(sys.argv[1:], "cdDsTvVw?") except getopt.error, msg: print __doc__ return 1 try: server_dir = os.environ["SERVER_DIR"] except KeyError, e: print "[server] Set SERVER_DIR environment variable and rerun!" return 1 data_dir = server_dir + '/DATA/' pid_path = data_dir + PIDFILE wrk_path = os.getcwd() wrk_dir = os.path.basename(wrk_path) os.chdir(data_dir) for o, a in opts: if o == '-d': debug_level += 1 elif o == '-c': check_flg = True elif o == '-D': daemon_flg = True elif o == '-s': tsilent_flg = True elif o == '-T': terminate_flg = True elif o == '-v': verbose_flg = True elif o == '-V': print "[dserver] Version: %s" % __version__ return 1 elif o == '-w': wait_flg = True elif o == '-?': print __doc__ return 1 print "[server] Server working directory is %s" % os.getcwd() if check_flg: check() return 0 if terminate_flg: terminate() return 0 if (debug_level > 0): print "[server] Debugging level set to %d" % debug_level if args: for arg in args: print arg signal.signal(signal.SIGTERM, sig_term) init() init_connection() dispatcher() return 0 #--------------------------------------------------------------------- if __name__ == '__main__' or __name__ == sys.argv[0]: try: sys.exit(main()) except KeyboardInterrupt, e: print "[server] Interrupted!" shutdown() #--------------------------------------------------------------------- """ Revision History: Date Who Description -------- --- -------------------------------------------------- 20031014 plh Initial implementation Problems to fix: To Do: Issues: """