Difference between revisions of "Implementing a Standard Library"

From PeformIQ Upgrade
Jump to navigation Jump to search
 
(7 intermediate revisions by the same user not shown)
Line 12: Line 12:


./performiq:
./performiq:
total 7
total 15
-rw-r--r-- 1 pharding Users  108 Feb 20 11:06 __init__.py
-rw-r--r-- 1 pharding Users  177 Feb 20 12:26 __init__.py
-rw-r--r-- 1 pharding Users  23 Feb 20 10:52 CONSTANTS.py
-rw-r--r-- 1 pharding Users  23 Feb 20 10:52 CONSTANTS.py
-rw-r--r-- 1 pharding Users 1248 Feb 20 12:44 CSV_Reader.py
-rw-r--r-- 1 pharding Users  361 Feb 20 10:55 Enum.py
-rw-r--r-- 1 pharding Users  361 Feb 20 10:55 Enum.py
-rw-r--r-- 1 pharding Users 2121 Feb 20 11:32 Logger.py
-rw-r--r-- 1 pharding Users 2121 Feb 20 11:32 Logger.py
-rw-r--r-- 1 pharding Users 2121 Feb 20 11:32 Timer.py
-rw-r--r-- 1 pharding Users 1077 Feb 20 12:08 Timer.py
</pre>
</pre>


Line 33: Line 34:
import CONSTANTS
import CONSTANTS


from CONSTANTS import VERSION
 
from Enum     import Enum
from CONSTANTS   import VERSION
from Logger   import Logger
from Enum       import Enum
from Timer     import Timer
from Logger     import Logger
from Timer       import Timer
from CSV_Reader  import CSV_Reader
</pre>
</pre>


Line 75: Line 78:
import sys
import sys
import logging
import logging
from datetime import datetime
#==========================================================================
class MyFormatter(logging.Formatter):
    converter = datetime.fromtimestamp
    def formatTime(self, record, datefmt=None):
        ct = self.converter(record.created)
        if datefmt:
            s = ct.strftime(datefmt)[:23]
        else:
            t = ct.strftime("%Y-%m-%d %H:%M:%S")
            s = "%s.%03d" % (t, record.msecs)
        return s


#==========================================================================
#==========================================================================
Line 81: Line 100:
     logger = None
     logger = None
     debug  = False
     debug  = False
    #----------------------------------------------------------------------


     @classmethod
     @classmethod
Line 134: Line 155:
             cls.logger  = logging.getLogger(name)
             cls.logger  = logging.getLogger(name)
             cls.hdlr    = logging.FileHandler(cls.log_file)
             cls.hdlr    = logging.FileHandler(cls.log_file)
             cls.fmtr    = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
             cls.fmtr    = MyFormatter('%(asctime)s %(levelname)s %(message)s', datefmt='%Y-%m-%d,%H:%M:%S.%f')


             cls.hdlr.setFormatter(cls.fmtr)
             cls.hdlr.setFormatter(cls.fmtr)
Line 148: Line 169:


#==========================================================================
#==========================================================================
</pre>
</pre>


Line 153: Line 175:


<pre>
<pre>
#==========================================================================
class Timer:
class Timer:
     t_reference = None
     t_reference = None
Line 176: Line 196:
       t_now  = datetime.now()
       t_now  = datetime.now()


       if (flg):
       if (init):
           cls.t_reference  = t_now
           cls.t_reference  = t_now
           t            = 0
           t            = 0
Line 188: Line 208:


#==========================================================================
#==========================================================================
</pre>
=CSV_Reader.py=
Just so that I can leave it around...
<pre>
$ cat CSV_Reader.py
import csv
import sys
#=========================================================================
class CSV_Reader:
    #---------------------------------------------------------------------
    @classmethod
    def read(cls, fname, skip=0, obj=None, limit=0):
        csv_data  = []
        try:
            f_in      = open(fname, "rb")
        except IOError, msg:
            sys.stderr.write(cls.log_file + ': cannot open: ' + `msg` + '\n')
            sys.exit(1)
        reader = csv.reader(f_in)
        cnt  = 0
        for row in reader:
          cnt += 1
          if skip > 0:
              skip -= 1
              continue  # Skip headings
          if obj:
              data = obj(row)
          else:
              data = row
          # print data
          csv_data.append(data)
          if limit and (cnt < limit): continue
        f_in.close()  # Explicitly close the file *NOW*
        no_lines  = len(csv_data)
        print "Read %d data items..." % no_lines
        print "                -> Total data  %d" % cnt
        return csv_data
    #---------------------------------------------------------------------
