
#-------------------------------------------------
# help
#-------------------------------------------------

"""
***************************
``utopya_runscript`` module
***************************

The ``utopya_runscript`` module provides access to UTOPyA's run script classes.
Note that all entities could be imported directly from the main ``utopya`` module too.

Two classes are provided:
  
* The :py:class:`UtopyaRunScript` class could be used for a standard script without 
  specific arguments.
* The :py:class:`UtopyaRunScriptRc` class requires the name of an rcfile with settings
  as command line argument, and settings could be read directly from this class.

Class hierarchy
===============

The classes are defined according to following hierarchy:

* :py:class:`.UtopyaBase`

  * :py:class:`.UtopyaRunScript`

* :py:class:`.UtopyaRc`

  * :py:class:`.UtopyaRunScriptRc`

Classes
=======

"""

#-------------------------------------------------
# modules
#-------------------------------------------------

# modules:
import logging

# tools:
from utopya_base import UtopyaBase
from utopya_rc   import UtopyaRc


#-------------------------------------------------
# Runscript
#-------------------------------------------------

class UtopyaRunScript( UtopyaBase ) :

    """
    Base class for script object, to be used in user defined scripts 
    to quickly perform some common tasks:
    
    * setup logging to put out informative messages;
    * define some default arguments;
    * parse the arguments.
    
    Example script::
        
        #! /usr/bin/env python
    
        # modules:
        import logging
        
        # tools:
        import utopya
        
        # setup logging:
        logging.basicConfig( stream=sys.stdout, level=logging.INFO,
                               format='[%(levelname)-8s] %(message)s' )

        # init script:
        utos = utopya.UtopyaRunScript()

        # setup default command line arguments:
        utos.ArgumentsSetup( description='UTOPyA test script' )

        # evaluate known arguments, store the other ;
        # might show help text and exit:
        args,xargs = utos.ArgumentsParse()

        # do something:
        logging.info( 'boe!')
    
    """
    
    def __init__( self ) :
    
        """
        Performs the initialization of the ancestor class,
        in this mainly the setup of the logging system.
        """
        
        # setup base class:
        UtopyaBase.__init__( self )
        
    #enddef __init__
        
    # *
    
    def ArgumentsSetup( self, description=None ) :
    
        """
        Defines data object 'parser' of class :py:class:`argparse.ArgumentParser` .
        The parser is populated with default arguments for:
          
        * verbose option to shout not only info but also debug messages.
        
        """
        
        # modules:
        import argparse
        
        #: setup argument parser:
        self.parser = argparse.ArgumentParser( description=description )
        
        # messages:
        self.parser.add_argument( '-v', '--verbose', help='Show debug messages.', 
                                   action='store_true', dest='verbose' )
        
    #enddef ArgumentsSetup
    
    # *
    
    def ArgumentsAdd( self, *args, **kwargs ) :

        """
        Add a new command line argument.
        
        The arguments provided to this routine are passed directly
        to the :py:meth:`argparse.ArgumentParser.add_argument` routine of the 'parser' 
        object that was defined by the 'SetupArguments' routine.
        See the documentation of this underlying  method for useful arguments.
        
        Examples::
        
            # argument with value:
            ArgumentsAdd( '-n', '--name', help='name used for something',
                                   action='store', dest='name' )
            # flag:
            ArgumentsAdd( '-f', '--flag', help='enable something', 
                                   action='store_true', dest='flag' )

        After the call to :meth:`ArgumentsParse`, the arguments are available through::
        
            # parse arguments, return known and extra:
            args,xargs = ArgumentsParse()
            # show:
            print( 'name = ', args.name )
            print( 'flag = ', args.flag )
        
        """
        
        # pass settings:
        self.parser.add_argument( *args, **kwargs )
        
    #enddef ArgumentsAdd
    
    # *
    
    def ArgumentsParse( self ) :
    
        """
        Parse known arguments.
        
        The optional verbose setting is evaluated, and if necessary, the logging level is changed.
        
        In case the arguments included the '-h' or '--help' flag,
        an automatically created help tekst is displayed and the program is terminated.
        Otherwise, the method returns with the following arguments:
            
        * args    : namespace with defined arguments and values
        * xargs   : extra arguments
        """

        # evaluate known arguments, store the other:
        args,xargs = self.parser.parse_known_args()
        
        # Explict request for debugging info ?
        # Note there is no way to reset the logging ...
        if args.verbose : logging.setLevel( level=logging.DEBUG )

        # ok
        return args,xargs
        
    #enddef ArgumentsParse
        
#endclass UtopyaRunScript
        

#-------------------------------------------------
# Runscript with rcfile settings
#-------------------------------------------------

