#!/usr/bin/env python
# Consider this template file public domain.  The __license__ is just an example.
# Replace values as needed

# subversion commands:
# svn propset svn:keywords 'Revision Date' template.py
# svn propset svn:executable ON template.py

__author__    = 'Kurt Schwehr'
__version__   = '$Revision: 4799 $'.split()[1]
__revision__  = __version__ # For pylint
__date__ = '$Date: 2006-09-25 11:09:02 -0400 (Mon, 25 Sep 2006) $'.split()[1]
__copyright__ = '2008'
__license__   = 'GPL v3'
__contact__   = 'kurt at ccom.unh.edu'
__deprecated__ = 'what goes here?'

__doc__ ='''
Example python file that is all tricked out.  Designed for epydoc,
unittest and doctest.  Please keep updating to make this the best
possible template file.

Decimate these requirements to meet what you need

@requires: U{Python<http://python.org/>} >= 2.5
@requires: U{epydoc<http://epydoc.sourceforge.net/>} >= 3.0.1
@requires: U{psycopg2<http://initd.org/projects/psycopg2/>} >= 2.0.6

@undocumented: __doc__
@since: 2008-Feb-09
@status: under development
@organization: U{CCOM<http://ccom.unh.edu/>} 

@bug: epydoc --check complains about unittest additions
@bug: Bug two
@todo: logging, fuzzing, etc
@todo: To make your code executable after check-in (to allow for doc and unittest), do svn propset svn:executable ON yourfile.py
@todo: "svn propedit svn:keywords yourfile.py", then put in "Date Revision"
@todo: What to make of "pylint --with-line-length=150" ... does this really lead to better code?
@todo: Run pychecker on your files.
@todo: decorators

@see: U{python idioms<http://jaynes.colorado.edu/PythonIdioms.html>} - Read this before modifying any code here.
@see: U{Python Tips, Tricks, and Hacks<http://www.siafoo.net/article/52}
@see: U{Sean Gillies How to lay out Python project code http://sgillies.net/blog/845/how-to-lay-out-python-project-code/}
'''

# Optional...
# @author: U{'''+__author__+'''<http://vislab-ccom.unh.edu/>} FIX: replace with your name/url


import sys
import os

import time
import datetime

import exceptions # For KeyboardInterupt pychecker complaint
import traceback

######################################################################
class Template:
    '''
    Class documentation goes here.

    >>> print 'This is a doctest'
    This is a doctest
    '''
    def __init__(self, some_arg=None):
        '''
        Initialize the class.  Add some detail here.

        @param some_arg: example argument
        '''
        self.some_arg = some_arg

    def a_method(self, another_arg):
        '''
        This is a really dumb method that prints its arg.

        This is the detailed description of aMethod that tells you it
        is a really moronic method.  It does howver show how to
        document a class method.

        And a doctest on how to use this exciting method

        >>> Template().a_method('hello world')
        hello world

        @param another_arg: what to print
        @return: prints the arg to stdout.
        '''
        print another_arg, self.some_arg

    def a_do_nothing_method(self):
        '''
        How to write a stub that does not do anything
        '''
        pass

######################################################################
# UNIT TESTING
######################################################################
import unittest

class TestTemplate(unittest.TestCase):
    '''Unit testing of the Template class.  
    Make lots of testFoo methods to exercise the class.
    '''
    def test_something(self):
        '''Can have many test methods like this.  The name must start with test.
        '''
        template = Template()
        template.a_do_nothing_method()
        # FIX: assert some stuff about template
        self.failUnless(1 == 1)

######################################################################
def do_doctest(verbose=False):
    '''
    @return: success
    @rtype: bool
    '''
    success = True

    print os.path.basename(sys.argv[0]), 'doctests ...',
    argv_orig = sys.argv
    sys.argv = [sys.argv[0]]
    if verbose:
        sys.argv.append('-v')
    import doctest
    numfail, numtests = doctest.testmod()
    if numfail == 0:
        print 'ok  numtests:', numtests
    else: 
        print 'FAILED', numfail, 'tests out of', numtests
        success = False
    sys.argv = argv_orig # Restore the original args
    return success

def main():
    '''
    FIX: document main
    '''
    from optparse import OptionParser
    parser = OptionParser(usage="%prog [options]",
                          version="%prog "+__version__+' ('+__date__+')')
    parser.add_option('--doc-test', dest='doctest', default=False, action='store_true',
                      help='run the documentation tests')
    parser.add_option('--unit-test', dest='unittest', default=False, action='store_true',
                      help='run the unit tests')

    time_fmts = {
        'caris':'%Y/%m/%d %H:%M:%S'
        ,'matlab':'%Y\t%m\t%d\t%H\t%M\t%S\t'
        }

    parser.add_option('-f','--format-time'
                      ,dest='time_format'
                      ,type='choice'
                      ,default='caris'
                      ,choices=time_fmts.keys()
                      ,help= 'One of ' + ', '.join(time_fmts)+ ' [default: %default] ')

    parser.add_option('-v', '--verbose', dest='verbose', default=False, action='store_true',
                      help='run the tests run in verbose mode')

    (options, args) = parser.parse_args()
    v = options.verbose

    timestamp = time.time()
    now = datetime.datetime.utcfromtimestamp(timestamp)
    time_str = now.strftime(time_fmts[options.time_format])
    print timestamp, '->', time_str

    if options.doctest:
        if not do_doctest(options.verbose):
            sys.exit('Something Failed')

    if options.unittest:
        sys.argv = [sys.argv[0]] # Must drop all arguments
        if options.verbose:
            sys.argv.append('-v')
        unittest.main()
        # Never reaches here

    for item in args:
        print 'arg item', item

    # For multithreaded apps that need to cleanup...
    running = True
    i = 0
    timeout = .1
    print 'Press Ctrl-C to quit loop'
    try:
        while running:
            i+=1
            time.sleep(timeout*5)
            if v: sys.stderr.write('ping '+str(i)+'\n')
    except exceptions.KeyboardInterrupt:
        running=False
        if v: sys.stderr.write('\bshutting down...\n')

    return

######################################################################
# Code that runs when this is this file is executed directly
######################################################################
if __name__ == '__main__':
    main()


######################################################################
# Misc
######################################################################

#############
# Warnings
#############

# http://blog.doughellmann.com/2008/06/pymotw-warnings.html

import warnings
import logging

logging.basicConfig(level=logging.INFO)

def send_warnings_to_log(message, category, filename, lineno, file=None):
    logging.warning(
        '%s:%s: %s:%s' % 
        (filename, lineno, category.__name__, message))
    return

old_showwarning = warnings.showwarning
warnings.showwarning = send_warnings_to_log

warnings.warn('This is a warning message')


#############
# Exceptions 
#############

class MyError(Exception):
    def __init__(self,foo,bar):
        self.foo = foo
        self.bar = bar
    def __str__(self):
        return repr(self.foo)+' '+repr(self.bar)

try:
    raise MyError('a','b')
except Exception, e:
    logging.exception("Some exception.  %s " % str(e))
    sys.stderr.write('    Exception:' + str(type(Exception))+'\n')
    sys.stderr.write('    Exception args:'+ str(e)+'\n')
    traceback.print_exc(file=sys.stderr)

import os.path
PROJECT_DIR = os.path.dirname(__file__)

def checkpoint():
    import inspect
    f = inspect.currentframe().f_back
    print '%s:%d: Function %s CHECKPOINT' % (__file__,f.f_lineno,f.f_code.co_name)

checkpoint()