#=========================================================================
</pre>
</pre>


Line 206: Line 288:
debug_level  = 0
debug_level  = 0
verbose_flg  = True
verbose_flg  = True
#==========================================================================
class Data:
    #--------------------------------------------------------------------
    def __init__(self, row):
        self.One = row[0]
        self.Two = row[1]
        self.Three = row[2]
        self.Four = row[3]
    #--------------------------------------------------------------------
    def __str__(self):
        return "%s,%s,%s,%s" % (self.One, self.Two, self.Three, self.Four)
    #--------------------------------------------------------------------
#==========================================================================




Line 219: Line 322:
Logger.Error("Testing - Error...")
Logger.Error("Testing - Error...")


time.sleep(3)
time.sleep(1.4)


print "Get timer - %5.3f" % performiq.Timer.time()
print "Get timer - %5.3f" % performiq.Timer.time()


csv_data = """\
a,b,c,d
e,f,g,h
i,j,k,l
"""
csv_file = 'tst.csv'
f_out = open(csv_file, 'w+')
f_out.write(csv_data)
f_out.close()
data = performiq.CSV_Reader.read(csv_file, obj=Data)
if data:
    for d in data:
        print d
</pre>
</pre>


Line 236: Line 357:
[logger::ERROR]  Testing - Error...
[logger::ERROR]  Testing - Error...
Get timer - 3.001
Get timer - 3.001
Read 3 data items...
                -> Total data  3
a,b,c,d
e,f,g,h
i,j,k,l
</pre>
</pre>


Line 243: Line 369:


<pre>
<pre>
$ cat skel.py
#!/usr/bin/env python
#
#      Author:  Peter Harding  <plh@performiq.com.au>
#
#                PerformIQ Pty. Ltd.
#                Suite 230,
#                Level 2,
#                1 Queens Road,
#                MELBOURNE, VIC, 3004
#
#                Mobile:  0418 375 085
#
#          @(#) [2.3.01] skel.py 2013-02-20
#
#
# NAME
#  skel.py - Skeleton python script
#
# SYNOPSIS
#  skel.py [-dv]
#
# PARAMETERS
#  See __doc__ below
#
# DESCRIPTION
#  ...
#
# RETURNS
#  0 for successful completion, 1 for any error
#
# FILES
#  ...
#
#--------------------------------------------------------------------------
"""
Usage:
  $ skel.py [-dv] -apn 10y
  $ skel.py [-dv] -o            # ...
Parameters:
  -a              ...
  -p              ...
  -n 10          No of ...
  -o              ...
  -d              Debug
  -v              Verbose
"""
#--------------------------------------------------------------------------
import os
import re
import sys
import time
import getopt
import random
import pickle
import pprint
import logging
import urllib
from datetime import datetime
from performiq import Enum, Logger
#--------------------------------------------------------------------------
__version__  = "2.3.01"
__at_id__    = "@(#)  skel.py  [%s]  2013-02-20" % __version__
verbose_flg  = False
debug_level  = 0
table_name    = "people"
DSERVER_PORT  = 9570
MAX_REQUESTS  = 200
lf            = None
log          = None
LOG_DIR      = "/tmp"
home_dir      = None
p_crlf        = re.compile(r'[\r\n]*')
pp            = pprint.PrettyPrinter(indent=3)
#==========================================================================
class Data:
  TotalCount = 0
  #--------------------------------------------------------------------
  @classmethod
  def count_row(cls):
      cls.TotalCount += 1
  #--------------------------------------------------------------------
  def __init__(self, row):
      Data.count_row()
      cols = row.split(',')
      self.One = cols[0]
      self.Two = cols[1]