class UtopyaRunScriptRc( UtopyaRc ) :

    """
    Base class for script object, to be used in user defined scripts 
    that need a rcfile argument. 
    The following tasks are performed by the class:
    
    * setup logging to put out informative messages;
    * define default arguments including rcfile name;
    * parse the arguments, and read the settings from the rcfile.
    
    Example script::
        
        #! /usr/bin/env python
    
        # modules:
        import logging
        
        # tools:
        import utopya
        
        # init script, pass default rcfile settings:
        utos = utopya.UtopyaRunScriptRc()

        # setup default command line arguments:
        utos.ArgumentsSetup( description='UTOPyA test script',
                              rcfile='test.rc', rcbase='appl' )

        # evaluate known arguments, store the other ;
        # might show help text and exit:
        args,xargs = utos.ArgumentsParse()

        # do something:
        logging.info( 'boe!')
    
    """
    
    def __init__( self ) :
    
        """
        Performs the initialization of the ancestor class,
        in this mainly the setup of the logging system.
        """
        
        # setup base class, currently without rcfile settings,
        # these will be added after parsing command line arguments:
        UtopyaRc.__init__( self )
        
    #enddef __init__
        
    # *
    
    def ArgumentsSetup( self, description=None, rcbase='' ) :
    
        """
        Defines data object 'parser' of class :py:class:`argparse.ArgumentParser` .
        The parser is populated with arguments for:
          
        * verbose option to shout not only info but also debug messages;            
        * name of the rcfile with settings;
        * base key for relevant rcfile settings (default to optional argument 'rcbase').
        """
        
        # modules:
        import argparse
        
        # setup argument parser:
        self.parser = argparse.ArgumentParser( description=description )
        
        # settings file:
        self.parser.add_argument( 'rcfile', help='Settings file.' )
        # messages:
        self.parser.add_argument( '-v', '--verbose', help='Show debug messages.', 
                                   action='store_true', dest='verbose' )

        # prefix of settings:
        self.parser.add_argument( '-r', '--rcbase', help='Base of rcfile keys (default "%s")' % rcbase,
                                   action='store', dest='rcbase', default=rcbase )

        # single job only?
        self.parser.add_argument( '-s', '--single', help='Single job step only.',
                                   action='store_true', dest='single', default=False )
        
    #enddef ArgumentsSetup
    
    # *
    
    def ArgumentsAdd( self, *args, **kwargs ) :

        """
        Add a new command line argument.
        
        The arguments provided to this routine are passed directly
        to the :py:meth:`argparse.ArgumentParser.add_argument` routine of the 'parser' 
        object that was defined by the 'SetupArguments' routine.
        See the documentation of this underlying  method for useful arguments.
        
        Examples::
        
            # argument with value:
            ArgumentsAdd( '-n', '--name', help='name used for something',
                                   action='store', dest='name' )
            # flag:
            ArgumentsAdd( '-f', '--flag', help='enable something', 
                                   action='store_true', dest='flag' )
        
        After the call to :meth:`ArgumentsParse`, the arguments are available through::
        
            # parse arguments, return known and extra:
            args,xargs = ArgumentsParse()
            # show:
            print( 'name = ', args.name )
            print( 'flag = ', args.flag )
        
        """
        
        # pass settings:
        self.parser.add_argument( *args, **kwargs )
        
    #enddef ArgumentsAdd
        
    # *
    
    def ArgumentsParse( self, env={} ) :
    
        """
        Parse known command line arguments.
        
        In case the arguments included the '-h' or '--help' flag,
        an automatically created help tekst is displayed and the program is terminated.
        Otherwise, the method returns with the following arguments:
            
        * args    : namespace with defined arguments and values
        * xargs   : extra arguments
        
        The 'rcfile' and 'rcbase' passed as command line arguments,
        and eventually the optional 'env' dictionairy passed to this method,
        are used to initalize the :py:class:`.RcFile` base class.
        The following optional settings are read from the 'rcfile' immediately
        to setup the logging:
          
            <rcbase>.logging.format           :  [%(levelname)-8s] %(message)s
            <rcbase>.logging.level            :  info
        
        Note that instead of an 'rcbase' the settings could also start with an asterix '*'.
        The logging level is changed to 'debug' if case the 'verbose' flag is enabled
        in the arguments passed to the script.
        """
        
        # modules:
        import sys
        import logging
        
        # evaluate known arguments, store the other:
        args,xargs = self.parser.parse_known_args()
        
        # init rcfile settings:
        self.InitRc( args.rcfile, rcbase=args.rcbase, env=env )
        
        # optional logging format:
        format = self.GetSetting( 'logging.format', default='None' )
        if format == 'None' : format = None
        
        # optional logging level, default is INFO:
        level  = self.GetSetting( 'logging.level', default='info' )
        # module has level numbers as upper case attributes:
        if hasattr(logging,level.upper()) :
            level = getattr(logging,level.upper())
        else :
            print( 'ERROR - unsupported logging level "%s"' % level )
            raise Exception
        #endif
        # Explict request for debugging info ?
        # Note there is no way to reset the logging ...
        if args.verbose : level = logging.DEBUG
        
        # setup logging:
        logging.basicConfig( stream=sys.stdout, level=level, format=format )

        # ok
        return args,xargs
        
    #enddef ArgumentsParse
        
#endclass UtopyaRunScriptRc


#-------------------------------------------------
# end
#-------------------------------------------------