#==========================================================================
# And here is the real work...
def do_work(fname):
  Logger.Info("[do_work]")
  fname_in  = "%s.log" % fname
  fname_out = "%s.dat" % fname
  try:
      f_in = open(fname_in, 'r')
  except IOError, msg:
      sys.stderr.write(fname_in + ': cannot open: ' + `msg` + '\n')
      sys.exit(1)
  try:
      f_out = open(fname_out, 'a+')
  except IOError, msg:
      sys.stderr.write(fname_out + ': cannot open: ' + `msg` + '\n')
      sys.exit(1)
  while True:
      line = f_in.readline()
      if not line: break
      #  Truncate EoL markers from end of line
      line = p_crlf.sub('', line)  # or 'line = line[:-1]'
      data = Data(line)
      f_out.write("[%s]\n" % (line, ))
  f_in.close()
  f_out.close()
#=========================================================================
def usage():
  print __doc__
#-------------------------------------------------------------------------
def main(argv):
  global verbose_flg
  global debug_level
  global target
  global home_dir
  try:
      home_dir = os.environ['HOME']
  except:
      print "Set HOME environment variable and re-run"
      sys.exit(0)
  Modes    = Enum(["Info", "Parse", ])
  mode    = Modes.Info
  filename = "test"
  try:
      opts, args = getopt.getopt(argv, "dD:f:hvV?",
              ("debug", "debug-level=", "file=", "help", "verbose", "version"))
  except getopt.error, msg:
      usage()
      return 1
  for opt, arg in opts:
      if opt in ("-?", "-h", "--help"):
        usage()
        return 0
      elif opt in ('-d', '--debug'):
        debug_level    += 1
      elif opt in ('-D', '--debug-level'):
        debug_level    = int(arg)
      elif opt in ('-f', '--file'):
        mode = Modes.Parse
        filename        = arg
      elif opt in ('-v', '--verbose'):
        verbose_flg    = True
      elif opt in ('-v', '--version'):
        print "[skel]  Version: %s" % __version__
        return 1
      else:
        usage()
        return 1
  sys.stderr.write("[skel]  Working directory is %s\n" % os.getcwd())
  if (debug_level > 0): sys.stderr.write("[skel]  Debugging level set to %d\n" % debug_level)
  sys.stderr.flush()
  Logger.Init(name='skel')
  if mode == Modes.Info:
      Logger.Info('Info')
  elif mode == Modes.Parse:
      Logger.Info('Parsing')
      do_work(filename)
  else:
      Logger.Info('Nothing to do')
  return 0
#--------------------------------------------------------------------------
if __name__ == '__main__' or __name__ == sys.argv[0]:
  try:
      sys.exit(main(sys.argv[1:]))
  except KeyboardInterrupt, e:
      print "[skel]  Interrupted!"
#--------------------------------------------------------------------------
"""
Revision History:
    Date    Who  Description
  --------  ---  ------------------------------------------------------------
  20031014  plh  Initial implementation
  20111101  plh  Add in Enums for modal behaviour
  20130220  plh  Reconstructed performiq module
Problems to fix:
To Do:
Issues:




"""
</pre>
</pre>

Latest revision as of 09:27, 13 March 2013

Components

I use the following for building up utility scripts.

$ ls -lR ~/lib/py

/home/pharding/lib/py:
total 4
drwxr-xr-x+ 1 pharding Users 0 Feb 20 11:44 performiq

./performiq:
total 15
-rw-r--r-- 1 pharding Users  177 Feb 20 12:26 __init__.py
-rw-r--r-- 1 pharding Users   23 Feb 20 10:52 CONSTANTS.py
-rw-r--r-- 1 pharding Users 1248 Feb 20 12:44 CSV_Reader.py
-rw-r--r-- 1 pharding Users  361 Feb 20 10:55 Enum.py
-rw-r--r-- 1 pharding Users 2121 Feb 20 11:32 Logger.py
-rw-r--r-- 1 pharding Users 1077 Feb 20 12:08 Timer.py
env | grep PYTHONPATH

PYTHONPATH=/home/pharding/lib/py

__init__.py

$ cat __init__.py

import CONSTANTS


from CONSTANTS   import VERSION
from Enum        import Enum
from Logger      import Logger
from Timer       import Timer
from CSV_Reader  import CSV_Reader

CONSTANTS.py

$ cat CONSTANTS.py

VERSION   = "1.0.0"

Enum.py

$ cat Enum.py

#==========================================================================

class Enum(set):
   pass

   #--------------------------------------------------------------------

   def __getattr__(self, name):
      if name in self:
         return name
      raise AttributeError

#==========================================================================

Logger.py

$ cat Logger.py

import os
import sys
import logging

from datetime import datetime

#==========================================================================

class MyFormatter(logging.Formatter):
    converter = datetime.fromtimestamp

    def formatTime(self, record, datefmt=None):
        ct = self.converter(record.created)
        if datefmt:
            s = ct.strftime(datefmt)[:23]
        else:
            t = ct.strftime("%Y-%m-%d %H:%M:%S")
            s = "%s.%03d" % (t, record.msecs)
        return s

#==========================================================================

class Logger:
    logger = None
    debug  = False

    #----------------------------------------------------------------------

    @classmethod
    def Info(cls, msg):
        global debug_level, verbose_flg

        if not cls.logger:
            cls.Init()

        cls.logger.info(' ' + msg)

        if cls.debug: sys.stderr.write("[%s::INFO]  %s\n" % (cls.name, msg))

    #----------------------------------------------------------------------

    @classmethod
    def Error(cls, msg):
        global debug_level, verbose_flg

        if not cls.logger:
            cls.Init()

        cls.logger.error(msg)

        if cls.debug: sys.stderr.write("[%s::ERROR]  %s\n" % (cls.name, msg))

    #----------------------------------------------------------------------

    @classmethod
    def Warning(cls, msg):
        global debug_level, verbose_flg

        if not cls.logger:
            cls.Init()

        cls.logger.warning('*****' + msg + '*****')

        if cls.debug: sys.stderr.write("[%s::WARNING]  %s\n" % (cls.name, msg))

    #----------------------------------------------------------------------

    @classmethod
    def Init(cls, name='logger', log_dir='/c/temp', debug=False):
        cls.debug = debug
        cls.name  = name
        cls.pid   = os.getpid()

        if cls.debug: sys.stderr.write("[%s::Init] PID is %d\n" % (cls.name, cls.pid))

        cls.log_file = '%s/%s.log' % (log_dir, name)

        try:
            cls.logger  = logging.getLogger(name)
            cls.hdlr    = logging.FileHandler(cls.log_file)
            cls.fmtr    = MyFormatter('%(asctime)s %(levelname)s %(message)s', datefmt='%Y-%m-%d,%H:%M:%S.%f')

            cls.hdlr.setFormatter(cls.fmtr)
            cls.logger.addHandler(cls.hdlr)
            cls.logger.setLevel(logging.INFO)

            cls.logger.info("===== Started processing %s" % ('=' * 20))
 
            cls.count = 0
        except IOError, msg:
            sys.stderr.write(cls.log_file + ': cannot open: ' + `msg` + '\n')
            sys.exit(1)

#==========================================================================

Timer.py

class Timer:
    t_reference = None

    #----------------------------------------------------------------------

    @classmethod
    def init(cls):
       return float(cls.get_reference_time(init=True)) * 0.001

    #----------------------------------------------------------------------

    @classmethod
    def time(cls):
       return float(cls.get_reference_time()) * 0.001

    #----------------------------------------------------------------------

    @classmethod
    def get_reference_time(cls, init=False):
       t_now  = datetime.now()

       if (init):
          cls.t_reference   = t_now
          t             = 0
       else:
          t_delta       = t_now - cls.t_reference
          t             = ((t_delta.seconds * 1000000) + t_delta.microseconds)/1000.0

       return t

    #----------------------------------------------------------------------

#==========================================================================

CSV_Reader.py

Just so that I can leave it around...

$ cat CSV_Reader.py

import csv
import sys

#=========================================================================

class CSV_Reader:

    #---------------------------------------------------------------------

    @classmethod
    def read(cls, fname, skip=0, obj=None, limit=0):
        csv_data  = []

        try:
            f_in      = open(fname, "rb")
        except IOError, msg:
            sys.stderr.write(cls.log_file + ': cannot open: ' + `msg` + '\n')
            sys.exit(1)

        reader = csv.reader(f_in)

        cnt   = 0

        for row in reader:
           cnt += 1

           if skip > 0:
               skip -= 1
               continue   # Skip headings

           if obj:
               data = obj(row)
           else:
               data = row

           # print data

           csv_data.append(data)

           if limit and (cnt < limit): continue

        f_in.close()  # Explicitly close the file *NOW*

        no_lines  = len(csv_data)

        print "Read %d data items..." % no_lines
        print "                 -> Total data  %d" % cnt

        return csv_data

    #---------------------------------------------------------------------

#=========================================================================

A Test Harness

Use this to test the performiq module...

$ cat tst_module.py 
#!/usr/bin/env python

import time

import performiq

from performiq import Logger

debug_level  = 0
verbose_flg  = True

#==========================================================================

class Data:

    #--------------------------------------------------------------------

    def __init__(self, row):
        self.One = row[0]
        self.Two = row[1]
        self.Three = row[2]
        self.Four = row[3]

    #--------------------------------------------------------------------

    def __str__(self):
        return "%s,%s,%s,%s" % (self.One, self.Two, self.Three, self.Four)

    #--------------------------------------------------------------------

#==========================================================================


print "performiq version [%s]" % performiq.VERSION


print "Set timer - %5.3f" % performiq.Timer.init()

Logger.Init(debug=True)

Logger.Info("Testing - Info...")
Logger.Warning("Testing - Warning...")
Logger.Error("Testing - Error...")

time.sleep(1.4)

print "Get timer - %5.3f" % performiq.Timer.time()

csv_data = """\
a,b,c,d
e,f,g,h
i,j,k,l
"""

csv_file = 'tst.csv'

f_out = open(csv_file, 'w+')

f_out.write(csv_data)
f_out.close()

data = performiq.CSV_Reader.read(csv_file, obj=Data)

if data:
    for d in data:
        print d

Running it:

$ ./tst_module.py 
performiq version [1.0.0]
Set timer - 0.000
[logger::Init] PID is 8404
[logger::INFO]  Testing - Info...
[logger::WARNING]  Testing - Warning...
[logger::ERROR]  Testing - Error...
Get timer - 3.001
Read 3 data items...
                 -> Total data  3
a,b,c,d
e,f,g,h
i,j,k,l

A Variant skel.py

This variant of my skel.py script uses the module.

$ cat skel.py 
#!/usr/bin/env python
#
#       Author:  Peter Harding  <plh@performiq.com.au>
#
#                PerformIQ Pty. Ltd.
#                Suite 230,
#                Level 2,
#                1 Queens Road,
#                MELBOURNE, VIC, 3004
#
#                Mobile:  0418 375 085
#
#           @(#) [2.3.01] skel.py 2013-02-20
#
#
# NAME
#   skel.py - Skeleton python script
#
# SYNOPSIS
#   skel.py [-dv]
#
# PARAMETERS
#   See __doc__ below
#
# DESCRIPTION
#   ...
#
# RETURNS
#   0 for successful completion, 1 for any error
#
# FILES
#   ...
#
#--------------------------------------------------------------------------
"""
Usage:

   $ skel.py [-dv] -apn 10y

   $ skel.py [-dv] -o             # ...

Parameters:

   -a              ...
   -p              ...
   -n 10           No of ...
   -o              ...
   -d              Debug
   -v              Verbose

"""
#--------------------------------------------------------------------------

import os
import re
import sys
import time
import getopt
import random
import pickle
import pprint
import logging
import urllib

from datetime import datetime

from performiq import Enum, Logger

#--------------------------------------------------------------------------

__version__   = "2.3.01"
__at_id__     = "@(#)  skel.py  [%s]  2013-02-20" % __version__

verbose_flg   = False

debug_level   = 0

table_name    = "people"
DSERVER_PORT  = 9570
MAX_REQUESTS  = 200

lf            = None
log           = None

LOG_DIR       = "/tmp"
home_dir      = None

p_crlf        = re.compile(r'[\r\n]*')

pp            = pprint.PrettyPrinter(indent=3)

#==========================================================================

class Data:
   TotalCount = 0

   #--------------------------------------------------------------------

   @classmethod
   def count_row(cls):
      cls.TotalCount += 1

   #--------------------------------------------------------------------

   def __init__(self, row):
      Data.count_row()
      cols = row.split(',')
      self.One = cols[0]
      self.Two = cols[1]

#==========================================================================
# And here is the real work...

def do_work(fname):
   Logger.Info("[do_work]")

   fname_in  = "%s.log" % fname
   fname_out = "%s.dat" % fname

   try:
      f_in = open(fname_in, 'r')
   except IOError, msg:
      sys.stderr.write(fname_in + ': cannot open: ' + `msg` + '\n')
      sys.exit(1)

   try:
      f_out = open(fname_out, 'a+')
   except IOError, msg:
      sys.stderr.write(fname_out + ': cannot open: ' + `msg` + '\n')
      sys.exit(1)

   while True:
      line = f_in.readline()

      if not line: break

      #  Truncate EoL markers from end of line

      line = p_crlf.sub('', line)  # or 'line = line[:-1]'

      data = Data(line)

      f_out.write("[%s]\n" % (line, ))

   f_in.close()
   f_out.close()

#=========================================================================

def usage():
   print __doc__

#-------------------------------------------------------------------------

def main(argv):
   global verbose_flg
   global debug_level
   global target
   global home_dir

   try:
      home_dir = os.environ['HOME']
   except:
      print "Set HOME environment variable and re-run"
      sys.exit(0)

   Modes    = Enum(["Info", "Parse", ])

   mode     = Modes.Info
   filename = "test"

   try:
      opts, args = getopt.getopt(argv, "dD:f:hvV?",
              ("debug", "debug-level=", "file=", "help", "verbose", "version"))
   except getopt.error, msg:
      usage()
      return 1

   for opt, arg in opts:
      if opt in ("-?", "-h", "--help"):
         usage()
         return 0
      elif opt in ('-d', '--debug'):
         debug_level    += 1
      elif opt in ('-D', '--debug-level'):
         debug_level     = int(arg)
      elif opt in ('-f', '--file'):
         mode = Modes.Parse
         filename        = arg
      elif opt in ('-v', '--verbose'):
         verbose_flg     = True
      elif opt in ('-v', '--version'):
         print "[skel]  Version: %s" % __version__
         return 1
      else:
         usage()
         return 1

   sys.stderr.write("[skel]  Working directory is %s\n" % os.getcwd())

   if (debug_level > 0): sys.stderr.write("[skel]  Debugging level set to %d\n" % debug_level)

   sys.stderr.flush()

   Logger.Init(name='skel')

   if mode == Modes.Info:
      Logger.Info('Info')
   elif mode == Modes.Parse:
      Logger.Info('Parsing')
      do_work(filename)
   else:
      Logger.Info('Nothing to do')

   return 0

#--------------------------------------------------------------------------

if __name__ == '__main__' or __name__ == sys.argv[0]:
   try:
      sys.exit(main(sys.argv[1:]))
   except KeyboardInterrupt, e:
      print "[skel]  Interrupted!"

#--------------------------------------------------------------------------

"""
Revision History:

     Date     Who   Description
   --------   ---   ------------------------------------------------------------
   20031014   plh   Initial implementation
   20111101   plh   Add in Enums for modal behaviour
   20130220   plh   Reconstructed performiq module

Problems to fix:

To Do:

Issues:


"""