]> SALOME platform Git repositories - tools/sat.git/commitdiff
Salome HOME
sat --help and logingSat for unittest and begin fix ./test/test_xxx_zzz.py
authorChristian Van Wambeke <chvw@orange.fr>
Sun, 1 Apr 2018 18:25:09 +0000 (20:25 +0200)
committerChristian Van Wambeke <chvw@orange.fr>
Sun, 1 Apr 2018 18:25:09 +0000 (20:25 +0200)
91 files changed:
.gitignore
AllTestLauncherSat.py
commands/config.py
sat
src/__init__.py
src/coloringSat.py
src/configManager.py [new file with mode: 0644]
src/debug.py
src/i18n/fr/LC_MESSAGES/salomeTools.po
src/loggingSat.py
src/options.py
src/salomeTools.py
src/test/APPLI_TEST/APPLI_TEST.pyconf [deleted file]
src/test/APPLI_TEST_Test.py [deleted file]
src/test/README_config_0_3_9.txt [deleted file]
src/test/__init__.py [deleted file]
src/test/config_0_3_9/LICENSE [deleted file]
src/test/config_0_3_9/PKG-INFO [deleted file]
src/test/config_0_3_9/README.txt [deleted file]
src/test/config_0_3_9/__init__.py [deleted file]
src/test/config_0_3_9/config.py [deleted file]
src/test/config_0_3_9/logconfig.cfg [deleted file]
src/test/config_0_3_9/logconfig.py [deleted file]
src/test/config_0_3_9/setup.py [deleted file]
src/test/config_0_3_9/styles.json [deleted file]
src/test/config_0_3_9/test_config.py [deleted file]
src/test/debugTest.py [deleted file]
src/test/pyconfTest.py [deleted file]
src/test/satHelpTest.py [deleted file]
src/test/test_pyconf.py [deleted file]
test/APPLI_TEST/APPLI_TEST.pyconf [new file with mode: 0644]
test/README_config_0_3_9.txt [new file with mode: 0644]
test/__init__.py [changed mode: 0644->0755]
test/compilation/test_compilation.py [deleted file]
test/compilation/test_configure.py [deleted file]
test/compilation/test_make.py [deleted file]
test/compilation/test_makeinstall.py [deleted file]
test/config/test_create_user_pyconf.py [deleted file]
test/config/test_option_copy.py [deleted file]
test/config/test_option_edit.py [deleted file]
test/config/test_option_value.py [deleted file]
test/config/test_option_value_2.py [deleted file]
test/config_0_3_9/LICENSE [new file with mode: 0644]
test/config_0_3_9/PKG-INFO [new file with mode: 0644]
test/config_0_3_9/README.txt [new file with mode: 0644]
test/config_0_3_9/__init__.py [new file with mode: 0644]
test/config_0_3_9/config.py [new file with mode: 0644]
test/config_0_3_9/logconfig.cfg [new file with mode: 0644]
test/config_0_3_9/logconfig.py [new file with mode: 0644]
test/config_0_3_9/setup.py [new file with mode: 0644]
test/config_0_3_9/styles.json [new file with mode: 0644]
test/config_0_3_9/test_config.py [new file with mode: 0644]
test/environ/test_environ.py [deleted file]
test/job/test_job.py [deleted file]
test/jobs/test_jobs.py [deleted file]
test/log/test_launch_browser.py [deleted file]
test/log/test_launch_browser2.py [deleted file]
test/prepare/test_clean.py [deleted file]
test/prepare/test_patch.py [deleted file]
test/prepare/test_prepare.py [deleted file]
test/prepare/test_source.py [deleted file]
test/run_all.sh [deleted file]
test/shell/test_shell.py [deleted file]
test/test/test_command.py [deleted file]
test/test_020_debug.py [new file with mode: 0755]
test/test_025_pyconf.py [new file with mode: 0755]
test/test_030_pyconf_0_3_9.py [new file with mode: 0755]
test/test_100_satHelp.py [new file with mode: 0755]
test/test_500_APPLI_TEST.py [new file with mode: 0755]
test/test_sat5_0/__init__.py [new file with mode: 0644]
test/test_sat5_0/compilation/test_compilation.py [new file with mode: 0755]
test/test_sat5_0/compilation/test_configure.py [new file with mode: 0755]
test/test_sat5_0/compilation/test_make.py [new file with mode: 0755]
test/test_sat5_0/compilation/test_makeinstall.py [new file with mode: 0755]
test/test_sat5_0/config/test_create_user_pyconf.py [new file with mode: 0755]
test/test_sat5_0/config/test_option_copy.py [new file with mode: 0755]
test/test_sat5_0/config/test_option_edit.py [new file with mode: 0755]
test/test_sat5_0/config/test_option_value.py [new file with mode: 0755]
test/test_sat5_0/config/test_option_value_2.py [new file with mode: 0755]
test/test_sat5_0/environ/test_environ.py [new file with mode: 0755]
test/test_sat5_0/job/test_job.py [new file with mode: 0755]
test/test_sat5_0/jobs/test_jobs.py [new file with mode: 0755]
test/test_sat5_0/log/test_launch_browser.py [new file with mode: 0755]
test/test_sat5_0/log/test_launch_browser2.py [new file with mode: 0755]
test/test_sat5_0/prepare/test_clean.py [new file with mode: 0755]
test/test_sat5_0/prepare/test_patch.py [new file with mode: 0755]
test/test_sat5_0/prepare/test_prepare.py [new file with mode: 0755]
test/test_sat5_0/prepare/test_source.py [new file with mode: 0755]
test/test_sat5_0/run_all.sh [new file with mode: 0755]
test/test_sat5_0/shell/test_shell.py [new file with mode: 0755]
test/test_sat5_0/test/test_command.py [new file with mode: 0755]

index 86431c49c75dd6ae97c4f64ffba4c404d95d072d..6bab5df61411b5d782ae9bfffec92659df0799b8 100644 (file)
@@ -13,3 +13,5 @@ test/htmlcov
 test/test_res.html
 doc/src/commands/apidoc*
 .idea
+.spyderproject
+
index 59f4fbda168664280f986233477f38b572badbb2..45f2a59ce8ab451baec7b777c84c4d524e927d5a 100755 (executable)
@@ -2,7 +2,7 @@
 # -*- coding: utf-8 -*-
 
 # %% LICENSE_SALOME_CEA_BEGIN
-# Copyright (C) 2008-2016  CEA/DEN
+# Copyright (C) 2008-2018  CEA/DEN
 # 
 # This library is free software; you can redistribute it and/or
 # modify it under the terms of the GNU Lesser General Public
@@ -69,7 +69,7 @@ verboseImport = True
 satdir  = os.path.dirname(os.path.realpath(__file__))
 
 def errPrint(aStr):
-  """to avoid write in html or xml file log message"""
+  """stderr to avoid write in html or xml file log message"""
   sys.stderr.write(aStr + '\n')
 
 try:
@@ -87,7 +87,7 @@ try:
 except:
   XTST = None
   errPrint("""
-WARNING: no XML output available.
+WARNING: no XML output available for unittest.
          try 'pip install unittest-xml-reporting'.
 """)
 
@@ -180,8 +180,9 @@ def runOnArgs(args):
       if done: 
         del sys.path[0] #attention of sys.path appends
         done = False
-      errPrint("ERROR: AllTestLauncher: import '%s':" % aFile)
-      errPrint("       %s\n" % e)
+      errPrint("""\
+ERROR: AllTestLauncher: import '%s':
+       %s\n""" % (aFile, e))
       continue
 
   listfilesForTest = sorted(filesForTest.keys())
@@ -255,7 +256,7 @@ def runFromEnvVar(envVar, fileTestPattern="*Test.py"):
 
 ###################################################################
 def getParser():
-  parser = AP.ArgumentParser(description='launch All SAT python tests', argument_default=None)
+  parser = AP.ArgumentParser(description='launch All salomeTools python tests', argument_default=None)
 
   parser.add_argument(
     '-d', '--debug', 
@@ -280,7 +281,7 @@ of recursive searching unittest python files
   parser.add_argument(
     '-p', '--pattern', 
     help="file pattern for unittest files ['test_*.py'|'*Test.py'...]",
-    default="test_*.py",
+    default="test_???_*.py", # as alphabetical ordered test site
     metavar='filePattern'
   )
   parser.add_argument(
@@ -302,12 +303,14 @@ If name = 'stdout' then all-in-one xml output at 'sys.stdout'. For pipe redirect
   )
   return parser
 
-#export PATH=/volatile/wambeke/SAT5/SAT5_S840_MATIX24/salomeTools-5-cvw:${PATH}
+#export PATH=satdir:${PATH}
 
 ###################################################################
 if __name__ == '__main__':
   # Make the src & command package accessible from all code
+  # as export PATH=satdir:${PATH}
   sys.path.insert(0, satdir)
+  errPrint("WARNING: export PATH=%s:${PATH}\n" % satdir)
 
   args = getParser().parse_args(sys.argv[1:])
   debug = args.debug
index 515c2a6e1fdb8f30ca3e37cd6fe4530750cfe5f0..07c2cf29d12e170bffac85bfa1686d91d7783344 100644 (file)
 #  License along with this library; if not, write to the Free Software
 #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 
-import os
+"""import os
 import platform
 import datetime
 import shutil
-import sys
+import sys"""
 
 import src
 import src.debug as DBG
+import src.loggingSat as LOG
 import src.returnCode as RCO
 from src.salomeTools import _BaseCommand
+import src.configManager as CFGMGR
 
 
-class ConfigOpener:
-    '''Class that helps to find an application pyconf 
-       in all the possible directories (pathList)
-    '''
-    def __init__(self, pathList):
-        '''Initialization
-        
-        :param pathList list: The list of paths where to search a pyconf.
-        '''
-        self.pathList = pathList
-
-    def __call__(self, name):
-        if os.path.isabs(name):
-            return src.pyconf.ConfigInputStream(open(name, 'rb'))
-        else:
-            return src.pyconf.ConfigInputStream( 
-                        open(os.path.join( self.get_path(name), name ), 'rb') )
-        raise IOError(_("Configuration file '%s' not found") % name)
-
-    def get_path( self, name ):
-        '''The method that returns the entire path of the pyconf searched
-        :param name str: The name of the searched pyconf.
-        '''
-        for path in self.pathList:
-            if os.path.exists(os.path.join(path, name)):
-                return path
-        raise IOError(_("Configuration file '%s' not found") % name)
-
-class ConfigManager:
-    '''Class that manages the read of all the configuration files of salomeTools
-    '''
-    def __init__(self, datadir=None):
-        pass
-
-    def _create_vars(self, application=None, command=None, datadir=None):
-        '''Create a dictionary that stores all information about machine,
-           user, date, repositories, etc...
-        
-        :param application str: The application for which salomeTools is called.
-        :param command str: The command that is called.
-        :param datadir str: The repository that contain external data 
-                            for salomeTools.
-        :return: The dictionary that stores all information.
-        :rtype: dict
-        '''
-        var = {}      
-        var['user'] = src.architecture.get_user()
-        var['salometoolsway'] = os.path.dirname(
-                                    os.path.dirname(os.path.abspath(__file__)))
-        var['srcDir'] = os.path.join(var['salometoolsway'], 'src')
-        var['internal_dir'] = os.path.join(var['srcDir'], 'internal_config')
-        var['sep']= os.path.sep
-        
-        # datadir has a default location
-        var['datadir'] = os.path.join(var['salometoolsway'], 'data')
-        if datadir is not None:
-            var['datadir'] = datadir
-
-        var['personalDir'] = os.path.join(os.path.expanduser('~'),
-                                           '.salomeTools')
-        src.ensure_path_exists(var['personalDir'])
-
-        var['personal_applications_dir'] = os.path.join(var['personalDir'],
-                                                        "Applications")
-        src.ensure_path_exists(var['personal_applications_dir'])
-        
-        var['personal_products_dir'] = os.path.join(var['personalDir'],
-                                                    "products")
-        src.ensure_path_exists(var['personal_products_dir'])
-        
-        var['personal_archives_dir'] = os.path.join(var['personalDir'],
-                                                    "Archives")
-        src.ensure_path_exists(var['personal_archives_dir'])
-
-        var['personal_jobs_dir'] = os.path.join(var['personalDir'],
-                                                "Jobs")
-        src.ensure_path_exists(var['personal_jobs_dir'])
-
-        var['personal_machines_dir'] = os.path.join(var['personalDir'],
-                                                    "Machines")
-        src.ensure_path_exists(var['personal_machines_dir'])
-
-        # read linux distributions dictionary
-        distrib_cfg = src.pyconf.Config(os.path.join(var['srcDir'],
-                                                      'internal_config',
-                                                      'distrib.pyconf'))
-        
-        # set platform parameters
-        dist_name = src.architecture.get_distribution(
-                                            codes=distrib_cfg.DISTRIBUTIONS)
-        dist_version = src.architecture.get_distrib_version(dist_name, 
-                                                    codes=distrib_cfg.VERSIONS)
-        dist = dist_name + dist_version
-        
-        var['dist_name'] = dist_name
-        var['dist_version'] = dist_version
-        var['dist'] = dist
-        var['python'] = src.architecture.get_python_version()
-
-        var['nb_proc'] = src.architecture.get_nb_proc()
-        node_name = platform.node()
-        var['node'] = node_name
-        var['hostname'] = node_name
-
-        # set date parameters
-        dt = datetime.datetime.now()
-        var['date'] = dt.strftime('%Y%m%d')
-        var['datehour'] = dt.strftime('%Y%m%d_%H%M%S')
-        var['hour'] = dt.strftime('%H%M%S')
-
-        var['command'] = str(command)
-        var['application'] = str(application)
-
-        # Root dir for temporary files 
-        var['tmp_root'] = os.sep + 'tmp' + os.sep + var['user']
-        # particular win case 
-        if src.architecture.is_windows() : 
-            var['tmp_root'] =  os.path.expanduser('~') + os.sep + 'tmp'
-        
-        return var
-
-    def get_command_line_overrides(self, options, sections):
-        '''get all the overwrites that are in the command line
-        
-        :param options: the options from salomeTools class 
-                        initialization (like -l5 or --overwrite)
-        :param sections str: The config section to overwrite.
-        :return: The list of all the overwrites to apply.
-        :rtype: list
-        '''
-        # when there are no options or not the overwrite option, 
-        # return an empty list
-        if options is None or options.overwrite is None:
-            return []
-        
-        over = []
-        for section in sections:
-            # only overwrite the sections that correspond to the option 
-            over.extend(filter(lambda l: l.startswith(section + "."), 
-                               options.overwrite))
-        return over
-
-    def get_config(self, application=None, options=None, command=None,
-                    datadir=None):
-        '''get the config from all the configuration files.
-        
-        :param application str: The application for which salomeTools is called.
-        :param options class Options: The general salomeTools
-                                      options (--overwrite or -v5, for example)
-        :param command str: The command that is called.
-        :param datadir str: The repository that contain 
-                            external data for salomeTools.
-        :return: The final config.
-        :rtype: class 'src.pyconf.Config'
-        '''        
-        
-        # create a ConfigMerger to handle merge
-        merger = src.pyconf.ConfigMerger() #MergeHandler())
-        
-        # create the configuration instance
-        cfg = src.pyconf.Config()
-        
-        # =====================================================================
-        # create VARS section
-        var = self._create_vars(application=application, command=command, 
-                                datadir=datadir)
-        # add VARS to config
-        cfg.VARS = src.pyconf.Mapping(cfg)
-        for variable in var:
-            cfg.VARS[variable] = var[variable]
-        
-        # apply overwrite from command line if needed
-        for rule in self.get_command_line_overrides(options, ["VARS"]):
-            exec('cfg.' + rule) # this cannot be factorized because of the exec
-        
-        # =====================================================================
-        # Load INTERNAL config
-        # read src/internal_config/salomeTools.pyconf
-        src.pyconf.streamOpener = ConfigOpener([
-                            os.path.join(cfg.VARS.srcDir, 'internal_config')])
-        try:
-            internal_cfg = src.pyconf.Config(open(os.path.join(cfg.VARS.srcDir, 
-                                    'internal_config', 'salomeTools.pyconf')))
-        except src.pyconf.ConfigError as e:
-            raise src.SatException(_("Error in configuration file:"
-                                     " salomeTools.pyconf\n  %(error)s") % \
-                                   {'error': str(e) })
-        
-        merger.merge(cfg, internal_cfg)
-
-        # apply overwrite from command line if needed
-        for rule in self.get_command_line_overrides(options, ["INTERNAL"]):
-            exec('cfg.' + rule) # this cannot be factorized because of the exec        
-               
-        # =====================================================================
-        # Load LOCAL config file
-        # search only in the data directory
-        src.pyconf.streamOpener = ConfigOpener([cfg.VARS.datadir])
-        try:
-            local_cfg = src.pyconf.Config(open(os.path.join(cfg.VARS.datadir, 
-                                                           'local.pyconf')),
-                                         PWD = ('LOCAL', cfg.VARS.datadir) )
-        except src.pyconf.ConfigError as e:
-            raise src.SatException(_("Error in configuration file: "
-                                     "local.pyconf\n  %(error)s") % \
-                {'error': str(e) })
-        except IOError as error:
-            e = str(error)
-            raise src.SatException( e );
-        merger.merge(cfg, local_cfg)
-
-        # When the key is "default", put the default value
-        if cfg.LOCAL.base == "default":
-            cfg.LOCAL.base = os.path.abspath(
-                                        os.path.join(cfg.VARS.salometoolsway,
-                                                     "..",
-                                                     "BASE"))
-        if cfg.LOCAL.workdir == "default":
-            cfg.LOCAL.workdir = os.path.abspath(
-                                        os.path.join(cfg.VARS.salometoolsway,
-                                                     ".."))
-        if cfg.LOCAL.log_dir == "default":
-            cfg.LOCAL.log_dir = os.path.abspath(
-                                        os.path.join(cfg.VARS.salometoolsway,
-                                                     "..",
-                                                     "LOGS"))
-
-        if cfg.LOCAL.archive_dir == "default":
-            cfg.LOCAL.archive_dir = os.path.abspath(
-                                        os.path.join(cfg.VARS.salometoolsway,
-                                                     "..",
-                                                     "ARCHIVES"))
-
-        # apply overwrite from command line if needed
-        for rule in self.get_command_line_overrides(options, ["LOCAL"]):
-            exec('cfg.' + rule) # this cannot be factorized because of the exec
-        
-        # =====================================================================
-        # Load the PROJECTS
-        projects_cfg = src.pyconf.Config()
-        projects_cfg.addMapping("PROJECTS",
-                                src.pyconf.Mapping(projects_cfg),
-                                "The projects\n")
-        projects_cfg.PROJECTS.addMapping("projects",
-                                src.pyconf.Mapping(cfg.PROJECTS),
-                                "The projects definition\n")
-        
-        for project_pyconf_path in cfg.PROJECTS.project_file_paths:
-            if not os.path.exists(project_pyconf_path):
-                msg = _("WARNING: The project file %s cannot be found. "
-                        "It will be ignored\n") % project_pyconf_path
-                sys.stdout.write(msg)
-                continue
-            project_name = os.path.basename(project_pyconf_path)[:-len(".pyconf")]
-            try:
-                project_pyconf_dir = os.path.dirname(project_pyconf_path)
-                project_cfg = src.pyconf.Config(open(project_pyconf_path),
-                                                PWD=("", project_pyconf_dir))
-            except Exception as e:
-                msg = _("ERROR: Error in configuration file: %(file_path)s\n  %(error)s\n") % \
-                       {'file_path' : project_pyconf_path, 'error': str(e) }
-                sys.stdout.write(msg)
-                continue
-            projects_cfg.PROJECTS.projects.addMapping(project_name,
-                             src.pyconf.Mapping(projects_cfg.PROJECTS.projects),
-                             "The %s project\n" % project_name)
-            projects_cfg.PROJECTS.projects[project_name]=project_cfg
-            projects_cfg.PROJECTS.projects[project_name]["file_path"] = \
-                                                        project_pyconf_path
-                   
-        merger.merge(cfg, projects_cfg)
-
-        # apply overwrite from command line if needed
-        for rule in self.get_command_line_overrides(options, ["PROJECTS"]):
-            exec('cfg.' + rule) # this cannot be factorized because of the exec
-        
-        # =====================================================================
-        # Create the paths where to search the application configurations, 
-        # the product configurations, the products archives, 
-        # the jobs configurations and the machines configurations
-        cfg.addMapping("PATHS", src.pyconf.Mapping(cfg), "The paths\n")
-        cfg.PATHS["APPLICATIONPATH"] = src.pyconf.Sequence(cfg.PATHS)
-        cfg.PATHS.APPLICATIONPATH.append(cfg.VARS.personal_applications_dir, "")
-        
-        cfg.PATHS["PRODUCTPATH"] = src.pyconf.Sequence(cfg.PATHS)
-        cfg.PATHS.PRODUCTPATH.append(cfg.VARS.personal_products_dir, "")
-        cfg.PATHS["ARCHIVEPATH"] = src.pyconf.Sequence(cfg.PATHS)
-        cfg.PATHS.ARCHIVEPATH.append(cfg.VARS.personal_archives_dir, "")
-        cfg.PATHS["JOBPATH"] = src.pyconf.Sequence(cfg.PATHS)
-        cfg.PATHS.JOBPATH.append(cfg.VARS.personal_jobs_dir, "")
-        cfg.PATHS["MACHINEPATH"] = src.pyconf.Sequence(cfg.PATHS)
-        cfg.PATHS.MACHINEPATH.append(cfg.VARS.personal_machines_dir, "")
-
-        # initialise the path with local directory
-        cfg.PATHS["ARCHIVEPATH"].append(cfg.LOCAL.archive_dir, "")
-
-        # Loop over the projects in order to complete the PATHS variables
-        for project in cfg.PROJECTS.projects:
-            for PATH in ["APPLICATIONPATH",
-                         "PRODUCTPATH",
-                         "ARCHIVEPATH",
-                         "JOBPATH",
-                         "MACHINEPATH"]:
-                if PATH not in cfg.PROJECTS.projects[project]:
-                    continue
-                cfg.PATHS[PATH].append(cfg.PROJECTS.projects[project][PATH], "")
-        
-        # apply overwrite from command line if needed
-        for rule in self.get_command_line_overrides(options, ["PATHS"]):
-            exec('cfg.' + rule) # this cannot be factorized because of the exec
-
-        # =====================================================================
-        # Load APPLICATION config file
-        if application is not None:
-            # search APPLICATION file in all directories in configPath
-            cp = cfg.PATHS.APPLICATIONPATH
-            src.pyconf.streamOpener = ConfigOpener(cp)
-            do_merge = True
-            try:
-                application_cfg = src.pyconf.Config(application + '.pyconf')
-            except IOError as e:
-                raise src.SatException(_("%s, use 'config --list' to get the"
-                                         " list of available applications.") % e)
-            except src.pyconf.ConfigError as e:
-                if (not ('-e' in parser.parse_args()[1]) 
-                                         or ('--edit' in parser.parse_args()[1]) 
-                                         and command == 'config'):
-                    raise src.SatException(
-                        _("Error in configuration file: (1)s.pyconf\n  %(2)s") % \
-                        { 'application': application, 'error': str(e) } )
-                else:
-                    sys.stdout.write(src.printcolors.printcWarning(
-                        "There is an error in the file %s.pyconf.\n" % \
-                        cfg.VARS.application))
-                    do_merge = False
-            except Exception as e:
-                if ( not('-e' in parser.parse_args()[1]) or
-                     ('--edit' in parser.parse_args()[1]) and
-                     command == 'config' ):
-                    sys.stdout.write(src.printcolors.printcWarning("%s\n" % str(e)))
-                    raise src.SatException(
-                        _("Error in configuration file: %s.pyconf\n") % application )
-                else:
-                    sys.stdout.write(src.printcolors.printcWarning(
-                        "ERROR: in file %s.pyconf. Opening the file with the default viewer\n" % \
-                        cfg.VARS.application))
-                    sys.stdout.write("\n%s\n" % src.printcolors.printcWarning(str(e)))
-                    do_merge = False
-        
-            else:
-                cfg['open_application'] = 'yes'
-
-        # =====================================================================
-        # Load product config files in PRODUCTS section
-        products_cfg = src.pyconf.Config()
-        products_cfg.addMapping("PRODUCTS",
-                                src.pyconf.Mapping(products_cfg),
-                                "The products\n")
-        if application is not None:
-            src.pyconf.streamOpener = ConfigOpener(cfg.PATHS.PRODUCTPATH)
-            for product_name in application_cfg.APPLICATION.products.keys():
-                # Loop on all files that are in softsDir directory
-                # and read their config
-                product_file_name = product_name + ".pyconf"
-                product_file_path = src.find_file_in_lpath(product_file_name, cfg.PATHS.PRODUCTPATH)
-                if product_file_path:
-                    products_dir = os.path.dirname(product_file_path)
-                    try:
-                        prod_cfg = src.pyconf.Config(open(product_file_path),
-                                                     PWD=("", products_dir))
-                        prod_cfg.from_file = product_file_path
-                        products_cfg.PRODUCTS[product_name] = prod_cfg
-                    except Exception as e:
-                        msg = _(
-                            "WARNING: Error in configuration file: %(prod)s\n  %(error)s" % \
-                            {'prod' :  product_name, 'error': str(e) })
-                        sys.stdout.write(msg)
-            
-            merger.merge(cfg, products_cfg)
-            
-            # apply overwrite from command line if needed
-            for rule in self.get_command_line_overrides(options, ["PRODUCTS"]):
-                exec('cfg.' + rule) # this cannot be factorized because of the exec
-            
-            if do_merge:
-                merger.merge(cfg, application_cfg)
-
-                # default launcher name ('salome')
-                if ('profile' in cfg.APPLICATION and 
-                    'launcher_name' not in cfg.APPLICATION.profile):
-                    cfg.APPLICATION.profile.launcher_name = 'salome'
-
-                # apply overwrite from command line if needed
-                for rule in self.get_command_line_overrides(options,
-                                                             ["APPLICATION"]):
-                    # this cannot be factorized because of the exec
-                    exec('cfg.' + rule)
-            
-        # =====================================================================
-        # load USER config
-        self.set_user_config_file(cfg)
-        user_cfg_file = self.get_user_config_file()
-        user_cfg = src.pyconf.Config(open(user_cfg_file))
-        merger.merge(cfg, user_cfg)
-
-        # apply overwrite from command line if needed
-        for rule in self.get_command_line_overrides(options, ["USER"]):
-            exec('cfg.' + rule) # this cannot be factorize because of the exec
-        
-        return cfg
-
-    def set_user_config_file(self, config):
-        '''Set the user config file name and path.
-        If necessary, build it from another one or create it from scratch.
-        
-        :param config class 'src.pyconf.Config': The global config 
-                                                 (containing all pyconf).
-        '''
-        # get the expected name and path of the file
-        self.config_file_name = 'SAT.pyconf'
-        self.user_config_file_path = os.path.join(config.VARS.personalDir,
-                                                   self.config_file_name)
-        
-        # if pyconf does not exist, create it from scratch
-        if not os.path.isfile(self.user_config_file_path): 
-            self.create_config_file(config)
-    
-    def create_config_file(self, config):
-        '''This method is called when there are no user config file. 
-           It build it from scratch.
-        
-        :param config class 'src.pyconf.Config': The global config.
-        :return: the config corresponding to the file created.
-        :rtype: config class 'src.pyconf.Config'
-        '''
-        
-        cfg_name = self.get_user_config_file()
-
-        user_cfg = src.pyconf.Config()
-        #
-        user_cfg.addMapping('USER', src.pyconf.Mapping(user_cfg), "")
-
-        user_cfg.USER.addMapping('cvs_user', config.VARS.user,
-            "This is the user name used to access salome cvs base.\n")
-        user_cfg.USER.addMapping('svn_user', config.VARS.user,
-            "This is the user name used to access salome svn base.\n")
-        user_cfg.USER.addMapping('output_verbose_level', 3,
-            "This is the default output_verbose_level you want."
-            " 0=>no output, 5=>debug.\n")
-        user_cfg.USER.addMapping('publish_dir', 
-                                 os.path.join(os.path.expanduser('~'),
-                                 'websupport', 
-                                 'satreport'), 
-                                 "")
-        user_cfg.USER.addMapping('editor',
-                                 'vi', 
-                                 "This is the editor used to "
-                                 "modify configuration files\n")
-        user_cfg.USER.addMapping('browser', 
-                                 'firefox', 
-                                 "This is the browser used to "
-                                 "read html documentation\n")
-        user_cfg.USER.addMapping('pdf_viewer', 
-                                 'evince', 
-                                 "This is the pdf_viewer used "
-                                 "to read pdf documentation\n")
-# CNC 25/10/17 : plus nécessaire a priori
-#        user_cfg.USER.addMapping("base",
-#                                 src.pyconf.Reference(
-#                                            user_cfg,
-#                                            src.pyconf.DOLLAR,
-#                                            'workdir  + $VARS.sep + "BASE"'),
-#                                 "The products installation base (could be "
-#                                 "ignored if this key exists in the local.pyconf"
-#                                 " file of salomTools).\n")
-               
-        # 
-        src.ensure_path_exists(config.VARS.personalDir)
-        src.ensure_path_exists(os.path.join(config.VARS.personalDir, 
-                                            'Applications'))
-
-        f = open(cfg_name, 'w')
-        user_cfg.__save__(f)
-        f.close()
-
-        return user_cfg   
-
-    def get_user_config_file(self):
-        '''Get the user config file
-        :return: path to the user config file.
-        :rtype: str
-        '''
-        if not self.user_config_file_path:
-            raise src.SatException(
-                _("Error in get_user_config_file: missing user config file path") )
-        return self.user_config_file_path     
-
-def check_path(path, ext=[]):
-    '''Construct a text with the input path and "not found" if it does not
-       exist.
-    
-    :param path Str: the path to check.
-    :param ext List: An extension. Verify that the path extension 
-                     is in the list
-    :return: The string of the path with information
-    :rtype: Str
-    '''
-    # check if file exists
-    if not os.path.exists(path):
-        return "'%s' %s" % (path, src.printcolors.printcError(_("** not found")))
-
-    # check extension
-    if len(ext) > 0:
-        fe = os.path.splitext(path)[1].lower()
-        if fe not in ext:
-            return "'%s' %s" % (path, src.printcolors.printcError(_("** bad extension")))
-
-    return path
-
-def show_product_info(config, name, logger):
-    '''Display on the terminal and logger information about a product.
-    
-    :param config Config: the global configuration.
-    :param name Str: The name of the product
-    :param logger Logger: The logger instance to use for the display
-    '''
-    
-    logger.write(_("%s is a product\n") % src.printcolors.printcLabel(name), 2)
-    pinfo = src.product.get_product_config(config, name)
-    
-    if "depend" in pinfo:
-        src.printcolors.print_value(logger, 
-                                    "depends on", 
-                                    ', '.join(pinfo.depend), 2)
-
-    if "opt_depend" in pinfo:
-        src.printcolors.print_value(logger, 
-                                    "optional", 
-                                    ', '.join(pinfo.opt_depend), 2)
-
-    # information on pyconf
-    logger.write("\n", 2)
-    logger.write(src.printcolors.printcLabel("configuration:") + "\n", 2)
-    if "from_file" in pinfo:
-        src.printcolors.print_value(logger, 
-                                    "pyconf file path", 
-                                    pinfo.from_file, 
-                                    2)
-    if "section" in pinfo:
-        src.printcolors.print_value(logger, 
-                                    "section", 
-                                    pinfo.section, 
-                                    2)
-
-    # information on prepare
-    logger.write("\n", 2)
-    logger.write(src.printcolors.printcLabel("prepare:") + "\n", 2)
-
-    is_dev = src.product.product_is_dev(pinfo)
-    method = pinfo.get_source
-    if is_dev:
-        method += " (dev)"
-    src.printcolors.print_value(logger, "get method", method, 2)
-
-    if method == 'cvs':
-        src.printcolors.print_value(logger, "server", pinfo.cvs_info.server, 2)
-        src.printcolors.print_value(logger, "base module",
-                                    pinfo.cvs_info.module_base, 2)
-        src.printcolors.print_value(logger, "source", pinfo.cvs_info.source, 2)
-        src.printcolors.print_value(logger, "tag", pinfo.cvs_info.tag, 2)
-
-    elif method == 'svn':
-        src.printcolors.print_value(logger, "repo", pinfo.svn_info.repo, 2)
-
-    elif method == 'git':
-        src.printcolors.print_value(logger, "repo", pinfo.git_info.repo, 2)
-        src.printcolors.print_value(logger, "tag", pinfo.git_info.tag, 2)
-
-    elif method == 'archive':
-        src.printcolors.print_value(logger, 
-                                    "get from", 
-                                    check_path(pinfo.archive_info.archive_name), 
-                                    2)
-
-    if 'patches' in pinfo:
-        for patch in pinfo.patches:
-            src.printcolors.print_value(logger, "patch", check_path(patch), 2)
-
-    if src.product.product_is_fixed(pinfo):
-        src.printcolors.print_value(logger, "install_dir", 
-                                    check_path(pinfo.install_dir), 2)
-
-    if src.product.product_is_native(pinfo) or src.product.product_is_fixed(pinfo):
-        return
-    
-    # information on compilation
-    if src.product.product_compiles(pinfo):
-        logger.write("\n", 2)
-        logger.write(src.printcolors.printcLabel("compile:") + "\n", 2)
-        src.printcolors.print_value(logger, 
-                                    "compilation method", 
-                                    pinfo.build_source, 
-                                    2)
-        
-        if pinfo.build_source == "script" and "compil_script" in pinfo:
-            src.printcolors.print_value(logger, 
-                                        "Compilation script", 
-                                        pinfo.compil_script, 
-                                        2)
-        
-        if 'nb_proc' in pinfo:
-            src.printcolors.print_value(logger, "make -j", pinfo.nb_proc, 2)
-    
-        src.printcolors.print_value(logger, 
-                                    "source dir", 
-                                    check_path(pinfo.source_dir), 
-                                    2)
-        if 'install_dir' in pinfo:
-            src.printcolors.print_value(logger, 
-                                        "build dir", 
-                                        check_path(pinfo.build_dir), 
-                                        2)
-            src.printcolors.print_value(logger, 
-                                        "install dir", 
-                                        check_path(pinfo.install_dir), 
-                                        2)
-        else:
-            logger.write("  %s\n" % src.printcolors.printcWarning(_("no install dir")) , 2)
-    else:
-        logger.write("\n", 2)
-        msg = _("This product does not compile")
-        logger.write("%s\n" % msg, 2)
-
-    # information on environment
-    logger.write("\n", 2)
-    logger.write(src.printcolors.printcLabel("environ :") + "\n", 2)
-    if "environ" in pinfo and "env_script" in pinfo.environ:
-        src.printcolors.print_value(logger, 
-                                    "script", 
-                                    check_path(pinfo.environ.env_script), 
-                                    2)
-
-    zz = src.environment.SalomeEnviron(config, 
-                                       src.fileEnviron.ScreenEnviron(logger), 
-                                       False)
-    zz.set_python_libdirs()
-    zz.set_a_product(name, logger)
-        
-def show_patchs(config, logger):
-    '''Prints all the used patchs in the application.
-    
-    :param config Config: the global configuration.
-    :param logger Logger: The logger instance to use for the display
-    '''
-    len_max = max([len(p) for p in config.APPLICATION.products]) + 2
-    for product in config.APPLICATION.products:
-        product_info = src.product.get_product_config(config, product)
-        if src.product.product_has_patches(product_info):
-            logger.write("%s: " % product, 1)
-            logger.write(src.printcolors.printcInfo(
-                                            " " * (len_max - len(product) -2) +
-                                            "%s\n" % product_info.patches[0]),
-                         1)
-            if len(product_info.patches) > 1:
-                for patch in product_info.patches[1:]:
-                    logger.write(src.printcolors.printcInfo(len_max*" " +
-                                                            "%s\n" % patch), 1)
-            logger.write("\n", 1)
-
-def print_value(config, path, show_label, logger, level=0, show_full_path=False):
-    '''Prints a value from the configuration. Prints recursively the values 
-       under the initial path.
-    
-    :param config class 'src.pyconf.Config': The configuration 
-                                             from which the value is displayed.
-    :param path str : the path in the configuration of the value to print.
-    :param show_label boolean: if True, do a basic display. 
-                               (useful for bash completion)
-    :param logger Logger: the logger instance
-    :param level int: The number of spaces to add before display.
-    :param show_full_path :
-    '''            
-    
-    # Make sure that the path does not ends with a point
-    if path.endswith('.'):
-        path = path[:-1]
-    
-    # display all the path or not
-    if show_full_path:
-        vname = path
-    else:
-        vname = path.split('.')[-1]
-
-    # number of spaces before the display
-    tab_level = "  " * level
-    
-    # call to the function that gets the value of the path.
-    try:
-        val = config.getByPath(path)
-    except Exception as e:
-        logger.write(tab_level)
-        logger.write("%s: ERROR %s\n" % (src.printcolors.printcLabel(vname), 
-                                         src.printcolors.printcError(str(e))))
-        return
-
-    # in this case, display only the value
-    if show_label:
-        logger.write(tab_level)
-        logger.write("%s: " % src.printcolors.printcLabel(vname))
-
-    # The case where the value has under values, 
-    # do a recursive call to the function
-    if dir(val).__contains__('keys'):
-        if show_label: logger.write("\n")
-        for v in sorted(val.keys()):
-            print_value(config, path + '.' + v, show_label, logger, level + 1)
-    elif val.__class__ == src.pyconf.Sequence or isinstance(val, list): 
-        # in this case, value is a list (or a Sequence)
-        if show_label: logger.write("\n")
-        index = 0
-        for v in val:
-            print_value(config, path + "[" + str(index) + "]", 
-                        show_label, logger, level + 1)
-            index = index + 1
-    else: # case where val is just a str
-        logger.write("%s\n" % val)
-        
-def print_debug(config, aPath, show_label, logger, level=0, show_full_path=False):
-    """
-    logger output for debugging a config/pyconf
-    lines contains:
-       path : expression --> 'evaluation'
-    example:
-      .PROJECTS.projects.salome.project_path : $PWD --> '/volatile/wambeke/SAT5/SAT5_S840_MATIX24/SAT_SALOME'
-    """
-    path = str(aPath)
-    if path == "." :
-      val = config
-      path = ""
-    else:
-      if path.endswith('.'): # Make sure that the path does not ends with a point
-        path = path[:-1]
-      val = config.getByPath(path)
-      
-    outStream = DBG.OutStream()
-    DBG.saveConfigDbg(val, outStream, path=path)
-    res = outStream.value
-    logger.write(res)
-    return
-
-def get_config_children(config, args):
-    '''Gets the names of the children of the given parameter.
-       Useful only for completion mechanism
-    
-    :param config Config: The configuration where to read the values
-    :param args: The path in the config from which get the keys
-    '''
-    vals = []
-    rootkeys = config.keys()
-    
-    if len(args) == 0:
-        # no parameter returns list of root keys
-        vals = rootkeys
-    else:
-        parent = args[0]
-        pos = parent.rfind('.')
-        if pos < 0:
-            # Case where there is only on key as parameter.
-            # For example VARS
-            vals = [m for m in rootkeys if m.startswith(parent)]
-        else:
-            # Case where there is a part from a key
-            # for example VARS.us  (for VARS.user)
-            head = parent[0:pos]
-            tail = parent[pos+1:]
-            try:
-                a = config.getByPath(head)
-                if dir(a).__contains__('keys'):
-                    vals = map(lambda x: head + '.' + x,
-                               [m for m in a.keys() if m.startswith(tail)])
-            except:
-                pass
-
-    for v in sorted(vals):
-        sys.stdout.write("%s\n" % v)
-
 
 ########################################################################
 # Command class for command 'sat config etc.'
 ########################################################################
 class Command(_BaseCommand):
+  """\
+  The config command allows manipulation and operation on config '.pyconf' files.
+
+  examples:
+    >> sat config --list
+    >> sat config SALOME --edit
+    >> sat config SALOME --copy SALOME-new
+    >> sat config SALOME --value VARS
+    >> sat config SALOME --debug VARS
+    >> sat config SALOME --info ParaView
+    >> sat config SALOME --show_patchs
+  """
+  
+  name = "config"
   
   def getParser(self):
     # Define all possible option for config command :  sat config <options>
     parser = src.options.Options()
+    parser.add_option('h', 'help', 'boolean', 'help', 
+                      _("shows help on command."))
     parser.add_option('v', 'value', 'string', 'value',
         _("Optional: print the value of CONFIG_VARIABLE."))
     parser.add_option('d', 'debug', 'string', 'debug',
@@ -833,43 +65,41 @@ class Command(_BaseCommand):
         _("Optional: get information on a product."))
     parser.add_option('l', 'list', 'boolean', 'list',
         _("Optional: list all available applications."))
-    parser.add_option('', 'show_patchs', 'boolean', 'show_patchs',
+    parser.add_option('p', 'show_patchs', 'boolean', 'show_patchs',
         _("Optional: synthetic view of all patches used in the application"))
     parser.add_option('c', 'copy', 'boolean', 'copy',
         _("""Optional: copy a config file (.pyconf) to the personal config files directory.
-    \tWarning: the included files are not copied.
-    \tIf a name is given the new config file takes the given name."""))
+      Warning: the included files are not copied.
+      If a name is given the new config file takes the given name."""))
     parser.add_option('n', 'no_label', 'boolean', 'no_label',
         _("Internal use: do not print labels, Works only with --value and --list."))
-    parser.add_option('', 'completion', 'boolean', 'completion',
+    parser.add_option('o', 'completion', 'boolean', 'completion',
         _("Internal use: print only keys, works only with --value."))
     parser.add_option('s', 'schema', 'boolean', 'schema',
         _("Internal use."))
     return parser
 
-  def description(self):
-    '''method that is called when salomeTools is called with --help option.
-    
-    :return: The text to display for the config command description.
-    :rtype: str
-    '''
-    return _("""\
-The config command allows manipulation and operation on config files.
+  def run(self, cmd_arguments):
+      """method that is called when salomeTools is called with config parameter."""
+      argList = self.assumeAsList(cmd_arguments)
 
-example:
->> sat config SALOME-master --info ParaView""")
+      # print general help and returns
+      if len(argList) == 0:
+        self.print_help()
+        return RCO.ReturnCode("OK", "No arguments, as 'sat %s --help'" % self.name)
         
-
-  def run(self, args):
-      '''method that is called when salomeTools is called with config parameter.
-      '''
+      self._options, remaindersArgs = self.parseArguments(argList)
+      
+      if self._options.help:
+        self.print_help()
+        return RCO.ReturnCode("OK", "Done 'sat %s --help'" % self.name)
+     
+      # shortcuts
       runner = self.getRunner()
       config = self.getConfig()
       logger = self.getLogger()
+      options = self.getOptions()
   
-      # Parse the options
-      (options, argsc) = self.parse_args(args)
-
       # Only useful for completion mechanism : print the keys of the config
       if options.schema:
           get_config_children(config, args)
diff --git a/sat b/sat
index d374a93f21786f98eeceafae8352ca5bcc124c80..eb1cc101345d66463d13ec319d7ae50f54937b2d 100755 (executable)
--- a/sat
+++ b/sat
 #  License along with this library; if not, write to the Free Software
 #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 
-'''\
+"""\
 This file is the main entry file to use salomeTools,
 in mode Command Line Argument(s) (CLI)
-'''
+"""
 
 import os
 import sys
 
-# OKSYS and KOSYS seems equal on linux or windows
+# exit OKSYS and KOSYS seems equal on linux or windows
 OKSYS = 0  # OK 
 KOSYS = 1  # KO
 
@@ -35,27 +35,41 @@ satdir  = os.path.dirname(os.path.realpath(__file__))
 # Make the src & commands package accessible from all code
 sys.path.insert(0, satdir)
 
+import src.loggingSat as LOG
+import src.debug as DBG # Easy print stderr (for DEBUG only)
 
+logger = LOG.getDefaultLogger()
+
+    
 #################################
 # MAIN
 #################################
 if __name__ == "__main__":
-    import src.loggingSat as LOG
-    import src.debug as DBG # Easy print stderr (for DEBUG only)from src.salomeTools import Sat
-    from src.salomeTools import Sat
+    from src.salomeTools import Sat # it is time...
     
-    _debug = True # Have to be False in production (for DEBUG only)
-    DBG.push_debug(_debug)
-
-    logger = LOG.getDefaultLogger()
-    # instantiate the salomeTools class
-    sat = Sat(logger)
-    returnCode = sat.execute_cli(sys.argv[1:])
-    logger.debug("sat exit code: %s" % returnCode)
+    _debug = False # Have to be False in production (for programmers DEBUG only)
+    DBG.push_debug(_debug) # as __main__ with sys.exit so no need pop_debug
 
-    sys.exit(returnCode.toSys())
+    sat = Sat(logger) # instantiate the salomeTools class
+    args = sys.argv[1:] # skip useless "sat'
+   
+    try:
+      returnCode = sat.execute_cli(args)
+      logger.debug("sat exit code: %s" % returnCode)
+      sys.exit(returnCode.toSys())
+      
+    except Exception as e:
+      msg = "Exception raised for execute_cli('%s'):\n\n<yellow>%s<reset>"
+      if (_debug) or (DBG._user in DBG._developpers):
+        # verbose debug message with traceback
+        import traceback
+        logger.critical( msg % (args, traceback.format_exc()) )
+      else:
+        # short production message
+        logger.critical( msg % (args, e) )
+      sys.exit(KOSYS)
 
 else:
-    sys.stderr.write("\nERROR: unexpected mode __name__ '%s'" % __name__)
+    logger.critical("forbidden/unexpected mode for __name__ '%s'" % __name__)
     sys.exit(KOSYS)
             
index 5ac98048d595e6f8c7153e556d8355146fac982e..3cdf70178df47f899ee52106bbd2cfe231b9c101 100644 (file)
@@ -1,2 +1,4 @@
 
-import src.pyconf
\ No newline at end of file
+# https://www.python.org/dev/peps/pep-0396/
+__version__ = "5.1.0"
+__name__ = "SalomeTools"
\ No newline at end of file
index 8fc13c69b36f3c292ca5ce56e797b90cf091e5f2..7d88a9e7f38b99561f70e2368fd2af190bc6c9b6 100755 (executable)
@@ -51,11 +51,10 @@ import colorama as CLRM
 from colorama import Fore as FG
 from colorama import Style as ST
 #from colorama import AnsiToWin32
-from ansitowin32 import AnsiToWin32 # debug is os.name == 'nt' ?
+from colorama import AnsiToWin32 # debug is os.name == 'nt' ?
 
 CLRM.init(wrap=False) # choose NO wrapping
 
-
 """
 from colorama:
 Available formatting constants are:
@@ -65,8 +64,10 @@ Style: DIM, NORMAL, BRIGHT, RESET_ALL
 
 n.b. DIM is not assumed in win32
 """
-dir(ST)
-# order matters for replace
+
+# dir(ST)
+
+# order matters for items replaces forward to color
 _tags = (
   ("<black>", FG.BLACK),
   ("<red>", FG.RED),
@@ -79,12 +80,14 @@ _tags = (
   ("<bright>", ST.BRIGHT),
   ("<normal>", ST.NORMAL),
   ("<reset>", ST.RESET_ALL),
+  ("<header>", FG.BLUE),
   ("<OK>", FG.GREEN + ST.BRIGHT + "OK" + ST.RESET_ALL),
   ("<KO>", FG.RED + ST.BRIGHT + "KO" + ST.RESET_ALL),
 )
 
 # _tagsNone = ((i, "") for i,j in _tags) # to clean tags when log not tty
-_tagsNone = (
+# reversed order matters for item replaces backward to no color
+_tagsNone = reversed( (
   ("<black>", ""),
   ("<red>", ""),
   ("<green>", ""),
@@ -96,9 +99,10 @@ _tagsNone = (
   ("<bright>", ""),
   ("<normal>", ""),
   ("<reset>", ""),
+  ("<header>", ""),
   ("<OK>", "OK"),
   ("<KO>", "KO"),
-)
+) )
 
 def indent(msg, nb, car=" "):
   """indent nb car (spaces) multi lines message except first one"""
@@ -176,7 +180,7 @@ if __name__ == "__main__":
   log("import <green>colorama in <blue>%s" % __file__)
   log("set <green>green and not reset...")
   log("...and here is not green because appended reset at end of message")
-  log("dir(FG):\n<blue>%s" % dir(FG))
-  log("dir(ST):\n<blue>%s" % dir(ST))
+  log("dir(FG):\n<blue>%s ... <OK> or <KO> ??" % dir(FG))
+  log("dir(ST):\n<blue>%s ... <OK> or <KO> ??" % dir(ST))
 
-  
\ No newline at end of file
+  
diff --git a/src/configManager.py b/src/configManager.py
new file mode 100644 (file)
index 0000000..e05eed5
--- /dev/null
@@ -0,0 +1,935 @@
+#!/usr/bin/env python
+#-*- coding:utf-8 -*-
+#  Copyright (C) 2010-2012  CEA/DEN
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2.1 of the License.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+import os
+import platform
+import datetime
+import shutil
+import sys
+
+import src.debug as DBG
+import src.loggingSat as LOG
+import src.returnCode as RCO
+import src.architecture as ARCH
+import src.utilsSat as UTS
+
+
+class ConfigOpener:
+    '''Class that helps to find an application pyconf 
+       in all the possible directories (pathList)
+    '''
+    def __init__(self, pathList):
+        '''Initialization
+        
+        :param pathList list: The list of paths where to search a pyconf.
+        '''
+        self.pathList = pathList
+
+    def __call__(self, name):
+        if os.path.isabs(name):
+            return src.pyconf.ConfigInputStream(open(name, 'rb'))
+        else:
+            return src.pyconf.ConfigInputStream( 
+                        open(os.path.join( self.get_path(name), name ), 'rb') )
+        raise IOError(_("Configuration file '%s' not found") % name)
+
+    def get_path( self, name ):
+        '''The method that returns the entire path of the pyconf searched
+        :param name str: The name of the searched pyconf.
+        '''
+        for path in self.pathList:
+            if os.path.exists(os.path.join(path, name)):
+                return path
+        raise IOError(_("Configuration file '%s' not found") % name)
+
+class ConfigManager:
+    '''Class that manages the read of all the configuration files of salomeTools
+    '''
+    def __init__(self, datadir=None):
+        self.logger = LOG.getDefaultLogger()
+
+
+    def _create_vars(self, application=None, command=None, datadir=None):
+        '''Create a dictionary that stores all information about machine,
+           user, date, repositories, etc...
+        
+        :param application str: The application for which salomeTools is called.
+        :param command str: The command that is called.
+        :param datadir str: The repository that contain external data 
+                            for salomeTools.
+        :return: The dictionary that stores all information.
+        :rtype: dict
+        '''
+        var = {}      
+        var['user'] = ARCH.get_user()
+        var['salometoolsway'] = os.path.dirname(
+                                    os.path.dirname(os.path.abspath(__file__)))
+        var['srcDir'] = os.path.join(var['salometoolsway'], 'src')
+        var['internal_dir'] = os.path.join(var['srcDir'], 'internal_config')
+        var['sep']= os.path.sep
+        
+        # datadir has a default location
+        var['datadir'] = os.path.join(var['salometoolsway'], 'data')
+        if datadir is not None:
+            var['datadir'] = datadir
+
+        var['personalDir'] = os.path.join(os.path.expanduser('~'),
+                                           '.salomeTools')
+        UTS.ensure_path_exists(var['personalDir'])
+
+        var['personal_applications_dir'] = os.path.join(var['personalDir'],
+                                                        "Applications")
+        UTS.ensure_path_exists(var['personal_applications_dir'])
+        
+        var['personal_products_dir'] = os.path.join(var['personalDir'],
+                                                    "products")
+        UTS.ensure_path_exists(var['personal_products_dir'])
+        
+        var['personal_archives_dir'] = os.path.join(var['personalDir'],
+                                                    "Archives")
+        UTS.ensure_path_exists(var['personal_archives_dir'])
+
+        var['personal_jobs_dir'] = os.path.join(var['personalDir'],
+                                                "Jobs")
+        UTS.ensure_path_exists(var['personal_jobs_dir'])
+
+        var['personal_machines_dir'] = os.path.join(var['personalDir'],
+                                                    "Machines")
+        UTS.ensure_path_exists(var['personal_machines_dir'])
+
+        # read linux distributions dictionary
+        distrib_cfg = src.pyconf.Config(os.path.join(var['srcDir'],
+                                                      'internal_config',
+                                                      'distrib.pyconf'))
+        
+        # set platform parameters
+        dist_name = ARCH.get_distribution(codes=distrib_cfg.DISTRIBUTIONS)
+        dist_version = ARCH.get_distrib_version(dist_name, 
+                                                codes=distrib_cfg.VERSIONS)
+        dist = dist_name + dist_version
+        
+        var['dist_name'] = dist_name
+        var['dist_version'] = dist_version
+        var['dist'] = dist
+        var['python'] = ARCH.get_python_version()
+
+        var['nb_proc'] = ARCH.get_nb_proc()
+        node_name = platform.node()
+        var['node'] = node_name
+        var['hostname'] = node_name
+
+        # set date parameters
+        dt = datetime.datetime.now()
+        var['date'] = dt.strftime('%Y%m%d')
+        var['datehour'] = dt.strftime('%Y%m%d_%H%M%S')
+        var['hour'] = dt.strftime('%H%M%S')
+
+        var['command'] = str(command)
+        var['application'] = str(application)
+
+        # Root dir for temporary files 
+        var['tmp_root'] = os.sep + 'tmp' + os.sep + var['user']
+        # particular win case 
+        if ARCH.is_windows() : 
+            var['tmp_root'] =  os.path.expanduser('~') + os.sep + 'tmp'
+        
+        return var
+
+    def get_command_line_overrides(self, options, sections):
+        '''get all the overwrites that are in the command line
+        
+        :param options: the options from salomeTools class 
+                        initialization (like -l5 or --overwrite)
+        :param sections str: The config section to overwrite.
+        :return: The list of all the overwrites to apply.
+        :rtype: list
+        '''
+        # when there are no options or not the overwrite option, 
+        # return an empty list
+        if options is None or options.overwrite is None:
+            return []
+        
+        over = []
+        for section in sections:
+            # only overwrite the sections that correspond to the option 
+            over.extend(filter(lambda l: l.startswith(section + "."), 
+                               options.overwrite))
+        return over
+
+    def get_config(self, application=None, options=None, command=None,
+                    datadir=None):
+        '''get the config from all the configuration files.
+        
+        :param application str: The application for which salomeTools is called.
+        :param options class Options: The general salomeTools
+                                      options (--overwrite or -v5, for example)
+        :param command str: The command that is called.
+        :param datadir str: The repository that contain 
+                            external data for salomeTools.
+        :return: The final config.
+        :rtype: class 'src.pyconf.Config'
+        '''        
+        
+        # create a ConfigMerger to handle merge
+        merger = src.pyconf.ConfigMerger() #MergeHandler())
+        
+        # create the configuration instance
+        cfg = src.pyconf.Config()
+        
+        # =====================================================================
+        # create VARS section
+        var = self._create_vars(application=application, command=command, 
+                                datadir=datadir)
+        # add VARS to config
+        cfg.VARS = src.pyconf.Mapping(cfg)
+        for variable in var:
+            cfg.VARS[variable] = var[variable]
+        
+        # apply overwrite from command line if needed
+        for rule in self.get_command_line_overrides(options, ["VARS"]):
+            exec('cfg.' + rule) # this cannot be factorized because of the exec
+        
+        # =====================================================================
+        # Load INTERNAL config
+        # read src/internal_config/salomeTools.pyconf
+        src.pyconf.streamOpener = ConfigOpener([
+                            os.path.join(cfg.VARS.srcDir, 'internal_config')])
+        try:
+            internal_cfg = src.pyconf.Config(open(os.path.join(cfg.VARS.srcDir, 
+                                    'internal_config', 'salomeTools.pyconf')))
+        except src.pyconf.ConfigError as e:
+            raise src.SatException(_("Error in configuration file:"
+                                     " salomeTools.pyconf\n  %(error)s") % \
+                                   {'error': str(e) })
+        
+        merger.merge(cfg, internal_cfg)
+
+        # apply overwrite from command line if needed
+        for rule in self.get_command_line_overrides(options, ["INTERNAL"]):
+            exec('cfg.' + rule) # this cannot be factorized because of the exec        
+               
+        # =====================================================================
+        # Load LOCAL config file
+        # search only in the data directory
+        src.pyconf.streamOpener = ConfigOpener([cfg.VARS.datadir])
+        try:
+            local_cfg = src.pyconf.Config(open(os.path.join(cfg.VARS.datadir, 
+                                                           'local.pyconf')),
+                                         PWD = ('LOCAL', cfg.VARS.datadir) )
+        except src.pyconf.ConfigError as e:
+            raise src.SatException(_("Error in configuration file: "
+                                     "local.pyconf\n  %(error)s") % \
+                {'error': str(e) })
+        except IOError as error:
+            e = str(error)
+            raise src.SatException( e );
+        merger.merge(cfg, local_cfg)
+
+        # When the key is "default", put the default value
+        if cfg.LOCAL.base == "default":
+            cfg.LOCAL.base = os.path.abspath(
+                                        os.path.join(cfg.VARS.salometoolsway,
+                                                     "..",
+                                                     "BASE"))
+        if cfg.LOCAL.workdir == "default":
+            cfg.LOCAL.workdir = os.path.abspath(
+                                        os.path.join(cfg.VARS.salometoolsway,
+                                                     ".."))
+        if cfg.LOCAL.log_dir == "default":
+            cfg.LOCAL.log_dir = os.path.abspath(
+                                        os.path.join(cfg.VARS.salometoolsway,
+                                                     "..",
+                                                     "LOGS"))
+
+        if cfg.LOCAL.archive_dir == "default":
+            cfg.LOCAL.archive_dir = os.path.abspath(
+                                        os.path.join(cfg.VARS.salometoolsway,
+                                                     "..",
+                                                     "ARCHIVES"))
+
+        # apply overwrite from command line if needed
+        for rule in self.get_command_line_overrides(options, ["LOCAL"]):
+            exec('cfg.' + rule) # this cannot be factorized because of the exec
+        
+        # =====================================================================
+        # Load the PROJECTS
+        projects_cfg = src.pyconf.Config()
+        projects_cfg.addMapping("PROJECTS",
+                                src.pyconf.Mapping(projects_cfg),
+                                "The projects\n")
+        projects_cfg.PROJECTS.addMapping("projects",
+                                src.pyconf.Mapping(cfg.PROJECTS),
+                                "The projects definition\n")
+        
+        for project_pyconf_path in cfg.PROJECTS.project_file_paths:
+            if not os.path.exists(project_pyconf_path):
+                msg = _("Cannot find project file <red>%s<reset>, Ignored.") % project_pyconf_path
+                self.logger.warning(msg)
+                continue
+            project_name = os.path.basename(project_pyconf_path)[:-len(".pyconf")]
+            try:
+                project_pyconf_dir = os.path.dirname(project_pyconf_path)
+                project_cfg = src.pyconf.Config(open(project_pyconf_path),
+                                                PWD=("", project_pyconf_dir))
+            except Exception as e:
+                msg = _("ERROR: Error in configuration file: %(file_path)s\n  %(error)s\n") % \
+                       {'file_path' : project_pyconf_path, 'error': str(e) }
+                sys.stdout.write(msg)
+                continue
+            projects_cfg.PROJECTS.projects.addMapping(project_name,
+                             src.pyconf.Mapping(projects_cfg.PROJECTS.projects),
+                             "The %s project\n" % project_name)
+            projects_cfg.PROJECTS.projects[project_name]=project_cfg
+            projects_cfg.PROJECTS.projects[project_name]["file_path"] = \
+                                                        project_pyconf_path
+                   
+        merger.merge(cfg, projects_cfg)
+
+        # apply overwrite from command line if needed
+        for rule in self.get_command_line_overrides(options, ["PROJECTS"]):
+            exec('cfg.' + rule) # this cannot be factorized because of the exec
+        
+        # =====================================================================
+        # Create the paths where to search the application configurations, 
+        # the product configurations, the products archives, 
+        # the jobs configurations and the machines configurations
+        cfg.addMapping("PATHS", src.pyconf.Mapping(cfg), "The paths\n")
+        cfg.PATHS["APPLICATIONPATH"] = src.pyconf.Sequence(cfg.PATHS)
+        cfg.PATHS.APPLICATIONPATH.append(cfg.VARS.personal_applications_dir, "")
+        
+        cfg.PATHS["PRODUCTPATH"] = src.pyconf.Sequence(cfg.PATHS)
+        cfg.PATHS.PRODUCTPATH.append(cfg.VARS.personal_products_dir, "")
+        cfg.PATHS["ARCHIVEPATH"] = src.pyconf.Sequence(cfg.PATHS)
+        cfg.PATHS.ARCHIVEPATH.append(cfg.VARS.personal_archives_dir, "")
+        cfg.PATHS["JOBPATH"] = src.pyconf.Sequence(cfg.PATHS)
+        cfg.PATHS.JOBPATH.append(cfg.VARS.personal_jobs_dir, "")
+        cfg.PATHS["MACHINEPATH"] = src.pyconf.Sequence(cfg.PATHS)
+        cfg.PATHS.MACHINEPATH.append(cfg.VARS.personal_machines_dir, "")
+
+        # initialise the path with local directory
+        cfg.PATHS["ARCHIVEPATH"].append(cfg.LOCAL.archive_dir, "")
+
+        # Loop over the projects in order to complete the PATHS variables
+        for project in cfg.PROJECTS.projects:
+            for PATH in ["APPLICATIONPATH",
+                         "PRODUCTPATH",
+                         "ARCHIVEPATH",
+                         "JOBPATH",
+                         "MACHINEPATH"]:
+                if PATH not in cfg.PROJECTS.projects[project]:
+                    continue
+                cfg.PATHS[PATH].append(cfg.PROJECTS.projects[project][PATH], "")
+        
+        # apply overwrite from command line if needed
+        for rule in self.get_command_line_overrides(options, ["PATHS"]):
+            exec('cfg.' + rule) # this cannot be factorized because of the exec
+
+        # =====================================================================
+        # Load APPLICATION config file
+        if application is not None:
+            # search APPLICATION file in all directories in configPath
+            cp = cfg.PATHS.APPLICATIONPATH
+            src.pyconf.streamOpener = ConfigOpener(cp)
+            do_merge = True
+            try:
+                application_cfg = src.pyconf.Config(application + '.pyconf')
+            except IOError as e:
+                raise src.SatException(_("%s, use 'config --list' to get the"
+                                         " list of available applications.") % e)
+            except src.pyconf.ConfigError as e:
+                if (not ('-e' in parser.parse_args()[1]) 
+                                         or ('--edit' in parser.parse_args()[1]) 
+                                         and command == 'config'):
+                    raise src.SatException(
+                        _("Error in configuration file: (1)s.pyconf\n  %(2)s") % \
+                        { 'application': application, 'error': str(e) } )
+                else:
+                    sys.stdout.write(src.printcolors.printcWarning(
+                        "There is an error in the file %s.pyconf.\n" % \
+                        cfg.VARS.application))
+                    do_merge = False
+            except Exception as e:
+                if ( not('-e' in parser.parse_args()[1]) or
+                     ('--edit' in parser.parse_args()[1]) and
+                     command == 'config' ):
+                    sys.stdout.write(src.printcolors.printcWarning("%s\n" % str(e)))
+                    raise src.SatException(
+                        _("Error in configuration file: %s.pyconf\n") % application )
+                else:
+                    sys.stdout.write(src.printcolors.printcWarning(
+                        "ERROR: in file %s.pyconf. Opening the file with the default viewer\n" % \
+                        cfg.VARS.application))
+                    sys.stdout.write("\n%s\n" % src.printcolors.printcWarning(str(e)))
+                    do_merge = False
+        
+            else:
+                cfg['open_application'] = 'yes'
+
+        # =====================================================================
+        # Load product config files in PRODUCTS section
+        products_cfg = src.pyconf.Config()
+        products_cfg.addMapping("PRODUCTS",
+                                src.pyconf.Mapping(products_cfg),
+                                "The products\n")
+        if application is not None:
+            src.pyconf.streamOpener = ConfigOpener(cfg.PATHS.PRODUCTPATH)
+            for product_name in application_cfg.APPLICATION.products.keys():
+                # Loop on all files that are in softsDir directory
+                # and read their config
+                product_file_name = product_name + ".pyconf"
+                product_file_path = src.find_file_in_lpath(product_file_name, cfg.PATHS.PRODUCTPATH)
+                if product_file_path:
+                    products_dir = os.path.dirname(product_file_path)
+                    try:
+                        prod_cfg = src.pyconf.Config(open(product_file_path),
+                                                     PWD=("", products_dir))
+                        prod_cfg.from_file = product_file_path
+                        products_cfg.PRODUCTS[product_name] = prod_cfg
+                    except Exception as e:
+                        msg = _(
+                            "WARNING: Error in configuration file: %(prod)s\n  %(error)s" % \
+                            {'prod' :  product_name, 'error': str(e) })
+                        sys.stdout.write(msg)
+            
+            merger.merge(cfg, products_cfg)
+            
+            # apply overwrite from command line if needed
+            for rule in self.get_command_line_overrides(options, ["PRODUCTS"]):
+                exec('cfg.' + rule) # this cannot be factorized because of the exec
+            
+            if do_merge:
+                merger.merge(cfg, application_cfg)
+
+                # default launcher name ('salome')
+                if ('profile' in cfg.APPLICATION and 
+                    'launcher_name' not in cfg.APPLICATION.profile):
+                    cfg.APPLICATION.profile.launcher_name = 'salome'
+
+                # apply overwrite from command line if needed
+                for rule in self.get_command_line_overrides(options,
+                                                             ["APPLICATION"]):
+                    # this cannot be factorized because of the exec
+                    exec('cfg.' + rule)
+            
+        # =====================================================================
+        # load USER config
+        self.set_user_config_file(cfg)
+        user_cfg_file = self.get_user_config_file()
+        user_cfg = src.pyconf.Config(open(user_cfg_file))
+        merger.merge(cfg, user_cfg)
+
+        # apply overwrite from command line if needed
+        for rule in self.get_command_line_overrides(options, ["USER"]):
+            exec('cfg.' + rule) # this cannot be factorize because of the exec
+        
+        return cfg
+
+    def set_user_config_file(self, config):
+        '''Set the user config file name and path.
+        If necessary, build it from another one or create it from scratch.
+        
+        :param config class 'src.pyconf.Config': The global config 
+                                                 (containing all pyconf).
+        '''
+        # get the expected name and path of the file
+        self.config_file_name = 'SAT.pyconf'
+        self.user_config_file_path = os.path.join(config.VARS.personalDir,
+                                                   self.config_file_name)
+        
+        # if pyconf does not exist, create it from scratch
+        if not os.path.isfile(self.user_config_file_path): 
+            self.create_config_file(config)
+    
+    def create_config_file(self, config):
+        '''This method is called when there are no user config file. 
+           It build it from scratch.
+        
+        :param config class 'src.pyconf.Config': The global config.
+        :return: the config corresponding to the file created.
+        :rtype: config class 'src.pyconf.Config'
+        '''
+        
+        cfg_name = self.get_user_config_file()
+
+        user_cfg = src.pyconf.Config()
+        #
+        user_cfg.addMapping('USER', src.pyconf.Mapping(user_cfg), "")
+
+        user_cfg.USER.addMapping('cvs_user', config.VARS.user,
+            "This is the user name used to access salome cvs base.\n")
+        user_cfg.USER.addMapping('svn_user', config.VARS.user,
+            "This is the user name used to access salome svn base.\n")
+        user_cfg.USER.addMapping('output_verbose_level', 3,
+            "This is the default output_verbose_level you want."
+            " 0=>no output, 5=>debug.\n")
+        user_cfg.USER.addMapping('publish_dir', 
+                                 os.path.join(os.path.expanduser('~'),
+                                 'websupport', 
+                                 'satreport'), 
+                                 "")
+        user_cfg.USER.addMapping('editor',
+                                 'vi', 
+                                 "This is the editor used to "
+                                 "modify configuration files\n")
+        user_cfg.USER.addMapping('browser', 
+                                 'firefox', 
+                                 "This is the browser used to "
+                                 "read html documentation\n")
+        user_cfg.USER.addMapping('pdf_viewer', 
+                                 'evince', 
+                                 "This is the pdf_viewer used "
+                                 "to read pdf documentation\n")
+# CNC 25/10/17 : plus nécessaire a priori
+#        user_cfg.USER.addMapping("base",
+#                                 src.pyconf.Reference(
+#                                            user_cfg,
+#                                            src.pyconf.DOLLAR,
+#                                            'workdir  + $VARS.sep + "BASE"'),
+#                                 "The products installation base (could be "
+#                                 "ignored if this key exists in the local.pyconf"
+#                                 " file of salomTools).\n")
+               
+        # 
+        src.ensure_path_exists(config.VARS.personalDir)
+        src.ensure_path_exists(os.path.join(config.VARS.personalDir, 
+                                            'Applications'))
+
+        f = open(cfg_name, 'w')
+        user_cfg.__save__(f)
+        f.close()
+
+        return user_cfg   
+
+    def get_user_config_file(self):
+        '''Get the user config file
+        :return: path to the user config file.
+        :rtype: str
+        '''
+        if not self.user_config_file_path:
+            raise src.SatException(
+                _("Error in get_user_config_file: missing user config file path") )
+        return self.user_config_file_path     
+
+def check_path(path, ext=[]):
+    '''Construct a text with the input path and "not found" if it does not
+       exist.
+    
+    :param path Str: the path to check.
+    :param ext List: An extension. Verify that the path extension 
+                     is in the list
+    :return: The string of the path with information
+    :rtype: Str
+    '''
+    # check if file exists
+    if not os.path.exists(path):
+        return "'%s' %s" % (path, src.printcolors.printcError(_("** not found")))
+
+    # check extension
+    if len(ext) > 0:
+        fe = os.path.splitext(path)[1].lower()
+        if fe not in ext:
+            return "'%s' %s" % (path, src.printcolors.printcError(_("** bad extension")))
+
+    return path
+
+def show_product_info(config, name, logger):
+    '''Display on the terminal and logger information about a product.
+    
+    :param config Config: the global configuration.
+    :param name Str: The name of the product
+    :param logger Logger: The logger instance to use for the display
+    '''
+    
+    logger.write(_("%s is a product\n") % src.printcolors.printcLabel(name), 2)
+    pinfo = src.product.get_product_config(config, name)
+    
+    if "depend" in pinfo:
+        src.printcolors.print_value(logger, 
+                                    "depends on", 
+                                    ', '.join(pinfo.depend), 2)
+
+    if "opt_depend" in pinfo:
+        src.printcolors.print_value(logger, 
+                                    "optional", 
+                                    ', '.join(pinfo.opt_depend), 2)
+
+    # information on pyconf
+    logger.write("\n", 2)
+    logger.write(src.printcolors.printcLabel("configuration:") + "\n", 2)
+    if "from_file" in pinfo:
+        src.printcolors.print_value(logger, 
+                                    "pyconf file path", 
+                                    pinfo.from_file, 
+                                    2)
+    if "section" in pinfo:
+        src.printcolors.print_value(logger, 
+                                    "section", 
+                                    pinfo.section, 
+                                    2)
+
+    # information on prepare
+    logger.write("\n", 2)
+    logger.write(src.printcolors.printcLabel("prepare:") + "\n", 2)
+
+    is_dev = src.product.product_is_dev(pinfo)
+    method = pinfo.get_source
+    if is_dev:
+        method += " (dev)"
+    src.printcolors.print_value(logger, "get method", method, 2)
+
+    if method == 'cvs':
+        src.printcolors.print_value(logger, "server", pinfo.cvs_info.server, 2)
+        src.printcolors.print_value(logger, "base module",
+                                    pinfo.cvs_info.module_base, 2)
+        src.printcolors.print_value(logger, "source", pinfo.cvs_info.source, 2)
+        src.printcolors.print_value(logger, "tag", pinfo.cvs_info.tag, 2)
+
+    elif method == 'svn':
+        src.printcolors.print_value(logger, "repo", pinfo.svn_info.repo, 2)
+
+    elif method == 'git':
+        src.printcolors.print_value(logger, "repo", pinfo.git_info.repo, 2)
+        src.printcolors.print_value(logger, "tag", pinfo.git_info.tag, 2)
+
+    elif method == 'archive':
+        src.printcolors.print_value(logger, 
+                                    "get from", 
+                                    check_path(pinfo.archive_info.archive_name), 
+                                    2)
+
+    if 'patches' in pinfo:
+        for patch in pinfo.patches:
+            src.printcolors.print_value(logger, "patch", check_path(patch), 2)
+
+    if src.product.product_is_fixed(pinfo):
+        src.printcolors.print_value(logger, "install_dir", 
+                                    check_path(pinfo.install_dir), 2)
+
+    if src.product.product_is_native(pinfo) or src.product.product_is_fixed(pinfo):
+        return
+    
+    # information on compilation
+    if src.product.product_compiles(pinfo):
+        logger.write("\n", 2)
+        logger.write(src.printcolors.printcLabel("compile:") + "\n", 2)
+        src.printcolors.print_value(logger, 
+                                    "compilation method", 
+                                    pinfo.build_source, 
+                                    2)
+        
+        if pinfo.build_source == "script" and "compil_script" in pinfo:
+            src.printcolors.print_value(logger, 
+                                        "Compilation script", 
+                                        pinfo.compil_script, 
+                                        2)
+        
+        if 'nb_proc' in pinfo:
+            src.printcolors.print_value(logger, "make -j", pinfo.nb_proc, 2)
+    
+        src.printcolors.print_value(logger, 
+                                    "source dir", 
+                                    check_path(pinfo.source_dir), 
+                                    2)
+        if 'install_dir' in pinfo:
+            src.printcolors.print_value(logger, 
+                                        "build dir", 
+                                        check_path(pinfo.build_dir), 
+                                        2)
+            src.printcolors.print_value(logger, 
+                                        "install dir", 
+                                        check_path(pinfo.install_dir), 
+                                        2)
+        else:
+            logger.write("  %s\n" % src.printcolors.printcWarning(_("no install dir")) , 2)
+    else:
+        logger.write("\n", 2)
+        msg = _("This product does not compile")
+        logger.write("%s\n" % msg, 2)
+
+    # information on environment
+    logger.write("\n", 2)
+    logger.write(src.printcolors.printcLabel("environ :") + "\n", 2)
+    if "environ" in pinfo and "env_script" in pinfo.environ:
+        src.printcolors.print_value(logger, 
+                                    "script", 
+                                    check_path(pinfo.environ.env_script), 
+                                    2)
+
+    zz = src.environment.SalomeEnviron(config, 
+                                       src.fileEnviron.ScreenEnviron(logger), 
+                                       False)
+    zz.set_python_libdirs()
+    zz.set_a_product(name, logger)
+        
+def show_patchs(config, logger):
+    """
+    Prints all the used patchs in the application.
+    
+    :param config Config: the global configuration.
+    :param logger Logger: The logger instance to use for the display
+    """
+    len_max = max([len(p) for p in config.APPLICATION.products]) + 2
+    msg = ""
+    for product in config.APPLICATION.products:
+        nb = len_max-len(product)-2
+        product_info = src.product.get_product_config(config, product)
+        if src.product.product_has_patches(product_info):
+            msg += "<header>%s: <reset>" % product
+            msg += " "*nb + "%s\n" % product_info.patches[0]
+            if len(product_info.patches) > 1:
+                for patch in product_info.patches[1:]:
+                    msg += " "*nb + "%s\n" % patch
+            msg += "\n"
+    logger.info(msg)
+    return
+
+def getConfigColored(config, path, stream, show_label=False, level=0, show_full_path=False):
+    """
+    get a colored representation value from a config pyconf instance.
+    used recursively from the initial path.
+    
+    :param config class 'src.pyconf.Config': The configuration 
+                                             from which the value is displayed.
+    :param path str : the path in the configuration of the value to print.
+    :param show_label boolean: if True, do a basic display. 
+                               (useful for bash completion)
+    :param stream: the output stream used
+    :param level int: The number of spaces to add before display.
+    :param show_full_path: display full path, else relative
+    """           
+    
+    # Make sure that the path does not ends with a point
+    if path.endswith('.'):
+        path = path[:-1]
+    
+    # display all the path or not
+    if show_full_path:
+        vname = path
+    else:
+        vname = path.split('.')[-1]
+
+    # number of spaces before the display
+    tab_level = "  " * level
+    
+    # call to the function that gets the value of the path.
+    try:
+        val = config.getByPath(path)
+    except Exception as e:
+        stream.write(tab_level)
+        stream.write("<header>%s: <red>ERROR %s<reset>\n" % (vname, str(e)))
+        return
+
+    # in this case, display only the value
+    if show_label:
+        stream.write(tab_level)
+        stream.write("<header%s: <reset>" % vname)
+
+    # The case where the value has under values, 
+    # do a recursive call to the function
+    if dir(val).__contains__('keys'):
+        if show_label: strean.write("\n")
+        for v in sorted(val.keys()):
+            print_value(config, path + '.' + v, stream, show_label, level + 1)
+    elif val.__class__ == src.pyconf.Sequence or isinstance(val, list): 
+        # in this case, value is a list (or a Sequence)
+        if show_label: stream.write("\n")
+        index = 0
+        for v in val:
+            p = path + "[" + str(index) + "]"
+            print_value(config, p, stream, show_label, level + 1)
+            index += 1
+    else: # case where val is just a str
+        stream.write("%s\n" % val)
+        
+def print_value(config, path, logger, show_label=False, level=0, show_full_path=False):
+    """
+    print a colored representation value from a config pyconf instance.
+    used recursively from the initial path.
+    
+    :param see getConfigColored
+    """           
+    outStream = DBG.OutStream()
+    getConfigColored(config, path, outStream, show_label, level, show_full_path)
+    res = outStream.value
+    logger.info(res)
+    return
+
+     
+def print_debug(config, path, logger, show_label=False, level=0, show_full_path=False):
+    """
+    logger output for debugging a config/pyconf
+    lines contains:
+       path : expression --> 'evaluation'
+    example:
+      .PROJECTS.projects.salome.project_path : $PWD --> '/tmp/SALOME'
+    """
+    path = str(aPath)
+    if path == "." :
+      val = config
+      path = ""
+    else:
+      if path.endswith('.'): # Make sure that the path does not ends with a point
+        path = path[:-1]
+      val = config.getByPath(path)
+      
+    outStream = DBG.OutStream()
+    DBG.saveConfigDbg(val, outStream, path=path)
+    res = outStream.value
+    logger.info(res)
+    return
+
+
+def get_config_children(config, args):
+    """
+    Gets the names of the children of the given parameter.
+    Useful only for completion mechanism
+    
+    :param config Config: The configuration where to read the values
+    :param args: The path in the config from which get the keys
+    """
+    vals = []
+    rootkeys = config.keys()
+    
+    if len(args) == 0:
+        # no parameter returns list of root keys
+        vals = rootkeys
+    else:
+        parent = args[0]
+        pos = parent.rfind('.')
+        if pos < 0:
+            # Case where there is only on key as parameter.
+            # For example VARS
+            vals = [m for m in rootkeys if m.startswith(parent)]
+        else:
+            # Case where there is a part from a key
+            # for example VARS.us  (for VARS.user)
+            head = parent[0:pos]
+            tail = parent[pos+1:]
+            try:
+                a = config.getByPath(head)
+                if dir(a).__contains__('keys'):
+                    vals = map(lambda x: head + '.' + x,
+                               [m for m in a.keys() if m.startswith(tail)])
+            except:
+                pass
+
+    for v in sorted(vals):
+        sys.stdout.write("%s\n" % v)
+
+
+def _getConfig(self, appliToLoad):
+        '''The function that will load the configuration (all pyconf)
+        and returns the config from some files .pyconf
+        '''
+        if self.runner.config is not None:
+          raise Exception("config existing yet in '%s' instance" % self.runner.getClassName())
+          
+
+        # read the configuration from all the pyconf files    
+        cfgManager = getConfigManager() # commands.config.ConfigManager()
+        DBG.write("appli to load", appliToLoad, True)
+        config = cfgManager.get_config(datadir=self.runner.datadir, 
+                                       application=appliToLoad, 
+                                       options=self.runner.options, 
+                                       command=self.name)
+        self.runner.nameAppliLoaded = appliToLoad
+        # DBG.write("appli loaded", config, True)
+                       
+        # Set the verbose mode if called
+        DBG.tofix("verbose/batch/logger_add_link -1/False/None", True)
+        verbose = -1
+        batch = False
+        logger_add_link = None
+        if verbose > -1:
+            verbose_save = self.options.output_verbose_level
+            self.options.__setattr__("output_verbose_level", verbose)    
+
+        # Set batch mode if called
+        if batch:
+            batch_save = self.options.batch
+            self.options.__setattr__("batch", True)
+
+        # set output level
+        if self.runner.options.output_verbose_level is not None:
+            config.USER.output_verbose_level = self.runner.options.output_verbose_level
+        if config.USER.output_verbose_level < 1:
+            config.USER.output_verbose_level = 0
+        silent = (config.USER.output_verbose_level == 0)
+
+        # create log file
+        micro_command = False
+        if logger_add_link:
+            micro_command = True
+        logger_command = src.logger.Logger(config, 
+                           silent_sysstd=silent,
+                           all_in_terminal=self.runner.options.all_in_terminal,
+                           micro_command=micro_command)
+        
+        # Check that the path given by the logs_paths_in_file option
+        # is a file path that can be written
+        if self.runner.options.logs_paths_in_file and not micro_command:
+            try:
+                self.options.logs_paths_in_file = os.path.abspath(
+                                        self.options.logs_paths_in_file)
+                dir_file = os.path.dirname(self.options.logs_paths_in_file)
+                if not os.path.exists(dir_file):
+                    os.makedirs(dir_file)
+                if os.path.exists(self.options.logs_paths_in_file):
+                    os.remove(self.options.logs_paths_in_file)
+                file_test = open(self.options.logs_paths_in_file, "w")
+                file_test.close()
+            except Exception as e:
+                msg = _("WARNING: the logs_paths_in_file option will "
+                        "not be taken into account.\nHere is the error:")
+                logger_command.write("%s\n%s\n\n" % (
+                                     src.printcolors.printcWarning(msg),
+                                     str(e)))
+                self.options.logs_paths_in_file = None
+                
+        return config
+
+def get_products_list(self, options, cfg, logger):
+        '''method that gives the product list with their informations from 
+           configuration regarding the passed options.
+        
+        :param options Options: The Options instance that stores the commands 
+                                arguments
+        :param config Config: The global configuration
+        :param logger Logger: The logger instance to use for the display and logging
+        :return: The list of (product name, product_informations).
+        :rtype: List
+        '''
+        # Get the products to be prepared, regarding the options
+        if options.products is None:
+            # No options, get all products sources
+            products = cfg.APPLICATION.products
+        else:
+            # if option --products, check that all products of the command line
+            # are present in the application.
+            products = options.products
+            for p in products:
+                if p not in cfg.APPLICATION.products:
+                    raise Exception(_("Product %(product)s "
+                                "not defined in application %(application)s") %
+                            { 'product': p, 'application': cfg.VARS.application} )
+        
+        # Construct the list of tuple containing 
+        # the products name and their definition
+        products_infos = src.product.get_products_infos(products, cfg)
+        
+        return products_infos
\ No newline at end of file
index dbf7e67d4160d50642642a6827afb4aac6c204fd..9a9056d479976ca8bdc3664f6b69e1e08781cde6 100644 (file)
@@ -38,6 +38,10 @@ import pprint as PP
 
 _debug = [False] #support push/pop for temporary activate debug outputs
 
+_user = os.environ['USER']
+_developpers = ["christian", "wambeke", ] # crouzet, kloss ...
+
+
 def indent(text, amount=2, ch=' '):
     """indent multi lines message"""
     padding = amount * ch
@@ -46,8 +50,10 @@ def indent(text, amount=2, ch=' '):
 def write(title, var="", force=None, fmt="\n#### DEBUG: %s:\n%s\n"):
     """write sys.stderr a message if _debug[-1]==True or optionaly force=True"""
     if _debug[-1] or force:
-        if 'src.pyconf.Config' in str(type(var)): 
+        if 'pyconf.Config' in str(type(var)): 
             sys.stderr.write(fmt % (title, indent(getStrConfigDbg(var))))
+        if 'loggingSat.UnittestStream' in str(type(var)): 
+            sys.stderr.write(fmt % (title, indent(var.getLogs())))
         elif type(var) is not str:
             sys.stderr.write(fmt % (title, indent(PP.pformat(var))))
         else:
index 1101bdfcb62c19aa4db41c968b5ec05102472d1a..692522d1fab3275401459245e9c80299d2df9fe4 100644 (file)
@@ -42,46 +42,38 @@ msgid "batch mode (no question)."
 msgstr "mode batch (pas de question)."
 
 msgid "all traces in the terminal (for example compilation logs)."
-msgstr "toutes traces dans le terminal (par exemple: log de compilation)"
+msgstr "toutes traces dans le terminal (par exemple: log de compilation)."
 
-msgid "put the command result and paths to log files."
+msgid "put the command result and paths to log files"
 msgstr "redirige resultats de commandes vers log files"
 
 msgid " is not a valid command"
 msgstr " n'est pas une commande valide"
 
-msgid ""
-"WARNING: the logs_paths_in_file option will not be taken into account.\n"
-"Here is the error:"
-msgstr ""
+msgid "the 'logs_paths_in_file' option will not be taken into account:"
+msgstr "l'option 'logs_paths_in_file' ne sera pas prise en compte:"
 
-msgid "Usage: "
-msgstr "Utilisation : "
+msgid "Usage:"
+msgstr "Utilisation:"
 
-msgid "Available commands are:\n"
-msgstr "Les commandes disponibles sont:\n"
+msgid "Available commands are:"
+msgstr "Les commandes disponibles sont:"
 
-msgid ""
-"\n"
-"Getting the help for a specific command: "
-msgstr ""
-"\n"
-"Obtenir l'aide d'une commande spécifique : "
+msgid "Getting help for a specific command: "
+msgstr "Obtenir l'aide d'une commande spécifique: "
 
-msgid "lsb_release not installed\n"
-msgstr "lsb_release n'est pas installé\n"
+msgid "'lsb_release' is not installed"
+msgstr "'lsb_release' n'est pas installé"
 
-msgid "You can define $LSB_PATH to give the path to lsb_release\n"
-msgstr "Vous pouvez définir $LSB_PATH pour donner le chemin vers lsb_release\n"
+msgid "You can define $LSB_PATH to give the path to lsb_release"
+msgstr "Vous pouvez définir $LSB_PATH pour donner le chemin vers lsb_release"
 
 #, python-format
-msgid "Unknown distribution: '%s'\n"
-msgstr "Distribution inconnue : '%s'\n"
+msgid "Unknown distribution: '%s'"
+msgstr "Distribution inconnue : '%s'"
 
-msgid "Please add your distribution to src/internal_config/distrib.pyconf\n"
-msgstr ""
-"SVP ajoutez votre distribution au fichier src/internal_config/distrib."
-"pyconf\n"
+msgid "Add your distribution to src/internal_config/distrib.pyconf"
+msgstr "Ajoutez votre distribution au fichier src/internal_config/distrib.pyconf"
 
 msgid " is not a valid option"
 msgstr " n'est pas une option valide"
index 2ac44a0c9307fbe4bcbf22b337a877569fc74492..30f1a5e6fbc26feb31e9803b9a92acc0b40c3f63 100755 (executable)
@@ -16,6 +16,7 @@ import os
 import sys
 import logging
 import pprint as PP
+import src.coloringSat as COLS
 
 _verbose = False
 _name = "loggingSat"
@@ -37,6 +38,7 @@ log("import logging on %s" % logging.__file__)
 _loggerDefaultName = 'SatDefaultLogger'
 _loggerUnittestName = 'SatUnittestLogger'
 
+
 def getDefaultLogger():
   log("getDefaultLogger %s" % _loggerDefaultName)
   return logging.getLogger(_loggerDefaultName)
@@ -53,18 +55,34 @@ _loggerUnittest = getUnittestLogger()
 
 
 class DefaultFormatter(logging.Formatter):
+  
+  # to set color prefix, problem with indent format
+  _ColorLevelname = {
+    "DEBUG": "<blue>",
+    "INFO": "<green>",
+    "WARNING": "<red>",
+    "ERROR": "<yellow>",
+    "CRITICAL": "<yellow>",
+  }
+  
   def format(self, record):
-    # print "", record.levelname #type(record), dir(record)
-    if record.levelname == "INFO": 
-      return str(record.msg)
+    if record.levelname == "INFO":
+      res = str(record.msg)
     else:
-      return indent(super(DefaultFormatter, self).format(record), 12)
+      #record.levelname = self.setColorLevelname(record.levelname)
+      res = indent(super(DefaultFormatter, self).format(record), 12)
+    return COLS.toColor(res)
+  
+  def setColorLevelname(self, levelname):
+    return self._ColorLevelname[levelname] + levelname + "<reset>"
+
 
 class UnittestFormatter(logging.Formatter):
   def format(self, record):
     # print "", record.levelname #type(record), dir(record)
     nb = len("2018-03-17 12:15:41 :: INFO     :: ")
-    return indent(super(UnittestFormatter, self).format(record), nb)
+    res = indent(super(UnittestFormatter, self).format(record), nb)
+    return COLS.toColor(res)
 
 
 class UnittestStream(object):
@@ -75,17 +93,25 @@ class UnittestStream(object):
   https://stackoverflow.com/questions/31999627/storing-logger-messages-in-a-string
   """
   def __init__(self):
-    self.logs = ''
+    self._logs = ''
+    
+  def getLogs(self):
+    return self._logs
+  
+  def getLogsAndClear(self):
+    res = self._logs
+    self._logs = ''
+    return res
 
   def write(self, astr):
     # log("UnittestStream.write('%s')" % astr)
-    self.logs += astr
+    self._logs += astr
 
   def flush(self):
     pass
 
   def __str__(self):
-    return self.logs
+    return self._logs
 
 
 def initLoggerAsDefault(logger, fmt=None, level=None):
@@ -94,7 +120,7 @@ def initLoggerAsDefault(logger, fmt=None, level=None):
   exept info() outed 'as it' without any format
   """
   log("initLoggerAsDefault name=%s\nfmt='%s' level='%s'" % (logger.name, fmt, level))
-  handler = logging.StreamHandler() # Logging vers console
+  handler = logging.StreamHandler(sys.stdout) # Logging vers console
   if fmt is not None:
     # formatter = logging.Formatter(fmt, "%Y-%m-%d %H:%M:%S")
     formatter = DefaultFormatter(fmt, "%y-%m-%d %H:%M:%S")
@@ -120,7 +146,9 @@ def initLoggerAsUnittest(logger, fmt=None, level=None):
     formatter = UnittestFormatter(fmt, "%Y-%m-%d %H:%M:%S")
     handler.setFormatter(formatter)
   logger.addHandler(handler)
-  logger.streamUnittest = stream
+  logger.stream = stream
+  logger.getLogs = stream.getLogs
+  logger.getLogsAndClear = stream.getLogsAndClear
   if level is not None:
     logger.setLevel(level)
   else:
@@ -135,16 +163,17 @@ def testLogger_1(logger):
   logger.warning('test logger warning')
   logger.error('test logger error')
   logger.critical('test logger critical')
-  logger.info('test logger info:\n- second line\n- third line')
+  logger.info('\ntest logger info: no indent\n- second line\n- third line\n')
   logger.warning('test logger warning:\n- second line\n- third line')
 
   
 if __name__ == "__main__":
-  print("\n**** DEFAULT")
+  print("\n**** DEFAULT logger")
   logdef = getDefaultLogger()
+  # problem if add +2? if append 2 setColorLevelname <color><reset>, not fixed
   initLoggerAsDefault(logdef, '%(levelname)-8s :: %(message)s', level=logging.INFO)
   testLogger_1(logdef)
-  print("\n**** UNITTEST")
+  print("\n**** UNITTEST logger")
   loguni = getUnittestLogger()
   initLoggerAsUnittest(loguni, '%(asctime)s :: %(levelname)-8s :: %(message)s', level=logging.DEBUG)
   testLogger_1(loguni) # is silent
@@ -153,5 +182,10 @@ if __name__ == "__main__":
   
   from colorama import Fore as FG
   from colorama import Style as ST
-  print("this is %scolored%s!" % (FG.G))
-  
\ No newline at end of file
+  print("this is %scolored in green%s !!!" % (FG.GREEN, ST.RESET_ALL))
+  
+else:  
+  _loggerDefault = getDefaultLogger()
+  _loggerUnittest = getUnittestLogger()
+  initLoggerAsDefault(_loggerDefault, '%(levelname)-8s :: %(message)s', level=logging.INFO)
+  initLoggerAsUnittest(_loggerUnittest, '%(asctime)s :: %(levelname)-8s :: %(message)s', level=logging.DEBUG)
index ac7270ee7837270ac0aacce84655552da665d66c..714fcc46c21dc02a5a340b90029d2e64affcf82e 100644 (file)
 #  You should have received a copy of the GNU Lesser General Public
 #  License along with this library; if not, write to the Free Software
 #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
-'''The Options class that manages the access to all options passed as 
-   parameters in salomeTools command lines
-'''
+
+"""\
+The Options class that manages the access to all options passed as 
+parameters in salomeTools command lines
+"""
+
 import getopt
 import sys
 import pprint as PP
 
 import src
 import src.debug as DBG # Easy print stderr (for DEBUG only)
-import src.printcolors
 
 class OptResult(object):
-    '''An instance of this class will be the object manipulated
-       in code of all salomeTools commands
-       The aim of this class is to have an elegant syntax 
-       to manipulate the options. 
-       ex: 
-       print(options.level)
-       5
-    '''
+    """
+    An instance of this class will be the object manipulated
+    in code of all salomeTools commands
+    The aim of this class is to have an elegant syntax to manipulate the options.
+    
+    example: 
+      >> print(options.level)
+      >> 5
+    """
     def __init__(self):
         '''Initialization
         '''
@@ -99,6 +102,13 @@ class Options(object):
         :return: Nothing.
         :rtype: N\A
         '''
+        tmp = [o['shortName'] for o in self.options if o['shortName'] != '']
+        if shortName in tmp: 
+          raise Exception("option '-%s' existing yet" % shortName)
+        tmp = [o['longName'] for o in self.options if o['longName'] != '']
+        if longName in tmp: 
+          raise Exception("option '--%s' existing yet" % longName)
+
         option = dict()
         option['shortName'] = shortName
         option['longName'] = longName
@@ -111,6 +121,7 @@ class Options(object):
         option['destName'] = destName
         option['helpString'] = helpString
         option['result'] = default
+        
         self.options.append(option)
 
     def get_help(self):
@@ -127,7 +138,7 @@ class Options(object):
 
         # for all options, gets its values. 
         # "shortname" is an optional field of the options 
-        msg += src.printcolors.printcHeader(_("Available options are:")) + "\n"
+        msg += "<header>" + _("Available options are:") + "<reset>\n"
         for option in self.options:
             if 'shortName' in option and len(option['shortName']) > 0:
                 msg +=  "\n -%(shortName)1s, --%(longName)s" \
@@ -137,9 +148,6 @@ class Options(object):
                        % option
         return msg
                        
-    def print_help(self):
-        print(self.get_help())
-
 
     def parse_args(self, argList=None):
         '''Method that instantiates the class OptResult 
@@ -177,7 +185,7 @@ class Options(object):
         try:
           optlist, args = getopt.getopt(argList, shortNameOption, longNameOption)
         except Exception as e:
-          msg = str(e) + ", expected:\n\n%s" % str(self)
+          msg = str(e) + "\n\n" + self.get_help()
           raise Exception(msg)
 
         # instantiate and completing the optResult that will be returned
index a009fdb136ec18946bde3ee1f00b4ae0a2a35a82..12e51018f7c1ebd37dad65bff9296c9918366f36 100755 (executable)
@@ -18,7 +18,7 @@
 #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 
 '''This file is the main entry file to salomeTools
-NO __main__ entry allowed, use sat
+NO __main__ entry allowed, use 'sat' (in parent directory)
 '''
 
 ########################################################################
@@ -39,9 +39,9 @@ import traceback
 import subprocess as SP
 import pprint as PP
 
+import src # for __version__
 import src.debug as DBG # Easy print stderr (for DEBUG only)
 import src.returnCode as RCO # Easy (ok/ko, why) return methods code
-from src.exceptionSat import ExceptionSat
 
 # get path to src
 rootdir = os.path.realpath( os.path.join(os.path.dirname(__file__), "..") )
@@ -50,7 +50,7 @@ srcdir = os.path.join(rootdir, "src")
 cmdsdir = os.path.join(rootdir, "commands")
 
 # load resources for internationalization
-gettext.install('salomeTools', os.path.join(srcdir, 'i18n'))
+gettext.install("salomeTools", os.path.join(srcdir, "i18n"))
 
 # The possible hooks : 
 # pre is for hooks to be executed before commands
@@ -64,69 +64,91 @@ _LANG = os.environ["LANG"] # original locale
 # utility methods
 ########################################################################
 def find_command_list(dirPath):
-    '''Parse files in dirPath that end with .py : it gives commands list
+    """
+    Parse files in dirPath that end with '.py' : it gives commands list
     
     :param dirPath str: The directory path where to search the commands
     :return: cmd_list : the list containing the commands name 
     :rtype: list
-    '''
+    """
     cmd_list = []
     for item in os.listdir(dirPath):
         if item in ["__init__.py"]: #avoid theses files
             continue
-        if item.endswith('.py'):
-            cmd_list.append(item[:-len('.py')])
-    return cmd_list
+        if item.endswith(".py"):
+            cmd_list.append(item[:-len(".py")])
+    return sorted(cmd_list)
 
 # The list of valid salomeTools commands from cmdsdir
 #_COMMANDS_NAMES = ['config', 'compile', 'prepare',...]
 _COMMANDS_NAMES = find_command_list(cmdsdir)
 
 def getCommandsList():
-    """Gives commands list (as basename of files cmdsdir/*.py)
-    """ 
+    """Gives commands list (as basename of files cmdsdir/*.py)""" 
     return _COMMANDS_NAMES
 
 def launchSat(command):
-    """launch sat as subprocess popen
+    """
+    launch sat as subprocess popen
     command as string ('sat --help' for example)
     used for unittest, or else...
     returns tuple (stdout, stderr)
     """
     if "sat" not in command.split()[0]:
       raise Exception(_("Not a valid command for launchSat: '%s'") % command)
-    env = dict(os.environ)
-    env["PATH"] = rootdir + ":" + env["PATH"]
+    env = dict(os.environ) #copy
+    # theorically useless
+    # env["PATH"] = rootdir + ":" + env["PATH"]
     res =SP.Popen(command, shell=True, env=env, stdout=SP.PIPE, stderr=SP.PIPE).communicate()
     return res
 
 def setNotLocale():
     """force english at any moment"""
     os.environ["LANG"] = ''
-    gettext.install('salomeTools', os.path.join(srcdir, 'i18n'))
+    gettext.install("salomeTools", os.path.join(srcdir, "i18n"))
     DBG.write("setNotLocale", os.environ["LANG"])
     
 def setLocale():
     """reset initial locale at any moment 
-    'fr' or else 'TODO' from initial environment var '$LANG'
+    'fr' or else (TODO) from initial environment var '$LANG'
+    'i18n' as 'internationalization'
     """
     os.environ["LANG"] = _LANG
-    gettext.install('salomeTools', os.path.join(srcdir, 'i18n'))
+    gettext.install("salomeTools", os.path.join(srcdir, "i18n"))
     DBG.write("setLocale", os.environ["LANG"])
     
+def getVersion():
+    """get version number as string"""
+    return src.__version__
+def assumeAsList(strOrList):
+    """return a list as sys.argv if string"""
+    if type(strOrList) is list:
+      return list(strOrList) # copy
+    else:
+      res = strOrList.split(" ")
+      return [r for r in res if r != ""] # supposed string to split for convenience
 
 ########################################################################
 # _BaseCmd class
 ########################################################################
 class _BaseCommand(object):
-    """_BaseCmd is the base class for all inherited commands of salomeTools
+    """
+    _BaseCmd is the base class for all inherited commands of salomeTools
     instancied as classes 'Command' in files '.../commands/*.py'
     """
-    def __init__(self, name):
-        self.name = name
-        self.runner = None # runner (as caller) usually as Sat instance
-        # self.config = None # config pyconf usually loaded with _getConfig method
-        self.logger = None # logger (from caller) usually as Sat instance logger
+  
+    # supposed never seen, set "config", "prepare"... in inherited commands
+    name = "salomeTools"
+    
+    def __init__(self, runner):
+        # runner (as caller) usually as Sat instance
+        self._runner = runner
+        # config pyconf usually loaded in runner, but sometimes local value
+        self._config = None
+        # logger (from caller) usually as Sat instance logger, but sometimes local value
+        self._logger = runner.logger
+        self._options = None
         
     def getClassName(self):
         """
@@ -135,230 +157,117 @@ class _BaseCommand(object):
         '.../commands/config.py' or '.../commands/prepare.py'
         """
         return "%s.%s" % (self.name, self.__class__.__name__)
-        
+
     def __repr__(self):
         tmp = PP.pformat(self.__dict__)
         res = "%s(\n %s)\n" % (self.getClassName(), tmp[1:-1])
         return res
 
     def run(self, args):
-        return RCO.ReturnCode("KO", "_BaseCommand.run() have to be inherited")
-    
-    def setRunner(self, runner):
-        """set who owns me, and use me whith method run()"""
-        self.runner  = runner
-        
+        """
+        virtual example method for Command instance
+        have to return RCO.ReturnCode()
+        """
+        return RCO.ReturnCode("KO", "_BaseCommand.run() have not to be instancied and called")
+           
     def setLogger(self, logger):
         """set logger for run command"""
-        self.logger = logger
-        
+        if self._logger is not None:
+          # supposed logger.debug for future
+          self._logger.warning("change logger for %s, are you sure" % self.getClassName())
+        self._logger = logger
+            
     def getLogger(self):
-        if self.logger is None: # could use runner Sat instance logger
-          return self.runner.getLogger()
-        else:                   # could use local logger
-          return self.logger
-        
+        if self._logger is None:
+          raise Exception("%s instance needs self._logger not None, fix it." % self.getClassName())
+        else:
+          return self._logger
+
+    def getOptions(self):
+        if self._options is None:
+          raise Exception("%s instance needs self._option not None, fix it." % self.getClassName())
+        else:
+          return self._options
+
     def getRunner(self):
-        if self.runner is None:
-          raise Exception("have to set runner attribute, fix it.")
+        if self._runner is None:
+          raise Exception("%s instance needs self.runner not None, fix it." % self.getClassName())
         else:
-          return self.runner
+          return self._runner
+
+    def getConfig(self):
+        """
+        supposedly (for now) no multiply local config(s)
+        only one config in runner.config
+        may be some for future...
+        """
+        if self._runner.config is None:
+          self._logger.error("%s instance have runner.config None, fix it." % self.getClassName())
+        return self._runner.config
+
+    def assumeAsList(self, strOrList):
+        return assumeAsList(strOrList)
                   
     def getParser(self):
         raise Exception("_BaseCmd class have not to be instancied, only for inheritage")
 
-    def parse_args(self, args):
-        """smart parse command arguments skipping first argument name appli to load if present"""
-        parser = self.getParser()
-        if type(args) is list:
-          argList = args
-        else:
-          argList = args.split(' ')
-        DBG.write("%s args" % self.name, args, True)
-        # or if args[0][0] == "-": #as argument name appli without "--"
-        if self.runner.nameAppliLoaded is None:
-          (options, argsc) = parser.parse_args(args)
-        else:
-          (options, argsc) = parser.parse_args(args[1:]) # skip name appli
-        DBG.write("%s options" % self.name, options)
-        DBG.write("%s remainders args" % self.name, argsc)
-        if argsc != []:
-          self.getLogger().error("\n\ncommand '%s' remainders args %s\n\n" % (self.name, argsc))
-        return (options, argsc)
+    def parseArguments(self, cmd_arguments):
+        """
+        smart parse command arguments skip
+        first argument name appli to load, if present
+        """
+        argList = self.assumeAsList(cmd_arguments)
+        DBG.write("%s.Command arguments" % self.name, argList)
+        commandOptions, remaindersArgs = self.getParser().parse_args(argList)
+        DBG.write("%s.Command options" % self.name, commandOptions)
+        DBG.write("%s.Command remainders arguments" % self.name, remaindersArgs)
+        if remaindersArgs != []:
+          self.getLogger().error("%s.Command have unknown remainders arguments:\n%s\n" % \
+                                 (self.name, remaindersArgs))
+        return commandOptions, remaindersArgs
     
     def description(self):
-        '''method that is called when salomeTools is called with --help option.
-        
-        :return: The text to display for the config command description.
-        :rtype: str
-        '''
-        raise Exception("_BaseCmd class have not to be instancied, only for inheritage")
+        """
+        method called when salomeTools have '--help' argument.
+        returns The text to display for the command description
+        which is current Command class docstring 'self.__doc__',
+        with traduction
+        """
+        return _(self.__doc__)
     
-    def run(self, args, runner, logger):
-        '''method that is called when salomeTools is called with self.name parameter.
-        '''
-        raise Exception("_BaseCmd class have not to be instancied, only for inheritage")
-
-    def getConfig(self):
-        if self.runner.config is None:
-          self.runner.config = self._getConfig()
-        #DBG.write("_baseCommand runner", self.runner)
-        DBG.write("_baseCommand runner.config", self.runner.config)
-        return self.runner.config
-
-    def _getConfig(self):
-        '''The function that will load the configuration (all pyconf)
-        and returns the config from files .pyconf
-        '''
-        if self.runner.config is not None:
-          raise Exception("config existing yet in 's' instance" % self.runner.getClassName())
-          
-        # Get the arguments in a list and remove the empty elements
-        # DBG.write("%s.runner.arguments" % self.name, self.runner.arguments)
-
-        self.parser = self.getParser() 
-        try:
-            options, args = self.parser.parse_args(self.runner.arguments[1:])
-            DBG.write("%s args" % self.name, args)
-            DBG.write("%s options" % self.name, options)    
-        except Exception as exc:
-            write_exception(exc)
-            sys.exit(RCO.KOSYS)
-
-        self.arguments = args # args are postfixes options: args[0] is the 'commands' command
-        self.options = options # the options passed to salomeTools
-          
-        if type(args) == type(''):
-            # split by spaces without considering spaces in quotes
-            argv_0 = re.findall(r'(?:"[^"]*"|[^\s"])+', args)
-        else:
-            argv_0 = args
-        
-        if argv_0 != ['']:
-            while "" in argv_0: argv_0.remove("")
-        
-        # Format the argv list in order to prevent strings 
-        # that contain a blank to be separated
-        argv = []
-        elem_old = ""
-        for elem in argv_0:
-            if argv == [] or elem_old.startswith("-") or elem.startswith("-"):
-                argv.append(elem)
-            else:
-                argv[-1] += " " + elem
-            elem_old = elem
-                   
-        # if it is provided by the command line, get the application
-        appliToLoad = None
-        if argv not in [[''], []] and argv[0][0] != "-":
-            appliToLoad = argv[0].rstrip('*')
-            argv = argv[1:]
-        
-        # Check if the global options of salomeTools have to be changed
-        if options:
-            options_save = self.options
-            self.options = options  
-
-        # read the configuration from all the pyconf files    
-        cfgManager = getConfigManager() # commands.config.ConfigManager()
-        DBG.write("appli to load", appliToLoad, True)
-        config = cfgManager.get_config(datadir=self.runner.datadir, 
-                                       application=appliToLoad, 
-                                       options=self.runner.options, 
-                                       command=self.name) # command=__nameCmd__)
-        self.runner.nameAppliLoaded = appliToLoad
-        # DBG.write("appli loaded", config, True)
-                       
-        # Set the verbose mode if called
-        DBG.tofix("verbose/batch/logger_add_link -1/False/None", True)
-        verbose = -1
-        batch = False
-        logger_add_link = None
-        if verbose > -1:
-            verbose_save = self.options.output_verbose_level
-            self.options.__setattr__("output_verbose_level", verbose)    
-
-        # Set batch mode if called
-        if batch:
-            batch_save = self.options.batch
-            self.options.__setattr__("batch", True)
-
-        # set output level
-        if self.runner.options.output_verbose_level is not None:
-            config.USER.output_verbose_level = self.runner.options.output_verbose_level
-        if config.USER.output_verbose_level < 1:
-            config.USER.output_verbose_level = 0
-        silent = (config.USER.output_verbose_level == 0)
-
-        # create log file
-        micro_command = False
-        if logger_add_link:
-            micro_command = True
-        logger_command = src.logger.Logger(config, 
-                           silent_sysstd=silent,
-                           all_in_terminal=self.runner.options.all_in_terminal,
-                           micro_command=micro_command)
-        
-        # Check that the path given by the logs_paths_in_file option
-        # is a file path that can be written
-        if self.runner.options.logs_paths_in_file and not micro_command:
-            try:
-                self.options.logs_paths_in_file = os.path.abspath(
-                                        self.options.logs_paths_in_file)
-                dir_file = os.path.dirname(self.options.logs_paths_in_file)
-                if not os.path.exists(dir_file):
-                    os.makedirs(dir_file)
-                if os.path.exists(self.options.logs_paths_in_file):
-                    os.remove(self.options.logs_paths_in_file)
-                file_test = open(self.options.logs_paths_in_file, "w")
-                file_test.close()
-            except Exception as e:
-                msg = _("WARNING: the logs_paths_in_file option will "
-                        "not be taken into account.\nHere is the error:")
-                logger_command.write("%s\n%s\n\n" % (
-                                     src.printcolors.printcWarning(msg),
-                                     str(e)))
-                self.options.logs_paths_in_file = None
-                
-        return config
+    def run(self, cmd_arguments):
+        """
+        method called when salomeTools processes command(s) parameters"""
+        raise Exception("_BaseCmd class have not to be instancied, useful only for inheritage")
 
-    def get_products_list(self, options, cfg, logger):
-        '''method that gives the product list with their informations from 
-           configuration regarding the passed options.
-        
-        :param options Options: The Options instance that stores the commands 
-                                arguments
-        :param config Config: The global configuration
-        :param logger Logger: The logger instance to use for the display and logging
-        :return: The list of (product name, product_informations).
-        :rtype: List
-        '''
-        # Get the products to be prepared, regarding the options
-        if options.products is None:
-            # No options, get all products sources
-            products = cfg.APPLICATION.products
-        else:
-            # if option --products, check that all products of the command line
-            # are present in the application.
-            products = options.products
-            for p in products:
-                if p not in cfg.APPLICATION.products:
-                    raise src.SatException(_("Product %(product)s "
-                                "not defined in application %(application)s") %
-                            { 'product': p, 'application': cfg.VARS.application} )
-        
-        # Construct the list of tuple containing 
-        # the products name and their definition
-        products_infos = src.product.get_products_infos(products, cfg)
+    def print_help(self):
+        """
+        Prints help for a command. Function called with 
+        'sat --help <command>' or
+        'sat --help <command> --help' or
+        'sat <command>' without any trailing arguments
+        """
+        msg = self.get_help()
+        self._logger.info(msg)
+            
+    def get_help(self):
+        """get string help for inherited Command classes"""
+        version = getVersion() + "\n\n" # salomeTools version
+        msg = "<header>Version:<reset> " + version
+        # description of the command that is done in the command.py file
+        msg += "<header>Description:<reset>\n"
+        msg += self.description() + "\n\n"
         
-        return products_infos
-
+        # description of the command options
+        msg += self.getParser().get_help() + "\n"
+        return msg
 
 ########################################################################
 # Sat class
 ########################################################################
 class Sat(object):
     """The main class that stores all the commands of salomeTools
+    (usually known as 'runner' argument in Command classes)
     """
     def __init__(self, logger):
         """Initialization
@@ -373,8 +282,9 @@ class Sat(object):
 
         self.CONFIG_FILENAME = "sat-config.pyconf"
         
+        self.configManager = None # the config Manager that will be used to set self.config
         self.config = None # the config that will be read using pyconf module
-        self.logger = None # the logger that will be use
+        self.logger = logger # the logger that will be use
         self.arguments = None # args are postfixes options: args[0] is the 'commands' command
         self.options = None # the options passed to salomeTools
         
@@ -404,19 +314,16 @@ class Sat(object):
         if self.logger is None: # could use owner Sat instance logger
           import src.loggingSat as LOG
           self.logger=LOG.getDefaultLogger()
-          self.logger.error("Sat logger not set, fixed as default")
+          self.logger.critical("Sat logger not set, unexpected situation, fixed as default")
           return self.logger
         else:                   # could use local logger
           return self.logger
         
+    def getConfig(self):
+        return self.config
+        
     def assumeAsList(self, strOrList):
-        """return a list as sys.argv if string
-        """
-        if type(strOrList) is list:
-          return list(strOrList) # copy
-        else:
-          return strOrList.split(" ") # supposed string to split for convenience
-
+        return assumeAsList(strOrList)
 
     def _getParser(self):
         """
@@ -442,47 +349,53 @@ class Sat(object):
         return parser
  
      
-    def parseGenericArguments(self, arguments):
+    def parseArguments(self, arguments):
         args = self.assumeAsList(arguments)
         genericOptions, remaindersArgs = self.parser.parse_args(args)
-        DBG.write("Sat generic arguments", genericArgs)
+        DBG.write("Sat generic options", genericOptions)
         DBG.write("Sat remainders arguments", remaindersArgs)
         return genericOptions, remaindersArgs
                
     
-    def _getCommand(self, name):
+    def _getModule(self, name):
         """
-        create and add Command 'name' as instance of class in dict self.commands
-        create only one instance
+        load and add module Command 'name' in dict self.commands
+        have to be called only one time maximum for each module Command
         """
         if name not in _COMMANDS_NAMES:
-            raise AttributeError(_("command not valid: '%s'") % name)
+            raise Exception(_("module command not valid: '%s'") % name)
         if name in self.commands.keys():
-            raise AttributeError(_("command existing yet: '%s', use getCommand") % name)
+            raise Exception(_("module command existing yet: '%s', use getModule") % name)
         file_, pathname, description = imp.find_module(name, [cmdsdir])
+        # could raise Exception in load (catched in sat, logger.critical)
         module = imp.load_module(name, file_, pathname, description)
-        try:
-          cmdInstance = module.Command(name)
-        except:
-          DBG.tofix("no Command() class in %s" % pathname, dir(module), True)
-          raise Exception("no Command() class in %s" % pathname)
-
-        cmdInstance.setRunner(self) # self is runner, owns cmdInstance
-        DBG.write("Sat load new command", cmdInstance)
-        return cmdInstance       
-                    
-    def getCommand(self, name):
+        self.commands[name] = module # store module loaded (only one time)
+        self.logger.debug("Sat load module command %s" % name)
+        return module
+      
+    def getModule(self, name):
+        """
+        returns only-one-time loaded module Command 'name'
+        assume load if not done yet
         """
-        returns inherited instance of _BaseCmd for command 'name'
-        if not existing as self.commands[name], create it.
+        if name in self.commands.keys():
+          return self.commands[name]
+        else:
+          return self._getModule(name)
         
-        example:
-        returns Command() from command.config 
+    def getCommandInstance(self, name):
         """
-        if name not in self.commands.keys():
-            self.commands[name] = self._getCommand(name)
-        return self.commands[name]    
-       
+        returns inherited instance of Command(_BaseCmd) for command 'name'
+        if module not loaded yet, load it.
+        """
+        module = self.getModule(name)
+        try:
+          commandInstance = module.Command(self)  # set runner as 'parent' (and logger...)
+        except Exception as e:
+          raise Exception("Problem instance %s.Command(): %s" % (name, e))
+        self.logger.debug("Sat new instance %s.Command()" % name)
+        return commandInstance                          
+
     def execute_cli(self, cli_arguments):
         """select first argument as a command in directory 'commands', and launch on arguments
         
@@ -492,146 +405,57 @@ class Sat(object):
 
         # print general help and returns
         if len(args) == 0:
-            print_help()
-            return RCO.ReturnCode("OK", "No arguments as --help")
-            
+            self.print_help()
+            return RCO.ReturnCode("OK", "No arguments, as 'sat --help'")
+        
+        self.options, remaindersArgs = self.parseArguments(args)
+        
         # if the help option has been called, print command help and returns
         if self.options.help:
-            self.print_help(self.arguments)
+            self.print_help()
             return RCO.ReturnCode("OK", "Option --help")
        
         # the command called
-        cmdName = args[0]
+        cmdName = remaindersArgs[0]
         # create/get dynamically the command instance to call its 'run' method
-        cmdInstance = self.getCommand(cmdName)
+        cmdInstance = self.getCommandInstance(cmdName)
         # Run the command using the arguments
-        returnCode = cmdInstance.run(args[1:])
+        returnCode = cmdInstance.run(remaindersArgs[1:])
         return returnCode
-
-    def print_help(self, opt):
-        '''Prints help for a command. Function called when "sat -h <command>"
-        
-        :param argv str: the options passed (to get the command name)
-        '''
-        # if no command as argument (sat -h)
-        if len(opt)==0:
-            print_help()
-            return
-            
-        # get command name
-        cmdName = opt[0]
-        # read the configuration from all the pyconf files
-        cfgManager = getConfigManager()
-        self.cfg = cfgManager.get_config(datadir=self.datadir)
-
-        cmdInstance = self.getCommand(cmdName)
-                   
-        msg = self.get_command_help(cmdInstance)
-            
-        if isStdoutPipe():
-            # clean color if the terminal is redirected by user
-            # ex: sat compile appli > log.txt
-            msg = src.printcolors.cleancolor(msg)  
-        print(msg)
-        return 
-            
-    def get_command_help(self, module):
-        """get help for a command
-        as 'sat --help config' for example
-        """
-        # get salomeTools version
-        msg = get_version() + "\n\n"
-        
-        # print the description of the command that is done in the command file
-        try:
-            msg += src.printcolors.printcHeader( _("Description:") ) + "\n"
-            msg += module.description() + "\n\n"
-        except:
-            DBG.tofix("no description() for", module.name, True)
-
-        # print the description of the command options
-        try:
-            msg += module.getParser().get_help() + "\n"
-        except:
-            DBG.tofix("no getParser() for", module.name, True)
-        return msg
       
-        
-###################################################################     
-def getConfigManager():
-    import commands.config 
-    return commands.config.ConfigManager()
-        
-def get_text_from_options(options):
-    text_options = ""
-    for attr in dir(options):
-        if attr.startswith("__"):
-            continue
-        if options.__getattr__(attr) != None:
-            option_contain = options.__getattr__(attr)
-            if type(option_contain)==type([]):
-                option_contain = ",".join(option_contain)
-            if type(option_contain)==type(True):
-                option_contain = ""
-            text_options+= "--%s %s " % (attr, option_contain)
-    return text_options
-         
-
-def isStdoutPipe():
-    """check if the terminal is redirected by user (elsewhere a tty) 
-    example: 
-    >> sat compile appli > log.txt
-    """
-    return not ('isatty' in dir(sys.stdout) and sys.stdout.isatty())
-     
-def get_version():
-    """get version colored string
-    """
-    cfgManager = getConfigManager()
-    cfg = cfgManager.get_config()
-    # print the key corresponding to salomeTools version
-    msg = src.printcolors.printcHeader( _("Version: ") ) + \
-          cfg.INTERNAL.sat_version
-    return msg
-  
-def get_help():
-    """get general help colored string
-    """
-    # read the config 
-    msg = get_version() + "\n\n"
-    msg += src.printcolors.printcHeader(_("Usage: ")) + \
-          "sat [generic_options] <command> [product] [command_options]\n\n"
-    msg += Sat()._getParser().get_help() + "\n"
-    msg += src.printcolors.printcHeader(_("Available commands are:")) + "\n\n"
-    for command in _COMMANDS_NAMES:
-        msg += " - %s\n" % (command)
-    msg += "\n"
-    # Explain how to get the help for a specific command
-    msg += src.printcolors.printcHeader(
-           _("Getting the help for a specific command: ")) + \
-           "sat --help <command>\n"
-    return msg
-
-def print_help():
-    """prints salomeTools general help
-    """
-    msg = get_help() 
-    if isStdoutPipe():
-        # clean color if the terminal is redirected by user
-        # ex: sat compile appli > log.txt
-        msg = src.printcolors.cleancolor(msg)  
-    print(msg)
-    return
-
-def write_exception(exc):
-    '''write in stderr exception in case of error in a command
+    def get_help(self):
+        """get general help colored string"""
+        msg = self.getColoredVersion() + "\n\n"
+        msg += "<header>Usage:<reset>  sat [generic_options] <command> [product] [command_options]\n\n"
+        msg += self._getParser().get_help() + "\n"
+        msg += "<header>" + _("Available commands are:") + "<reset>\n\n"
+        for command in _COMMANDS_NAMES:
+            msg += " - %s\n" % (command)
+        msg += "\n"
+        # how to get the help for a specific command
+        msg += "<header>" + _("Getting the help for a specific command: ") + \
+               "<reset>sat <command> --help\n"
+        return msg
     
-    :param exc exception: the exception to print
-    '''
-    sys.stderr.write("\n***** ")
-    sys.stderr.write(src.printcolors.printcError("salomeTools ERROR:"))
-    sys.stderr.write("\n" + str(exc) + "\n")
-
+    def print_help(self):
+        """prints salomeTools general help"""
+        self.logger.info(self.get_help())
+          
+    def getConfigManager(self):
+        import src.configManager as CFGMGR
+        return CFGMGR.ConfigManager(self.logger)
+        
+    def getColoredVersion(self):
+        """get colored salomeTools version message"""
+        version = getVersion()
+        if self.config is not None:
+          # verify coherency with config.INTERNAL.sat_version
+          if config.INTERNAL.sat_version != version:
+            self.logger.warning("verify version with INTERNAL.sat_version")
+        msg = "<header>Version:<reset> " + version
+        return msg
+   
+       
 
 
 
diff --git a/src/test/APPLI_TEST/APPLI_TEST.pyconf b/src/test/APPLI_TEST/APPLI_TEST.pyconf
deleted file mode 100644 (file)
index 5fc08b3..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-
-APPLICATION :
-{
-    name : 'APPLI_TEST'
-    workdir : $LOCAL.workdir + $VARS.sep + $APPLICATION.name + '-' + $VARS.dist
-    base : 'base'
-    tag : 'master'
-    get_method : 'git'
-    environ :
-    {
-        ACCEPT_SALOME_WARNINGS : '1'
-        LC_NUMERIC : 'C'
-        TESTS_ROOT_DIR : "/tmp/" + $VARS.user+ "/TESTS/APPLI_TEST"
-    }
-    products :
-    {
-        # PREREQUISITES :
-        'Python' : 'native'
-
-        # SALOME MODULES :
-        'CONFIGURATION'
-        'MEDCOUPLING'
-        'KERNEL'
-        'GUI'
-        'GEOM'
-        'SMESH'
-
-    }
-    grid_to_test : 'SALOME_V8'
-    profile :
-    {
-        launcher_name : "appli_test"
-        product : "SALOME"
-    }
-    virtual_app:
-    {
-        name : "appli_test"
-        application_name : "APPLI"
-    }
-    test_base : 
-    {
-        name : "SALOME"
-        tag : "SalomeV8"
-    }
-}
diff --git a/src/test/APPLI_TEST_Test.py b/src/test/APPLI_TEST_Test.py
deleted file mode 100755 (executable)
index e29e0a7..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-#!/usr/bin/env python
-#-*- coding:utf-8 -*-
-
-#  Copyright (C) 2010-2018  CEA/DEN
-#
-#  This library is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU Lesser General Public
-#  License as published by the Free Software Foundation; either
-#  version 2.1 of the License.
-#
-#  This library is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-#  Lesser General Public License for more details.
-#
-#  You should have received a copy of the GNU Lesser General Public
-#  License along with this library; if not, write to the Free Software
-#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
-
-import os
-import sys
-import unittest
-
-import src.salomeTools as SAT
-import src
-import src.debug as DBG # Easy print stderr (for DEBUG only)
-
-class TestCase(unittest.TestCase):
-  "Test the sat commands on APPLI_TEST configuration pyconf etc. files"""
-  
-  def test_000(self):
-    # one shot setUp() for this TestCase
-    # DBG.push_debug(True)
-    SAT.setNotLocale() # test english
-    return
-
-  def test_010(self):
-    cmd = "-v 5 config -l"
-    s = SAT.Sat(cmd)
-    # DBG.push_debug(True)
-    DBG.write("s.cfg", s.cfg) #none
-    DBG.write("s.__dict__", s.__dict__) # have 
-    exitCode = s.execute_command()
-    # DBG.write("s.cfg", s.cfg)
-    self.assertEqual(src.okToStr(exitCode), "OK")
-    DBG.pop_debug()
-      
-  def test_999(self):
-    # one shot tearDown() for this TestCase
-    SAT.setLocale() # end test english
-    # DBG.pop_debug()
-    return
-      
-if __name__ == '__main__':
-    unittest.main(exit=False)
-    pass
diff --git a/src/test/README_config_0_3_9.txt b/src/test/README_config_0_3_9.txt
deleted file mode 100644 (file)
index 4605ae9..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-#TODO
-switch pyconf.py 0.3.7.1 -> 0.3.9, here for test
diff --git a/src/test/__init__.py b/src/test/__init__.py
deleted file mode 100755 (executable)
index e69de29..0000000
diff --git a/src/test/config_0_3_9/LICENSE b/src/test/config_0_3_9/LICENSE
deleted file mode 100644 (file)
index 98773c8..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-Copyright (C) 2004-2010 by Vinay Sajip. All Rights Reserved.\r
-\r
-Permission to use, copy, modify, and distribute this software and its\r
-documentation for any purpose and without fee is hereby granted,\r
-provided that the above copyright notice appear in all copies and that\r
-both that copyright notice and this permission notice appear in\r
-supporting documentation, and that the name of Vinay Sajip\r
-not be used in advertising or publicity pertaining to distribution\r
-of the software without specific, written prior permission.\r
-\r
-VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING\r
-ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL\r
-VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR\r
-ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN\r
-AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR\r
-IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/src/test/config_0_3_9/PKG-INFO b/src/test/config_0_3_9/PKG-INFO
deleted file mode 100644 (file)
index 69ba705..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-Metadata-Version: 1.0
-Name: config
-Version: 0.3.9
-Summary: A hierarchical, easy-to-use, powerful configuration module for Python
-Home-page: http://www.red-dove.com/python_config.html
-Author: Vinay Sajip
-Author-email: vinay_sajip@red-dove.com
-License: Copyright (C) 2004-2010 by Vinay Sajip. All Rights Reserved. See LICENSE for license.
-Description: This module allows a hierarchical configuration scheme with support for mappings
-        and sequences, cross-references between one part of the configuration and
-        another, the ability to flexibly access real Python objects without full-blown
-        eval(), an include facility, simple expression evaluation and the ability to
-        change, save, cascade and merge configurations. Interfaces easily with
-        environment variables and command-line options. It has been developed on python
-        2.3 but should work on version 2.2 or greater.
-Platform: UNKNOWN
diff --git a/src/test/config_0_3_9/README.txt b/src/test/config_0_3_9/README.txt
deleted file mode 100644 (file)
index 0c20eab..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-This module is intended to provide configuration functionality for Python\r
-programs.\r
-\r
-Change History\r
---------------\r
-\r
-Version   Date        Description\r
-=============================================================================\r
-0.3.9     11 May 2010 Fixed parsing bug which caused failure for numbers with\r
-                      exponents.\r
------------------------------------------------------------------------------\r
-0.3.8     03 Mar 2010 Fixed parsing bug which caused failure for negative\r
-                      numbers in sequences. Improved resolution logic.\r
------------------------------------------------------------------------------\r
-0.3.7     05 Oct 2007 Added Mapping.__delitem__ (patch by John Drummond).\r
-                      Mapping.__getattribute__ no longer returns "" when\r
-                      asked for "__class__" - doing so causes pickle to\r
-                      crash (reported by Jamila Gunawardena).\r
-                      Allow negative numbers (reported by Gary Schoep; had\r
-                      already been fixed but not yet released).\r
------------------------------------------------------------------------------\r
-0.3.6     09 Mar 2006 Made classes derive from object (previously they were\r
-                      old-style classes).\r
-                      Changed ConfigMerger to use a more flexible merge\r
-                      strategy.\r
-                      Multiline strings (using """ or ''') are now supported.\r
-                      A typo involving raising a ConfigError was fixed.\r
-                      Patches received with thanks from David Janes & Tim\r
-                      Desjardins (BlogMatrix) and Erick Tryzelaar.\r
------------------------------------------------------------------------------\r
-0.3.5     27 Dec 2004 Added ConfigOutputStream to provide better Unicode\r
-                      output support. Altered save code to put platform-\r
-                      dependent newlines for Unicode.\r
------------------------------------------------------------------------------\r
-0.3.4     11 Nov 2004 Added ConfigInputStream to provide better Unicode\r
-                      support.\r
-                      Added ConfigReader.setStream().\r
------------------------------------------------------------------------------\r
-0.3.3     09 Nov 2004 Renamed config.get() to getByPath(), and likewise for\r
-                      ConfigList.\r
-                      Added Mapping.get() to work like dict.get().\r
-                      Added logconfig.py and logconfig.cfg to distribution.\r
------------------------------------------------------------------------------\r
-0.3.2     04 Nov 2004 Simplified parseMapping().\r
-                      Allowed Config.__init__ to accept a string as well as a\r
-                      stream. If a string is passed in, streamOpener is used\r
-                      to obtain the stream to be used.\r
------------------------------------------------------------------------------\r
-0.3.1     04 Nov 2004 Changed addNamespace/removeNamespace to make name\r
-                      specification easier.\r
-                      Refactored save(), added Container.writeToStream and\r
-                      Container.writeValue() to help with this.\r
------------------------------------------------------------------------------\r
-0.3       03 Nov 2004 Added test harness (test_config.py)\r
-                      Fixed bugs in bracket parsing.\r
-                      Refactored internal classes.\r
-                      Added merging functionality.\r
------------------------------------------------------------------------------\r
-0.2       01 Nov 2004 Added support for None.\r
-                      Stream closed in load() and save().\r
-                      Added support for changing configuration.\r
-                      Fixed bugs in identifier parsing and isword().\r
------------------------------------------------------------------------------\r
-0.1       31 Oct 2004 Initial implementation (for community feedback)\r
------------------------------------------------------------------------------\r
-\r
------------------------------------------------------------------------------\r
-COPYRIGHT\r
------------------------------------------------------------------------------\r
-Copyright 2004-2010 by Vinay Sajip. All Rights Reserved.\r
-\r
-Permission to use, copy, modify, and distribute this software and its\r
-documentation for any purpose and without fee is hereby granted,\r
-provided that the above copyright notice appear in all copies and that\r
-both that copyright notice and this permission notice appear in\r
-supporting documentation, and that the name of Vinay Sajip\r
-not be used in advertising or publicity pertaining to distribution\r
-of the software without specific, written prior permission.\r
-VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING\r
-ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL\r
-VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR\r
-ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN\r
-AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR\r
-IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\r
diff --git a/src/test/config_0_3_9/__init__.py b/src/test/config_0_3_9/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/src/test/config_0_3_9/config.py b/src/test/config_0_3_9/config.py
deleted file mode 100644 (file)
index 94d04c0..0000000
+++ /dev/null
@@ -1,1678 +0,0 @@
-# Copyright 2004-2010 by Vinay Sajip. All Rights Reserved.\r
-#\r
-# Permission to use, copy, modify, and distribute this software and its\r
-# documentation for any purpose and without fee is hereby granted,\r
-# provided that the above copyright notice appear in all copies and that\r
-# both that copyright notice and this permission notice appear in\r
-# supporting documentation, and that the name of Vinay Sajip\r
-# not be used in advertising or publicity pertaining to distribution\r
-# of the software without specific, written prior permission.\r
-# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING\r
-# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL\r
-# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR\r
-# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER\r
-# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT\r
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\r
-\r
-"""\r
-This is a configuration module for Python.\r
-\r
-This module should work under Python versions >= 2.2, and cannot be used with\r
-earlier versions since it uses new-style classes.\r
-\r
-Development and testing has only been carried out (so far) on Python 2.3.4 and\r
-Python 2.4.2. See the test module (test_config.py) included in the\r
-U{distribution<http://www.red-dove.com/python_config.html|_blank>} (follow the\r
-download link).\r
-\r
-A simple example - with the example configuration file::\r
-\r
-    messages:\r
-    [\r
-      {\r
-        stream : `sys.stderr`\r
-        message: 'Welcome'\r
-        name: 'Harry'\r
-      }\r
-      {\r
-        stream : `sys.stdout`\r
-        message: 'Welkom'\r
-        name: 'Ruud'\r
-      }\r
-      {\r
-        stream : $messages[0].stream\r
-        message: 'Bienvenue'\r
-        name: Yves\r
-      }\r
-    ]\r
-\r
-a program to read the configuration would be::\r
-\r
-    from config import Config\r
-\r
-    f = file('simple.cfg')\r
-    cfg = Config(f)\r
-    for m in cfg.messages:\r
-        s = '%s, %s' % (m.message, m.name)\r
-        try:\r
-            print >> m.stream, s\r
-        except IOError, e:\r
-            print e\r
-\r
-which, when run, would yield the console output::\r
-\r
-    Welcome, Harry\r
-    Welkom, Ruud\r
-    Bienvenue, Yves\r
-\r
-See U{this tutorial<http://www.red-dove.com/python_config.html|_blank>} for more\r
-information.\r
-\r
-@version: 0.3.9\r
-\r
-@author: Vinay Sajip\r
-\r
-@copyright: Copyright (C) 2004-2010 Vinay Sajip. All Rights Reserved.\r
-\r
-\r
-@var streamOpener: The default stream opener. This is a factory function which\r
-takes a string (e.g. filename) and returns a stream suitable for reading. If\r
-unable to open the stream, an IOError exception should be thrown.\r
-\r
-The default value of this variable is L{defaultStreamOpener}. For an example\r
-of how it's used, see test_config.py (search for streamOpener).\r
-"""\r
-\r
-__author__  = "Vinay Sajip <vinay_sajip@red-dove.com>"\r
-__status__  = "alpha"\r
-__version__ = "0.3.9"\r
-__date__    = "11 May 2010"\r
-\r
-from types import StringType, UnicodeType\r
-\r
-import codecs\r
-import logging\r
-import os\r
-import sys\r
-\r
-WORD = 'a'\r
-NUMBER = '9'\r
-STRING = '"'\r
-EOF = ''\r
-LCURLY = '{'\r
-RCURLY = '}'\r
-LBRACK = '['\r
-LBRACK2 = 'a['\r
-RBRACK = ']'\r
-LPAREN = '('\r
-LPAREN2 = '(('\r
-RPAREN = ')'\r
-DOT = '.'\r
-COMMA = ','\r
-COLON = ':'\r
-AT = '@'\r
-PLUS = '+'\r
-MINUS = '-'\r
-STAR = '*'\r
-SLASH = '/'\r
-MOD = '%'\r
-BACKTICK = '`'\r
-DOLLAR = '$'\r
-TRUE = 'True'\r
-FALSE = 'False'\r
-NONE = 'None'\r
-\r
-WORDCHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_"\r
-\r
-if sys.platform == 'win32':\r
-    NEWLINE = '\r\n'\r
-elif os.name == 'mac':\r
-    NEWLINE = '\r'\r
-else:\r
-    NEWLINE = '\n'\r
-\r
-try:\r
-    import encodings.utf_32\r
-    has_utf32 = True\r
-except:\r
-    has_utf32 = False\r
-\r
-try:\r
-    from logging.handlers import NullHandler\r
-except ImportError:\r
-    class NullHandler(logging.Handler):\r
-        def emit(self, record):\r
-            pass\r
-\r
-logger = logging.getLogger(__name__)\r
-if not logger.handlers:\r
-    logger.addHandler(NullHandler())\r
-\r
-class ConfigInputStream(object):\r
-    """\r
-    An input stream which can read either ANSI files with default encoding\r
-    or Unicode files with BOMs.\r
-\r
-    Handles UTF-8, UTF-16LE, UTF-16BE. Could handle UTF-32 if Python had\r
-    built-in support.\r
-    """\r
-    def __init__(self, stream):\r
-        """\r
-        Initialize an instance.\r
-\r
-        @param stream: The underlying stream to be read. Should be seekable.\r
-        @type stream: A stream (file-like object).\r
-        """\r
-        encoding = None\r
-        signature = stream.read(4)\r
-        used = -1\r
-        if has_utf32:\r
-            if signature == codecs.BOM_UTF32_LE:\r
-                encoding = 'utf-32le'\r
-            elif signature == codecs.BOM_UTF32_BE:\r
-                encoding = 'utf-32be'\r
-        if encoding is None:\r
-            if signature[:3] == codecs.BOM_UTF8:\r
-                used = 3\r
-                encoding = 'utf-8'\r
-            elif signature[:2] == codecs.BOM_UTF16_LE:\r
-                used = 2\r
-                encoding = 'utf-16le'\r
-            elif signature[:2] == codecs.BOM_UTF16_BE:\r
-                used = 2\r
-                encoding = 'utf-16be'\r
-            else:\r
-                used = 0\r
-        if used >= 0:\r
-            stream.seek(used)\r
-        if encoding:\r
-            reader = codecs.getreader(encoding)\r
-            stream = reader(stream)\r
-        self.stream = stream\r
-        self.encoding = encoding\r
-\r
-    def read(self, size):\r
-        if (size == 0) or (self.encoding is None):\r
-            rv = self.stream.read(size)\r
-        else:\r
-            rv = u''\r
-            while size > 0:\r
-                rv += self.stream.read(1)\r
-                size -= 1\r
-        return rv\r
-\r
-    def close(self):\r
-        self.stream.close()\r
-\r
-    def readline(self):\r
-        if self.encoding is None:\r
-            line = ''\r
-        else:\r
-            line = u''\r
-        while True:\r
-            c = self.stream.read(1)\r
-            if c:\r
-                line += c\r
-            if c == '\n':\r
-                break\r
-        return line\r
-\r
-class ConfigOutputStream(object):\r
-    """\r
-    An output stream which can write either ANSI files with default encoding\r
-    or Unicode files with BOMs.\r
-\r
-    Handles UTF-8, UTF-16LE, UTF-16BE. Could handle UTF-32 if Python had\r
-    built-in support.\r
-    """\r
-\r
-    def __init__(self, stream, encoding=None):\r
-        """\r
-        Initialize an instance.\r
-\r
-        @param stream: The underlying stream to be written.\r
-        @type stream: A stream (file-like object).\r
-        @param encoding: The desired encoding.\r
-        @type encoding: str\r
-        """\r
-        if encoding is not None:\r
-            encoding = str(encoding).lower()\r
-        self.encoding = encoding\r
-        if encoding == "utf-8":\r
-            stream.write(codecs.BOM_UTF8)\r
-        elif encoding == "utf-16be":\r
-            stream.write(codecs.BOM_UTF16_BE)\r
-        elif encoding == "utf-16le":\r
-            stream.write(codecs.BOM_UTF16_LE)\r
-        elif encoding == "utf-32be":\r
-            stream.write(codecs.BOM_UTF32_BE)\r
-        elif encoding == "utf-32le":\r
-            stream.write(codecs.BOM_UTF32_LE)\r
-\r
-        if encoding is not None:\r
-            writer = codecs.getwriter(encoding)\r
-            stream = writer(stream)\r
-        self.stream = stream\r
-\r
-    def write(self, data):\r
-        self.stream.write(data)\r
-\r
-    def flush(self):\r
-        self.stream.flush()\r
-\r
-    def close(self):\r
-        self.stream.close()\r
-\r
-def defaultStreamOpener(name):\r
-    """\r
-    This function returns a read-only stream, given its name. The name passed\r
-    in should correspond to an existing stream, otherwise an exception will be\r
-    raised.\r
-\r
-    This is the default value of L{streamOpener}; assign your own callable to\r
-    streamOpener to return streams based on names. For example, you could use\r
-    urllib2.urlopen().\r
-\r
-    @param name: The name of a stream, most commonly a file name.\r
-    @type name: str\r
-    @return: A stream with the specified name.\r
-    @rtype: A read-only stream (file-like object)\r
-    """\r
-    return ConfigInputStream(file(name, 'rb'))\r
-\r
-streamOpener = None\r
-\r
-class ConfigError(Exception):\r
-    """\r
-    This is the base class of exceptions raised by this module.\r
-    """\r
-    pass\r
-\r
-class ConfigFormatError(ConfigError):\r
-    """\r
-    This is the base class of exceptions raised due to syntax errors in\r
-    configurations.\r
-    """\r
-    pass\r
-\r
-class ConfigResolutionError(ConfigError):\r
-    """\r
-    This is the base class of exceptions raised due to semantic errors in\r
-    configurations.\r
-    """\r
-    pass\r
-\r
-def isWord(s):\r
-    """\r
-    See if a passed-in value is an identifier. If the value passed in is not a\r
-    string, False is returned. An identifier consists of alphanumerics or\r
-    underscore characters.\r
-\r
-    Examples::\r
-\r
-        isWord('a word') ->False\r
-        isWord('award') -> True\r
-        isWord(9) -> False\r
-        isWord('a_b_c_') ->True\r
-\r
-    @note: isWord('9abc') will return True - not exactly correct, but adequate\r
-    for the way it's used here.\r
-\r
-    @param s: The name to be tested\r
-    @type s: any\r
-    @return: True if a word, else False\r
-    @rtype: bool\r
-    """\r
-    if type(s) != type(''):\r
-        return False\r
-    s = s.replace('_', '')\r
-    return s.isalnum()\r
-\r
-def makePath(prefix, suffix):\r
-    """\r
-    Make a path from a prefix and suffix.\r
-\r
-    Examples::\r
-\r
-        makePath('', 'suffix') -> 'suffix'\r
-        makePath('prefix', 'suffix') -> 'prefix.suffix'\r
-        makePath('prefix', '[1]') -> 'prefix[1]'\r
-\r
-    @param prefix:  The prefix to use. If it evaluates as false, the suffix\r
-                    is returned.\r
-    @type prefix:   str\r
-    @param suffix:  The suffix to use. It is either an identifier or an\r
-                    index in brackets.\r
-    @type suffix:   str\r
-    @return:        The path concatenation of prefix and suffix, with a\r
-                    dot if the suffix is not a bracketed index.\r
-    @rtype:         str\r
-\r
-    """\r
-    if not prefix:\r
-        rv = suffix\r
-    elif suffix[0] == '[':\r
-        rv = prefix + suffix\r
-    else:\r
-        rv = prefix + '.' + suffix\r
-    return rv\r
-\r
-\r
-class Container(object):\r
-    """\r
-    This internal class is the base class for mappings and sequences.\r
-\r
-    @ivar path: A string which describes how to get\r
-    to this instance from the root of the hierarchy.\r
-\r
-    Example::\r
-\r
-        a.list.of[1].or['more'].elements\r
-    """\r
-    def __init__(self, parent):\r
-        """\r
-        Initialize an instance.\r
-\r
-        @param parent: The parent of this instance in the hierarchy.\r
-        @type parent: A L{Container} instance.\r
-        """\r
-        object.__setattr__(self, 'parent', parent)\r
-\r
-    def setPath(self, path):\r
-        """\r
-        Set the path for this instance.\r
-        @param path: The path - a string which describes how to get\r
-        to this instance from the root of the hierarchy.\r
-        @type path: str\r
-        """\r
-        object.__setattr__(self, 'path', path)\r
-\r
-    def evaluate(self, item):\r
-        """\r
-        Evaluate items which are instances of L{Reference} or L{Expression}.\r
-\r
-        L{Reference} instances are evaluated using L{Reference.resolve},\r
-        and L{Expression} instances are evaluated using\r
-        L{Expression.evaluate}.\r
-\r
-        @param item: The item to be evaluated.\r
-        @type item: any\r
-        @return: If the item is an instance of L{Reference} or L{Expression},\r
-        the evaluated value is returned, otherwise the item is returned\r
-        unchanged.\r
-        """\r
-        if isinstance(item, Reference):\r
-            item = item.resolve(self)\r
-        elif isinstance(item, Expression):\r
-            item = item.evaluate(self)\r
-        return item\r
-\r
-    def writeToStream(self, stream, indent, container):\r
-        """\r
-        Write this instance to a stream at the specified indentation level.\r
-\r
-        Should be redefined in subclasses.\r
-\r
-        @param stream: The stream to write to\r
-        @type stream: A writable stream (file-like object)\r
-        @param indent: The indentation level\r
-        @type indent: int\r
-        @param container: The container of this instance\r
-        @type container: L{Container}\r
-        @raise NotImplementedError: If a subclass does not override this\r
-        """\r
-        raise NotImplementedError\r
-\r
-    def writeValue(self, value, stream, indent):\r
-        if isinstance(self, Mapping):\r
-            indstr = ' '\r
-        else:\r
-            indstr = indent * '  '\r
-        if isinstance(value, Reference) or isinstance(value, Expression):\r
-            stream.write('%s%r%s' % (indstr, value, NEWLINE))\r
-        else:\r
-            if (type(value) is StringType): # and not isWord(value):\r
-                value = repr(value)\r
-            stream.write('%s%s%s' % (indstr, value, NEWLINE))\r
-\r
-class Mapping(Container):\r
-    """\r
-    This internal class implements key-value mappings in configurations.\r
-    """\r
-\r
-    def __init__(self, parent=None):\r
-        """\r
-        Initialize an instance.\r
-\r
-        @param parent: The parent of this instance in the hierarchy.\r
-        @type parent: A L{Container} instance.\r
-        """\r
-        Container.__init__(self, parent)\r
-        object.__setattr__(self, 'path', '')\r
-        object.__setattr__(self, 'data', {})\r
-        object.__setattr__(self, 'order', [])   # to preserve ordering\r
-        object.__setattr__(self, 'comments', {})\r
-\r
-    def __delitem__(self, key):\r
-        """\r
-        Remove an item\r
-        """\r
-        data = object.__getattribute__(self, 'data')\r
-        if key not in data:\r
-            raise AttributeError(key)\r
-        order = object.__getattribute__(self, 'order')\r
-        comments = object.__getattribute__(self, 'comments')\r
-        del data[key]\r
-        order.remove(key)\r
-        del comments[key]\r
-\r
-    def __getitem__(self, key):\r
-        data = object.__getattribute__(self, 'data')\r
-        if key not in data:\r
-            raise AttributeError(key)\r
-        rv = data[key]\r
-        return self.evaluate(rv)\r
-\r
-    __getattr__ = __getitem__\r
-\r
-    def __getattribute__(self, name):\r
-        if name == "__dict__":\r
-            return {}\r
-        if name in ["__methods__", "__members__"]:\r
-            return []\r
-        #if name == "__class__":\r
-        #    return ''\r
-        data = object.__getattribute__(self, "data")\r
-        useData = data.has_key(name)\r
-        if useData:\r
-            rv = getattr(data, name)\r
-        else:\r
-            rv = object.__getattribute__(self, name)\r
-            if rv is None:\r
-                raise AttributeError(name)\r
-        return rv\r
-\r
-    def iteritems(self):\r
-        for key in self.keys():\r
-            yield(key, self[key])\r
-        raise StopIteration\r
-\r
-    def __contains__(self, item):\r
-        order = object.__getattribute__(self, 'order')\r
-        return item in order\r
-\r
-    def addMapping(self, key, value, comment, setting=False):\r
-        """\r
-        Add a key-value mapping with a comment.\r
-\r
-        @param key: The key for the mapping.\r
-        @type key: str\r
-        @param value: The value for the mapping.\r
-        @type value: any\r
-        @param comment: The comment for the key (can be None).\r
-        @type comment: str\r
-        @param setting: If True, ignore clashes. This is set\r
-        to true when called from L{__setattr__}.\r
-        @raise ConfigFormatError: If an existing key is seen\r
-        again and setting is False.\r
-        """\r
-        data = object.__getattribute__(self, 'data')\r
-        order = object.__getattribute__(self, 'order')\r
-        comments = object.__getattribute__(self, 'comments')\r
-\r
-        data[key] = value\r
-        if key not in order:\r
-            order.append(key)\r
-        elif not setting:\r
-            raise ConfigFormatError("repeated key: %s" % key)\r
-        comments[key] = comment\r
-\r
-    def __setattr__(self, name, value):\r
-        self.addMapping(name, value, None, True)\r
-\r
-    __setitem__ = __setattr__\r
-\r
-    def keys(self):\r
-        """\r
-        Return the keys in a similar way to a dictionary.\r
-        """\r
-        return object.__getattribute__(self, 'order')\r
-\r
-    def get(self, key, default=None):\r
-        """\r
-        Allows a dictionary-style get operation.\r
-        """\r
-        if key in self:\r
-            return self[key]\r
-        return default\r
-\r
-    def __str__(self):\r
-        return str(object.__getattribute__(self, 'data'))\r
-\r
-    def __repr__(self):\r
-        return repr(object.__getattribute__(self, 'data'))\r
-\r
-    def __len__(self):\r
-        return len(object.__getattribute__(self, 'order'))\r
-\r
-    def __iter__(self):\r
-        return self.iterkeys()\r
-\r
-    def iterkeys(self):\r
-        order = object.__getattribute__(self, 'order')\r
-        return order.__iter__()\r
-\r
-    def writeToStream(self, stream, indent, container):\r
-        """\r
-        Write this instance to a stream at the specified indentation level.\r
-\r
-        Should be redefined in subclasses.\r
-\r
-        @param stream: The stream to write to\r
-        @type stream: A writable stream (file-like object)\r
-        @param indent: The indentation level\r
-        @type indent: int\r
-        @param container: The container of this instance\r
-        @type container: L{Container}\r
-        """\r
-        indstr = indent * '  '\r
-        if len(self) == 0:\r
-            stream.write(' { }%s' % NEWLINE)\r
-        else:\r
-            if isinstance(container, Mapping):\r
-                stream.write(NEWLINE)\r
-            stream.write('%s{%s' % (indstr, NEWLINE))\r
-            self.save(stream, indent + 1)\r
-            stream.write('%s}%s' % (indstr, NEWLINE))\r
-\r
-    def save(self, stream, indent=0):\r
-        """\r
-        Save this configuration to the specified stream.\r
-        @param stream: A stream to which the configuration is written.\r
-        @type stream: A write-only stream (file-like object).\r
-        @param indent: The indentation level for the output.\r
-        @type indent: int\r
-        """\r
-        indstr = indent * '  '\r
-        order = object.__getattribute__(self, 'order')\r
-        data = object.__getattribute__(self, 'data')\r
-        maxlen = 0 # max(map(lambda x: len(x), order))\r
-        for key in order:\r
-            comment = self.comments[key]\r
-            if isWord(key):\r
-                skey = key\r
-            else:\r
-                skey = repr(key)\r
-            if comment:\r
-                stream.write('%s#%s' % (indstr, comment))\r
-            stream.write('%s%-*s :' % (indstr, maxlen, skey))\r
-            value = data[key]\r
-            if isinstance(value, Container):\r
-                value.writeToStream(stream, indent, self)\r
-            else:\r
-                self.writeValue(value, stream, indent)\r
-\r
-class Config(Mapping):\r
-    """\r
-    This class represents a configuration, and is the only one which clients\r
-    need to interface to, under normal circumstances.\r
-    """\r
-\r
-    class Namespace(object):\r
-        """\r
-        This internal class is used for implementing default namespaces.\r
-\r
-        An instance acts as a namespace.\r
-        """\r
-        def __init__(self):\r
-            self.sys = sys\r
-            self.os = os\r
-\r
-        def __repr__(self):\r
-            return "<Namespace('%s')>" % ','.join(self.__dict__.keys())\r
-\r
-    def __init__(self, streamOrFile=None, parent=None):\r
-        """\r
-        Initializes an instance.\r
-\r
-        @param streamOrFile: If specified, causes this instance to be loaded\r
-        from the stream (by calling L{load}). If a string is provided, it is\r
-        passed to L{streamOpener} to open a stream. Otherwise, the passed\r
-        value is assumed to be a stream and used as is.\r
-        @type streamOrFile: A readable stream (file-like object) or a name.\r
-        @param parent: If specified, this becomes the parent of this instance\r
-        in the configuration hierarchy.\r
-        @type parent: a L{Container} instance.\r
-        """\r
-        Mapping.__init__(self, parent)\r
-        object.__setattr__(self, 'reader', ConfigReader(self))\r
-        object.__setattr__(self, 'namespaces', [Config.Namespace()])\r
-        object.__setattr__(self, 'resolving', set())\r
-        if streamOrFile is not None:\r
-            if isinstance(streamOrFile, StringType) or isinstance(streamOrFile, UnicodeType):\r
-                global streamOpener\r
-                if streamOpener is None:\r
-                    streamOpener = defaultStreamOpener\r
-                streamOrFile = streamOpener(streamOrFile)\r
-            load = object.__getattribute__(self, "load")\r
-            load(streamOrFile)\r
-\r
-    def load(self, stream):\r
-        """\r
-        Load the configuration from the specified stream. Multiple streams can\r
-        be used to populate the same instance, as long as there are no\r
-        clashing keys. The stream is closed.\r
-        @param stream: A stream from which the configuration is read.\r
-        @type stream: A read-only stream (file-like object).\r
-        @raise ConfigError: if keys in the loaded configuration clash with\r
-        existing keys.\r
-        @raise ConfigFormatError: if there is a syntax error in the stream.\r
-        """\r
-        reader = object.__getattribute__(self, 'reader')\r
-        #object.__setattr__(self, 'root', reader.load(stream))\r
-        reader.load(stream)\r
-        stream.close()\r
-\r
-    def addNamespace(self, ns, name=None):\r
-        """\r
-        Add a namespace to this configuration which can be used to evaluate\r
-        (resolve) dotted-identifier expressions.\r
-        @param ns: The namespace to be added.\r
-        @type ns: A module or other namespace suitable for passing as an\r
-        argument to vars().\r
-        @param name: A name for the namespace, which, if specified, provides\r
-        an additional level of indirection.\r
-        @type name: str\r
-        """\r
-        namespaces = object.__getattribute__(self, 'namespaces')\r
-        if name is None:\r
-            namespaces.append(ns)\r
-        else:\r
-            setattr(namespaces[0], name, ns)\r
-\r
-    def removeNamespace(self, ns, name=None):\r
-        """\r
-        Remove a namespace added with L{addNamespace}.\r
-        @param ns: The namespace to be removed.\r
-        @param name: The name which was specified when L{addNamespace} was\r
-        called.\r
-        @type name: str\r
-        """\r
-        namespaces = object.__getattribute__(self, 'namespaces')\r
-        if name is None:\r
-            namespaces.remove(ns)\r
-        else:\r
-            delattr(namespaces[0], name)\r
-\r
-    def save(self, stream, indent=0):\r
-        """\r
-        Save this configuration to the specified stream. The stream is\r
-        closed if this is the top-level configuration in the hierarchy.\r
-        L{Mapping.save} is called to do all the work.\r
-        @param stream: A stream to which the configuration is written.\r
-        @type stream: A write-only stream (file-like object).\r
-        @param indent: The indentation level for the output.\r
-        @type indent: int\r
-        """\r
-        Mapping.save(self, stream, indent)\r
-        if indent == 0:\r
-            stream.close()\r
-\r
-    def getByPath(self, path):\r
-        """\r
-        Obtain a value in the configuration via its path.\r
-        @param path: The path of the required value\r
-        @type path: str\r
-        @return the value at the specified path.\r
-        @rtype: any\r
-        @raise ConfigError: If the path is invalid\r
-        """\r
-        s = 'self.' + path\r
-        try:\r
-            return eval(s)\r
-        except Exception, e:\r
-            raise ConfigError(str(e))\r
-\r
-class Sequence(Container):\r
-    """\r
-    This internal class implements a value which is a sequence of other values.\r
-    """\r
-    class SeqIter(object):\r
-        """\r
-        This internal class implements an iterator for a L{Sequence} instance.\r
-        """\r
-        def __init__(self, seq):\r
-            self.seq = seq\r
-            self.limit = len(object.__getattribute__(seq, 'data'))\r
-            self.index = 0\r
-\r
-        def __iter__(self):\r
-            return self\r
-\r
-        def next(self):\r
-            if self.index >= self.limit:\r
-                raise StopIteration\r
-            rv = self.seq[self.index]\r
-            self.index += 1\r
-            return rv\r
-\r
-    def __init__(self, parent=None):\r
-        """\r
-        Initialize an instance.\r
-\r
-        @param parent: The parent of this instance in the hierarchy.\r
-        @type parent: A L{Container} instance.\r
-        """\r
-        Container.__init__(self, parent)\r
-        object.__setattr__(self, 'data', [])\r
-        object.__setattr__(self, 'comments', [])\r
-\r
-    def append(self, item, comment):\r
-        """\r
-        Add an item to the sequence.\r
-\r
-        @param item: The item to add.\r
-        @type item: any\r
-        @param comment: A comment for the item.\r
-        @type comment: str\r
-        """\r
-        data = object.__getattribute__(self, 'data')\r
-        comments = object.__getattribute__(self, 'comments')\r
-        data.append(item)\r
-        comments.append(comment)\r
-\r
-    def __getitem__(self, index):\r
-        data = object.__getattribute__(self, 'data')\r
-        try:\r
-            rv = data[index]\r
-        except (IndexError, KeyError, TypeError):\r
-            raise ConfigResolutionError('%r is not a valid index for %r' % (index, object.__getattribute__(self, 'path')))\r
-        if not isinstance(rv, list):\r
-            rv = self.evaluate(rv)\r
-        else:\r
-            # deal with a slice\r
-            result = []\r
-            for a in rv:\r
-                result.append(self.evaluate(a))\r
-            rv = result\r
-        return rv\r
-\r
-    def __iter__(self):\r
-        return Sequence.SeqIter(self)\r
-\r
-    def __repr__(self):\r
-        return repr(object.__getattribute__(self, 'data'))\r
-\r
-    def __str__(self):\r
-        return str(self[:]) # using the slice evaluates the contents\r
-\r
-    def __len__(self):\r
-        return len(object.__getattribute__(self, 'data'))\r
-\r
-    def writeToStream(self, stream, indent, container):\r
-        """\r
-        Write this instance to a stream at the specified indentation level.\r
-\r
-        Should be redefined in subclasses.\r
-\r
-        @param stream: The stream to write to\r
-        @type stream: A writable stream (file-like object)\r
-        @param indent: The indentation level\r
-        @type indent: int\r
-        @param container: The container of this instance\r
-        @type container: L{Container}\r
-        """\r
-        indstr = indent * '  '\r
-        if len(self) == 0:\r
-            stream.write(' [ ]%s' % NEWLINE)\r
-        else:\r
-            if isinstance(container, Mapping):\r
-                stream.write(NEWLINE)\r
-            stream.write('%s[%s' % (indstr, NEWLINE))\r
-            self.save(stream, indent + 1)\r
-            stream.write('%s]%s' % (indstr, NEWLINE))\r
-\r
-    def save(self, stream, indent):\r
-        """\r
-        Save this instance to the specified stream.\r
-        @param stream: A stream to which the configuration is written.\r
-        @type stream: A write-only stream (file-like object).\r
-        @param indent: The indentation level for the output, > 0\r
-        @type indent: int\r
-        """\r
-        if indent == 0:\r
-            raise ConfigError("sequence cannot be saved as a top-level item")\r
-        data = object.__getattribute__(self, 'data')\r
-        comments = object.__getattribute__(self, 'comments')\r
-        indstr = indent * '  '\r
-        for i in xrange(0, len(data)):\r
-            value = data[i]\r
-            comment = comments[i]\r
-            if comment:\r
-                stream.write('%s#%s' % (indstr, comment))\r
-            if isinstance(value, Container):\r
-                value.writeToStream(stream, indent, self)\r
-            else:\r
-                self.writeValue(value, stream, indent)\r
-\r
-class Reference(object):\r
-    """\r
-    This internal class implements a value which is a reference to another value.\r
-    """\r
-    def __init__(self, config, type, ident):\r
-        """\r
-        Initialize an instance.\r
-\r
-        @param config: The configuration which contains this reference.\r
-        @type config: A L{Config} instance.\r
-        @param type: The type of reference.\r
-        @type type: BACKTICK or DOLLAR\r
-        @param ident: The identifier which starts the reference.\r
-        @type ident: str\r
-        """\r
-        self.config = config\r
-        self.type = type\r
-        self.elements = [ident]\r
-\r
-    def addElement(self, type, ident):\r
-        """\r
-        Add an element to the reference.\r
-\r
-        @param type: The type of reference.\r
-        @type type: BACKTICK or DOLLAR\r
-        @param ident: The identifier which continues the reference.\r
-        @type ident: str\r
-        """\r
-        self.elements.append((type, ident))\r
-\r
-    def findConfig(self, container):\r
-        """\r
-        Find the closest enclosing configuration to the specified container.\r
-\r
-        @param container: The container to start from.\r
-        @type container: L{Container}\r
-        @return: The closest enclosing configuration, or None.\r
-        @rtype: L{Config}\r
-        """\r
-        while (container is not None) and not isinstance(container, Config):\r
-            container = object.__getattribute__(container, 'parent')\r
-        return container\r
-\r
-    def resolve(self, container):\r
-        """\r
-        Resolve this instance in the context of a container.\r
-\r
-        @param container: The container to resolve from.\r
-        @type container: L{Container}\r
-        @return: The resolved value.\r
-        @rtype: any\r
-        @raise ConfigResolutionError: If resolution fails.\r
-        """\r
-        rv = None\r
-        path = object.__getattribute__(container, 'path')\r
-        current = self.findConfig(container)\r
-        while current is not None:\r
-            if self.type == BACKTICK:\r
-                namespaces = object.__getattribute__(current, 'namespaces')\r
-                found = False\r
-                s = str(self)[1:-1]\r
-                for ns in namespaces:\r
-                    try:\r
-                        try:\r
-                            rv = eval(s, vars(ns))\r
-                        except TypeError: #Python 2.7 - vars is a dictproxy\r
-                            rv = eval(s, {}, vars(ns))\r
-                        found = True\r
-                        break\r
-                    except:\r
-                        logger.debug("unable to resolve %r in %r", s, ns)\r
-                        pass\r
-                if found:\r
-                    break\r
-            else:\r
-                firstkey = self.elements[0]\r
-                if firstkey in current.resolving:\r
-                    current.resolving.remove(firstkey)\r
-                    raise ConfigResolutionError("Circular reference: %r" % firstkey)\r
-                current.resolving.add(firstkey)\r
-                key = firstkey\r
-                try:\r
-                    rv = current[key]\r
-                    for item in self.elements[1:]:\r
-                        key = item[1]\r
-                        rv = rv[key]\r
-                    current.resolving.remove(firstkey)\r
-                    break\r
-                except ConfigResolutionError:\r
-                    raise\r
-                except:\r
-                    logger.debug("Unable to resolve %r: %s", key, sys.exc_info()[1])\r
-                    rv = None\r
-                    pass\r
-                current.resolving.discard(firstkey)\r
-            current = self.findConfig(object.__getattribute__(current, 'parent'))\r
-        if current is None:\r
-            raise ConfigResolutionError("unable to evaluate %r in the configuration %s" % (self, path))\r
-        return rv\r
-\r
-    def __str__(self):\r
-        s = self.elements[0]\r
-        for tt, tv in self.elements[1:]:\r
-            if tt == DOT:\r
-                s += '.%s' % tv\r
-            else:\r
-                s += '[%r]' % tv\r
-        if self.type == BACKTICK:\r
-            return BACKTICK + s + BACKTICK\r
-        else:\r
-            return DOLLAR + s\r
-\r
-    def __repr__(self):\r
-        return self.__str__()\r
-\r
-class Expression(object):\r
-    """\r
-    This internal class implements a value which is obtained by evaluating an expression.\r
-    """\r
-    def __init__(self, op, lhs, rhs):\r
-        """\r
-        Initialize an instance.\r
-\r
-        @param op: the operation expressed in the expression.\r
-        @type op: PLUS, MINUS, STAR, SLASH, MOD\r
-        @param lhs: the left-hand-side operand of the expression.\r
-        @type lhs: any Expression or primary value.\r
-        @param rhs: the right-hand-side operand of the expression.\r
-        @type rhs: any Expression or primary value.\r
-        """\r
-        self.op = op\r
-        self.lhs = lhs\r
-        self.rhs = rhs\r
-\r
-    def __str__(self):\r
-        return '%r %s %r' % (self.lhs, self.op, self.rhs)\r
-\r
-    def __repr__(self):\r
-        return self.__str__()\r
-\r
-    def evaluate(self, container):\r
-        """\r
-        Evaluate this instance in the context of a container.\r
-\r
-        @param container: The container to evaluate in from.\r
-        @type container: L{Container}\r
-        @return: The evaluated value.\r
-        @rtype: any\r
-        @raise ConfigResolutionError: If evaluation fails.\r
-        @raise ZeroDivideError: If division by zero occurs.\r
-        @raise TypeError: If the operation is invalid, e.g.\r
-        subtracting one string from another.\r
-        """\r
-        lhs = self.lhs\r
-        if isinstance(lhs, Reference):\r
-            lhs = lhs.resolve(container)\r
-        elif isinstance(lhs, Expression):\r
-            lhs = lhs.evaluate(container)\r
-        rhs = self.rhs\r
-        if isinstance(rhs, Reference):\r
-            rhs = rhs.resolve(container)\r
-        elif isinstance(rhs, Expression):\r
-            rhs = rhs.evaluate(container)\r
-        op = self.op\r
-        if op == PLUS:\r
-            rv = lhs + rhs\r
-        elif op == MINUS:\r
-            rv = lhs - rhs\r
-        elif op == STAR:\r
-            rv = lhs * rhs\r
-        elif op == SLASH:\r
-            rv = lhs / rhs\r
-        else:\r
-            rv = lhs % rhs\r
-        return rv\r
-\r
-class ConfigReader(object):\r
-    """\r
-    This internal class implements a parser for configurations.\r
-    """\r
-\r
-    def __init__(self, config):\r
-        self.filename = None\r
-        self.config = config\r
-        self.lineno = 0\r
-        self.colno = 0\r
-        self.lastc = None\r
-        self.last_token = None\r
-        self.commentchars = '#'\r
-        self.whitespace = ' \t\r\n'\r
-        self.quotes = '\'"'\r
-        self.punct = ':-+*/%,.{}[]()@`$'\r
-        self.digits = '0123456789'\r
-        self.wordchars = '%s' % WORDCHARS # make a copy\r
-        self.identchars = self.wordchars + self.digits\r
-        self.pbchars = []\r
-        self.pbtokens = []\r
-        self.comment = None\r
-\r
-    def location(self):\r
-        """\r
-        Return the current location (filename, line, column) in the stream\r
-        as a string.\r
-\r
-        Used when printing error messages,\r
-\r
-        @return: A string representing a location in the stream being read.\r
-        @rtype: str\r
-        """\r
-        return "%s(%d,%d)" % (self.filename, self.lineno, self.colno)\r
-\r
-    def getChar(self):\r
-        """\r
-        Get the next char from the stream. Update line and column numbers\r
-        appropriately.\r
-\r
-        @return: The next character from the stream.\r
-        @rtype: str\r
-        """\r
-        if self.pbchars:\r
-            c = self.pbchars.pop()\r
-        else:\r
-            c = self.stream.read(1)\r
-            self.colno += 1\r
-            if c == '\n':\r
-                self.lineno += 1\r
-                self.colno = 1\r
-        return c\r
-\r
-    def __repr__(self):\r
-        return "<ConfigReader at 0x%08x>" % id(self)\r
-\r
-    __str__ = __repr__\r
-\r
-    def getToken(self):\r
-        """\r
-        Get a token from the stream. String values are returned in a form\r
-        where you need to eval() the returned value to get the actual\r
-        string. The return value is (token_type, token_value).\r
-\r
-        Multiline string tokenizing is thanks to David Janes (BlogMatrix)\r
-\r
-        @return: The next token.\r
-        @rtype: A token tuple.\r
-        """\r
-        if self.pbtokens:\r
-            return self.pbtokens.pop()\r
-        stream = self.stream\r
-        self.comment = None\r
-        token = ''\r
-        tt = EOF\r
-        while True:\r
-            c = self.getChar()\r
-            if not c:\r
-                break\r
-            elif c == '#':\r
-                self.comment = stream.readline()\r
-                self.lineno += 1\r
-                continue\r
-            if c in self.quotes:\r
-                token = c\r
-                quote = c\r
-                tt = STRING\r
-                escaped = False\r
-                multiline = False\r
-                c1 = self.getChar()\r
-                if c1 == quote:\r
-                    c2 = self.getChar()\r
-                    if c2 == quote:\r
-                        multiline = True\r
-                        token += quote\r
-                        token += quote\r
-                    else:\r
-                        self.pbchars.append(c2)\r
-                        self.pbchars.append(c1)\r
-                else:\r
-                    self.pbchars.append(c1)\r
-                while True:\r
-                    c = self.getChar()\r
-                    if not c:\r
-                        break\r
-                    token += c\r
-                    if (c == quote) and not escaped:\r
-                        if not multiline or (len(token) >= 6 and token.endswith(token[:3]) and token[-4] != '\\'):\r
-                            break\r
-                    if c == '\\':\r
-                        escaped = not escaped\r
-                    else:\r
-                        escaped = False\r
-                if not c:\r
-                    raise ConfigFormatError('%s: Unterminated quoted string: %r, %r' % (self.location(), token, c))\r
-                break\r
-            if c in self.whitespace:\r
-                self.lastc = c\r
-                continue\r
-            elif c in self.punct:\r
-                token = c\r
-                tt = c\r
-                if (self.lastc == ']') or (self.lastc in self.identchars):\r
-                    if c == '[':\r
-                        tt = LBRACK2\r
-                    elif c == '(':\r
-                        tt = LPAREN2\r
-                break\r
-            elif c in self.digits:\r
-                token = c\r
-                tt = NUMBER\r
-                in_exponent=False\r
-                while True:\r
-                    c = self.getChar()\r
-                    if not c:\r
-                        break\r
-                    if c in self.digits:\r
-                        token += c\r
-                    elif (c == '.') and token.find('.') < 0 and not in_exponent:\r
-                        token += c\r
-                    elif (c == '-') and token.find('-') < 0 and in_exponent:\r
-                        token += c\r
-                    elif (c in 'eE') and token.find('e') < 0 and\\r
-                         token.find('E') < 0:\r
-                        token += c\r
-                        in_exponent = True\r
-                    else:\r
-                        if c and (c not in self.whitespace):\r
-                            self.pbchars.append(c)\r
-                        break\r
-                break\r
-            elif c in self.wordchars:\r
-                token = c\r
-                tt = WORD\r
-                c = self.getChar()\r
-                while c and (c in self.identchars):\r
-                    token += c\r
-                    c = self.getChar()\r
-                if c: # and c not in self.whitespace:\r
-                    self.pbchars.append(c)\r
-                if token == "True":\r
-                    tt = TRUE\r
-                elif token == "False":\r
-                    tt = FALSE\r
-                elif token == "None":\r
-                    tt = NONE\r
-                break\r
-            else:\r
-                raise ConfigFormatError('%s: Unexpected character: %r' % (self.location(), c))\r
-        if token:\r
-            self.lastc = token[-1]\r
-        else:\r
-            self.lastc = None\r
-        self.last_token = tt\r
-        return (tt, token)\r
-\r
-    def load(self, stream, parent=None, suffix=None):\r
-        """\r
-        Load the configuration from the specified stream.\r
-\r
-        @param stream: A stream from which to load the configuration.\r
-        @type stream: A stream (file-like object).\r
-        @param parent: The parent of the configuration (to which this reader\r
-        belongs) in the hierarchy. Specified when the configuration is\r
-        included in another one.\r
-        @type parent: A L{Container} instance.\r
-        @param suffix: The suffix of this configuration in the parent\r
-        configuration. Should be specified whenever the parent is not None.\r
-        @raise ConfigError: If parent is specified but suffix is not.\r
-        @raise ConfigFormatError: If there are syntax errors in the stream.\r
-        """\r
-        if parent is not None:\r
-            if suffix is None:\r
-                raise ConfigError("internal error: load called with parent but no suffix")\r
-            self.config.setPath(makePath(object.__getattribute__(parent, 'path'), suffix))\r
-        self.setStream(stream)\r
-        self.token = self.getToken()\r
-        self.parseMappingBody(self.config)\r
-        if self.token[0] != EOF:\r
-            raise ConfigFormatError('%s: expecting EOF, found %r' % (self.location(), self.token[1]))\r
-\r
-    def setStream(self, stream):\r
-        """\r
-        Set the stream to the specified value, and prepare to read from it.\r
-\r
-        @param stream: A stream from which to load the configuration.\r
-        @type stream: A stream (file-like object).\r
-        """\r
-        self.stream = stream\r
-        if hasattr(stream, 'name'):\r
-            filename = stream.name\r
-        else:\r
-            filename = '?'\r
-        self.filename = filename\r
-        self.lineno = 1\r
-        self.colno = 1\r
-\r
-    def match(self, t):\r
-        """\r
-        Ensure that the current token type matches the specified value, and\r
-        advance to the next token.\r
-\r
-        @param t: The token type to match.\r
-        @type t: A valid token type.\r
-        @return: The token which was last read from the stream before this\r
-        function is called.\r
-        @rtype: a token tuple - see L{getToken}.\r
-        @raise ConfigFormatError: If the token does not match what's expected.\r
-        """\r
-        if self.token[0] != t:\r
-            raise ConfigFormatError("%s: expecting %s, found %r" % (self.location(), t, self.token[1]))\r
-        rv = self.token\r
-        self.token = self.getToken()\r
-        return rv\r
-\r
-    def parseMappingBody(self, parent):\r
-        """\r
-        Parse the internals of a mapping, and add entries to the provided\r
-        L{Mapping}.\r
-\r
-        @param parent: The mapping to add entries to.\r
-        @type parent: A L{Mapping} instance.\r
-        """\r
-        while self.token[0] in [WORD, STRING]:\r
-            self.parseKeyValuePair(parent)\r
-\r
-    def parseKeyValuePair(self, parent):\r
-        """\r
-        Parse a key-value pair, and add it to the provided L{Mapping}.\r
-\r
-        @param parent: The mapping to add entries to.\r
-        @type parent: A L{Mapping} instance.\r
-        @raise ConfigFormatError: if a syntax error is found.\r
-        """\r
-        comment = self.comment\r
-        tt, tv = self.token\r
-        if tt == WORD:\r
-            key = tv\r
-            suffix = tv\r
-        elif tt == STRING:\r
-            key = eval(tv)\r
-            suffix = '[%s]' % tv\r
-        else:\r
-            msg = "%s: expecting word or string, found %r"\r
-            raise ConfigFormatError(msg % (self.location(), tv))\r
-        self.token = self.getToken()\r
-        # for now, we allow key on its own as a short form of key : True\r
-        if self.token[0] == COLON:\r
-            self.token = self.getToken()\r
-            value = self.parseValue(parent, suffix)\r
-        else:\r
-            value = True\r
-        try:\r
-            parent.addMapping(key, value, comment)\r
-        except Exception, e:\r
-            raise ConfigFormatError("%s: %s, %r" % (self.location(), e,\r
-                                    self.token[1]))\r
-        tt = self.token[0]\r
-        if tt not in [EOF, WORD, STRING, RCURLY, COMMA]:\r
-            msg = "%s: expecting one of EOF, WORD, STRING,\\r
-RCURLY, COMMA, found %r"\r
-            raise ConfigFormatError(msg  % (self.location(), self.token[1]))\r
-        if tt == COMMA:\r
-            self.token = self.getToken()\r
-\r
-    def parseValue(self, parent, suffix):\r
-        """\r
-        Parse a value.\r
-\r
-        @param parent: The container to which the value will be added.\r
-        @type parent: A L{Container} instance.\r
-        @param suffix: The suffix for the value.\r
-        @type suffix: str\r
-        @return: The value\r
-        @rtype: any\r
-        @raise ConfigFormatError: if a syntax error is found.\r
-        """\r
-        tt = self.token[0]\r
-        if tt in [STRING, WORD, NUMBER, LPAREN, DOLLAR,\r
-                  TRUE, FALSE, NONE, BACKTICK, MINUS]:\r
-            rv = self.parseScalar()\r
-        elif tt == LBRACK:\r
-            rv = self.parseSequence(parent, suffix)\r
-        elif tt in [LCURLY, AT]:\r
-            rv = self.parseMapping(parent, suffix)\r
-        else:\r
-            raise ConfigFormatError("%s: unexpected input: %r" %\r
-               (self.location(), self.token[1]))\r
-        return rv\r
-\r
-    def parseSequence(self, parent, suffix):\r
-        """\r
-        Parse a sequence.\r
-\r
-        @param parent: The container to which the sequence will be added.\r
-        @type parent: A L{Container} instance.\r
-        @param suffix: The suffix for the value.\r
-        @type suffix: str\r
-        @return: a L{Sequence} instance representing the sequence.\r
-        @rtype: L{Sequence}\r
-        @raise ConfigFormatError: if a syntax error is found.\r
-        """\r
-        rv = Sequence(parent)\r
-        rv.setPath(makePath(object.__getattribute__(parent, 'path'), suffix))\r
-        self.match(LBRACK)\r
-        comment = self.comment\r
-        tt = self.token[0]\r
-        while tt in [STRING, WORD, NUMBER, LCURLY, LBRACK, LPAREN, DOLLAR,\r
-                     TRUE, FALSE, NONE, BACKTICK, MINUS]:\r
-            suffix = '[%d]' % len(rv)\r
-            value = self.parseValue(parent, suffix)\r
-            rv.append(value, comment)\r
-            tt = self.token[0]\r
-            comment = self.comment\r
-            if tt == COMMA:\r
-                self.match(COMMA)\r
-                tt = self.token[0]\r
-                comment = self.comment\r
-                continue\r
-        self.match(RBRACK)\r
-        return rv\r
-\r
-    def parseMapping(self, parent, suffix):\r
-        """\r
-        Parse a mapping.\r
-\r
-        @param parent: The container to which the mapping will be added.\r
-        @type parent: A L{Container} instance.\r
-        @param suffix: The suffix for the value.\r
-        @type suffix: str\r
-        @return: a L{Mapping} instance representing the mapping.\r
-        @rtype: L{Mapping}\r
-        @raise ConfigFormatError: if a syntax error is found.\r
-        """\r
-        if self.token[0] == LCURLY:\r
-            self.match(LCURLY)\r
-            rv = Mapping(parent)\r
-            rv.setPath(\r
-               makePath(object.__getattribute__(parent, 'path'), suffix))\r
-            self.parseMappingBody(rv)\r
-            self.match(RCURLY)\r
-        else:\r
-            self.match(AT)\r
-            tt, fn = self.match(STRING)\r
-            rv = Config(eval(fn), parent)\r
-        return rv\r
-\r
-    def parseScalar(self):\r
-        """\r
-        Parse a scalar - a terminal value such as a string or number, or\r
-        an L{Expression} or L{Reference}.\r
-\r
-        @return: the parsed scalar\r
-        @rtype: any scalar\r
-        @raise ConfigFormatError: if a syntax error is found.\r
-        """\r
-        lhs = self.parseTerm()\r
-        tt = self.token[0]\r
-        while tt in [PLUS, MINUS]:\r
-            self.match(tt)\r
-            rhs = self.parseTerm()\r
-            lhs = Expression(tt, lhs, rhs)\r
-            tt = self.token[0]\r
-        return lhs\r
-\r
-    def parseTerm(self):\r
-        """\r
-        Parse a term in an additive expression (a + b, a - b)\r
-\r
-        @return: the parsed term\r
-        @rtype: any scalar\r
-        @raise ConfigFormatError: if a syntax error is found.\r
-        """\r
-        lhs = self.parseFactor()\r
-        tt = self.token[0]\r
-        while tt in [STAR, SLASH, MOD]:\r
-            self.match(tt)\r
-            rhs = self.parseFactor()\r
-            lhs = Expression(tt, lhs, rhs)\r
-            tt = self.token[0]\r
-        return lhs\r
-\r
-    def parseFactor(self):\r
-        """\r
-        Parse a factor in an multiplicative expression (a * b, a / b, a % b)\r
-\r
-        @return: the parsed factor\r
-        @rtype: any scalar\r
-        @raise ConfigFormatError: if a syntax error is found.\r
-        """\r
-        tt = self.token[0]\r
-        if tt in [NUMBER, WORD, STRING, TRUE, FALSE, NONE]:\r
-            rv = self.token[1]\r
-            if tt != WORD:\r
-                rv = eval(rv)\r
-            self.match(tt)\r
-        elif tt == LPAREN:\r
-            self.match(LPAREN)\r
-            rv = self.parseScalar()\r
-            self.match(RPAREN)\r
-        elif tt == DOLLAR:\r
-            self.match(DOLLAR)\r
-            rv = self.parseReference(DOLLAR)\r
-        elif tt == BACKTICK:\r
-            self.match(BACKTICK)\r
-            rv = self.parseReference(BACKTICK)\r
-            self.match(BACKTICK)\r
-        elif tt == MINUS:\r
-            self.match(MINUS)\r
-            rv = -self.parseScalar()\r
-        else:\r
-            raise ConfigFormatError("%s: unexpected input: %r" %\r
-               (self.location(), self.token[1]))\r
-        return rv\r
-\r
-    def parseReference(self, type):\r
-        """\r
-        Parse a reference.\r
-\r
-        @return: the parsed reference\r
-        @rtype: L{Reference}\r
-        @raise ConfigFormatError: if a syntax error is found.\r
-        """\r
-        word = self.match(WORD)\r
-        rv = Reference(self.config, type, word[1])\r
-        while self.token[0] in [DOT, LBRACK2]:\r
-            self.parseSuffix(rv)\r
-        return rv\r
-\r
-    def parseSuffix(self, ref):\r
-        """\r
-        Parse a reference suffix.\r
-\r
-        @param ref: The reference of which this suffix is a part.\r
-        @type ref: L{Reference}.\r
-        @raise ConfigFormatError: if a syntax error is found.\r
-        """\r
-        tt = self.token[0]\r
-        if tt == DOT:\r
-            self.match(DOT)\r
-            word = self.match(WORD)\r
-            ref.addElement(DOT, word[1])\r
-        else:\r
-            self.match(LBRACK2)\r
-            tt, tv = self.token\r
-            if tt not in [NUMBER, STRING]:\r
-                raise ConfigFormatError("%s: expected number or string, found %r" % (self.location(), tv))\r
-            self.token = self.getToken()\r
-            tv = eval(tv)\r
-            self.match(RBRACK)\r
-            ref.addElement(LBRACK, tv)\r
-\r
-def defaultMergeResolve(map1, map2, key):\r
-    """\r
-    A default resolver for merge conflicts. Returns a string\r
-    indicating what action to take to resolve the conflict.\r
-\r
-    @param map1: The map being merged into.\r
-    @type map1: L{Mapping}.\r
-    @param map2: The map being used as the merge operand.\r
-    @type map2: L{Mapping}.\r
-    @param key: The key in map2 (which also exists in map1).\r
-    @type key: str\r
-    @return: One of "merge", "append", "mismatch" or "overwrite"\r
-             indicating what action should be taken. This should\r
-             be appropriate to the objects being merged - e.g.\r
-             there is no point returning "merge" if the two objects\r
-             are instances of L{Sequence}.\r
-    @rtype: str\r
-    """\r
-    obj1 = map1[key]\r
-    obj2 = map2[key]\r
-    if isinstance(obj1, Mapping) and isinstance(obj2, Mapping):\r
-        rv = "merge"\r
-    elif isinstance(obj1, Sequence) and isinstance(obj2, Sequence):\r
-        rv = "append"\r
-    else:\r
-        rv = "mismatch"\r
-    return rv\r
-\r
-def overwriteMergeResolve(map1, map2, key):\r
-    """\r
-    An overwriting resolver for merge conflicts. Calls L{defaultMergeResolve},\r
-    but where a "mismatch" is detected, returns "overwrite" instead.\r
-\r
-    @param map1: The map being merged into.\r
-    @type map1: L{Mapping}.\r
-    @param map2: The map being used as the merge operand.\r
-    @type map2: L{Mapping}.\r
-    @param key: The key in map2 (which also exists in map1).\r
-    @type key: str\r
-    """\r
-    rv = defaultMergeResolve(map1, map2, key)\r
-    if rv == "mismatch":\r
-        rv = "overwrite"\r
-    return rv\r
-\r
-class ConfigMerger(object):\r
-    """\r
-    This class is used for merging two configurations. If a key exists in the\r
-    merge operand but not the merge target, then the entry is copied from the\r
-    merge operand to the merge target. If a key exists in both configurations,\r
-    then a resolver (a callable) is called to decide how to handle the\r
-    conflict.\r
-    """\r
-\r
-    def __init__(self, resolver=defaultMergeResolve):\r
-        """\r
-        Initialise an instance.\r
-\r
-        @param resolver:\r
-        @type resolver: A callable which takes the argument list\r
-        (map1, map2, key) where map1 is the mapping being merged into,\r
-        map2 is the merge operand and key is the clashing key. The callable\r
-        should return a string indicating how the conflict should be resolved.\r
-        For possible return values, see L{defaultMergeResolve}. The default\r
-        value preserves the old behaviour\r
-        """\r
-        self.resolver = resolver\r
-\r
-    def merge(self, merged, mergee):\r
-        """\r
-        Merge two configurations. The second configuration is unchanged,\r
-        and the first is changed to reflect the results of the merge.\r
-\r
-        @param merged: The configuration to merge into.\r
-        @type merged: L{Config}.\r
-        @param mergee: The configuration to merge.\r
-        @type mergee: L{Config}.\r
-        """\r
-        self.mergeMapping(merged, mergee)\r
-\r
-    def mergeMapping(self, map1, map2):\r
-        """\r
-        Merge two mappings recursively. The second mapping is unchanged,\r
-        and the first is changed to reflect the results of the merge.\r
-\r
-        @param map1: The mapping to merge into.\r
-        @type map1: L{Mapping}.\r
-        @param map2: The mapping to merge.\r
-        @type map2: L{Mapping}.\r
-        """\r
-        keys = map1.keys()\r
-        for key in map2.keys():\r
-            if key not in keys:\r
-                map1[key] = map2[key]\r
-            else:\r
-                obj1 = map1[key]\r
-                obj2 = map2[key]\r
-                decision = self.resolver(map1, map2, key)\r
-                if decision == "merge":\r
-                    self.mergeMapping(obj1, obj2)\r
-                elif decision == "append":\r
-                    self.mergeSequence(obj1, obj2)\r
-                elif decision == "overwrite":\r
-                    map1[key] = obj2\r
-                elif decision == "mismatch":\r
-                    self.handleMismatch(obj1, obj2)\r
-                else:\r
-                    msg = "unable to merge: don't know how to implement %r"\r
-                    raise ValueError(msg % decision)\r
-\r
-    def mergeSequence(self, seq1, seq2):\r
-        """\r
-        Merge two sequences. The second sequence is unchanged,\r
-        and the first is changed to have the elements of the second\r
-        appended to it.\r
-\r
-        @param seq1: The sequence to merge into.\r
-        @type seq1: L{Sequence}.\r
-        @param seq2: The sequence to merge.\r
-        @type seq2: L{Sequence}.\r
-        """\r
-        data1 = object.__getattribute__(seq1, 'data')\r
-        data2 = object.__getattribute__(seq2, 'data')\r
-        for obj in data2:\r
-            data1.append(obj)\r
-        comment1 = object.__getattribute__(seq1, 'comments')\r
-        comment2 = object.__getattribute__(seq2, 'comments')\r
-        for obj in comment2:\r
-            comment1.append(obj)\r
-\r
-    def handleMismatch(self, obj1, obj2):\r
-        """\r
-        Handle a mismatch between two objects.\r
-\r
-        @param obj1: The object to merge into.\r
-        @type obj1: any\r
-        @param obj2: The object to merge.\r
-        @type obj2: any\r
-        """\r
-        raise ConfigError("unable to merge %r with %r" % (obj1, obj2))\r
-\r
-class ConfigList(list):\r
-    """\r
-    This class implements an ordered list of configurations and allows you\r
-    to try getting the configuration from each entry in turn, returning\r
-    the first successfully obtained value.\r
-    """\r
-\r
-    def getByPath(self, path):\r
-        """\r
-        Obtain a value from the first configuration in the list which defines\r
-        it.\r
-\r
-        @param path: The path of the value to retrieve.\r
-        @type path: str\r
-        @return: The value from the earliest configuration in the list which\r
-        defines it.\r
-        @rtype: any\r
-        @raise ConfigError: If no configuration in the list has an entry with\r
-        the specified path.\r
-        """\r
-        found = False\r
-        rv = None\r
-        for entry in self:\r
-            try:\r
-                rv = entry.getByPath(path)\r
-                found = True\r
-                break\r
-            except ConfigError:\r
-                pass\r
-        if not found:\r
-            raise ConfigError("unable to resolve %r" % path)\r
-        return rv\r
diff --git a/src/test/config_0_3_9/logconfig.cfg b/src/test/config_0_3_9/logconfig.cfg
deleted file mode 100644 (file)
index 2845e3c..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-# Configuration file for logconfig.py\r
-\r
-# root logger configuration\r
-root:\r
-{\r
-  level     : `DEBUG`\r
-  handlers  : [$handlers.console, $handlers.file]\r
-}\r
-formatters: {\r
-  brief:\r
-  {\r
-    format: '%(levelname)-8s: %(name)s: %(message)s'\r
-  }\r
-  precise:\r
-  {\r
-    format: '%(asctime)s %(name)-15s %(levelname)-8s %(message)s'\r
-  }\r
-}\r
-handlers:\r
-{\r
-  console:\r
-  {\r
-    class : `logconfig.StreamHandler`\r
-    config:\r
-    {\r
-      level   : `INFO`\r
-      stream  : `sys.stdout`\r
-      formatter: $formatters.brief\r
-    }\r
-  }\r
-  file:\r
-  {\r
-    class : `logconfig.RotatingFileHandler`\r
-    config:\r
-    {\r
-      name: 'logconfig.log'\r
-      maxBytes: 1024\r
-      backupCount: 3\r
-      formatter: $formatters.precise\r
-    }\r
-  }\r
-  debugfile:\r
-  {\r
-    class : `logconfig.FileHandler`\r
-    config:\r
-    {\r
-      name: 'logconfig-detail.log'\r
-      mode: 'a'\r
-      formatter: $formatters.precise\r
-    }\r
-  }\r
-}\r
-loggers:\r
-{\r
-  area1:\r
-  {\r
-    level : `ERROR`\r
-    handlers: [$handlers.debugfile]\r
-  }\r
-  area2:\r
-  {\r
-    level : `CRITICAL`\r
-    handlers: [$handlers.debugfile]\r
-  }\r
-}
\ No newline at end of file
diff --git a/src/test/config_0_3_9/logconfig.py b/src/test/config_0_3_9/logconfig.py
deleted file mode 100644 (file)
index 44ae1ed..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-#!/usr/bin/env python\r
-#\r
-# Copyright 2001-2004 by Vinay Sajip. All Rights Reserved.\r
-#\r
-# Permission to use, copy, modify, and distribute this software and its\r
-# documentation for any purpose and without fee is hereby granted,\r
-# provided that the above copyright notice appear in all copies and that\r
-# both that copyright notice and this permission notice appear in\r
-# supporting documentation, and that the name of Vinay Sajip\r
-# not be used in advertising or publicity pertaining to distribution\r
-# of the software without specific, written prior permission.\r
-# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING\r
-# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL\r
-# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR\r
-# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER\r
-# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT\r
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\r
-#\r
-# This file is part of the Python config distribution. See\r
-# http://www.red-dove.com/python_config.html\r
-#\r
-"""\r
-A test for the config module through seeing how to use it to configure logging.\r
-\r
-Copyright (C) 2004 Vinay Sajip. All Rights Reserved.\r
-"""\r
-\r
-from config import Config\r
-from optparse import OptionParser, get_prog_name\r
-from random import choice\r
-import logging\r
-import logging.handlers\r
-import sys\r
-\r
-class Usage(Exception):\r
-    pass\r
-\r
-class BaseHandler:\r
-    def __init__(self, config):\r
-        if 'level' in config:\r
-            self.setLevel(config.level)\r
-        if 'formatter' in config:\r
-            self.setFormatter(config.formatter)\r
-\r
-class StreamHandler(logging.StreamHandler, BaseHandler):\r
-    def __init__(self, config):\r
-        stream = config.get('stream')\r
-        logging.StreamHandler.__init__(self, stream)\r
-        BaseHandler.__init__(self, config)\r
-\r
-class RotatingFileHandler(logging.handlers.RotatingFileHandler, BaseHandler):\r
-    def __init__(self, config):\r
-        name = config.get('name')\r
-        if name is None:\r
-            raise ValueError('RotatingFileHandler: name not specified')\r
-        mode = config.get('mode', 'a')\r
-        maxBytes = config.get('maxBytes', 0)\r
-        backupCount = config.get('backupCount', 0)\r
-        logging.handlers.RotatingFileHandler.__init__(self, name, mode, maxBytes, backupCount)\r
-        BaseHandler.__init__(self, config)\r
-\r
-class FileHandler(logging.FileHandler, BaseHandler):\r
-    def __init__(self, config):\r
-        name = config.get('name')\r
-        if name is None:\r
-            raise ValueError('FileHandler: name not specified')\r
-        mode = config.get('mode', 'a')\r
-        logging.FileHandler.__init__(self, name, mode)\r
-        BaseHandler.__init__(self, config)\r
-\r
-def configLogger(logger, config):\r
-    for handler in logger.handlers:\r
-        logger.removeHandler(handler)\r
-    if 'level' in config:\r
-        logger.setLevel(config.level)\r
-    if 'handlers' in config:\r
-        for handler in config.handlers:\r
-            logger.addHandler(handler)\r
-\r
-def fileConfig(fname, *args, **kwargs):\r
-    cfg = Config(fname)\r
-    cfg.addNamespace(logging)\r
-    cfg.addNamespace(sys.modules[StreamHandler.__module__], 'logconfig')\r
-\r
-    for name in cfg.formatters.keys():\r
-        formatterConfig = cfg.formatters[name]\r
-        fmt = formatterConfig.get('format')\r
-        datefmt = formatterConfig.get('datefmt')\r
-        formatter = logging.Formatter(fmt, datefmt)\r
-        cfg.formatters[name] = formatter\r
-\r
-    for name in cfg.handlers.keys():\r
-        klass = cfg.handlers[name].get('class')\r
-        config = cfg.handlers[name].get('config')\r
-        cfg.handlers[name] = klass(config)\r
-\r
-    for name in cfg.loggers.keys():\r
-        loggerConfig = cfg.loggers[name]\r
-        logger = logging.getLogger(name)\r
-        configLogger(logger, loggerConfig)\r
-\r
-    if 'root' in cfg:\r
-        configLogger(logging.getLogger(''), cfg.root)\r
-\r
-def testConfig():\r
-    levels = [logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL]\r
-    loggers = ['', 'area1', 'area2']\r
-    for i in xrange(1000):\r
-        logger = logging.getLogger(choice(loggers))\r
-        level = choice(levels)\r
-        logger.log(level, "Message number %d", i)\r
-\r
-def main(args=None):\r
-    rv = 0\r
-    if args is None:\r
-        args = sys.argv[1:]\r
-    parser = OptionParser(usage="usage: %prog [options] CONFIG-FILE")\r
-\r
-    (options, args) = parser.parse_args(args)\r
-    try:\r
-        if len(args) == 0:\r
-            raise Usage("No configuration file specified")\r
-        fileConfig(args[0])\r
-        testConfig()\r
-    except Usage, e:\r
-        parser.print_help()\r
-        print "\n%s: error: %s" % (get_prog_name(), e)\r
-        rv = 1\r
-    except Exception, e:\r
-        print "\n%s: error: %s" % (get_prog_name(), e)\r
-        typ, val, tb = sys.exc_info()\r
-        import traceback\r
-        traceback.print_tb(tb)\r
-        rv = 2\r
-    return rv\r
-\r
-if __name__ == "__main__":\r
-    sys.exit(main())\r
diff --git a/src/test/config_0_3_9/setup.py b/src/test/config_0_3_9/setup.py
deleted file mode 100644 (file)
index 9c7dfab..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-from distutils.core import setup
-
-setup(name = "config",
-   description="A hierarchical, easy-to-use, powerful configuration module for Python",
-   long_description = """This module allows a hierarchical configuration scheme with support for mappings
-and sequences, cross-references between one part of the configuration and
-another, the ability to flexibly access real Python objects without full-blown
-eval(), an include facility, simple expression evaluation and the ability to
-change, save, cascade and merge configurations. Interfaces easily with
-environment variables and command-line options. It has been developed on python
-2.3 but should work on version 2.2 or greater.""",
-   license="""Copyright (C) 2004-2010 by Vinay Sajip. All Rights Reserved. See LICENSE for license.""",
-            version = "0.3.9",
-            author = "Vinay Sajip",
-            author_email = "vinay_sajip@red-dove.com",
-            maintainer = "Vinay Sajip",
-            maintainer_email = "vinay_sajip@red-dove.com",
-            url = "http://www.red-dove.com/python_config.html",
-            py_modules = ["config"],
-            )
diff --git a/src/test/config_0_3_9/styles.json b/src/test/config_0_3_9/styles.json
deleted file mode 100644 (file)
index 259697e..0000000
+++ /dev/null
@@ -1,554 +0,0 @@
-{
-  "embeddedFonts" : [ ],
-  "pageSetup" : {
-    "size": "A4",
-    "width": null,
-    "height": null,
-    "margin-top": "2cm",
-    "margin-bottom": "2cm",
-    "margin-left": "2cm",
-    "margin-right": "2cm",
-    "margin-gutter": "0cm",
-    "spacing-header": "5mm",
-    "spacing-footer": "5mm",
-    "firstTemplate": "oneColumn"
-  },
-  "pageTemplates" : {
-    "coverPage": {
-        "frames": [
-            ["0cm", "0cm", "100%", "100%"]
-        ],
-        "showHeader" : false,
-        "showFooter" : false
-    },
-    "oneColumn": {
-        "frames": [
-            ["0cm", "0cm", "100%", "100%"]
-        ],
-        "showHeader" : true,
-        "showFooter" : true
-    },
-    "twoColumn": {
-        "frames": [
-            ["0cm", "0cm", "49%", "100%"],
-            ["51%", "0cm", "49%", "100%"]
-        ],
-        "showHeader" : true,
-        "showFooter" : true
-    },
-    "threeColumn": {
-        "frames": [
-            ["2%", "0cm", "29.333%", "100%"],
-            ["35.333%", "0cm", "29.333%", "100%"],
-            ["68.666%", "0cm", "29.333%", "100%"]
-        ],
-        "showHeader" : true,
-        "showFooter" : true
-    },
-    "cutePage": {
-        "frames": [
-            ["0%", "0%", "100%", "100%"]
-        ],
-        "showHeader" : true,
-        "showFooter" : true,
-        "defaultFooter" : "###Page###",
-        "defaultHeader" : "###Section###"
-    }
-  },
-  "fontsAlias" : {
-    "stdFont": "Helvetica",     
-    "stdBold": "Helvetica-Bold",
-    "stdItalic": "Helvetica-Oblique",
-    "stdBoldItalic": "Helvetica-BoldOblique",
-    "stdSans": "Helvetica",
-    "stdSansBold": "Helvetica-Bold",
-    "stdSansItalic": "Helvetica-Oblique",
-    "stdSansBoldItalic": "Helvetica-BoldOblique",
-    "stdMono": "Courier",
-    "stdMonoItalic": "Courier-Oblique",
-    "stdMonoBold": "Courier-Bold",
-    "stdMonoBoldItalic": "Courier-BoldOblique",
-    "stdSerif": "Times-Roman"
-  },
-  "linkColor" : "navy",
-  "styles" : [
-    [ "base" , {
-      "parent": null,
-      "fontName": "stdFont",
-      "fontSize":10,
-      "leading":12,
-      "leftIndent":0,
-      "rightIndent":0,
-      "firstLineIndent":0,
-      "alignment":"TA_LEFT",
-      "spaceBefore":0,
-      "spaceAfter":0,
-      "bulletFontName":"stdFont",
-      "bulletFontSize":10,
-      "bulletIndent":0,
-      "textColor": "black",
-      "backColor": null,
-      "wordWrap": null,
-      "borderWidth": 0,
-      "borderPadding": 0,
-      "borderColor": null,
-      "borderRadius": null,
-      "allowWidows": false,
-      "allowOrphans": false,
-      "hyphenation": false,
-      "kerning": false
-    }] ,
-    ["normal" , {
-      "parent": "base"
-    }],
-    ["title_reference" , {
-      "parent": "normal",
-      "fontName": "stdItalic"
-    }],
-    ["bodytext" , {
-      "parent": "normal",
-      "spaceBefore": 6,
-      "alignment": "TA_JUSTIFY",
-      "hyphenation": true
-    }],
-    ["toc" , {
-      "parent": "normal"
-    }],
-    ["blockquote" , {
-      "parent": "bodytext",
-      "leftIndent": 20
-    }],
-    ["lineblock" , {
-      "parent": "bodytext"
-    }],
-    ["line" , {
-      "parent": "lineblock",
-      "spaceBefore": 0
-    }],
-    ["toc1" , {
-      "parent": "toc",
-      "fontName": "stdBold"
-    }],
-    ["toc2" , {
-      "parent": "toc",
-      "leftIndent": 20
-    }],
-    ["toc3" , {
-      "parent": "toc",
-      "leftIndent": 40
-    }],
-    ["toc4" , {
-      "parent": "toc",
-      "leftIndent": 60
-    }],
-    ["toc5" , {
-      "parent": "toc",
-      "leftIndent": 80
-    }],
-    ["toc6" , {
-      "parent": "toc",
-      "leftIndent": 100
-    }],
-    ["toc7" , {
-      "parent": "toc",
-      "leftIndent": 100
-    }],
-    ["toc8" , {
-      "parent": "toc",
-      "leftIndent": 100
-    }],
-    ["toc9" , {
-      "parent": "toc",
-      "leftIndent": 100
-    }],
-    ["toc10" , {
-      "parent": "toc",
-      "leftIndent": 100
-    }],
-    ["toc11" , {
-      "parent": "toc",
-      "leftIndent": 100
-    }],
-    ["toc12" , {
-      "parent": "toc",
-      "leftIndent": 100
-    }],
-    ["toc13" , {
-      "parent": "toc",
-      "leftIndent": 100
-    }],
-    ["toc14" , {
-      "parent": "toc",
-      "leftIndent": 100
-    }],
-    ["toc15" , {
-      "parent": "toc",
-      "leftIndent": 100
-    }],
-    ["footer" , {
-      "parent": "normal",
-      "alignment": "TA_CENTER"
-    }],
-    ["header" , {
-      "parent": "normal",
-      "alignment": "TA_CENTER"
-    }],
-    ["attribution" , {
-      "parent": "bodytext",
-      "alignment": "TA_RIGHT"
-    }],
-    ["figure" , {
-      "parent": "bodytext",
-      "alignment": "TA_CENTER"
-    }],
-    ["figure-caption" , {
-      "parent": "bodytext",
-      "fontName": "stdItalic",
-      "alignment": "TA_CENTER"
-    }],
-    ["figure-legend" , {
-      "parent": "bodytext",
-      "alignment": "TA_CENTER"
-    }],
-    ["bullet_list", {
-      "parent": "bodytext",
-      "commands": [
-            [ "VALIGN", [ 0, 0 ], [ -1, -1 ], "TOP" ],
-            [ "RIGHTPADDING", [ 0, 0 ], [ 1, -1 ], 0 ] 
-        ], 
-        "colWidths": ["20",null]
-    }],
-    ["bullet_list_item" , {
-      "parent": "bodytext"
-    }],
-    ["item_list", { 
-      "parent": "bodytext",
-      "commands": [
-            [ "VALIGN", [ 0, 0 ], [ -1, -1 ], "TOP" ], 
-            [ "RIGHTPADDING", [ 0, 0 ], [ 1, -1 ], 0 ] 
-        ],
-        "colWidths": ["20pt",null]
-    }],
-    ["item_list_item" , {
-      "parent": "bodytext"
-    }],
-    ["definition_list_term" , {
-      "parent": "normal",
-      "fontName": "stdBold",
-      "spaceBefore": 4,
-      "spaceAfter": 0,
-      "keepWithNext": true
-    }],
-    ["definition_list_classifier" , {
-      "parent": "normal",
-      "fontName": "stdItalic"
-    }],
-    ["definition" , {
-      "parent": "bodytext",
-      "firstLineIndent": 0,
-      "bulletIndent": 0,
-      "spaceBefore": 0
-    }],
-    ["fieldname" , {
-      "parent": "bodytext",
-      "alignment": "TA_RIGHT",
-      "fontName": "stdBold"
-    }],
-    ["fieldvalue" , {
-      "parent": "bodytext"
-    }],
-    ["rubric" , {
-      "parent": "bodytext",
-      "textColor": "darkred",
-      "alignment": "TA_CENTER"
-    }],
-    ["italic" , {
-      "parent": "bodytext",
-      "fontName": "stdItalic"
-    }],
-    ["heading" , {
-      "parent": "normal",
-      "keepWithNext": true,
-      "spaceBefore": 12,
-      "spaceAfter": 6
-    }],
-    ["title" , {
-      "parent": "heading",
-      "fontName": "stdBold",
-      "fontSize": "200%",
-      "alignment": "TA_CENTER",
-      "keepWithNext": false,
-      "spaceAfter": 10
-    }],
-    ["subtitle" , {
-      "parent": "title",
-      "spaceBefore": 12,
-      "fontSize": "75%"
-    }],
-    ["heading1" , {
-      "parent": "heading",
-      "fontName": "stdBold",
-      "fontSize": "175%"
-    }],
-    ["heading2" , {
-      "parent": "heading",
-      "fontName": "stdBold",
-      "fontSize": "150%"
-    }],
-    ["heading3" , {
-      "parent": "heading",
-      "fontName": "stdBoldItalic",
-      "fontSize": "125%"
-    }],
-    ["heading4" , {
-      "parent": "heading",
-      "fontName": "stdBoldItalic"
-    }],
-    ["heading5" , {
-      "parent": "heading",
-      "fontName": "stdBoldItalic"
-    }],
-    ["heading6" , {
-      "parent": "heading",
-      "fontName": "stdBoldItalic"
-    }],
-    ["topic-title" , {
-      "parent": "heading3"
-    }],
-    ["sidebar-title" , {
-      "parent": "heading3"
-    }],
-    ["sidebar-subtitle" , {
-      "parent": "heading4"
-    }],
-    ["sidebar" , {
-      "float": "none",
-      "width": "100%",
-      "parent": "normal",
-      "backColor": "beige",
-      "borderColor": "darkgray",
-      "borderPadding": 8,
-      "borderWidth": 0.5
-    }],
-    ["admonition" , {
-      "parent": "normal",
-      "spaceBefore": 12,
-      "spaceAfter": 6,
-      "borderPadding": [16,16,16,16],
-      "backColor": "beige",
-      "borderColor": "darkgray",
-      "borderWidth": 0.5,
-      "commands":[
-            [ "VALIGN", [ 0, 0 ], [ -1, -1 ], "TOP" ]
-      ]
-    }],
-    ["attention" , {
-      "parent": "admonition"
-    }],
-    ["caution" , {
-      "parent": "admonition"
-    }],
-    ["danger" , {
-      "parent": "admonition"
-    }],
-    ["error" , {
-      "parent": "admonition"
-    }],
-    ["hint" , {
-      "parent": "admonition"
-    }],
-    ["important" , {
-      "parent": "admonition"
-    }],
-    ["note" , {
-      "parent": "admonition"
-    }],
-    ["tip" , {
-      "parent": "admonition"
-    }],
-    ["warning" , {
-      "parent": "admonition"
-    }],
-    ["admonition-title" , {
-      "parent": "heading3"
-    }],
-    ["admonition-heading" , {
-      "parent": "heading3"
-    }],
-    ["attention-heading" , {
-      "parent": "admonition-heading"
-    }],
-    ["caution-heading" , {
-      "parent": "admonition-heading"
-    }],
-    ["danger-heading" , {
-      "parent": "admonition-heading"
-    }],
-    ["error-heading" , {
-      "parent": "admonition-heading"
-    }],
-    ["hint-heading" , {
-      "parent": "admonition-heading"
-    }],
-    ["important-heading" , {
-      "parent": "admonition-heading"
-    }],
-    ["note-heading" , {
-      "parent": "admonition-heading"
-    }],
-    ["tip-heading" , {
-      "parent": "admonition-heading"
-    }],
-    ["warning-heading" , {
-      "parent": "admonition-heading"
-    }],
-    ["literal" , {
-      "parent": "normal",
-      "fontName": "stdMono",
-      "firstLineIndent": 0,
-      "hyphenation": false
-    }],
-    ["aafigure" , {
-      "parent": "literal"
-    }],
-    ["table" , {
-      "spaceBefore":6,
-      "spaceAfter":0,
-      "alignment": "TA_CENTER",
-      "commands": [
-            [ "VALIGN", [ 0, 0 ], [ -1, -1 ], "TOP" ], 
-            [ "INNERGRID", [ 0, 0 ], [ -1, -1 ], 0.25, "black" ], 
-            [ "ROWBACKGROUNDS", [0, 0], [-1, -1], ["white","#E0E0E0"]],
-            [ "BOX", [ 0, 0 ], [ -1, -1 ], 0.25, "black" ]
-      ]
-    }],
-    ["table-title" , {
-      "parent" : "heading4",
-      "keepWithNext": false,
-      "alignment" : "TA_CENTER"
-    }],
-    ["table-heading" , {
-      "parent" : "heading",
-      "backColor" : "beige",
-      "alignment" : "TA_CENTER",
-      "valign" : "BOTTOM",
-      "borderPadding" : 0
-    }],
-    ["table-body", {
-      "parent" : "normal"
-    }],
-    ["dedication" , {
-      "parent" : "normal"
-    }],
-    ["abstract" , {
-      "parent" : "normal"
-    }],
-    ["contents" , {
-      "parent" : "normal"
-    }],
-    ["tableofcontents" , {
-      "parent" : "normal"
-    }],
-    ["code" , {
-      "parent": "literal",
-      "leftIndent": 0,
-      "spaceBefore": 8,
-      "spaceAfter": 8,
-      "backColor": "beige",
-      "borderColor": "darkgray",
-      "borderWidth": 0.5,
-      "borderPadding": 6
-    }],
-    ["pygments-n" , {"parent": "code"}],
-    ["pygments-nx" , {"parent": "code"}],
-    ["pygments-p" , {"parent": "code"}],
-    ["pygments-hll", {"parent": "code", "backColor": "#ffffcc"}],
-    ["pygments-c", {"textColor": "#008800", "parent": "code"}],
-    ["pygments-err", {"parent": "code"}],
-    ["pygments-k", {"textColor": "#AA22FF", "parent": "code"}],
-    ["pygments-o", {"textColor": "#666666", "parent": "code"}],
-    ["pygments-cm", {"textColor": "#008800", "parent": "code"}],
-    ["pygments-cp", {"textColor": "#008800", "parent": "code"}],
-    ["pygments-c1", {"textColor": "#008800", "parent": "code"}],
-    ["pygments-cs", {"textColor": "#008800", "parent": "code"}],
-    ["pygments-gd", {"textColor": "#A00000", "parent": "code"}],
-    ["pygments-ge", {"parent": "code"}],
-    ["pygments-gr", {"textColor": "#FF0000", "parent": "code"}],
-    ["pygments-gh", {"textColor": "#000080", "parent": "code"}],
-    ["pygments-gi", {"textColor": "#00A000", "parent": "code"}],
-    ["pygments-go", {"textColor": "#808080", "parent": "code"}],
-    ["pygments-gp", {"textColor": "#000080", "parent": "code"}],
-    ["pygments-gs", {"parent": "code"}],
-    ["pygments-gu", {"textColor": "#800080", "parent": "code"}],
-    ["pygments-gt", {"textColor": "#0040D0", "parent": "code"}],
-    ["pygments-kc", {"textColor": "#AA22FF", "parent": "code"}],
-    ["pygments-kd", {"textColor": "#AA22FF", "parent": "code"}],
-    ["pygments-kn", {"textColor": "#AA22FF", "parent": "code"}],
-    ["pygments-kp", {"textColor": "#AA22FF", "parent": "code"}],
-    ["pygments-kr", {"textColor": "#AA22FF", "parent": "code"}],
-    ["pygments-kt", {"textColor": "#00BB00", "parent": "code"}],
-    ["pygments-m", {"textColor": "#666666", "parent": "code"}],
-    ["pygments-s", {"textColor": "#BB4444", "parent": "code"}],
-    ["pygments-na", {"textColor": "#BB4444", "parent": "code"}],
-    ["pygments-nb", {"textColor": "#AA22FF", "parent": "code"}],
-    ["pygments-nc", {"textColor": "#0000FF", "parent": "code"}],
-    ["pygments-no", {"textColor": "#880000", "parent": "code"}],
-    ["pygments-nd", {"textColor": "#AA22FF", "parent": "code"}],
-    ["pygments-ni", {"textColor": "#999999", "parent": "code"}],
-    ["pygments-ne", {"textColor": "#D2413A", "parent": "code"}],
-    ["pygments-nf", {"textColor": "#00A000", "parent": "code"}],
-    ["pygments-nl", {"textColor": "#A0A000", "parent": "code"}],
-    ["pygments-nn", {"textColor": "#0000FF", "parent": "code"}],
-    ["pygments-nt", {"textColor": "#008000", "parent": "code"}],
-    ["pygments-nv", {"textColor": "#B8860B", "parent": "code"}],
-    ["pygments-ow", {"textColor": "#AA22FF", "parent": "code"}],
-    ["pygments-w", {"textColor": "#bbbbbb", "parent": "code"}],
-    ["pygments-mf", {"textColor": "#666666", "parent": "code"}],
-    ["pygments-mh", {"textColor": "#666666", "parent": "code"}],
-    ["pygments-mi", {"textColor": "#666666", "parent": "code"}],
-    ["pygments-mo", {"textColor": "#666666", "parent": "code"}],
-    ["pygments-sb", {"textColor": "#BB4444", "parent": "code"}],
-    ["pygments-sc", {"textColor": "#BB4444", "parent": "code"}],
-    ["pygments-sd", {"textColor": "#BB4444", "parent": "code"}],
-    ["pygments-s2", {"textColor": "#BB4444", "parent": "code"}],
-    ["pygments-se", {"textColor": "#BB6622", "parent": "code"}],
-    ["pygments-sh", {"textColor": "#BB4444", "parent": "code"}],
-    ["pygments-si", {"textColor": "#BB6688", "parent": "code"}],
-    ["pygments-sx", {"textColor": "#008000", "parent": "code"}],
-    ["pygments-sr", {"textColor": "#BB6688", "parent": "code"}],
-    ["pygments-s1", {"textColor": "#BB4444", "parent": "code"}],
-    ["pygments-ss", {"textColor": "#B8860B", "parent": "code"}],
-    ["pygments-bp", {"textColor": "#AA22FF", "parent": "code"}],
-    ["pygments-vc", {"textColor": "#B8860B", "parent": "code"}],
-    ["pygments-vg", {"textColor": "#B8860B", "parent": "code"}],
-    ["pygments-vi", {"textColor": "#B8860B", "parent": "code"}],
-    ["pygments-il", {"textColor": "#666666", "parent": "code"}],
-    
-     [ "endnote", {
-         "parent": "bodytext",
-         "commands": [
-            [ "VALIGN", [ 0, 0 ], [ -1, -1 ], "TOP" ],
-            [ "TOPPADDING", [ 0, 0 ], [ -1, -1 ], 0 ], 
-            [ "BOTTOMPADDING", [ 0, 0 ], [ -1, -1 ], 0 ], 
-            [ "RIGHTPADDING", [ 0, 0 ], [ 1, -1 ], 0 ] 
-        ], 
-        "colWidths": ["3cm",null]
-    }],
-    [ "field_list", {
-         "parent": "bodytext",
-         "commands": [
-            [ "VALIGN", [ 0, 0 ], [ -1, -1 ], "TOP" ], 
-            [ "TOPPADDING", [ 0, 0 ], [ -1, -1 ], 0 ]
-        ], 
-        "colWidths": ["3cm",null],
-        "spaceBefore": 6
-    }],
-    [ "option_list", {
-         "commands": [
-            [ "VALIGN", [ 0, 0 ], [ -1, -1 ], "TOP" ], 
-            [ "TOPPADDING", [ 0, 0 ], [ -1, -1 ], 0 ]
-        ],
-        "colWidths": [null,null]
-    }]
-  ]
-}
diff --git a/src/test/config_0_3_9/test_config.py b/src/test/config_0_3_9/test_config.py
deleted file mode 100644 (file)
index 393be86..0000000
+++ /dev/null
@@ -1,439 +0,0 @@
-# Copyright 2004-2010 by Vinay Sajip. All Rights Reserved.\r
-#\r
-# Permission to use, copy, modify, and distribute this software and its\r
-# documentation for any purpose and without fee is hereby granted,\r
-# provided that the above copyright notice appear in all copies and that\r
-# both that copyright notice and this permission notice appear in\r
-# supporting documentation, and that the name of Vinay Sajip\r
-# not be used in advertising or publicity pertaining to distribution\r
-# of the software without specific, written prior permission.\r
-# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING\r
-# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL\r
-# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR\r
-# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER\r
-# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT\r
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\r
-\r
-"""\r
-Test harness for the configuration module 'config' for Python.\r
-"""\r
-\r
-import unittest\r
-# import test_support\r
-import config\r
-from config import Config, ConfigMerger, ConfigList\r
-from config import ConfigError, ConfigFormatError, ConfigResolutionError\r
-import logging\r
-from StringIO import StringIO\r
-\r
-STREAMS = {\r
-    "simple_1" :\r
-"""\r
-message: 'Hello, world!'\r
-""",\r
-    "malformed_1" :\r
-"""\r
-123\r
-""",\r
-    "malformed_2" :\r
-"""\r
-[ 123, 'abc' ]\r
-""",\r
-    "malformed_3" :\r
-"""\r
-{ a : 7, b : 1.3, c : 'test' }\r
-""",\r
-    "malformed_4" :\r
-"""\r
-test: $a [7] # note space before bracket\r
-""",\r
-    "malformed_5" :\r
-"""\r
-test: 'abc'\r
-test: 'def'\r
-""",\r
-    "wellformed_1" :\r
-"""\r
-test: $a[7] # note no space before bracket\r
-""",\r
-    "boolean_1":\r
-"""\r
-test : False\r
-another_test: True\r
-""",\r
-    "boolean_2":\r
-"""\r
-test : false\r
-another_test: true\r
-""",\r
-    "none_1":\r
-"""\r
-test : None\r
-""",\r
-    "none_2":\r
-"""\r
-test : none\r
-""",\r
-    "number_1":\r
-"""\r
-root: 1\r
-stream: 1.7\r
-neg: -1\r
-negfloat: -2.0\r
-posexponent: 2.0999999e-08\r
-negexponent: -2.0999999e-08\r
-exponent: 2.0999999e08\r
-""",\r
-    "sequence_1":\r
-"""\r
-mixed: [ "VALIGN", [ 0, 0 ], [ -1, -1 ], "TOP" ]\r
-simple: [1, 2]\r
-nested: [1, [2, 3], [4, [5, 6]]]\r
-""",\r
-    "include_1":\r
-"""\r
-included: @'include_2'\r
-""",\r
-    "include_2":\r
-"""\r
-test: 123\r
-another_test: 'abc'\r
-""",\r
-    "expr_1":\r
-"""\r
-value1 : 10\r
-value2 : 5\r
-value3 : 'abc'\r
-value4 : 'ghi'\r
-value5 : 0\r
-value6 : { 'a' : $value1, 'b': $value2 }\r
-derived1 : $value1 + $value2\r
-derived2 : $value1 - $value2\r
-derived3 : $value1 * $value2\r
-derived4 : $value1 / $value2\r
-derived5 : $value1 % $value2\r
-derived6 : $value3 + $value4\r
-derived7 : $value3 + 'def' + $value4\r
-derived8 : $value3 - $value4 # meaningless\r
-derived9 : $value1 / $value5    # div by zero\r
-derived10 : $value1 % $value5   # div by zero\r
-derived11 : $value17    # doesn't exist\r
-derived12 : $value6.a + $value6.b\r
-""",\r
-    "eval_1":\r
-"""\r
-stderr : `sys.stderr`\r
-stdout : `sys.stdout`\r
-stdin : `sys.stdin`\r
-debug : `debug`\r
-DEBUG : `DEBUG`\r
-derived: $DEBUG * 10\r
-""",\r
-    "merge_1":\r
-"""\r
-value1: True\r
-value3: [1, 2, 3]\r
-value5: [ 7 ]\r
-value6: { 'a' : 1, 'c' : 3 }\r
-""",\r
-    "merge_2":\r
-"""\r
-value2: False\r
-value4: [4, 5, 6]\r
-value5: ['abc']\r
-value6: { 'b' : 2, 'd' : 4 }\r
-""",\r
-    "merge_3":\r
-"""\r
-value1: True\r
-value2: 3\r
-value3: [1, 3, 5]\r
-value4: [1, 3, 5]\r
-""",\r
-    "merge_4":\r
-"""\r
-value1: False\r
-value2: 4\r
-value3: [2, 4, 6]\r
-value4: [2, 4, 6]\r
-""",\r
-    "list_1":\r
-"""\r
-verbosity : 1\r
-""",\r
-    "list_2":\r
-"""\r
-verbosity : 2\r
-program_value: 4\r
-""",\r
-    "list_3":\r
-"""\r
-verbosity : 3\r
-suite_value: 5\r
-""",\r
-    "get_1":\r
-"""\r
-value1 : 123\r
-value2 : 'abcd'\r
-value3 : True\r
-value4 : None\r
-value5:\r
-{\r
-    value1 : 123\r
-    value2 : 'abcd'\r
-    value3 : True\r
-    value4 : None\r
-}\r
-""",\r
-    "multiline_1":\r
-"""\r
-value1: '''Value One\r
-Value Two\r
-'''\r
-value2: \"\"\"Value Three\r
-Value Four\"\"\"\r
-"""\r
-}\r
-\r
-def makeStream(name):\r
-    s = StringIO(STREAMS[name])\r
-    s.name = name\r
-    return s\r
-\r
-class OutStream(StringIO):\r
-    def close(self):\r
-        self.value = self.getvalue()\r
-        StringIO.close(self)\r
-\r
-class TestConfig(unittest.TestCase):\r
-\r
-    def setUp(self):\r
-        self.cfg = Config(None)\r
-\r
-    def tearDown(self):\r
-        del self.cfg\r
-\r
-    def testCreation(self):\r
-        self.assertEqual(0, len(self.cfg))  # should be empty\r
-\r
-    def testSimple(self):\r
-        self.cfg.load(makeStream("simple_1"))\r
-        self.failUnless('message' in self.cfg)\r
-        self.failIf('root' in self.cfg)\r
-        self.failIf('stream' in self.cfg)\r
-        self.failIf('load' in self.cfg)\r
-        self.failIf('save' in self.cfg)\r
-\r
-    def testValueOnly(self):\r
-        self.assertRaises(ConfigError, self.cfg.load,\r
-           makeStream("malformed_1"))\r
-        self.assertRaises(ConfigError, self.cfg.load,\r
-           makeStream("malformed_2"))\r
-        self.assertRaises(ConfigError, self.cfg.load,\r
-           makeStream("malformed_3"))\r
-\r
-    def testBadBracket(self):\r
-        self.assertRaises(ConfigError, self.cfg.load,\r
-           makeStream("malformed_4"))\r
-\r
-    def testDuplicate(self):\r
-        self.assertRaises(ConfigError, self.cfg.load,\r
-           makeStream("malformed_5"))\r
-\r
-    def testGoodBracket(self):\r
-        self.cfg.load(makeStream("wellformed_1"))\r
-\r
-    def testBoolean(self):\r
-        self.cfg.load(makeStream("boolean_1"))\r
-        self.assertEqual(True, self.cfg.another_test)\r
-        self.assertEqual(False, self.cfg.test)\r
-\r
-    def testNotBoolean(self):\r
-        self.cfg.load(makeStream("boolean_2"))\r
-        self.assertEqual('true', self.cfg.another_test)\r
-        self.assertEqual('false', self.cfg.test)\r
-\r
-    def testNone(self):\r
-        self.cfg.load(makeStream("none_1"))\r
-        self.assertEqual(None, self.cfg.test)\r
-\r
-    def testNotNone(self):\r
-        self.cfg.load(makeStream("none_2"))\r
-        self.assertEqual('none', self.cfg.test)\r
-\r
-    def testNumber(self):\r
-        self.cfg.load(makeStream("number_1"))\r
-        self.assertEqual(1, self.cfg.root)\r
-        self.assertEqual(1.7, self.cfg.stream)\r
-        self.assertEqual(-1, self.cfg.neg)\r
-        self.assertEqual(-2.0, self.cfg.negfloat)\r
-        self.assertAlmostEqual(-2.0999999e-08, self.cfg.negexponent)\r
-        self.assertAlmostEqual(2.0999999e-08, self.cfg.posexponent)\r
-        self.assertAlmostEqual(2.0999999e08, self.cfg.exponent)\r
-\r
-    def testChange(self):\r
-        self.cfg.load(makeStream("simple_1"))\r
-        self.cfg.message = 'Goodbye, cruel world!'\r
-        self.assertEqual('Goodbye, cruel world!', self.cfg.message)\r
-\r
-    def testSave(self):\r
-        self.cfg.load(makeStream("simple_1"))\r
-        self.cfg.message = 'Goodbye, cruel world!'\r
-        out = OutStream()\r
-        self.cfg.save(out)\r
-        self.assertEqual("message : 'Goodbye, cruel world!'" + config.NEWLINE,\r
-           out.value)\r
-\r
-    def testInclude(self):\r
-        config.streamOpener = makeStream\r
-        self.cfg = Config("include_1")\r
-        config.streamOpener = config.defaultStreamOpener\r
-        out = OutStream()\r
-        self.cfg.save(out)\r
-        s = "included :%s{%s  test : 123%s  another_test : 'abc'%s}%s" % (5 *\r
-           (config.NEWLINE,))\r
-        self.assertEqual(s, out.value)\r
-\r
-    def testExpression(self):\r
-        self.cfg.load(makeStream("expr_1"))\r
-        self.assertEqual(15, self.cfg.derived1)\r
-        self.assertEqual(5, self.cfg.derived2)\r
-        self.assertEqual(50, self.cfg.derived3)\r
-        self.assertEqual(2, self.cfg.derived4)\r
-        self.assertEqual(0, self.cfg.derived5)\r
-        self.assertEqual('abcghi', self.cfg.derived6)\r
-        self.assertEqual('abcdefghi', self.cfg.derived7)\r
-        self.assertRaises(TypeError, lambda x: x.derived8, self.cfg)\r
-        self.assertRaises(ZeroDivisionError, lambda x: x.derived9, self.cfg)\r
-        self.assertRaises(ZeroDivisionError, lambda x: x.derived10, self.cfg)\r
-        self.assertRaises(ConfigResolutionError,\r
-           lambda x: x.derived11, self.cfg)\r
-        self.assertEqual(15, self.cfg.derived12)\r
-\r
-    def testEval(self):\r
-        import sys, logging\r
-        self.cfg.load(makeStream("eval_1"))\r
-        self.assertEqual(sys.stderr, self.cfg.stderr)\r
-        self.assertEqual(sys.stdout, self.cfg.stdout)\r
-        self.assertEqual(sys.stdin, self.cfg.stdin)\r
-        self.assertRaises(ConfigResolutionError, lambda x: x.debug, self.cfg)\r
-        self.cfg.addNamespace(logging.Logger)\r
-        self.assertEqual(logging.Logger.debug.im_func, self.cfg.debug)\r
-        self.assertRaises(ConfigResolutionError, lambda x: x.DEBUG, self.cfg)\r
-        self.cfg.addNamespace(logging)\r
-        self.assertEqual(logging.DEBUG, self.cfg.DEBUG)\r
-        self.cfg.removeNamespace(logging.Logger)\r
-        self.assertEqual(logging.debug, self.cfg.debug)\r
-        self.assertEqual(logging.DEBUG * 10, self.cfg.derived)\r
-\r
-    def testFunctions(self):\r
-        makePath = config.makePath\r
-        isWord = config.isWord\r
-        self.assertEqual('suffix', makePath('', 'suffix'))\r
-        self.assertEqual('suffix', makePath(None, 'suffix'))\r
-        self.assertEqual('prefix.suffix', makePath('prefix', 'suffix'))\r
-        self.assertEqual('prefix[1]', makePath('prefix', '[1]'))\r
-        self.failUnless(isWord('a9'))\r
-        self.failUnless(isWord('9a'))    #perverse, but there you go\r
-        self.failIf(isWord(9))\r
-        self.failIf(isWord(None))\r
-        self.failIf(isWord(self))\r
-        self.failIf(isWord(''))\r
-\r
-    def testMerge(self):\r
-        cfg1 = Config()\r
-        cfg1.load(makeStream("merge_1"))\r
-        cfg2 = Config(makeStream("merge_2"))\r
-        ConfigMerger().merge(cfg1, cfg2)\r
-        merged = cfg1\r
-        cfg1 = Config()\r
-        cfg1.load(makeStream("merge_1"))\r
-        for i in xrange(0, 5):\r
-            key = 'value%d' % (i + 1,)\r
-            self.failUnless(key in merged)\r
-        self.assertEqual(len(cfg1.value5) + len(cfg2.value5),\r
-           len(merged.value5))\r
-        cfg3 = Config()\r
-        cfg3.load(makeStream("merge_3"))\r
-        cfg4 = Config(makeStream("merge_4"))\r
-        merger = ConfigMerger()\r
-        self.assertRaises(ConfigError, merger.merge, cfg3, cfg4)\r
-\r
-        cfg3 = Config(makeStream("merge_3"))\r
-        cfg4 = Config(makeStream("merge_4"))\r
-        merger = ConfigMerger(config.overwriteMergeResolve)\r
-        merger.merge(cfg3, cfg4)\r
-        self.assertEqual(False, cfg3['value1'])\r
-        self.assertEqual(4, cfg3['value2'])\r
-\r
-        def customMergeResolve(map1, map2, key):\r
-            if key == "value3":\r
-                rv = "overwrite"\r
-            else:\r
-                rv = config.overwriteMergeResolve(map1, map2, key)\r
-            return rv\r
-\r
-        cfg3 = Config(makeStream("merge_3"))\r
-        cfg4 = Config(makeStream("merge_4"))\r
-        merger = ConfigMerger(customMergeResolve)\r
-        merger.merge(cfg3, cfg4)\r
-        self.assertEqual("[2, 4, 6]", str(cfg3.value3))\r
-        self.assertEqual("[1, 3, 5, 2, 4, 6]", str(cfg3.value4))\r
-\r
-    def testList(self):\r
-        list = ConfigList()\r
-        list.append(Config(makeStream("list_1")))\r
-        list.append(Config(makeStream("list_2")))\r
-        list.append(Config(makeStream("list_3")))\r
-        self.assertEqual(1, list.getByPath('verbosity'))\r
-        self.assertEqual(4, list.getByPath('program_value'))\r
-        self.assertEqual(5, list.getByPath('suite_value'))\r
-        self.assertRaises(ConfigError, list.getByPath, 'nonexistent_value')\r
-\r
-    def testGet(self):\r
-        cfg = self.cfg\r
-        cfg.load(makeStream("get_1"))\r
-        self.assertEqual(123, cfg.get('value1'))\r
-        self.assertEqual(123, cfg.get('value1', -123))\r
-        self.assertEqual(-123, cfg.get('value11', -123))\r
-        self.assertEqual('abcd', cfg.get('value2'))\r
-        self.failUnless(cfg.get('value3'))\r
-        self.failIf(cfg.get('value4') is not None)\r
-        self.assertEqual(123, cfg.value5.get('value1'))\r
-        self.assertEqual(123, cfg.value5.get('value1', -123))\r
-        self.assertEqual(-123, cfg.value5.get('value11', -123))\r
-        self.assertEqual('abcd', cfg.value5.get('value2'))\r
-        self.failUnless(cfg.value5.get('value3'))\r
-        self.failIf(cfg.value5.get('value4') is not None)\r
-\r
-    def testMultiline(self):\r
-        cfg = self.cfg\r
-        cfg.load(makeStream("multiline_1"))\r
-        self.assertEqual("Value One\nValue Two\n", cfg.get('value1'))\r
-        self.assertEqual("Value Three\nValue Four", cfg.get('value2'))\r
-\r
-    def testSequence(self):\r
-        cfg = self.cfg\r
-        strm = makeStream("sequence_1")\r
-        cfg.load(strm)\r
-        self.assertEqual(str(cfg.simple), "[1, 2]")\r
-        self.assertEqual(str(cfg.nested), "[1, [2, 3], [4, [5, 6]]]")\r
-        self.assertEqual(str(cfg.mixed), "['VALIGN', [0, 0], [-1, -1], 'TOP']")\r
-\r
-    def testJSON(self):\r
-        data = StringIO('dummy: ' + open('styles.json', 'r').read())\r
-        self.cfg.load(data)\r
-\r
-def init_logging():\r
-    logging.basicConfig(level=logging.DEBUG, filename="test_config.log",\r
-                        filemode="w", format="%(asctime)s %(levelname)-5s %(name)-10s %(message)s")\r
-"""\r
-def test_main():\r
-    init_logging()\r
-    test_support.run_unittest(TestConfig)\r
-"""\r
-\r
-if __name__ == "__main__":\r
-    unittest.main(exit=False)\r
-    pass\r
-    # test_main()\r
diff --git a/src/test/debugTest.py b/src/test/debugTest.py
deleted file mode 100755 (executable)
index bc84f53..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-#!/usr/bin/env python
-#-*- coding:utf-8 -*-
-
-#  Copyright (C) 2010-2018  CEA/DEN
-#
-#  This library is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU Lesser General Public
-#  License as published by the Free Software Foundation; either
-#  version 2.1 of the License.
-#
-#  This library is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-#  Lesser General Public License for more details.
-#
-#  You should have received a copy of the GNU Lesser General Public
-#  License along with this library; if not, write to the Free Software
-#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
-
-import os
-import sys
-import unittest
-
-import src
-import src.debug as DBG # Easy print stderr (for DEBUG only)
-import src.pyconf as PYF # 0.3.7
-import src.test.config_0_3_9.config as PYF9 # TODO 0.3.9
-
-_EXAMPLES = {
-1 : """\
-  messages:
-  [
-    {
-      stream : "sys.stderr" # modified
-      message: 111 # modified
-      name: 'Harry'
-    }
-    {
-      stream : $messages[0].stream
-      message: 1.23e4 # modified do not work 0.3.7
-      name: 'Ruud'
-    }
-    {
-      stream : "HELLO " + $messages[0].stream
-      message: 'Bienvenue'
-      name: "Yves"
-    }
-  ]
-""",
-
-2 : """\
-  aa: 111
-  bb: $aa + 222
-""",
-
-3 : """\
-  aa: Yves
-  bb: "Herve" # avoid Hervé -> 'utf8' codec can't decode byte
-""",
-
-4 : """\
-  aa: Yves
-  bb: "Hervé" # avoid Hervé -> 'utf8' codec can't decode byte
-""",
-
-
-}
-
-
-class TestCase(unittest.TestCase):
-  "Test the debug.py"""
-  
-  def test_000(self):
-    # one shot setUp() for this TestCase
-    # DBG.push_debug(True)
-    # SAT.setNotLocale() # test english
-    return
-    
-  def test_005(self):
-    res = DBG.getLocalEnv()
-    self.assertTrue(len(res.split()) > 0)
-    self.assertTrue("USER :" in res)
-    self.assertTrue("LANG :" in res)
-       
-  def test_010(self):
-    inStream = DBG.InStream(_EXAMPLES[1])
-    self.assertEqual(inStream.getvalue(), _EXAMPLES[1])
-    cfg = PYF.Config(inStream)
-    self.assertEqual(len(cfg.messages), 3)
-    outStream = DBG.OutStream()
-    DBG.saveConfigStd(cfg, outStream)
-    res = outStream.value
-    DBG.write("test_010 cfg std", res)
-    self.assertTrue("messages :" in res)
-    self.assertTrue("'sys.stderr'" in res)
-    
-  def test_020(self):
-    inStream = DBG.InStream(_EXAMPLES[2])
-    cfg = PYF.Config(inStream)
-    res = DBG.getStrConfigDbg(cfg)
-    DBG.write("test_020 cfg dbg", res)
-    ress = res.split("\n")
-    self.assertTrue(".aa : '111'" in ress[0])
-    self.assertTrue(".bb : $aa + 222 --> '333'" in ress[1])
-    
-  def test_025(self):
-    inStream = DBG.InStream(_EXAMPLES[1])
-    cfg = PYF.Config(inStream)
-    outStream = DBG.OutStream()
-    DBG.saveConfigDbg(cfg, outStream)
-    res = outStream.value
-    DBG.write("test_025 cfg dbg", res)
-    for i in range(len(cfg.messages)):
-      self.assertTrue("messages[%i].name" % i in res)
-    self.assertTrue("--> 'HELLO sys.stderr'" in res)
-
-      
-  def test_999(self):
-    # one shot tearDown() for this TestCase
-    # SAT.setLocale() # end test english
-    # DBG.pop_debug()
-    return
-    
-if __name__ == '__main__':
-    unittest.main(exit=False)
-    pass
-
diff --git a/src/test/pyconfTest.py b/src/test/pyconfTest.py
deleted file mode 100755 (executable)
index 2adaeb8..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-#!/usr/bin/env python
-#-*- coding:utf-8 -*-
-
-#  Copyright (C) 2010-2018  CEA/DEN
-#
-#  This library is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU Lesser General Public
-#  License as published by the Free Software Foundation; either
-#  version 2.1 of the License.
-#
-#  This library is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-#  Lesser General Public License for more details.
-#
-#  You should have received a copy of the GNU Lesser General Public
-#  License along with this library; if not, write to the Free Software
-#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
-
-import os
-import sys
-import unittest
-
-import src
-import src.debug as DBG # Easy print stderr (for DEBUG only)
-import src.pyconf as PYF # 0.3.7
-import src.test.config_0_3_9.config as PYF9 # TODO 0.3.9
-
-_EXAMPLES = {
-1 : """\
-  messages:
-  [
-    {
-      stream : "sys.stderr" # modified
-      message: 'Welcome'
-      name: 'Harry'
-    }
-    {
-      stream : "sys.stdout" # modified
-      message: 'Welkom'
-      name: 'Ruud'
-    }
-    {
-      stream : $messages[0].stream
-      message: 'Bienvenue'
-      name: "Yves"
-    }
-  ]
-""",
-
-2 : """\
-  aa: 111
-  bb: $aa + 222
-""",
-
-3 : """\
-  aa: Yves
-  bb: "Herve" # avoid Hervé -> 'utf8' codec can't decode byte
-""",
-
-4 : """\
-  aa: Yves
-  bb: "Hervé" # avoid Hervé -> 'utf8' codec can't decode byte
-""",
-
-
-}
-
-
-class TestCase(unittest.TestCase):
-  "Test the pyconf.py"""
-  
-  def test_000(self):
-    # one shot setUp() for this TestCase
-    # DBG.push_debug(True)
-    # SAT.setNotLocale() # test english
-    return
-
-  def test_010(self):
-    # pyconf.py doc example 0.3.7
-    # https://www.red-dove.com/config-doc/ is 0.3.9 !
-    # which, when run, would yield the console output:
-
-    expected = """\
-Welcome, Harry
-Welkom, Ruud
-Bienvenue, Yves
-"""
-    inStream = DBG.InStream(_EXAMPLES[1])
-    cfg = PYF.Config(inStream)
-    res = ''
-    for m in cfg.messages:
-        res += '%s, %s\n' % (m.message, m.name)
-    self.assertEqual(res, expected)
-    outStream = DBG.OutStream()
-    cfg.__save__(outStream) # sat renamed save() in __save__()
-    res = outStream.value
-    DBG.write("test_010 cfg", res)
-    self.assertTrue("name : 'Harry'" in res)
-    self.assertTrue("name : 'Ruud'" in res)
-    self.assertTrue("name : 'Yves'" in res)
-        
-  def test_020(self):
-    cfg = PYF.Config()
-    self.assertEqual(str(cfg), '{}')
-    self.assertEqual(cfg.__repr__(), '{}')
-    cfg.aa = "1111"
-    self.assertEqual(str(cfg), "{'aa': '1111'}")
-    cfg.bb = 2222
-    self.assertTrue("'bb': 2222" in str(cfg))
-    self.assertTrue("'aa': '1111'" in str(cfg))
-    cfg.cc = 3333.
-    self.assertTrue("'cc': 3333." in str(cfg))
-    
-  def test_030(self):
-    inStream = DBG.InStream(_EXAMPLES[2])
-    cfg = PYF.Config(inStream)
-    self.assertEqual(str(cfg),  "{'aa': 111, 'bb': $aa + 222}")
-    self.assertEqual(cfg.aa, 111)
-    self.assertEqual(cfg.bb, 333)
-      
-  def test_040(self):
-    inStream = DBG.InStream(_EXAMPLES[3])
-    cfg = PYF.Config(inStream)
-    self.assertEqual(cfg.aa, "Yves")
-    self.assertEqual(cfg.bb, "Herve")
-    self.assertEqual(type(cfg.bb), str)
-    cfg.bb = "Hervé" # try this
-    self.assertEqual(type(cfg.bb), str)
-    self.assertEqual(cfg.bb, "Hervé")
-    
-  def test_045(self):
-    """TODO: make Hervé valid with pyconf.py as 0.3.9"""
-    inStream = DBG.InStream(_EXAMPLES[4])
-    cfg = PYF9.Config(inStream)
-    outStream = DBG.OutStream()
-    cfg.save(outStream) # sat renamed save() in __save__()
-    res = outStream.value
-    DBG.write("test_045 cfg", res)
-    self.assertTrue("aa : 'Yves'" in res)
-    self.assertTrue(r"bb : 'Herv\xc3\xa9'" in res)
-    self.assertEqual(cfg.bb, "Hervé")
-      
-  def test_999(self):
-    # one shot tearDown() for this TestCase
-    # SAT.setLocale() # end test english
-    # DBG.pop_debug()
-    return
-    
-if __name__ == '__main__':
-    unittest.main(exit=False)
-    pass
diff --git a/src/test/satHelpTest.py b/src/test/satHelpTest.py
deleted file mode 100755 (executable)
index 23d8ba2..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-#!/usr/bin/env python
-#-*- coding:utf-8 -*-
-
-#  Copyright (C) 2010-2018  CEA/DEN
-#
-#  This library is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU Lesser General Public
-#  License as published by the Free Software Foundation; either
-#  version 2.1 of the License.
-#
-#  This library is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-#  Lesser General Public License for more details.
-#
-#  You should have received a copy of the GNU Lesser General Public
-#  License along with this library; if not, write to the Free Software
-#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
-
-import os
-import sys
-import unittest
-
-import src.salomeTools as SAT
-import src
-import src.debug as DBG # Easy print stderr (for DEBUG only)
-
-class TestCase(unittest.TestCase):
-  "Test the sat --help commands"""
-  
-  def test_000(self):
-    # one shot setUp() for this TestCase
-    # DBG.push_debug(True)
-    SAT.setNotLocale() # test english
-    return
-
-  def test_010(self):
-    cmd = "sat --help"
-    stdout, stderr = SAT.launchSat(cmd)
-    print stdout, stderr
-    self.assertEqual(stderr, "")
-    self.assertTrue(" - config" in stdout)
-
-  def xtest_011(self):
-    cmd = "--help"
-    s = SAT.Sat(cmd)
-    exitCode = s.execute_command()
-    self.assertEqual(src.okToStr(exitCode), "OK")
-    
-  def xtest_030(self):
-    cmd = "sat --help config"
-    stdout, stderr = SAT.launchSat(cmd)
-    self.assertEqual(stderr, "")
-    self.assertTrue("--value" in stdout)
-
-  def xtest_031(self):
-    cmd = "--help config"
-    s = SAT.Sat(cmd)
-    exitCode = s.execute_command()
-    self.assertEqual(src.okToStr(exitCode), "OK")
-      
-  def xtest_032(self):
-    cmd = "config -l"
-    s = SAT.Sat(cmd)
-    exitCode = s.execute_command()
-    self.assertEqual(src.okToStr(exitCode), "OK")
-  
-  def xtest_040(self):
-    cmds = SAT.getCommandsList()
-    for c in cmds:
-      cmd = "sat --help %s" % c
-      stdout, stderr = SAT.launchSat(cmd)
-      self.assertEqual(stderr, "")
-      # DBG.write("stdout '%s'" % cmd, stdout)
-      self.assertTrue("vailable options" in stdout)
-      
-  def test_999(self):
-    # one shot tearDown() for this TestCase
-    SAT.setLocale() # end test english
-    # DBG.pop_debug()
-    return
-      
-if __name__ == '__main__':
-    unittest.main(exit=False)
-    pass
diff --git a/src/test/test_pyconf.py b/src/test/test_pyconf.py
deleted file mode 100755 (executable)
index 7f884de..0000000
+++ /dev/null
@@ -1,450 +0,0 @@
-#!/usr/bin/env python
-#-*- coding:utf-8 -*-
-
-# Copyright 2004-2010 by Vinay Sajip. All Rights Reserved.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose and without fee is hereby granted,
-# provided that the above copyright notice appear in all copies and that
-# both that copyright notice and this permission notice appear in
-# supporting documentation, and that the name of Vinay Sajip
-# not be used in advertising or publicity pertaining to distribution
-# of the software without specific, written prior permission.
-# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
-# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
-# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
-# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
-# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-"""
-Test harness for the configuration module 'config' for Python.
-
-from test_config 0.3.9 modified to test 0.3.7.1
-this test obviously have FAILED (errors=6), TODO, fix upgrading 0.3.9, or not.
-"""
-
-import unittest
-# import test_support
-import src.pyconf as config
-from src.pyconf import Config, ConfigMerger, ConfigList
-from src.pyconf import ConfigError, ConfigFormatError, ConfigResolutionError
-import logging
-from StringIO import StringIO
-
-STREAMS = {
-    "simple_1" :
-"""
-message: 'Hello, world!'
-""",
-    "malformed_1" :
-"""
-123
-""",
-    "malformed_2" :
-"""
-[ 123, 'abc' ]
-""",
-    "malformed_3" :
-"""
-{ a : 7, b : 1.3, c : 'test' }
-""",
-    "malformed_4" :
-"""
-test: $a [7] # note space before bracket
-""",
-    "malformed_5" :
-"""
-test: 'abc'
-test: 'def'
-""",
-    "wellformed_1" :
-"""
-test: $a[7] # note no space before bracket
-""",
-    "boolean_1":
-"""
-test : False
-another_test: True
-""",
-    "boolean_2":
-"""
-test : false
-another_test: true
-""",
-    "none_1":
-"""
-test : None
-""",
-    "none_2":
-"""
-test : none
-""",
-    "number_1":
-"""
-root: 1
-stream: 1.7
-neg: -1
-negfloat: -2.0
-posexponent: 2.0999999e-08
-negexponent: -2.0999999e-08
-exponent: 2.0999999e08
-""",
-    "sequence_1":
-"""
-mixed: [ "VALIGN", [ 0, 0 ], [ -1, -1 ], "TOP" ]
-simple: [1, 2]
-nested: [1, [2, 3], [4, [5, 6]]]
-""",
-    "include_1":
-"""
-included: @'include_2'
-""",
-    "include_2":
-"""
-test: 123
-another_test: 'abc'
-""",
-    "expr_1":
-"""
-value1 : 10
-value2 : 5
-value3 : 'abc'
-value4 : 'ghi'
-value5 : 0
-value6 : { 'a' : $value1, 'b': $value2 }
-derived1 : $value1 + $value2
-derived2 : $value1 - $value2
-derived3 : $value1 * $value2
-derived4 : $value1 / $value2
-derived5 : $value1 % $value2
-derived6 : $value3 + $value4
-derived7 : $value3 + 'def' + $value4
-derived8 : $value3 - $value4 # meaningless
-derived9 : $value1 / $value5    # div by zero
-derived10 : $value1 % $value5   # div by zero
-derived11 : $value17    # doesn't exist
-derived12 : $value6.a + $value6.b
-""",
-    "eval_1":
-"""
-stderr : `sys.stderr`
-stdout : `sys.stdout`
-stdin : `sys.stdin`
-debug : `debug`
-DEBUG : `DEBUG`
-derived: $DEBUG * 10
-""",
-    "merge_1":
-"""
-value1: True
-value3: [1, 2, 3]
-value5: [ 7 ]
-value6: { 'a' : 1, 'c' : 3 }
-""",
-    "merge_2":
-"""
-value2: False
-value4: [4, 5, 6]
-value5: ['abc']
-value6: { 'b' : 2, 'd' : 4 }
-""",
-    "merge_3":
-"""
-value1: True
-value2: 3
-value3: [1, 3, 5]
-value4: [1, 3, 5]
-""",
-    "merge_4":
-"""
-value1: False
-value2: 4
-value3: [2, 4, 6]
-value4: [2, 4, 6]
-""",
-    "list_1":
-"""
-verbosity : 1
-""",
-    "list_2":
-"""
-verbosity : 2
-program_value: 4
-""",
-    "list_3":
-"""
-verbosity : 3
-suite_value: 5
-""",
-    "get_1":
-"""
-value1 : 123
-value2 : 'abcd'
-value3 : True
-value4 : None
-value5:
-{
-    value1 : 123
-    value2 : 'abcd'
-    value3 : True
-    value4 : None
-}
-""",
-    "multiline_1":
-"""
-value1: '''Value One
-Value Two
-'''
-value2: \"\"\"Value Three
-Value Four\"\"\"
-"""
-}
-
-def makeStream(name):
-    s = StringIO(STREAMS[name])
-    s.name = name
-    return s
-
-class OutStream(StringIO):
-    def close(self):
-        self.value = self.getvalue()
-        StringIO.close(self)
-
-class TestConfig(unittest.TestCase):
-
-    def setUp(self):
-        self.cfg = Config(None)
-
-    def tearDown(self):
-        del self.cfg
-
-    def testCreation(self):
-        self.assertEqual(0, len(self.cfg))  # should be empty
-
-    def testSimple(self):
-        self.cfg.load(makeStream("simple_1"))
-        self.failUnless('message' in self.cfg)
-        self.failIf('root' in self.cfg)
-        self.failIf('stream' in self.cfg)
-        self.failIf('load' in self.cfg)
-        self.failIf('save' in self.cfg)
-
-    def testValueOnly(self):
-        self.assertRaises(ConfigError, self.cfg.load,
-           makeStream("malformed_1"))
-        self.assertRaises(ConfigError, self.cfg.load,
-           makeStream("malformed_2"))
-        self.assertRaises(ConfigError, self.cfg.load,
-           makeStream("malformed_3"))
-
-    def testBadBracket(self):
-        self.assertRaises(ConfigError, self.cfg.load,
-           makeStream("malformed_4"))
-
-    def testDuplicate(self):
-        self.assertRaises(ConfigError, self.cfg.load,
-           makeStream("malformed_5"))
-
-    def testGoodBracket(self):
-        self.cfg.load(makeStream("wellformed_1"))
-
-    def testBoolean(self):
-        self.cfg.load(makeStream("boolean_1"))
-        self.assertEqual(True, self.cfg.another_test)
-        self.assertEqual(False, self.cfg.test)
-
-    def testNotBoolean(self):
-        self.cfg.load(makeStream("boolean_2"))
-        self.assertEqual('true', self.cfg.another_test)
-        self.assertEqual('false', self.cfg.test)
-
-    def testNone(self):
-        self.cfg.load(makeStream("none_1"))
-        self.assertEqual(None, self.cfg.test)
-
-    def testNotNone(self):
-        self.cfg.load(makeStream("none_2"))
-        self.assertEqual('none', self.cfg.test)
-
-    def testNumber(self):
-        self.cfg.load(makeStream("number_1"))
-        self.assertEqual(1, self.cfg.root)
-        self.assertEqual(1.7, self.cfg.stream)
-        self.assertEqual(-1, self.cfg.neg)
-        self.assertEqual(-2.0, self.cfg.negfloat)
-        self.assertAlmostEqual(-2.0999999e-08, self.cfg.negexponent)
-        self.assertAlmostEqual(2.0999999e-08, self.cfg.posexponent)
-        self.assertAlmostEqual(2.0999999e08, self.cfg.exponent)
-
-    def testChange(self):
-        self.cfg.load(makeStream("simple_1"))
-        self.cfg.message = 'Goodbye, cruel world!'
-        self.assertEqual('Goodbye, cruel world!', self.cfg.message)
-
-    def testSave(self):
-        self.cfg.load(makeStream("simple_1"))
-        self.cfg.message = 'Goodbye, cruel world!'
-        out = OutStream()
-        self.cfg.save(out)
-        self.assertEqual("message : 'Goodbye, cruel world!'" + config.NEWLINE,
-           out.value)
-
-    def testInclude(self):
-        config.streamOpener = makeStream
-        self.cfg = Config("include_1")
-        config.streamOpener = config.defaultStreamOpener
-        out = OutStream()
-        self.cfg.save(out)
-        s = "included :%s{%s  test : 123%s  another_test : 'abc'%s}%s" % (5 *
-           (config.NEWLINE,))
-        self.assertEqual(s, out.value)
-
-    def testExpression(self):
-        self.cfg.load(makeStream("expr_1"))
-        self.assertEqual(15, self.cfg.derived1)
-        self.assertEqual(5, self.cfg.derived2)
-        self.assertEqual(50, self.cfg.derived3)
-        self.assertEqual(2, self.cfg.derived4)
-        self.assertEqual(0, self.cfg.derived5)
-        self.assertEqual('abcghi', self.cfg.derived6)
-        self.assertEqual('abcdefghi', self.cfg.derived7)
-        self.assertRaises(TypeError, lambda x: x.derived8, self.cfg)
-        self.assertRaises(ZeroDivisionError, lambda x: x.derived9, self.cfg)
-        self.assertRaises(ZeroDivisionError, lambda x: x.derived10, self.cfg)
-        self.assertRaises(ConfigResolutionError,
-           lambda x: x.derived11, self.cfg)
-        self.assertEqual(15, self.cfg.derived12)
-
-    def testEval(self):
-        import sys, logging
-        self.cfg.load(makeStream("eval_1"))
-        self.assertEqual(sys.stderr, self.cfg.stderr)
-        self.assertEqual(sys.stdout, self.cfg.stdout)
-        self.assertEqual(sys.stdin, self.cfg.stdin)
-        self.assertRaises(ConfigResolutionError, lambda x: x.debug, self.cfg)
-        self.cfg.addNamespace(logging.Logger)
-        self.assertEqual(logging.Logger.debug.im_func, self.cfg.debug)
-        self.assertRaises(ConfigResolutionError, lambda x: x.DEBUG, self.cfg)
-        self.cfg.addNamespace(logging)
-        self.assertEqual(logging.DEBUG, self.cfg.DEBUG)
-        self.cfg.removeNamespace(logging.Logger)
-        self.assertEqual(logging.debug, self.cfg.debug)
-        self.assertEqual(logging.DEBUG * 10, self.cfg.derived)
-
-    def testFunctions(self):
-        makePath = config.makePath
-        isWord = config.isWord
-        self.assertEqual('suffix', makePath('', 'suffix'))
-        self.assertEqual('suffix', makePath(None, 'suffix'))
-        self.assertEqual('prefix.suffix', makePath('prefix', 'suffix'))
-        self.assertEqual('prefix[1]', makePath('prefix', '[1]'))
-        self.failUnless(isWord('a9'))
-        self.failUnless(isWord('9a'))    #perverse, but there you go
-        self.failIf(isWord(9))
-        self.failIf(isWord(None))
-        self.failIf(isWord(self))
-        self.failIf(isWord(''))
-
-    def testMerge(self):
-        cfg1 = Config()
-        cfg1.load(makeStream("merge_1"))
-        cfg2 = Config(makeStream("merge_2"))
-        ConfigMerger().merge(cfg1, cfg2)
-        merged = cfg1
-        cfg1 = Config()
-        cfg1.load(makeStream("merge_1"))
-        for i in xrange(0, 5):
-            key = 'value%d' % (i + 1,)
-            self.failUnless(key in merged)
-        self.assertEqual(len(cfg1.value5) + len(cfg2.value5),
-           len(merged.value5))
-        cfg3 = Config()
-        cfg3.load(makeStream("merge_3"))
-        cfg4 = Config(makeStream("merge_4"))
-        merger = ConfigMerger()
-        self.assertRaises(ConfigError, merger.merge, cfg3, cfg4)
-
-        cfg3 = Config(makeStream("merge_3"))
-        cfg4 = Config(makeStream("merge_4"))
-        merger = ConfigMerger(config.overwriteMergeResolve)
-        merger.merge(cfg3, cfg4)
-        self.assertEqual(False, cfg3['value1'])
-        self.assertEqual(4, cfg3['value2'])
-
-        def customMergeResolve(map1, map2, key):
-            if key == "value3":
-                rv = "overwrite"
-            else:
-                rv = config.overwriteMergeResolve(map1, map2, key)
-            return rv
-
-        cfg3 = Config(makeStream("merge_3"))
-        cfg4 = Config(makeStream("merge_4"))
-        merger = ConfigMerger(customMergeResolve)
-        merger.merge(cfg3, cfg4)
-        self.assertEqual("[2, 4, 6]", str(cfg3.value3))
-        self.assertEqual("[1, 3, 5, 2, 4, 6]", str(cfg3.value4))
-
-    def testList(self):
-        list = ConfigList()
-        list.append(Config(makeStream("list_1")))
-        list.append(Config(makeStream("list_2")))
-        list.append(Config(makeStream("list_3")))
-        self.assertEqual(1, list.getByPath('verbosity'))
-        self.assertEqual(4, list.getByPath('program_value'))
-        self.assertEqual(5, list.getByPath('suite_value'))
-        self.assertRaises(ConfigError, list.getByPath, 'nonexistent_value')
-
-    def testGet(self):
-        cfg = self.cfg
-        cfg.load(makeStream("get_1"))
-        self.assertEqual(123, cfg.get('value1'))
-        self.assertEqual(123, cfg.get('value1', -123))
-        self.assertEqual(-123, cfg.get('value11', -123))
-        self.assertEqual('abcd', cfg.get('value2'))
-        self.failUnless(cfg.get('value3'))
-        self.failIf(cfg.get('value4') is not None)
-        self.assertEqual(123, cfg.value5.get('value1'))
-        self.assertEqual(123, cfg.value5.get('value1', -123))
-        self.assertEqual(-123, cfg.value5.get('value11', -123))
-        self.assertEqual('abcd', cfg.value5.get('value2'))
-        self.failUnless(cfg.value5.get('value3'))
-        self.failIf(cfg.value5.get('value4') is not None)
-
-    def testMultiline(self):
-        cfg = self.cfg
-        cfg.load(makeStream("multiline_1"))
-        self.assertEqual("Value One\nValue Two\n", cfg.get('value1'))
-        self.assertEqual("Value Three\nValue Four", cfg.get('value2'))
-
-    def testSequence(self):
-        cfg = self.cfg
-        strm = makeStream("sequence_1")
-        cfg.load(strm)
-        self.assertEqual(str(cfg.simple), "[1, 2]")
-        self.assertEqual(str(cfg.nested), "[1, [2, 3], [4, [5, 6]]]")
-        self.assertEqual(str(cfg.mixed), "['VALIGN', [0, 0], [-1, -1], 'TOP']")
-
-    def testJSON(self):
-        data = StringIO('dummy: ' + open('styles.json', 'r').read())
-        self.cfg.load(data)
-
-def init_logging():
-    logging.basicConfig(level=logging.DEBUG, filename="test_config.log",
-                        filemode="w", format="%(asctime)s %(levelname)-5s %(name)-10s %(message)s")
-"""
-def test_main():
-    init_logging()
-    test_support.run_unittest(TestConfig)
-"""
-
-if __name__ == "__main__":
-    # test_main()
-    unittest.main(exit=False)
-    import sys
-    sys.stderr.write("""
-WARNING: this test obviously have FAILED (errors=6), 
-TODO:    fix upgrading 0.3.9, (or not).\n\n""")
-    pass
-  
diff --git a/test/APPLI_TEST/APPLI_TEST.pyconf b/test/APPLI_TEST/APPLI_TEST.pyconf
new file mode 100644 (file)
index 0000000..5fc08b3
--- /dev/null
@@ -0,0 +1,45 @@
+
+APPLICATION :
+{
+    name : 'APPLI_TEST'
+    workdir : $LOCAL.workdir + $VARS.sep + $APPLICATION.name + '-' + $VARS.dist
+    base : 'base'
+    tag : 'master'
+    get_method : 'git'
+    environ :
+    {
+        ACCEPT_SALOME_WARNINGS : '1'
+        LC_NUMERIC : 'C'
+        TESTS_ROOT_DIR : "/tmp/" + $VARS.user+ "/TESTS/APPLI_TEST"
+    }
+    products :
+    {
+        # PREREQUISITES :
+        'Python' : 'native'
+
+        # SALOME MODULES :
+        'CONFIGURATION'
+        'MEDCOUPLING'
+        'KERNEL'
+        'GUI'
+        'GEOM'
+        'SMESH'
+
+    }
+    grid_to_test : 'SALOME_V8'
+    profile :
+    {
+        launcher_name : "appli_test"
+        product : "SALOME"
+    }
+    virtual_app:
+    {
+        name : "appli_test"
+        application_name : "APPLI"
+    }
+    test_base : 
+    {
+        name : "SALOME"
+        tag : "SalomeV8"
+    }
+}
diff --git a/test/README_config_0_3_9.txt b/test/README_config_0_3_9.txt
new file mode 100644 (file)
index 0000000..4605ae9
--- /dev/null
@@ -0,0 +1,2 @@
+#TODO
+switch pyconf.py 0.3.7.1 -> 0.3.9, here for test
old mode 100644 (file)
new mode 100755 (executable)
diff --git a/test/compilation/test_compilation.py b/test/compilation/test_compilation.py
deleted file mode 100755 (executable)
index 79192ad..0000000
+++ /dev/null
@@ -1,227 +0,0 @@
-#!/usr/bin/env python
-#-*- coding:utf-8 -*-
-
-#  Copyright (C) 2010-2018  CEA/DEN
-#
-#  This library is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU Lesser General Public
-#  License as published by the Free Software Foundation; either
-#  version 2.1 of the License.
-#
-#  This library is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-#  Lesser General Public License for more details.
-#
-#  You should have received a copy of the GNU Lesser General Public
-#  License along with this library; if not, write to the Free Software
-#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
-
-import os
-import sys
-import unittest
-
-import src.product
-from src.salomeTools import Sat
-
-class TestCase(unittest.TestCase):
-    """Test of the compile command"""
-
-    def test_010(self):
-        # Test the compile command with '--products' option
-        OK = 'KO'
-
-        appli = 'appli-test'
-        product_name = 'PRODUCT_GIT'
-
-        sat = Sat()
-                            
-        sat.prepare(appli + ' --product ' + product_name)
-        expected_install_dir = src.product.get_product_config(sat.cfg, product_name).install_dir
-        expected_file_path = os.path.join(expected_install_dir, 'bin/hello')
-
-        sat.clean(appli + ' --build --install --product ' + product_name, batch=True)
-        sat.compile(appli + ' --product ' + product_name)
-        
-        if os.path.exists(expected_file_path):
-            OK = 'OK'         
-        # pyunit method to compare 2 str
-        self.assertEqual(OK, 'OK')
-
-    def test_020(self):
-        # Test the configure command with '--fathers' option
-        OK = 'KO'
-
-        appli = 'appli-test'
-        product_name = 'PRODUCT_GIT'
-        product_name2 = 'PRODUCT_ARCHIVE'
-
-        sat = Sat()
-                            
-        sat.prepare(appli + ' --product ' + product_name +"," +product_name2)
-        expected_install_dir = src.product.get_product_config(sat.cfg, product_name).install_dir
-        expected_file_path = os.path.join(expected_install_dir, 'bin/hello')
-        expected_install_dir2 = src.product.get_product_config(sat.cfg, product_name2).install_dir
-        expected_file_path2 = os.path.join(expected_install_dir2, 'bin/hello-archive')
-        
-        sat.clean(appli + ' --build --install --product ' + product_name +"," +product_name2, batch=True)
-        sat.compile(appli + ' --with_fathers --product ' + product_name)
-        
-        if os.path.exists(expected_file_path) and os.path.exists(expected_file_path2):
-            OK = 'OK'         
-        # pyunit method to compare 2 str
-        self.assertEqual(OK, 'OK')
-        
-    def test_030(self):
-        # Test the configure command with '--children' option
-        OK = 'KO'
-
-        appli = 'appli-test'
-        product_name = 'PRODUCT_GIT'
-        product_name2 = 'PRODUCT_ARCHIVE'
-
-        sat = Sat()
-                            
-        sat.prepare(appli + ' --product ' + product_name +"," +product_name2)
-        expected_install_dir = src.product.get_product_config(sat.cfg, product_name).install_dir
-        expected_file_path = os.path.join(expected_install_dir, 'bin/hello')
-        expected_install_dir2 = src.product.get_product_config(sat.cfg, product_name2).install_dir
-        expected_file_path2 = os.path.join(expected_install_dir2, 'bin/hello-archive')
-
-        sat.clean(appli + ' --build --install --product ' + product_name +"," +product_name2, batch=True)
-        sat.compile(appli + ' --with_children --product ' + product_name2)
-        
-        if os.path.exists(expected_file_path) and os.path.exists(expected_file_path2):
-            OK = 'OK'         
-        # pyunit method to compare 2 str
-        self.assertEqual(OK, 'OK')
-
-    def test_040(self):
-        # Test the configure command with '--clean_all' option
-        OK = 'KO'
-
-        appli = 'appli-test'
-        product_name = 'PRODUCT_GIT'
-        product_name2 = 'PRODUCT_ARCHIVE'
-
-        sat = Sat()
-                            
-        sat.prepare(appli + ' --product ' + product_name +"," +product_name2)
-        expected_install_dir = src.product.get_product_config(sat.cfg, product_name).install_dir
-        expected_file_path = os.path.join(expected_install_dir, 'bin/hello')
-        expected_install_dir2 = src.product.get_product_config(sat.cfg, product_name2).install_dir
-        expected_file_path2 = os.path.join(expected_install_dir2, 'bin/hello-archive')
-
-        sat.compile(appli + ' --with_children --product ' + product_name2)
-        
-        sat.compile(appli + ' --clean_all --with_children --product ' + product_name2, batch=True)
-        
-        if os.path.exists(expected_file_path) and os.path.exists(expected_file_path2):
-            OK = 'OK'         
-        # pyunit method to compare 2 str
-        self.assertEqual(OK, 'OK')
-
-    def test_050(self):
-        # Test the configure command with '--clean_install' option
-        OK = 'KO'
-
-        appli = 'appli-test'
-        product_name = 'PRODUCT_GIT'
-        product_name2 = 'PRODUCT_ARCHIVE'
-
-        sat = Sat()
-                            
-        sat.prepare(appli + ' --product ' + product_name +"," +product_name2)
-        expected_install_dir = src.product.get_product_config(sat.cfg, product_name).install_dir
-        expected_file_path = os.path.join(expected_install_dir, 'bin/hello')
-        expected_install_dir2 = src.product.get_product_config(sat.cfg, product_name2).install_dir
-        expected_file_path2 = os.path.join(expected_install_dir2, 'bin/hello-archive')
-
-        sat.compile(appli + ' --with_children --product ' + product_name2)
-        
-        sat.compile(appli + ' --clean_install --with_children --product ' + product_name2, batch=True)
-        
-        if os.path.exists(expected_file_path) and os.path.exists(expected_file_path2):
-            OK = 'OK'         
-        # pyunit method to compare 2 str
-        self.assertEqual(OK, 'OK')
-
-    def test_060(self):
-        # Test the configure command with '--make_flags' option
-        OK = 'KO'
-
-        appli = 'appli-test'
-        product_name = 'PRODUCT_GIT'
-
-        sat = Sat()
-                            
-        sat.prepare(appli + ' --product ' + product_name)
-        expected_install_dir = src.product.get_product_config(sat.cfg, product_name).install_dir
-        expected_file_path = os.path.join(expected_install_dir, 'bin/hello')
-
-        sat.clean(appli + ' --build --install --product ' + product_name, batch=True)
-        sat.compile(appli + ' --make_flags 3 --product ' + product_name)
-               
-        if os.path.exists(expected_file_path):
-            OK = 'OK'         
-        # pyunit method to compare 2 str
-        self.assertEqual(OK, 'OK')
-
-    def test_070(self):
-        # Test the configure command with '--show' option
-        OK = 'KO'
-
-        appli = 'appli-test'
-        product_name = 'PRODUCT_GIT'
-
-        sat = Sat()
-                            
-        sat.prepare(appli + ' --product ' + product_name)
-        expected_install_dir = src.product.get_product_config(sat.cfg, product_name).install_dir
-        expected_file_path = os.path.join(expected_install_dir, 'bin/hello')
-
-        sat.clean(appli + ' --build --install --product ' + product_name, batch=True)
-        sat.compile(appli + ' --show --product ' + product_name)
-               
-        if not(os.path.exists(expected_file_path)):
-            OK = 'OK'         
-        # pyunit method to compare 2 str
-        self.assertEqual(OK, 'OK')
-
-    def test_080(self):
-        # Test the configure command with '--stop_first_fail' option
-        OK = 'KO'
-
-        appli = 'appli-test'
-
-        sat = Sat()
-                            
-        sat.prepare(appli + ' --product PRODUCT_CVS,Python')
-        expected_install_dir = src.product.get_product_config(sat.cfg, "PRODUCT_CVS").install_dir
-
-        sat.clean(appli + ' --build --install --product PRODUCT_CVS', batch=True)
-        sat.compile(appli + ' --stop_first_fail --product PRODUCT_CVS,Python')
-               
-        if not(os.path.exists(expected_install_dir)):
-            OK = 'OK'         
-        # pyunit method to compare 2 str
-        self.assertEqual(OK, 'OK')
-
-    def test_090(self):
-        # Test the 'sat -h compile' command to get description       
-
-        OK = "KO"
-
-        import compile
-        
-        if "The compile command constructs the products" in compile.description():
-            OK = "OK"
-
-        # pyunit method to compare 2 str
-        self.assertEqual(OK, "OK")
-
-# test launch
-if __name__ == '__main__':
-    unittest.main()
-    pass
-
diff --git a/test/compilation/test_configure.py b/test/compilation/test_configure.py
deleted file mode 100755 (executable)
index 9d995a2..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-#!/usr/bin/env python
-#-*- coding:utf-8 -*-
-
-#  Copyright (C) 2010-2018  CEA/DEN
-#
-#  This library is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU Lesser General Public
-#  License as published by the Free Software Foundation; either
-#  version 2.1 of the License.
-#
-#  This library is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-#  Lesser General Public License for more details.
-#
-#  You should have received a copy of the GNU Lesser General Public
-#  License along with this library; if not, write to the Free Software
-#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
-
-import os
-import sys
-import unittest
-
-import src.product
-from src.salomeTools import Sat
-
-class TestCase(unittest.TestCase):
-    """Test of the configure command"""
-
-    def setUp(self):
-        print("setUp")
-
-    def tearDown(self):
-        print("tearDown")
-
-    def test_010(self):
-        # Test the configure command with a product in cmake
-        OK = 'KO'
-
-        appli = 'appli-test'
-        product_name = 'PRODUCT_GIT'
-
-        sat = Sat()
-                            
-        sat.prepare(appli + ' --product ' + product_name)
-        expected_build_dir = src.product.get_product_config(sat.cfg, product_name).build_dir
-        expected_file_path = os.path.join(expected_build_dir, 'CMakeCache.txt')
-       
-        sat.configure(appli + ' --product ' + product_name)
-        
-        if os.path.exists(os.path.join(expected_build_dir, expected_file_path)):
-            OK = 'OK'         
-        # pyunit method to compare 2 str
-        self.assertEqual(OK, 'OK')
-
-    def test_020(self):
-        # Test the configure command with a product in autotools
-        OK = 'KO'
-
-        appli = 'appli-test'
-        product_name = 'PRODUCT_CVS'
-
-        sat = Sat()
-                            
-        sat.prepare(appli + ' --product ' + product_name)
-        expected_build_dir = src.product.get_product_config(sat.cfg, product_name).build_dir
-        expected_file_path = os.path.join(expected_build_dir, 'config.log')
-       
-        sat.configure(appli + ' --product ' + product_name)
-        
-        if os.path.exists(os.path.join(expected_build_dir, expected_file_path)):
-            OK = 'OK'         
-        # pyunit method to compare 2 str
-        self.assertEqual(OK, 'OK')
-
-    def test_030(self):
-        # Test the configure command with a product in script mode
-        OK = 'KO'
-
-        appli = 'appli-test'
-        product_name = 'Python'
-
-        sat = Sat()
-                            
-        sat.prepare(appli + ' --product ' + product_name)
-        expected_build_dir = src.product.get_product_config(sat.cfg, product_name).build_dir
-      
-        sat.configure(appli + ' --product ' + product_name)
-        
-        if os.path.exists(expected_build_dir):
-            OK = 'OK'         
-        # pyunit method to compare 2 str
-        self.assertEqual(OK, 'OK')
-
-    def test_040(self):
-        # Test the 'sat -h configure'
-        OK = "KO"
-
-        import configure
-        
-        if "The configure command executes in the build directory" in configure.description():
-            OK = "OK"
-
-        # pyunit method to compare 2 str
-        self.assertEqual(OK, "OK")
-
-# test launch
-if __name__ == '__main__':
-    unittest.main()
-    pass
diff --git a/test/compilation/test_make.py b/test/compilation/test_make.py
deleted file mode 100755 (executable)
index c956965..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-#!/usr/bin/env python
-#-*- coding:utf-8 -*-
-
-#  Copyright (C) 2010-2018  CEA/DEN
-#
-#  This library is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU Lesser General Public
-#  License as published by the Free Software Foundation; either
-#  version 2.1 of the License.
-#
-#  This library is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-#  Lesser General Public License for more details.
-#
-#  You should have received a copy of the GNU Lesser General Public
-#  License along with this library; if not, write to the Free Software
-#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
-
-import os
-import sys
-import unittest
-
-import src.product
-from src.salomeTools import Sat
-
-class TestCase(unittest.TestCase):
-    """Test of the make command"""
-
-    def test_010(self):
-        # Test the configure command without any option
-        OK = 'KO'
-
-        appli = 'appli-test'
-        product_name = 'PRODUCT_GIT'
-
-        sat = Sat()
-                            
-        sat.prepare(appli + ' --product ' + product_name)
-        expected_build_dir = src.product.get_product_config(sat.cfg, product_name).build_dir
-        expected_file_path = os.path.join(expected_build_dir, 'hello')
-       
-        sat.configure(appli + ' --product ' + product_name)        
-        sat.make(appli + ' --product ' + product_name)
-        
-        if os.path.exists(os.path.join(expected_build_dir, expected_file_path)):
-            OK = 'OK'         
-        # pyunit method to compare 2 str
-        self.assertEqual(OK, 'OK')
-
-    def test_020(self):
-        # Test the make command with an option
-        OK = 'KO'
-        appli = 'appli-test'
-        product_name = 'PRODUCT_GIT'
-
-        sat = Sat()
-                            
-        sat.prepare(appli + ' --product ' + product_name)
-        expected_build_dir = src.product.get_product_config(sat.cfg, product_name).build_dir
-        expected_file_path = os.path.join(expected_build_dir, 'hello')
-       
-        sat.configure(appli + ' --product ' + product_name)   
-        sat.make(appli + ' --product ' + product_name + ' --option -j3')
-        
-        if os.path.exists(os.path.join(expected_build_dir, expected_file_path)):
-            OK = 'OK'         
-        # pyunit method to compare 2 str
-        self.assertEqual(OK, 'OK')
-
-    def test_030(self):
-        # Test the make command with a product in script mode
-        OK = 'KO'
-
-        appli = 'appli-test'
-        product_name = 'Python'
-
-        sat = Sat()
-                            
-        sat.prepare(appli + ' --product ' + product_name)
-        expected_install_dir = src.product.get_product_config(sat.cfg, product_name).install_dir
-        expected_file = "bin/python2.7"
-        
-        sat.make(appli + ' --product ' + product_name)
-        
-        if os.path.exists(os.path.join(expected_install_dir, expected_file)):
-            OK = 'OK'         
-        # pyunit method to compare 2 str
-        self.assertEqual(OK, 'OK')
-
-    def test_040(self):
-        # Test the sat -h make 
-        OK = "KO"
-
-        import make
-        
-        if "The make command executes the \"make\" command" in make.description():
-            OK = "OK"
-
-        # pyunit method to compare 2 str
-        self.assertEqual(OK, "OK")
-
-# test launch
-if __name__ == '__main__':
-    unittest.main()
-    pass
diff --git a/test/compilation/test_makeinstall.py b/test/compilation/test_makeinstall.py
deleted file mode 100755 (executable)
index 62aba79..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-#!/usr/bin/env python
-#-*- coding:utf-8 -*-
-
-#  Copyright (C) 2010-2018  CEA/DEN
-#
-#  This library is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU Lesser General Public
-#  License as published by the Free Software Foundation; either
-#  version 2.1 of the License.
-#
-#  This library is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-#  Lesser General Public License for more details.
-#
-#  You should have received a copy of the GNU Lesser General Public
-#  License along with this library; if not, write to the Free Software
-#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
-
-import os
-import sys
-import unittest
-
-import src.product
-from src.salomeTools import Sat
-
-class TestMakeinstall(unittest.TestCase):
-    """Test of the makeinstall command"""
-
-    def test_010(self):
-        # Test the configure-make-makeinstall command without any option
-        OK = 'KO'
-
-        appli = 'appli-test'
-        product_name = 'PRODUCT_GIT'
-
-        sat = Sat()
-                            
-        sat.prepare(appli + ' --product ' + product_name)
-        expected_install_dir = src.product.get_product_config(sat.cfg, product_name).install_dir
-        expected_file_path = os.path.join(expected_install_dir, 'bin/hello')
-       
-        sat.configure(appli + ' --product ' + product_name)
-        
-        sat.make(appli + ' --product ' + product_name)
-        
-        sat.makeinstall(appli + ' --product ' + product_name)
-        
-        if os.path.exists(expected_file_path):
-            OK = 'OK'         
-        # pyunit method to compare 2 str
-        self.assertEqual(OK, 'OK')
-
-    def test_020(self):
-        # Test the sat -h make
-        OK = "KO"
-
-        import makeinstall
-        
-        if "The makeinstall command executes the 'make install' command" in makeinstall.description():
-            OK = "OK"
-
-        # pyunit method to compare 2 str
-        self.assertEqual(OK, "OK")
-
-# test launch
-if __name__ == '__main__':
-    unittest.main()
-    pass
diff --git a/test/config/test_create_user_pyconf.py b/test/config/test_create_user_pyconf.py
deleted file mode 100755 (executable)
index df1c0b0..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-#!/usr/bin/env python
-#-*- coding:utf-8 -*-
-
-#  Copyright (C) 2010-2018  CEA/DEN
-#
-#  This library is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU Lesser General Public
-#  License as published by the Free Software Foundation; either
-#  version 2.1 of the License.
-#
-#  This library is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-#  Lesser General Public License for more details.
-#
-#  You should have received a copy of the GNU Lesser General Public
-#  License along with this library; if not, write to the Free Software
-#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
-
-import os
-import sys
-import shutil
-import unittest
-
-from src.salomeTools import Sat
-
-class TestCase(unittest.TestCase):
-    """Test create file .pyconf"""
-    
-    def test_010(self):
-        # Test creation of ~/.salomeTools/salomeTools.pyconf
-        res = "KO"
-        user_dir = os.path.expanduser(os.path.join('~','.salomeTools'))
-        user_dir_save = os.path.expanduser(os.path.join('~','.salomeTools_save'))
-        if os.path.exists(user_dir_save):
-            shutil.rmtree(user_dir_save)
-        if os.path.exists(user_dir):
-            shutil.move(user_dir, user_dir_save)
-               
-        # The command to test
-        sat = Sat('')
-        sat.config('-v .')
-
-        expected_file = os.path.expanduser(os.path.join('~','.salomeTools', 'salomeTools.pyconf'))
-
-        if os.path.exists(expected_file):
-            res = "OK"
-
-        shutil.rmtree(user_dir)
-        shutil.move(user_dir_save, user_dir)
-        self.assertEqual(res, "OK")
-
-    def test_020(self):
-        # Test override VARS
-        OK = "KO"
-        
-        # The command to test
-        sat = Sat("-oVARS.user='user_test'")
-        sat.config()
-
-        if sat.cfg.VARS.user == 'user_test':
-            OK = "OK"
-        self.assertEqual(OK, "OK")
-
-    def test_030(self):
-        # Test override INTERNAL
-        OK = "KO"
-        
-        # The command to test
-        sat = Sat("-oINTERNAL.sat_version='V0'")
-        sat.config()
-
-        if sat.cfg.INTERNAL.sat_version == 'V0':
-            OK = "OK"
-        self.assertEqual(OK, "OK")
-
-    """
-    def test_040(self):
-        # Test override SITE
-        OK = "KO"
-        
-        # The command to test
-        sat = Sat("-oSITE.jobs.config_path='/tmp'")
-        sat.config()
-
-        if sat.cfg.SITE.jobs.config_path == '/tmp':
-            OK = "OK"
-
-        self.assertEqual(OK, "OK")
-    """
-
-    def test_050(self):
-        # Test override APPLICATION
-        OK = "KO"
-        
-        # The command to test
-        sat = Sat("-oAPPLICATION.out_dir='/tmp'")
-        sat.config('appli-test')
-
-        if sat.cfg.APPLICATION.out_dir == '/tmp':
-            OK = "OK"
-        self.assertEqual(OK, "OK")
-
-    def test_060(self):
-        # Test override PRODUCTS
-        OK = "KO"
-        
-        # The command to test
-        sat = Sat("-oPRODUCTS.PRODUCT_GIT.default.name='test'")
-        sat.config('')
-
-        if sat.cfg.PRODUCTS.PRODUCT_GIT.default.name == 'test':
-            OK = "OK"
-        self.assertEqual(OK, "OK")
-
-# test launch
-if __name__ == '__main__':
-    unittest.main()
-    pass
diff --git a/test/config/test_option_copy.py b/test/config/test_option_copy.py
deleted file mode 100755 (executable)
index bb7fe0b..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-#!/usr/bin/env python
-#-*- coding:utf-8 -*-
-
-#  Copyright (C) 2010-2018  CEA/DEN
-#
-#  This library is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU Lesser General Public
-#  License as published by the Free Software Foundation; either
-#  version 2.1 of the License.
-#
-#  This library is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-#  Lesser General Public License for more details.
-#
-#  You should have received a copy of the GNU Lesser General Public
-#  License along with this library; if not, write to the Free Software
-#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
-
-import os
-import sys
-import unittest
-
-from src.salomeTools import Sat
-
-class TestCase(unittest.TestCase):
-    """sat config --copy"""
-    
-    def test_010(self):
-        # Test the copy of a pyconf
-        res = "KO"
-        appli_to_copy = "appli-test"
-
-        expected_file = os.path.expanduser(os.path.join('~','.salomeTools', 'Applications', 'LOCAL_' + appli_to_copy + '.pyconf'))
-        if os.path.exists(expected_file):
-            os.remove(expected_file)
-               
-        # The command to test
-        sat = Sat('')
-        sat.config('appli-test -c')
-
-        if os.path.exists(expected_file):
-            res = "OK"
-            os.remove(expected_file)
-        self.assertEqual(res, "OK")
-
-# test launch
-if __name__ == '__main__':
-    unittest.main()
-    pass
diff --git a/test/config/test_option_edit.py b/test/config/test_option_edit.py
deleted file mode 100755 (executable)
index c6674e9..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-#!/usr/bin/env python
-#-*- coding:utf-8 -*-
-
-#  Copyright (C) 2010-2018  CEA/DEN
-#
-#  This library is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU Lesser General Public
-#  License as published by the Free Software Foundation; either
-#  version 2.1 of the License.
-#
-#  This library is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-#  Lesser General Public License for more details.
-#
-#  You should have received a copy of the GNU Lesser General Public
-#  License along with this library; if not, write to the Free Software
-#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
-
-import os
-import sys
-import threading
-import time
-import unittest
-
-from src.salomeTools import Sat
-from unittestpy.tools import check_proc_existence_and_kill_multi
-
-sleep_time = 2
-
-class TestCase(unittest.TestCase):
-    """sat config --edit"""
-    
-    def test_010(self):
-        # Test the launch of the editor when invoking the config -e
-        OK = "KO"
-
-        sat = Sat("-oUSER.editor='cooledit'")
-        sat.config()
-        cmd_config = threading.Thread(target=sat.config, args=('-e',))
-        cmd_config.start()
-
-        time.sleep(sleep_time)
-
-        editor = sat.cfg.USER.editor
-        pid = check_proc_existence_and_kill_multi(editor + ".*" + "salomeTools\.pyconf", 10)
-
-        if pid:
-            OK = "OK"
-        self.assertEqual(OK, "OK")
-
-    def test_020(self):
-        # Test the launch of the editor when invoking the config -e appli-test
-        OK = "KO"
-
-        sat = Sat("-oUSER.editor='cooledit'")
-        sat.config()
-        cmd_config = threading.Thread(target=sat.config, args=('appli-test -e',))
-        cmd_config.start()
-
-        time.sleep(sleep_time)
-
-        editor = sat.cfg.USER.editor
-        pid = check_proc_existence_and_kill_multi(editor + ".*" + "appli-test\.pyconf", 10)
-
-        if pid:
-            OK = "OK"
-        self.assertEqual(OK, "OK")
-# test launch
-if __name__ == '__main__':
-    unittest.main()
-    pass
diff --git a/test/config/test_option_value.py b/test/config/test_option_value.py
deleted file mode 100755 (executable)
index 50a7d84..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-#!/usr/bin/env python
-#-*- coding:utf-8 -*-
-
-#  Copyright (C) 2010-2018  CEA/DEN
-#
-#  This library is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU Lesser General Public
-#  License as published by the Free Software Foundation; either
-#  version 2.1 of the License.
-#
-#  This library is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-#  Lesser General Public License for more details.
-#
-#  You should have received a copy of the GNU Lesser General Public
-#  License along with this library; if not, write to the Free Software
-#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
-
-import os
-import sys
-import platform
-import unittest
-
-from src.salomeTools import Sat
-from unittestpy.tools import outRedirection
-
-class TestCase(unittest.TestCase):
-    """sat config --value"""
-    
-    def test_010(self):
-        # Test the display of the right value of "sat config -v VARS.hostname"
-        OK = "KO"
-
-        # output redirection
-        my_out = outRedirection()
-
-        # The command to test
-        sat = Sat()
-        sat.config('-v VARS.hostname')
-
-        # stop output redirection
-        my_out.end_redirection()
-
-        # get results
-        res = my_out.read_results()
-
-        if platform.node() in res:
-            OK = "OK"
-        self.assertEqual(OK, "OK")
-
-    def test_020(self):
-        # Test the display of the right value of "sat config -l"
-        OK = "KO"
-
-        # output redirection
-        my_out = outRedirection()
-
-        # The command to test
-        sat = Sat()
-        sat.config('-l')
-
-        # stop output redirection
-        my_out.end_redirection()
-
-        # get results
-        res = my_out.read_results()
-
-        # get results
-        if "ERROR" not in res:
-            OK = "OK"
-        self.assertEqual(OK, "OK")
-    
-    """    
-    def test_030(self):
-        # Test the exception when salomeTools.pyconf has errors           
-        OK = "KO"
-        
-        # The command to test
-        sat = Sat()
-        sat.config()
-        
-        salomeToolspyconfPath = os.path.join(sat.cfg.VARS.srcDir, "internal_config", "salomeTools.pyconf")
-        salomeToolspyconfPath_save = os.path.join(sat.cfg.VARS.srcDir, "internal_config", "salomeTools.pyconf_save")
-        if os.path.exists(salomeToolspyconfPath_save):
-            os.remove(salomeToolspyconfPath_save)
-        shutil.copyfile(salomeToolspyconfPath, salomeToolspyconfPath_save)
-        f_read = open(salomeToolspyconfPath, 'r')
-        text = f_read.read()
-        f_read.close()
-        os.remove(salomeToolspyconfPath)
-        f_write = open(salomeToolspyconfPath, 'w')
-        f_write.write(text.replace(':', ''))
-        f_write.close()
-        
-        try:
-            sat.config()
-        except TypeError:
-            OK = "OK"
-        finally:
-            shutil.copyfile(salomeToolspyconfPath_save, salomeToolspyconfPath)
-            os.remove(salomeToolspyconfPath_save)
-        self.assertEqual(OK, "OK")
-    """       
-        
-# test launch
-if __name__ == '__main__':
-    unittest.main()
-    pass
diff --git a/test/config/test_option_value_2.py b/test/config/test_option_value_2.py
deleted file mode 100755 (executable)
index c11fee1..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-#!/usr/bin/env python
-#-*- coding:utf-8 -*-
-
-#  Copyright (C) 2010-2018  CEA/DEN
-#
-#  This library is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU Lesser General Public
-#  License as published by the Free Software Foundation; either
-#  version 2.1 of the License.
-#
-#  This library is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-#  Lesser General Public License for more details.
-#
-#  You should have received a copy of the GNU Lesser General Public
-#  License along with this library; if not, write to the Free Software
-#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
-
-import os
-import sys
-import platform
-import unittest
-
-from src.salomeTools import Sat
-from unittestpy.tools import outRedirection
-
-class TestCase(unittest.TestCase):
-    """sat config -v VARS.python"""
-    
-    def test_010(self):
-        # Test the display of the right value of 'sat config -v VARS.python'
-        OK = 'KO'
-
-        # output redirection
-        my_out = outRedirection()
-
-        # The command to test
-        sat = Sat('')
-        sat.config('-v VARS.python')
-
-        # stop output redirection
-        my_out.end_redirection()
-
-        # get results
-        res = my_out.read_results()
-        
-        
-        if platform.python_version() in res:
-            OK = 'OK'
-        self.assertEqual(OK, 'OK')
-
-    def test_020(self):
-        # Test the display of the right value of 'sat config -s'
-        OK = 'KO'
-
-        # output redirection
-        my_out = outRedirection()
-
-        # The command to test
-        sat = Sat('')
-        sat.config('-s')
-
-        # stop output redirection
-        my_out.end_redirection()
-
-        # get results
-        res = my_out.read_results()
-        
-        
-        if 'INTERNAL' in res:
-            OK = 'OK'
-        self.assertEqual(OK, 'OK')
-        
-    def test_030(self):
-        # Test the display of the right value of 'sat config --info'
-        application = 'appli-test'
-        product = 'PRODUCT_DEV'
-        
-        OK = 'KO'
-
-        # output redirection
-        my_out = outRedirection()
-
-        # The command to test
-        sat = Sat('')
-        sat.config(application + ' --info ' + product)
-
-        # stop output redirection
-        my_out.end_redirection()
-
-        # get results
-        res = my_out.read_results()
-        
-        
-        if 'compilation method = cmake' in res:
-            OK = 'OK'
-        self.assertEqual(OK, 'OK')
-
-# test launch
-if __name__ == '__main__':
-    unittest.main()
-    pass
diff --git a/test/config_0_3_9/LICENSE b/test/config_0_3_9/LICENSE
new file mode 100644 (file)
index 0000000..98773c8
--- /dev/null
@@ -0,0 +1,16 @@
+Copyright (C) 2004-2010 by Vinay Sajip. All Rights Reserved.\r
+\r
+Permission to use, copy, modify, and distribute this software and its\r
+documentation for any purpose and without fee is hereby granted,\r
+provided that the above copyright notice appear in all copies and that\r
+both that copyright notice and this permission notice appear in\r
+supporting documentation, and that the name of Vinay Sajip\r
+not be used in advertising or publicity pertaining to distribution\r
+of the software without specific, written prior permission.\r
+\r
+VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING\r
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL\r
+VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR\r
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN\r
+AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR\r
+IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/test/config_0_3_9/PKG-INFO b/test/config_0_3_9/PKG-INFO
new file mode 100644 (file)
index 0000000..69ba705
--- /dev/null
@@ -0,0 +1,16 @@
+Metadata-Version: 1.0
+Name: config
+Version: 0.3.9
+Summary: A hierarchical, easy-to-use, powerful configuration module for Python
+Home-page: http://www.red-dove.com/python_config.html
+Author: Vinay Sajip
+Author-email: vinay_sajip@red-dove.com
+License: Copyright (C) 2004-2010 by Vinay Sajip. All Rights Reserved. See LICENSE for license.
+Description: This module allows a hierarchical configuration scheme with support for mappings
+        and sequences, cross-references between one part of the configuration and
+        another, the ability to flexibly access real Python objects without full-blown
+        eval(), an include facility, simple expression evaluation and the ability to
+        change, save, cascade and merge configurations. Interfaces easily with
+        environment variables and command-line options. It has been developed on python
+        2.3 but should work on version 2.2 or greater.
+Platform: UNKNOWN
diff --git a/test/config_0_3_9/README.txt b/test/config_0_3_9/README.txt
new file mode 100644 (file)
index 0000000..0c20eab
--- /dev/null
@@ -0,0 +1,84 @@
+This module is intended to provide configuration functionality for Python\r
+programs.\r
+\r
+Change History\r
+--------------\r
+\r
+Version   Date        Description\r
+=============================================================================\r
+0.3.9     11 May 2010 Fixed parsing bug which caused failure for numbers with\r
+                      exponents.\r
+-----------------------------------------------------------------------------\r
+0.3.8     03 Mar 2010 Fixed parsing bug which caused failure for negative\r
+                      numbers in sequences. Improved resolution logic.\r
+-----------------------------------------------------------------------------\r
+0.3.7     05 Oct 2007 Added Mapping.__delitem__ (patch by John Drummond).\r
+                      Mapping.__getattribute__ no longer returns "" when\r
+                      asked for "__class__" - doing so causes pickle to\r
+                      crash (reported by Jamila Gunawardena).\r
+                      Allow negative numbers (reported by Gary Schoep; had\r
+                      already been fixed but not yet released).\r
+-----------------------------------------------------------------------------\r
+0.3.6     09 Mar 2006 Made classes derive from object (previously they were\r
+                      old-style classes).\r
+                      Changed ConfigMerger to use a more flexible merge\r
+                      strategy.\r
+                      Multiline strings (using """ or ''') are now supported.\r
+                      A typo involving raising a ConfigError was fixed.\r
+                      Patches received with thanks from David Janes & Tim\r
+                      Desjardins (BlogMatrix) and Erick Tryzelaar.\r
+-----------------------------------------------------------------------------\r
+0.3.5     27 Dec 2004 Added ConfigOutputStream to provide better Unicode\r
+                      output support. Altered save code to put platform-\r
+                      dependent newlines for Unicode.\r
+-----------------------------------------------------------------------------\r
+0.3.4     11 Nov 2004 Added ConfigInputStream to provide better Unicode\r
+                      support.\r
+                      Added ConfigReader.setStream().\r
+-----------------------------------------------------------------------------\r
+0.3.3     09 Nov 2004 Renamed config.get() to getByPath(), and likewise for\r
+                      ConfigList.\r
+                      Added Mapping.get() to work like dict.get().\r
+                      Added logconfig.py and logconfig.cfg to distribution.\r
+-----------------------------------------------------------------------------\r
+0.3.2     04 Nov 2004 Simplified parseMapping().\r
+                      Allowed Config.__init__ to accept a string as well as a\r
+                      stream. If a string is passed in, streamOpener is used\r
+                      to obtain the stream to be used.\r
+-----------------------------------------------------------------------------\r
+0.3.1     04 Nov 2004 Changed addNamespace/removeNamespace to make name\r
+                      specification easier.\r
+                      Refactored save(), added Container.writeToStream and\r
+                      Container.writeValue() to help with this.\r
+-----------------------------------------------------------------------------\r
+0.3       03 Nov 2004 Added test harness (test_config.py)\r
+                      Fixed bugs in bracket parsing.\r
+                      Refactored internal classes.\r
+                      Added merging functionality.\r
+-----------------------------------------------------------------------------\r
+0.2       01 Nov 2004 Added support for None.\r
+                      Stream closed in load() and save().\r
+                      Added support for changing configuration.\r
+                      Fixed bugs in identifier parsing and isword().\r
+-----------------------------------------------------------------------------\r
+0.1       31 Oct 2004 Initial implementation (for community feedback)\r
+-----------------------------------------------------------------------------\r
+\r
+-----------------------------------------------------------------------------\r
+COPYRIGHT\r
+-----------------------------------------------------------------------------\r
+Copyright 2004-2010 by Vinay Sajip. All Rights Reserved.\r
+\r
+Permission to use, copy, modify, and distribute this software and its\r
+documentation for any purpose and without fee is hereby granted,\r
+provided that the above copyright notice appear in all copies and that\r
+both that copyright notice and this permission notice appear in\r
+supporting documentation, and that the name of Vinay Sajip\r
+not be used in advertising or publicity pertaining to distribution\r
+of the software without specific, written prior permission.\r
+VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING\r
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL\r
+VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR\r
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN\r
+AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR\r
+IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\r
diff --git a/test/config_0_3_9/__init__.py b/test/config_0_3_9/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/test/config_0_3_9/config.py b/test/config_0_3_9/config.py
new file mode 100644 (file)
index 0000000..94d04c0
--- /dev/null
@@ -0,0 +1,1678 @@
+# Copyright 2004-2010 by Vinay Sajip. All Rights Reserved.\r
+#\r
+# Permission to use, copy, modify, and distribute this software and its\r
+# documentation for any purpose and without fee is hereby granted,\r
+# provided that the above copyright notice appear in all copies and that\r
+# both that copyright notice and this permission notice appear in\r
+# supporting documentation, and that the name of Vinay Sajip\r
+# not be used in advertising or publicity pertaining to distribution\r
+# of the software without specific, written prior permission.\r
+# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING\r
+# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL\r
+# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR\r
+# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER\r
+# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT\r
+# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\r
+\r
+"""\r
+This is a configuration module for Python.\r
+\r
+This module should work under Python versions >= 2.2, and cannot be used with\r
+earlier versions since it uses new-style classes.\r
+\r
+Development and testing has only been carried out (so far) on Python 2.3.4 and\r
+Python 2.4.2. See the test module (test_config.py) included in the\r
+U{distribution<http://www.red-dove.com/python_config.html|_blank>} (follow the\r
+download link).\r
+\r
+A simple example - with the example configuration file::\r
+\r
+    messages:\r
+    [\r
+      {\r
+        stream : `sys.stderr`\r
+        message: 'Welcome'\r
+        name: 'Harry'\r
+      }\r
+      {\r
+        stream : `sys.stdout`\r
+        message: 'Welkom'\r
+        name: 'Ruud'\r
+      }\r
+      {\r
+        stream : $messages[0].stream\r
+        message: 'Bienvenue'\r
+        name: Yves\r
+      }\r
+    ]\r
+\r
+a program to read the configuration would be::\r
+\r
+    from config import Config\r
+\r
+    f = file('simple.cfg')\r
+    cfg = Config(f)\r
+    for m in cfg.messages:\r
+        s = '%s, %s' % (m.message, m.name)\r
+        try:\r
+            print >> m.stream, s\r
+        except IOError, e:\r
+            print e\r
+\r
+which, when run, would yield the console output::\r
+\r
+    Welcome, Harry\r
+    Welkom, Ruud\r
+    Bienvenue, Yves\r
+\r
+See U{this tutorial<http://www.red-dove.com/python_config.html|_blank>} for more\r
+information.\r
+\r
+@version: 0.3.9\r
+\r
+@author: Vinay Sajip\r
+\r
+@copyright: Copyright (C) 2004-2010 Vinay Sajip. All Rights Reserved.\r
+\r
+\r
+@var streamOpener: The default stream opener. This is a factory function which\r
+takes a string (e.g. filename) and returns a stream suitable for reading. If\r
+unable to open the stream, an IOError exception should be thrown.\r
+\r
+The default value of this variable is L{defaultStreamOpener}. For an example\r
+of how it's used, see test_config.py (search for streamOpener).\r
+"""\r
+\r
+__author__  = "Vinay Sajip <vinay_sajip@red-dove.com>"\r
+__status__  = "alpha"\r
+__version__ = "0.3.9"\r
+__date__    = "11 May 2010"\r
+\r
+from types import StringType, UnicodeType\r
+\r
+import codecs\r
+import logging\r
+import os\r
+import sys\r
+\r
+WORD = 'a'\r
+NUMBER = '9'\r
+STRING = '"'\r
+EOF = ''\r
+LCURLY = '{'\r
+RCURLY = '}'\r
+LBRACK = '['\r
+LBRACK2 = 'a['\r
+RBRACK = ']'\r
+LPAREN = '('\r
+LPAREN2 = '(('\r
+RPAREN = ')'\r
+DOT = '.'\r
+COMMA = ','\r
+COLON = ':'\r
+AT = '@'\r
+PLUS = '+'\r
+MINUS = '-'\r
+STAR = '*'\r
+SLASH = '/'\r
+MOD = '%'\r
+BACKTICK = '`'\r
+DOLLAR = '$'\r
+TRUE = 'True'\r
+FALSE = 'False'\r
+NONE = 'None'\r
+\r
+WORDCHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_"\r
+\r
+if sys.platform == 'win32':\r
+    NEWLINE = '\r\n'\r
+elif os.name == 'mac':\r
+    NEWLINE = '\r'\r
+else:\r
+    NEWLINE = '\n'\r
+\r
+try:\r
+    import encodings.utf_32\r
+    has_utf32 = True\r
+except:\r
+    has_utf32 = False\r
+\r
+try:\r
+    from logging.handlers import NullHandler\r
+except ImportError:\r
+    class NullHandler(logging.Handler):\r
+        def emit(self, record):\r
+            pass\r
+\r
+logger = logging.getLogger(__name__)\r
+if not logger.handlers:\r
+    logger.addHandler(NullHandler())\r
+\r
+class ConfigInputStream(object):\r
+    """\r
+    An input stream which can read either ANSI files with default encoding\r
+    or Unicode files with BOMs.\r
+\r
+    Handles UTF-8, UTF-16LE, UTF-16BE. Could handle UTF-32 if Python had\r
+    built-in support.\r
+    """\r
+    def __init__(self, stream):\r
+        """\r
+        Initialize an instance.\r
+\r
+        @param stream: The underlying stream to be read. Should be seekable.\r
+        @type stream: A stream (file-like object).\r
+        """\r
+        encoding = None\r
+        signature = stream.read(4)\r
+        used = -1\r
+        if has_utf32:\r
+            if signature == codecs.BOM_UTF32_LE:\r
+                encoding = 'utf-32le'\r
+            elif signature == codecs.BOM_UTF32_BE:\r
+                encoding = 'utf-32be'\r
+        if encoding is None:\r
+            if signature[:3] == codecs.BOM_UTF8:\r
+                used = 3\r
+                encoding = 'utf-8'\r
+            elif signature[:2] == codecs.BOM_UTF16_LE:\r
+                used = 2\r
+                encoding = 'utf-16le'\r
+            elif signature[:2] == codecs.BOM_UTF16_BE:\r
+                used = 2\r
+                encoding = 'utf-16be'\r
+            else:\r
+                used = 0\r
+        if used >= 0:\r
+            stream.seek(used)\r
+        if encoding:\r
+            reader = codecs.getreader(encoding)\r
+            stream = reader(stream)\r
+        self.stream = stream\r
+        self.encoding = encoding\r
+\r
+    def read(self, size):\r
+        if (size == 0) or (self.encoding is None):\r
+            rv = self.stream.read(size)\r
+        else:\r
+            rv = u''\r
+            while size > 0:\r
+                rv += self.stream.read(1)\r
+                size -= 1\r
+        return rv\r
+\r
+    def close(self):\r
+        self.stream.close()\r
+\r
+    def readline(self):\r
+        if self.encoding is None:\r
+            line = ''\r
+        else:\r
+            line = u''\r
+        while True:\r
+            c = self.stream.read(1)\r
+            if c:\r
+                line += c\r
+            if c == '\n':\r
+                break\r
+        return line\r
+\r
+class ConfigOutputStream(object):\r
+    """\r
+    An output stream which can write either ANSI files with default encoding\r
+    or Unicode files with BOMs.\r
+\r
+    Handles UTF-8, UTF-16LE, UTF-16BE. Could handle UTF-32 if Python had\r
+    built-in support.\r
+    """\r
+\r
+    def __init__(self, stream, encoding=None):\r
+        """\r
+        Initialize an instance.\r
+\r
+        @param stream: The underlying stream to be written.\r
+        @type stream: A stream (file-like object).\r
+        @param encoding: The desired encoding.\r
+        @type encoding: str\r
+        """\r
+        if encoding is not None:\r
+            encoding = str(encoding).lower()\r
+        self.encoding = encoding\r
+        if encoding == "utf-8":\r
+            stream.write(codecs.BOM_UTF8)\r
+        elif encoding == "utf-16be":\r
+            stream.write(codecs.BOM_UTF16_BE)\r
+        elif encoding == "utf-16le":\r
+            stream.write(codecs.BOM_UTF16_LE)\r
+        elif encoding == "utf-32be":\r
+            stream.write(codecs.BOM_UTF32_BE)\r
+        elif encoding == "utf-32le":\r
+            stream.write(codecs.BOM_UTF32_LE)\r
+\r
+        if encoding is not None:\r
+            writer = codecs.getwriter(encoding)\r
+            stream = writer(stream)\r
+        self.stream = stream\r
+\r
+    def write(self, data):\r
+        self.stream.write(data)\r
+\r
+    def flush(self):\r
+        self.stream.flush()\r
+\r
+    def close(self):\r
+        self.stream.close()\r
+\r
+def defaultStreamOpener(name):\r
+    """\r
+    This function returns a read-only stream, given its name. The name passed\r
+    in should correspond to an existing stream, otherwise an exception will be\r
+    raised.\r
+\r
+    This is the default value of L{streamOpener}; assign your own callable to\r
+    streamOpener to return streams based on names. For example, you could use\r
+    urllib2.urlopen().\r
+\r
+    @param name: The name of a stream, most commonly a file name.\r
+    @type name: str\r
+    @return: A stream with the specified name.\r
+    @rtype: A read-only stream (file-like object)\r
+    """\r
+    return ConfigInputStream(file(name, 'rb'))\r
+\r
+streamOpener = None\r
+\r
+class ConfigError(Exception):\r
+    """\r
+    This is the base class of exceptions raised by this module.\r
+    """\r
+    pass\r
+\r
+class ConfigFormatError(ConfigError):\r
+    """\r
+    This is the base class of exceptions raised due to syntax errors in\r
+    configurations.\r
+    """\r
+    pass\r
+\r
+class ConfigResolutionError(ConfigError):\r
+    """\r
+    This is the base class of exceptions raised due to semantic errors in\r
+    configurations.\r
+    """\r
+    pass\r
+\r
+def isWord(s):\r
+    """\r
+    See if a passed-in value is an identifier. If the value passed in is not a\r
+    string, False is returned. An identifier consists of alphanumerics or\r
+    underscore characters.\r
+\r
+    Examples::\r
+\r
+        isWord('a word') ->False\r
+        isWord('award') -> True\r
+        isWord(9) -> False\r
+        isWord('a_b_c_') ->True\r
+\r
+    @note: isWord('9abc') will return True - not exactly correct, but adequate\r
+    for the way it's used here.\r
+\r
+    @param s: The name to be tested\r
+    @type s: any\r
+    @return: True if a word, else False\r
+    @rtype: bool\r
+    """\r
+    if type(s) != type(''):\r
+        return False\r
+    s = s.replace('_', '')\r
+    return s.isalnum()\r
+\r
+def makePath(prefix, suffix):\r
+    """\r
+    Make a path from a prefix and suffix.\r
+\r
+    Examples::\r
+\r
+        makePath('', 'suffix') -> 'suffix'\r
+        makePath('prefix', 'suffix') -> 'prefix.suffix'\r
+        makePath('prefix', '[1]') -> 'prefix[1]'\r
+\r
+    @param prefix:  The prefix to use. If it evaluates as false, the suffix\r
+                    is returned.\r
+    @type prefix:   str\r
+    @param suffix:  The suffix to use. It is either an identifier or an\r
+                    index in brackets.\r
+    @type suffix:   str\r
+    @return:        The path concatenation of prefix and suffix, with a\r
+                    dot if the suffix is not a bracketed index.\r
+    @rtype:         str\r
+\r
+    """\r
+    if not prefix:\r
+        rv = suffix\r
+    elif suffix[0] == '[':\r
+        rv = prefix + suffix\r
+    else:\r
+        rv = prefix + '.' + suffix\r
+    return rv\r
+\r
+\r
+class Container(object):\r
+    """\r
+    This internal class is the base class for mappings and sequences.\r
+\r
+    @ivar path: A string which describes how to get\r
+    to this instance from the root of the hierarchy.\r
+\r
+    Example::\r
+\r
+        a.list.of[1].or['more'].elements\r
+    """\r
+    def __init__(self, parent):\r
+        """\r
+        Initialize an instance.\r
+\r
+        @param parent: The parent of this instance in the hierarchy.\r
+        @type parent: A L{Container} instance.\r
+        """\r
+        object.__setattr__(self, 'parent', parent)\r
+\r
+    def setPath(self, path):\r
+        """\r
+        Set the path for this instance.\r
+        @param path: The path - a string which describes how to get\r
+        to this instance from the root of the hierarchy.\r
+        @type path: str\r
+        """\r
+        object.__setattr__(self, 'path', path)\r
+\r
+    def evaluate(self, item):\r
+        """\r
+        Evaluate items which are instances of L{Reference} or L{Expression}.\r
+\r
+        L{Reference} instances are evaluated using L{Reference.resolve},\r
+        and L{Expression} instances are evaluated using\r
+        L{Expression.evaluate}.\r
+\r
+        @param item: The item to be evaluated.\r
+        @type item: any\r
+        @return: If the item is an instance of L{Reference} or L{Expression},\r
+        the evaluated value is returned, otherwise the item is returned\r
+        unchanged.\r
+        """\r
+        if isinstance(item, Reference):\r
+            item = item.resolve(self)\r
+        elif isinstance(item, Expression):\r
+            item = item.evaluate(self)\r
+        return item\r
+\r
+    def writeToStream(self, stream, indent, container):\r
+        """\r
+        Write this instance to a stream at the specified indentation level.\r
+\r
+        Should be redefined in subclasses.\r
+\r
+        @param stream: The stream to write to\r
+        @type stream: A writable stream (file-like object)\r
+        @param indent: The indentation level\r
+        @type indent: int\r
+        @param container: The container of this instance\r
+        @type container: L{Container}\r
+        @raise NotImplementedError: If a subclass does not override this\r
+        """\r
+        raise NotImplementedError\r
+\r
+    def writeValue(self, value, stream, indent):\r
+        if isinstance(self, Mapping):\r
+            indstr = ' '\r
+        else:\r
+            indstr = indent * '  '\r
+        if isinstance(value, Reference) or isinstance(value, Expression):\r
+            stream.write('%s%r%s' % (indstr, value, NEWLINE))\r
+        else:\r
+            if (type(value) is StringType): # and not isWord(value):\r
+                value = repr(value)\r
+            stream.write('%s%s%s' % (indstr, value, NEWLINE))\r
+\r
+class Mapping(Container):\r
+    """\r
+    This internal class implements key-value mappings in configurations.\r
+    """\r
+\r
+    def __init__(self, parent=None):\r
+        """\r
+        Initialize an instance.\r
+\r
+        @param parent: The parent of this instance in the hierarchy.\r
+        @type parent: A L{Container} instance.\r
+        """\r
+        Container.__init__(self, parent)\r
+        object.__setattr__(self, 'path', '')\r
+        object.__setattr__(self, 'data', {})\r
+        object.__setattr__(self, 'order', [])   # to preserve ordering\r
+        object.__setattr__(self, 'comments', {})\r
+\r
+    def __delitem__(self, key):\r
+        """\r
+        Remove an item\r
+        """\r
+        data = object.__getattribute__(self, 'data')\r
+        if key not in data:\r
+            raise AttributeError(key)\r
+        order = object.__getattribute__(self, 'order')\r
+        comments = object.__getattribute__(self, 'comments')\r
+        del data[key]\r
+        order.remove(key)\r
+        del comments[key]\r
+\r
+    def __getitem__(self, key):\r
+        data = object.__getattribute__(self, 'data')\r
+        if key not in data:\r
+            raise AttributeError(key)\r
+        rv = data[key]\r
+        return self.evaluate(rv)\r
+\r
+    __getattr__ = __getitem__\r
+\r
+    def __getattribute__(self, name):\r
+        if name == "__dict__":\r
+            return {}\r
+        if name in ["__methods__", "__members__"]:\r
+            return []\r
+        #if name == "__class__":\r
+        #    return ''\r
+        data = object.__getattribute__(self, "data")\r
+        useData = data.has_key(name)\r
+        if useData:\r
+            rv = getattr(data, name)\r
+        else:\r
+            rv = object.__getattribute__(self, name)\r
+            if rv is None:\r
+                raise AttributeError(name)\r
+        return rv\r
+\r
+    def iteritems(self):\r
+        for key in self.keys():\r
+            yield(key, self[key])\r
+        raise StopIteration\r
+\r
+    def __contains__(self, item):\r
+        order = object.__getattribute__(self, 'order')\r
+        return item in order\r
+\r
+    def addMapping(self, key, value, comment, setting=False):\r
+        """\r
+        Add a key-value mapping with a comment.\r
+\r
+        @param key: The key for the mapping.\r
+        @type key: str\r
+        @param value: The value for the mapping.\r
+        @type value: any\r
+        @param comment: The comment for the key (can be None).\r
+        @type comment: str\r
+        @param setting: If True, ignore clashes. This is set\r
+        to true when called from L{__setattr__}.\r
+        @raise ConfigFormatError: If an existing key is seen\r
+        again and setting is False.\r
+        """\r
+        data = object.__getattribute__(self, 'data')\r
+        order = object.__getattribute__(self, 'order')\r
+        comments = object.__getattribute__(self, 'comments')\r
+\r
+        data[key] = value\r
+        if key not in order:\r
+            order.append(key)\r
+        elif not setting:\r
+            raise ConfigFormatError("repeated key: %s" % key)\r
+        comments[key] = comment\r
+\r
+    def __setattr__(self, name, value):\r
+        self.addMapping(name, value, None, True)\r
+\r
+    __setitem__ = __setattr__\r
+\r
+    def keys(self):\r
+        """\r
+        Return the keys in a similar way to a dictionary.\r
+        """\r
+        return object.__getattribute__(self, 'order')\r
+\r
+    def get(self, key, default=None):\r
+        """\r
+        Allows a dictionary-style get operation.\r
+        """\r
+        if key in self:\r
+            return self[key]\r
+        return default\r
+\r
+    def __str__(self):\r
+        return str(object.__getattribute__(self, 'data'))\r
+\r
+    def __repr__(self):\r
+        return repr(object.__getattribute__(self, 'data'))\r
+\r
+    def __len__(self):\r
+        return len(object.__getattribute__(self, 'order'))\r
+\r
+    def __iter__(self):\r
+        return self.iterkeys()\r
+\r
+    def iterkeys(self):\r
+        order = object.__getattribute__(self, 'order')\r
+        return order.__iter__()\r
+\r
+    def writeToStream(self, stream, indent, container):\r
+        """\r
+        Write this instance to a stream at the specified indentation level.\r
+\r
+        Should be redefined in subclasses.\r
+\r
+        @param stream: The stream to write to\r
+        @type stream: A writable stream (file-like object)\r
+        @param indent: The indentation level\r
+        @type indent: int\r
+        @param container: The container of this instance\r
+        @type container: L{Container}\r
+        """\r
+        indstr = indent * '  '\r
+        if len(self) == 0:\r
+            stream.write(' { }%s' % NEWLINE)\r
+        else:\r
+            if isinstance(container, Mapping):\r
+                stream.write(NEWLINE)\r
+            stream.write('%s{%s' % (indstr, NEWLINE))\r
+            self.save(stream, indent + 1)\r
+            stream.write('%s}%s' % (indstr, NEWLINE))\r
+\r
+    def save(self, stream, indent=0):\r
+        """\r
+        Save this configuration to the specified stream.\r
+        @param stream: A stream to which the configuration is written.\r
+        @type stream: A write-only stream (file-like object).\r
+        @param indent: The indentation level for the output.\r
+        @type indent: int\r
+        """\r
+        indstr = indent * '  '\r
+        order = object.__getattribute__(self, 'order')\r
+        data = object.__getattribute__(self, 'data')\r
+        maxlen = 0 # max(map(lambda x: len(x), order))\r
+        for key in order:\r
+            comment = self.comments[key]\r
+            if isWord(key):\r
+                skey = key\r
+            else:\r
+                skey = repr(key)\r
+            if comment:\r
+                stream.write('%s#%s' % (indstr, comment))\r
+            stream.write('%s%-*s :' % (indstr, maxlen, skey))\r
+            value = data[key]\r
+            if isinstance(value, Container):\r
+                value.writeToStream(stream, indent, self)\r
+            else:\r
+                self.writeValue(value, stream, indent)\r
+\r
+class Config(Mapping):\r
+    """\r
+    This class represents a configuration, and is the only one which clients\r
+    need to interface to, under normal circumstances.\r
+    """\r
+\r
+    class Namespace(object):\r
+        """\r
+        This internal class is used for implementing default namespaces.\r
+\r
+        An instance acts as a namespace.\r
+        """\r
+        def __init__(self):\r
+            self.sys = sys\r
+            self.os = os\r
+\r
+        def __repr__(self):\r
+            return "<Namespace('%s')>" % ','.join(self.__dict__.keys())\r
+\r
+    def __init__(self, streamOrFile=None, parent=None):\r
+        """\r
+        Initializes an instance.\r
+\r
+        @param streamOrFile: If specified, causes this instance to be loaded\r
+        from the stream (by calling L{load}). If a string is provided, it is\r
+        passed to L{streamOpener} to open a stream. Otherwise, the passed\r
+        value is assumed to be a stream and used as is.\r
+        @type streamOrFile: A readable stream (file-like object) or a name.\r
+        @param parent: If specified, this becomes the parent of this instance\r
+        in the configuration hierarchy.\r
+        @type parent: a L{Container} instance.\r
+        """\r
+        Mapping.__init__(self, parent)\r
+        object.__setattr__(self, 'reader', ConfigReader(self))\r
+        object.__setattr__(self, 'namespaces', [Config.Namespace()])\r
+        object.__setattr__(self, 'resolving', set())\r
+        if streamOrFile is not None:\r
+            if isinstance(streamOrFile, StringType) or isinstance(streamOrFile, UnicodeType):\r
+                global streamOpener\r
+                if streamOpener is None:\r
+                    streamOpener = defaultStreamOpener\r
+                streamOrFile = streamOpener(streamOrFile)\r
+            load = object.__getattribute__(self, "load")\r
+            load(streamOrFile)\r
+\r
+    def load(self, stream):\r
+        """\r
+        Load the configuration from the specified stream. Multiple streams can\r
+        be used to populate the same instance, as long as there are no\r
+        clashing keys. The stream is closed.\r
+        @param stream: A stream from which the configuration is read.\r
+        @type stream: A read-only stream (file-like object).\r
+        @raise ConfigError: if keys in the loaded configuration clash with\r
+        existing keys.\r
+        @raise ConfigFormatError: if there is a syntax error in the stream.\r
+        """\r
+        reader = object.__getattribute__(self, 'reader')\r
+        #object.__setattr__(self, 'root', reader.load(stream))\r
+        reader.load(stream)\r
+        stream.close()\r
+\r
+    def addNamespace(self, ns, name=None):\r
+        """\r
+        Add a namespace to this configuration which can be used to evaluate\r
+        (resolve) dotted-identifier expressions.\r
+        @param ns: The namespace to be added.\r
+        @type ns: A module or other namespace suitable for passing as an\r
+        argument to vars().\r
+        @param name: A name for the namespace, which, if specified, provides\r
+        an additional level of indirection.\r
+        @type name: str\r
+        """\r
+        namespaces = object.__getattribute__(self, 'namespaces')\r
+        if name is None:\r
+            namespaces.append(ns)\r
+        else:\r
+            setattr(namespaces[0], name, ns)\r
+\r
+    def removeNamespace(self, ns, name=None):\r
+        """\r
+        Remove a namespace added with L{addNamespace}.\r
+        @param ns: The namespace to be removed.\r
+        @param name: The name which was specified when L{addNamespace} was\r
+        called.\r
+        @type name: str\r
+        """\r
+        namespaces = object.__getattribute__(self, 'namespaces')\r
+        if name is None:\r
+            namespaces.remove(ns)\r
+        else:\r
+            delattr(namespaces[0], name)\r
+\r
+    def save(self, stream, indent=0):\r
+        """\r
+        Save this configuration to the specified stream. The stream is\r
+        closed if this is the top-level configuration in the hierarchy.\r
+        L{Mapping.save} is called to do all the work.\r
+        @param stream: A stream to which the configuration is written.\r
+        @type stream: A write-only stream (file-like object).\r
+        @param indent: The indentation level for the output.\r
+        @type indent: int\r
+        """\r
+        Mapping.save(self, stream, indent)\r
+        if indent == 0:\r
+            stream.close()\r
+\r
+    def getByPath(self, path):\r
+        """\r
+        Obtain a value in the configuration via its path.\r
+        @param path: The path of the required value\r
+        @type path: str\r
+        @return the value at the specified path.\r
+        @rtype: any\r
+        @raise ConfigError: If the path is invalid\r
+        """\r
+        s = 'self.' + path\r
+        try:\r
+            return eval(s)\r
+        except Exception, e:\r
+            raise ConfigError(str(e))\r
+\r
+class Sequence(Container):\r
+    """\r
+    This internal class implements a value which is a sequence of other values.\r
+    """\r
+    class SeqIter(object):\r
+        """\r
+        This internal class implements an iterator for a L{Sequence} instance.\r
+        """\r
+        def __init__(self, seq):\r
+            self.seq = seq\r
+            self.limit = len(object.__getattribute__(seq, 'data'))\r
+            self.index = 0\r
+\r
+        def __iter__(self):\r
+            return self\r
+\r
+        def next(self):\r
+            if self.index >= self.limit:\r
+                raise StopIteration\r
+            rv = self.seq[self.index]\r
+            self.index += 1\r
+            return rv\r
+\r
+    def __init__(self, parent=None):\r
+        """\r
+        Initialize an instance.\r
+\r
+        @param parent: The parent of this instance in the hierarchy.\r
+        @type parent: A L{Container} instance.\r
+        """\r
+        Container.__init__(self, parent)\r
+        object.__setattr__(self, 'data', [])\r
+        object.__setattr__(self, 'comments', [])\r
+\r
+    def append(self, item, comment):\r
+        """\r
+        Add an item to the sequence.\r
+\r
+        @param item: The item to add.\r
+        @type item: any\r
+        @param comment: A comment for the item.\r
+        @type comment: str\r
+        """\r
+        data = object.__getattribute__(self, 'data')\r
+        comments = object.__getattribute__(self, 'comments')\r
+        data.append(item)\r
+        comments.append(comment)\r
+\r
+    def __getitem__(self, index):\r
+        data = object.__getattribute__(self, 'data')\r
+        try:\r
+            rv = data[index]\r
+        except (IndexError, KeyError, TypeError):\r
+            raise ConfigResolutionError('%r is not a valid index for %r' % (index, object.__getattribute__(self, 'path')))\r
+        if not isinstance(rv, list):\r
+            rv = self.evaluate(rv)\r
+        else:\r
+            # deal with a slice\r
+            result = []\r
+            for a in rv:\r
+                result.append(self.evaluate(a))\r
+            rv = result\r
+        return rv\r
+\r
+    def __iter__(self):\r
+        return Sequence.SeqIter(self)\r
+\r
+    def __repr__(self):\r
+        return repr(object.__getattribute__(self, 'data'))\r
+\r
+    def __str__(self):\r
+        return str(self[:]) # using the slice evaluates the contents\r
+\r
+    def __len__(self):\r
+        return len(object.__getattribute__(self, 'data'))\r
+\r
+    def writeToStream(self, stream, indent, container):\r
+        """\r
+        Write this instance to a stream at the specified indentation level.\r
+\r
+        Should be redefined in subclasses.\r
+\r
+        @param stream: The stream to write to\r
+        @type stream: A writable stream (file-like object)\r
+        @param indent: The indentation level\r
+        @type indent: int\r
+        @param container: The container of this instance\r
+        @type container: L{Container}\r
+        """\r
+        indstr = indent * '  '\r
+        if len(self) == 0:\r
+            stream.write(' [ ]%s' % NEWLINE)\r
+        else:\r
+            if isinstance(container, Mapping):\r
+                stream.write(NEWLINE)\r
+            stream.write('%s[%s' % (indstr, NEWLINE))\r
+            self.save(stream, indent + 1)\r
+            stream.write('%s]%s' % (indstr, NEWLINE))\r
+\r
+    def save(self, stream, indent):\r
+        """\r
+        Save this instance to the specified stream.\r
+        @param stream: A stream to which the configuration is written.\r
+        @type stream: A write-only stream (file-like object).\r
+        @param indent: The indentation level for the output, > 0\r
+        @type indent: int\r
+        """\r
+        if indent == 0:\r
+            raise ConfigError("sequence cannot be saved as a top-level item")\r
+        data = object.__getattribute__(self, 'data')\r
+        comments = object.__getattribute__(self, 'comments')\r
+        indstr = indent * '  '\r
+        for i in xrange(0, len(data)):\r
+            value = data[i]\r
+            comment = comments[i]\r
+            if comment:\r
+                stream.write('%s#%s' % (indstr, comment))\r
+            if isinstance(value, Container):\r
+                value.writeToStream(stream, indent, self)\r
+            else:\r
+                self.writeValue(value, stream, indent)\r
+\r
+class Reference(object):\r
+    """\r
+    This internal class implements a value which is a reference to another value.\r
+    """\r
+    def __init__(self, config, type, ident):\r
+        """\r
+        Initialize an instance.\r
+\r
+        @param config: The configuration which contains this reference.\r
+        @type config: A L{Config} instance.\r
+        @param type: The type of reference.\r
+        @type type: BACKTICK or DOLLAR\r
+        @param ident: The identifier which starts the reference.\r
+        @type ident: str\r
+        """\r
+        self.config = config\r
+        self.type = type\r
+        self.elements = [ident]\r
+\r
+    def addElement(self, type, ident):\r
+        """\r
+        Add an element to the reference.\r
+\r
+        @param type: The type of reference.\r
+        @type type: BACKTICK or DOLLAR\r
+        @param ident: The identifier which continues the reference.\r
+        @type ident: str\r
+        """\r
+        self.elements.append((type, ident))\r
+\r
+    def findConfig(self, container):\r
+        """\r
+        Find the closest enclosing configuration to the specified container.\r
+\r
+        @param container: The container to start from.\r
+        @type container: L{Container}\r
+        @return: The closest enclosing configuration, or None.\r
+        @rtype: L{Config}\r
+        """\r
+        while (container is not None) and not isinstance(container, Config):\r
+            container = object.__getattribute__(container, 'parent')\r
+        return container\r
+\r
+    def resolve(self, container):\r
+        """\r
+        Resolve this instance in the context of a container.\r
+\r
+        @param container: The container to resolve from.\r
+        @type container: L{Container}\r
+        @return: The resolved value.\r
+        @rtype: any\r
+        @raise ConfigResolutionError: If resolution fails.\r
+        """\r
+        rv = None\r
+        path = object.__getattribute__(container, 'path')\r
+        current = self.findConfig(container)\r
+        while current is not None:\r
+            if self.type == BACKTICK:\r
+                namespaces = object.__getattribute__(current, 'namespaces')\r
+                found = False\r
+                s = str(self)[1:-1]\r
+                for ns in namespaces:\r
+                    try:\r
+                        try:\r
+                            rv = eval(s, vars(ns))\r
+                        except TypeError: #Python 2.7 - vars is a dictproxy\r
+                            rv = eval(s, {}, vars(ns))\r
+                        found = True\r
+                        break\r
+                    except:\r
+                        logger.debug("unable to resolve %r in %r", s, ns)\r
+                        pass\r
+                if found:\r
+                    break\r
+            else:\r
+                firstkey = self.elements[0]\r
+                if firstkey in current.resolving:\r
+                    current.resolving.remove(firstkey)\r
+                    raise ConfigResolutionError("Circular reference: %r" % firstkey)\r
+                current.resolving.add(firstkey)\r
+                key = firstkey\r
+                try:\r
+                    rv = current[key]\r
+                    for item in self.elements[1:]:\r
+                        key = item[1]\r
+                        rv = rv[key]\r
+                    current.resolving.remove(firstkey)\r
+                    break\r
+                except ConfigResolutionError:\r
+                    raise\r
+                except:\r
+                    logger.debug("Unable to resolve %r: %s", key, sys.exc_info()[1])\r
+                    rv = None\r
+                    pass\r
+                current.resolving.discard(firstkey)\r
+            current = self.findConfig(object.__getattribute__(current, 'parent'))\r
+        if current is None:\r
+            raise ConfigResolutionError("unable to evaluate %r in the configuration %s" % (self, path))\r
+        return rv\r
+\r
+    def __str__(self):\r
+        s = self.elements[0]\r
+        for tt, tv in self.elements[1:]:\r
+            if tt == DOT:\r
+                s += '.%s' % tv\r
+            else:\r
+                s += '[%r]' % tv\r
+        if self.type == BACKTICK:\r
+            return BACKTICK + s + BACKTICK\r
+        else:\r
+            return DOLLAR + s\r
+\r
+    def __repr__(self):\r
+        return self.__str__()\r
+\r
+class Expression(object):\r
+    """\r
+    This internal class implements a value which is obtained by evaluating an expression.\r
+    """\r
+    def __init__(self, op, lhs, rhs):\r
+        """\r
+        Initialize an instance.\r
+\r
+        @param op: the operation expressed in the expression.\r
+        @type op: PLUS, MINUS, STAR, SLASH, MOD\r
+        @param lhs: the left-hand-side operand of the expression.\r
+        @type lhs: any Expression or primary value.\r
+        @param rhs: the right-hand-side operand of the expression.\r
+        @type rhs: any Expression or primary value.\r
+        """\r
+        self.op = op\r
+        self.lhs = lhs\r
+        self.rhs = rhs\r
+\r
+    def __str__(self):\r
+        return '%r %s %r' % (self.lhs, self.op, self.rhs)\r
+\r
+    def __repr__(self):\r
+        return self.__str__()\r
+\r
+    def evaluate(self, container):\r
+        """\r
+        Evaluate this instance in the context of a container.\r
+\r
+        @param container: The container to evaluate in from.\r
+        @type container: L{Container}\r
+        @return: The evaluated value.\r
+        @rtype: any\r
+        @raise ConfigResolutionError: If evaluation fails.\r
+        @raise ZeroDivideError: If division by zero occurs.\r
+        @raise TypeError: If the operation is invalid, e.g.\r
+        subtracting one string from another.\r
+        """\r
+        lhs = self.lhs\r
+        if isinstance(lhs, Reference):\r
+            lhs = lhs.resolve(container)\r
+        elif isinstance(lhs, Expression):\r
+            lhs = lhs.evaluate(container)\r
+        rhs = self.rhs\r
+        if isinstance(rhs, Reference):\r
+            rhs = rhs.resolve(container)\r
+        elif isinstance(rhs, Expression):\r
+            rhs = rhs.evaluate(container)\r
+        op = self.op\r
+        if op == PLUS:\r
+            rv = lhs + rhs\r
+        elif op == MINUS:\r
+            rv = lhs - rhs\r
+        elif op == STAR:\r
+            rv = lhs * rhs\r
+        elif op == SLASH:\r
+            rv = lhs / rhs\r
+        else:\r
+            rv = lhs % rhs\r
+        return rv\r
+\r
+class ConfigReader(object):\r
+    """\r
+    This internal class implements a parser for configurations.\r
+    """\r
+\r
+    def __init__(self, config):\r
+        self.filename = None\r
+        self.config = config\r
+        self.lineno = 0\r
+        self.colno = 0\r
+        self.lastc = None\r
+        self.last_token = None\r
+        self.commentchars = '#'\r
+        self.whitespace = ' \t\r\n'\r
+        self.quotes = '\'"'\r
+        self.punct = ':-+*/%,.{}[]()@`$'\r
+        self.digits = '0123456789'\r
+        self.wordchars = '%s' % WORDCHARS # make a copy\r
+        self.identchars = self.wordchars + self.digits\r
+        self.pbchars = []\r
+        self.pbtokens = []\r
+        self.comment = None\r
+\r
+    def location(self):\r
+        """\r
+        Return the current location (filename, line, column) in the stream\r
+        as a string.\r
+\r
+        Used when printing error messages,\r
+\r
+        @return: A string representing a location in the stream being read.\r
+        @rtype: str\r
+        """\r
+        return "%s(%d,%d)" % (self.filename, self.lineno, self.colno)\r
+\r
+    def getChar(self):\r
+        """\r
+        Get the next char from the stream. Update line and column numbers\r
+        appropriately.\r
+\r
+        @return: The next character from the stream.\r
+        @rtype: str\r
+        """\r
+        if self.pbchars:\r
+            c = self.pbchars.pop()\r
+        else:\r
+            c = self.stream.read(1)\r
+            self.colno += 1\r
+            if c == '\n':\r
+                self.lineno += 1\r
+                self.colno = 1\r
+        return c\r
+\r
+    def __repr__(self):\r
+        return "<ConfigReader at 0x%08x>" % id(self)\r
+\r
+    __str__ = __repr__\r
+\r
+    def getToken(self):\r
+        """\r
+        Get a token from the stream. String values are returned in a form\r
+        where you need to eval() the returned value to get the actual\r
+        string. The return value is (token_type, token_value).\r
+\r
+        Multiline string tokenizing is thanks to David Janes (BlogMatrix)\r
+\r
+        @return: The next token.\r
+        @rtype: A token tuple.\r
+        """\r
+        if self.pbtokens:\r
+            return self.pbtokens.pop()\r
+        stream = self.stream\r
+        self.comment = None\r
+        token = ''\r
+        tt = EOF\r
+        while True:\r
+            c = self.getChar()\r
+            if not c:\r
+                break\r
+            elif c == '#':\r
+                self.comment = stream.readline()\r
+                self.lineno += 1\r
+                continue\r
+            if c in self.quotes:\r
+                token = c\r
+                quote = c\r
+                tt = STRING\r
+                escaped = False\r
+                multiline = False\r
+                c1 = self.getChar()\r
+                if c1 == quote:\r
+                    c2 = self.getChar()\r
+                    if c2 == quote:\r
+                        multiline = True\r
+                        token += quote\r
+                        token += quote\r
+                    else:\r
+                        self.pbchars.append(c2)\r
+                        self.pbchars.append(c1)\r
+                else:\r
+                    self.pbchars.append(c1)\r
+                while True:\r
+                    c = self.getChar()\r
+                    if not c:\r
+                        break\r
+                    token += c\r
+                    if (c == quote) and not escaped:\r
+                        if not multiline or (len(token) >= 6 and token.endswith(token[:3]) and token[-4] != '\\'):\r
+                            break\r
+                    if c == '\\':\r
+                        escaped = not escaped\r
+                    else:\r
+                        escaped = False\r
+                if not c:\r
+                    raise ConfigFormatError('%s: Unterminated quoted string: %r, %r' % (self.location(), token, c))\r
+                break\r
+            if c in self.whitespace:\r
+                self.lastc = c\r
+                continue\r
+            elif c in self.punct:\r
+                token = c\r
+                tt = c\r
+                if (self.lastc == ']') or (self.lastc in self.identchars):\r
+                    if c == '[':\r
+                        tt = LBRACK2\r
+                    elif c == '(':\r
+                        tt = LPAREN2\r
+                break\r
+            elif c in self.digits:\r
+                token = c\r
+                tt = NUMBER\r
+                in_exponent=False\r
+                while True:\r
+                    c = self.getChar()\r
+                    if not c:\r
+                        break\r
+                    if c in self.digits:\r
+                        token += c\r
+                    elif (c == '.') and token.find('.') < 0 and not in_exponent:\r
+                        token += c\r
+                    elif (c == '-') and token.find('-') < 0 and in_exponent:\r
+                        token += c\r
+                    elif (c in 'eE') and token.find('e') < 0 and\\r
+                         token.find('E') < 0:\r
+                        token += c\r
+                        in_exponent = True\r
+                    else:\r
+                        if c and (c not in self.whitespace):\r
+                            self.pbchars.append(c)\r
+                        break\r
+                break\r
+            elif c in self.wordchars:\r
+                token = c\r
+                tt = WORD\r
+                c = self.getChar()\r
+                while c and (c in self.identchars):\r
+                    token += c\r
+                    c = self.getChar()\r
+                if c: # and c not in self.whitespace:\r
+                    self.pbchars.append(c)\r
+                if token == "True":\r
+                    tt = TRUE\r
+                elif token == "False":\r
+                    tt = FALSE\r
+                elif token == "None":\r
+                    tt = NONE\r
+                break\r
+            else:\r
+                raise ConfigFormatError('%s: Unexpected character: %r' % (self.location(), c))\r
+        if token:\r
+            self.lastc = token[-1]\r
+        else:\r
+            self.lastc = None\r
+        self.last_token = tt\r
+        return (tt, token)\r
+\r
+    def load(self, stream, parent=None, suffix=None):\r
+        """\r
+        Load the configuration from the specified stream.\r
+\r
+        @param stream: A stream from which to load the configuration.\r
+        @type stream: A stream (file-like object).\r
+        @param parent: The parent of the configuration (to which this reader\r
+        belongs) in the hierarchy. Specified when the configuration is\r
+        included in another one.\r
+        @type parent: A L{Container} instance.\r
+        @param suffix: The suffix of this configuration in the parent\r
+        configuration. Should be specified whenever the parent is not None.\r
+        @raise ConfigError: If parent is specified but suffix is not.\r
+        @raise ConfigFormatError: If there are syntax errors in the stream.\r
+        """\r
+        if parent is not None:\r
+            if suffix is None:\r
+                raise ConfigError("internal error: load called with parent but no suffix")\r
+            self.config.setPath(makePath(object.__getattribute__(parent, 'path'), suffix))\r
+        self.setStream(stream)\r
+        self.token = self.getToken()\r
+        self.parseMappingBody(self.config)\r
+        if self.token[0] != EOF:\r
+            raise ConfigFormatError('%s: expecting EOF, found %r' % (self.location(), self.token[1]))\r
+\r
+    def setStream(self, stream):\r
+        """\r
+        Set the stream to the specified value, and prepare to read from it.\r
+\r
+        @param stream: A stream from which to load the configuration.\r
+        @type stream: A stream (file-like object).\r
+        """\r
+        self.stream = stream\r
+        if hasattr(stream, 'name'):\r
+            filename = stream.name\r
+        else:\r
+            filename = '?'\r
+        self.filename = filename\r
+        self.lineno = 1\r
+        self.colno = 1\r
+\r
+    def match(self, t):\r
+        """\r
+        Ensure that the current token type matches the specified value, and\r
+        advance to the next token.\r
+\r
+        @param t: The token type to match.\r
+        @type t: A valid token type.\r
+        @return: The token which was last read from the stream before this\r
+        function is called.\r
+        @rtype: a token tuple - see L{getToken}.\r
+        @raise ConfigFormatError: If the token does not match what's expected.\r
+        """\r
+        if self.token[0] != t:\r
+            raise ConfigFormatError("%s: expecting %s, found %r" % (self.location(), t, self.token[1]))\r
+        rv = self.token\r
+        self.token = self.getToken()\r
+        return rv\r
+\r
+    def parseMappingBody(self, parent):\r
+        """\r
+        Parse the internals of a mapping, and add entries to the provided\r
+        L{Mapping}.\r
+\r
+        @param parent: The mapping to add entries to.\r
+        @type parent: A L{Mapping} instance.\r
+        """\r
+        while self.token[0] in [WORD, STRING]:\r
+            self.parseKeyValuePair(parent)\r
+\r
+    def parseKeyValuePair(self, parent):\r
+        """\r
+        Parse a key-value pair, and add it to the provided L{Mapping}.\r
+\r
+        @param parent: The mapping to add entries to.\r
+        @type parent: A L{Mapping} instance.\r
+        @raise ConfigFormatError: if a syntax error is found.\r
+        """\r
+        comment = self.comment\r
+        tt, tv = self.token\r
+        if tt == WORD:\r
+            key = tv\r
+            suffix = tv\r
+        elif tt == STRING:\r
+            key = eval(tv)\r
+            suffix = '[%s]' % tv\r
+        else:\r
+            msg = "%s: expecting word or string, found %r"\r
+            raise ConfigFormatError(msg % (self.location(), tv))\r
+        self.token = self.getToken()\r
+        # for now, we allow key on its own as a short form of key : True\r
+        if self.token[0] == COLON:\r
+            self.token = self.getToken()\r
+            value = self.parseValue(parent, suffix)\r
+        else:\r
+            value = True\r
+        try:\r
+            parent.addMapping(key, value, comment)\r
+        except Exception, e:\r
+            raise ConfigFormatError("%s: %s, %r" % (self.location(), e,\r
+                                    self.token[1]))\r
+        tt = self.token[0]\r
+        if tt not in [EOF, WORD, STRING, RCURLY, COMMA]:\r
+            msg = "%s: expecting one of EOF, WORD, STRING,\\r
+RCURLY, COMMA, found %r"\r
+            raise ConfigFormatError(msg  % (self.location(), self.token[1]))\r
+        if tt == COMMA:\r
+            self.token = self.getToken()\r
+\r
+    def parseValue(self, parent, suffix):\r
+        """\r
+        Parse a value.\r
+\r
+        @param parent: The container to which the value will be added.\r
+        @type parent: A L{Container} instance.\r
+        @param suffix: The suffix for the value.\r
+        @type suffix: str\r
+        @return: The value\r
+        @rtype: any\r
+        @raise ConfigFormatError: if a syntax error is found.\r
+        """\r
+        tt = self.token[0]\r
+        if tt in [STRING, WORD, NUMBER, LPAREN, DOLLAR,\r
+                  TRUE, FALSE, NONE, BACKTICK, MINUS]:\r
+            rv = self.parseScalar()\r
+        elif tt == LBRACK:\r
+            rv = self.parseSequence(parent, suffix)\r
+        elif tt in [LCURLY, AT]:\r
+            rv = self.parseMapping(parent, suffix)\r
+        else:\r
+            raise ConfigFormatError("%s: unexpected input: %r" %\r
+               (self.location(), self.token[1]))\r
+        return rv\r
+\r
+    def parseSequence(self, parent, suffix):\r
+        """\r
+        Parse a sequence.\r
+\r
+        @param parent: The container to which the sequence will be added.\r
+        @type parent: A L{Container} instance.\r
+        @param suffix: The suffix for the value.\r
+        @type suffix: str\r
+        @return: a L{Sequence} instance representing the sequence.\r
+        @rtype: L{Sequence}\r
+        @raise ConfigFormatError: if a syntax error is found.\r
+        """\r
+        rv = Sequence(parent)\r
+        rv.setPath(makePath(object.__getattribute__(parent, 'path'), suffix))\r
+        self.match(LBRACK)\r
+        comment = self.comment\r
+        tt = self.token[0]\r
+        while tt in [STRING, WORD, NUMBER, LCURLY, LBRACK, LPAREN, DOLLAR,\r
+                     TRUE, FALSE, NONE, BACKTICK, MINUS]:\r
+            suffix = '[%d]' % len(rv)\r
+            value = self.parseValue(parent, suffix)\r
+            rv.append(value, comment)\r
+            tt = self.token[0]\r
+            comment = self.comment\r
+            if tt == COMMA:\r
+                self.match(COMMA)\r
+                tt = self.token[0]\r
+                comment = self.comment\r
+                continue\r
+        self.match(RBRACK)\r
+        return rv\r
+\r
+    def parseMapping(self, parent, suffix):\r
+        """\r
+        Parse a mapping.\r
+\r
+        @param parent: The container to which the mapping will be added.\r
+        @type parent: A L{Container} instance.\r
+        @param suffix: The suffix for the value.\r
+        @type suffix: str\r
+        @return: a L{Mapping} instance representing the mapping.\r
+        @rtype: L{Mapping}\r
+        @raise ConfigFormatError: if a syntax error is found.\r
+        """\r
+        if self.token[0] == LCURLY:\r
+            self.match(LCURLY)\r
+            rv = Mapping(parent)\r
+            rv.setPath(\r
+               makePath(object.__getattribute__(parent, 'path'), suffix))\r
+            self.parseMappingBody(rv)\r
+            self.match(RCURLY)\r
+        else:\r
+            self.match(AT)\r
+            tt, fn = self.match(STRING)\r
+            rv = Config(eval(fn), parent)\r
+        return rv\r
+\r
+    def parseScalar(self):\r
+        """\r
+        Parse a scalar - a terminal value such as a string or number, or\r
+        an L{Expression} or L{Reference}.\r
+\r
+        @return: the parsed scalar\r
+        @rtype: any scalar\r
+        @raise ConfigFormatError: if a syntax error is found.\r
+        """\r
+        lhs = self.parseTerm()\r
+        tt = self.token[0]\r
+        while tt in [PLUS, MINUS]:\r
+            self.match(tt)\r
+            rhs = self.parseTerm()\r
+            lhs = Expression(tt, lhs, rhs)\r
+            tt = self.token[0]\r
+        return lhs\r
+\r
+    def parseTerm(self):\r
+        """\r
+        Parse a term in an additive expression (a + b, a - b)\r
+\r
+        @return: the parsed term\r
+        @rtype: any scalar\r
+        @raise ConfigFormatError: if a syntax error is found.\r
+        """\r
+        lhs = self.parseFactor()\r
+        tt = self.token[0]\r
+        while tt in [STAR, SLASH, MOD]:\r
+            self.match(tt)\r
+            rhs = self.parseFactor()\r
+            lhs = Expression(tt, lhs, rhs)\r
+            tt = self.token[0]\r
+        return lhs\r
+\r
+    def parseFactor(self):\r
+        """\r
+        Parse a factor in an multiplicative expression (a * b, a / b, a % b)\r
+\r
+        @return: the parsed factor\r
+        @rtype: any scalar\r
+        @raise ConfigFormatError: if a syntax error is found.\r
+        """\r
+        tt = self.token[0]\r
+        if tt in [NUMBER, WORD, STRING, TRUE, FALSE, NONE]:\r
+            rv = self.token[1]\r
+            if tt != WORD:\r
+                rv = eval(rv)\r
+            self.match(tt)\r
+        elif tt == LPAREN:\r
+            self.match(LPAREN)\r
+            rv = self.parseScalar()\r
+            self.match(RPAREN)\r
+        elif tt == DOLLAR:\r
+            self.match(DOLLAR)\r
+            rv = self.parseReference(DOLLAR)\r
+        elif tt == BACKTICK:\r
+            self.match(BACKTICK)\r
+            rv = self.parseReference(BACKTICK)\r
+            self.match(BACKTICK)\r
+        elif tt == MINUS:\r
+            self.match(MINUS)\r
+            rv = -self.parseScalar()\r
+        else:\r
+            raise ConfigFormatError("%s: unexpected input: %r" %\r
+               (self.location(), self.token[1]))\r
+        return rv\r
+\r
+    def parseReference(self, type):\r
+        """\r
+        Parse a reference.\r
+\r
+        @return: the parsed reference\r
+        @rtype: L{Reference}\r
+        @raise ConfigFormatError: if a syntax error is found.\r
+        """\r
+        word = self.match(WORD)\r
+        rv = Reference(self.config, type, word[1])\r
+        while self.token[0] in [DOT, LBRACK2]:\r
+            self.parseSuffix(rv)\r
+        return rv\r
+\r
+    def parseSuffix(self, ref):\r
+        """\r
+        Parse a reference suffix.\r
+\r
+        @param ref: The reference of which this suffix is a part.\r
+        @type ref: L{Reference}.\r
+        @raise ConfigFormatError: if a syntax error is found.\r
+        """\r
+        tt = self.token[0]\r
+        if tt == DOT:\r
+            self.match(DOT)\r
+            word = self.match(WORD)\r
+            ref.addElement(DOT, word[1])\r
+        else:\r
+            self.match(LBRACK2)\r
+            tt, tv = self.token\r
+            if tt not in [NUMBER, STRING]:\r
+                raise ConfigFormatError("%s: expected number or string, found %r" % (self.location(), tv))\r
+            self.token = self.getToken()\r
+            tv = eval(tv)\r
+            self.match(RBRACK)\r
+            ref.addElement(LBRACK, tv)\r
+\r
+def defaultMergeResolve(map1, map2, key):\r
+    """\r
+    A default resolver for merge conflicts. Returns a string\r
+    indicating what action to take to resolve the conflict.\r
+\r
+    @param map1: The map being merged into.\r
+    @type map1: L{Mapping}.\r
+    @param map2: The map being used as the merge operand.\r
+    @type map2: L{Mapping}.\r
+    @param key: The key in map2 (which also exists in map1).\r
+    @type key: str\r
+    @return: One of "merge", "append", "mismatch" or "overwrite"\r
+             indicating what action should be taken. This should\r
+             be appropriate to the objects being merged - e.g.\r
+             there is no point returning "merge" if the two objects\r
+             are instances of L{Sequence}.\r
+    @rtype: str\r
+    """\r
+    obj1 = map1[key]\r
+    obj2 = map2[key]\r
+    if isinstance(obj1, Mapping) and isinstance(obj2, Mapping):\r
+        rv = "merge"\r
+    elif isinstance(obj1, Sequence) and isinstance(obj2, Sequence):\r
+        rv = "append"\r
+    else:\r
+        rv = "mismatch"\r
+    return rv\r
+\r
+def overwriteMergeResolve(map1, map2, key):\r
+    """\r
+    An overwriting resolver for merge conflicts. Calls L{defaultMergeResolve},\r
+    but where a "mismatch" is detected, returns "overwrite" instead.\r
+\r
+    @param map1: The map being merged into.\r
+    @type map1: L{Mapping}.\r
+    @param map2: The map being used as the merge operand.\r
+    @type map2: L{Mapping}.\r
+    @param key: The key in map2 (which also exists in map1).\r
+    @type key: str\r
+    """\r
+    rv = defaultMergeResolve(map1, map2, key)\r
+    if rv == "mismatch":\r
+        rv = "overwrite"\r
+    return rv\r
+\r
+class ConfigMerger(object):\r
+    """\r
+    This class is used for merging two configurations. If a key exists in the\r
+    merge operand but not the merge target, then the entry is copied from the\r
+    merge operand to the merge target. If a key exists in both configurations,\r
+    then a resolver (a callable) is called to decide how to handle the\r
+    conflict.\r
+    """\r
+\r
+    def __init__(self, resolver=defaultMergeResolve):\r
+        """\r
+        Initialise an instance.\r
+\r
+        @param resolver:\r
+        @type resolver: A callable which takes the argument list\r
+        (map1, map2, key) where map1 is the mapping being merged into,\r
+        map2 is the merge operand and key is the clashing key. The callable\r
+        should return a string indicating how the conflict should be resolved.\r
+        For possible return values, see L{defaultMergeResolve}. The default\r
+        value preserves the old behaviour\r
+        """\r
+        self.resolver = resolver\r
+\r
+    def merge(self, merged, mergee):\r
+        """\r
+        Merge two configurations. The second configuration is unchanged,\r
+        and the first is changed to reflect the results of the merge.\r
+\r
+        @param merged: The configuration to merge into.\r
+        @type merged: L{Config}.\r
+        @param mergee: The configuration to merge.\r
+        @type mergee: L{Config}.\r
+        """\r
+        self.mergeMapping(merged, mergee)\r
+\r
+    def mergeMapping(self, map1, map2):\r
+        """\r
+        Merge two mappings recursively. The second mapping is unchanged,\r
+        and the first is changed to reflect the results of the merge.\r
+\r
+        @param map1: The mapping to merge into.\r
+        @type map1: L{Mapping}.\r
+        @param map2: The mapping to merge.\r
+        @type map2: L{Mapping}.\r
+        """\r
+        keys = map1.keys()\r
+        for key in map2.keys():\r
+            if key not in keys:\r
+                map1[key] = map2[key]\r
+            else:\r
+                obj1 = map1[key]\r
+                obj2 = map2[key]\r
+                decision = self.resolver(map1, map2, key)\r
+                if decision == "merge":\r
+                    self.mergeMapping(obj1, obj2)\r
+                elif decision == "append":\r
+                    self.mergeSequence(obj1, obj2)\r
+                elif decision == "overwrite":\r
+                    map1[key] = obj2\r
+                elif decision == "mismatch":\r
+                    self.handleMismatch(obj1, obj2)\r
+                else:\r
+                    msg = "unable to merge: don't know how to implement %r"\r
+                    raise ValueError(msg % decision)\r
+\r
+    def mergeSequence(self, seq1, seq2):\r
+        """\r
+        Merge two sequences. The second sequence is unchanged,\r
+        and the first is changed to have the elements of the second\r
+        appended to it.\r
+\r
+        @param seq1: The sequence to merge into.\r
+        @type seq1: L{Sequence}.\r
+        @param seq2: The sequence to merge.\r
+        @type seq2: L{Sequence}.\r
+        """\r
+        data1 = object.__getattribute__(seq1, 'data')\r
+        data2 = object.__getattribute__(seq2, 'data')\r
+        for obj in data2:\r
+            data1.append(obj)\r
+        comment1 = object.__getattribute__(seq1, 'comments')\r
+        comment2 = object.__getattribute__(seq2, 'comments')\r
+        for obj in comment2:\r
+            comment1.append(obj)\r
+\r
+    def handleMismatch(self, obj1, obj2):\r
+        """\r
+        Handle a mismatch between two objects.\r
+\r
+        @param obj1: The object to merge into.\r
+        @type obj1: any\r
+        @param obj2: The object to merge.\r
+        @type obj2: any\r
+        """\r
+        raise ConfigError("unable to merge %r with %r" % (obj1, obj2))\r
+\r
+class ConfigList(list):\r
+    """\r
+    This class implements an ordered list of configurations and allows you\r
+    to try getting the configuration from each entry in turn, returning\r
+    the first successfully obtained value.\r
+    """\r
+\r
+    def getByPath(self, path):\r
+        """\r
+        Obtain a value from the first configuration in the list which defines\r
+        it.\r
+\r
+        @param path: The path of the value to retrieve.\r
+        @type path: str\r
+        @return: The value from the earliest configuration in the list which\r
+        defines it.\r
+        @rtype: any\r
+        @raise ConfigError: If no configuration in the list has an entry with\r
+        the specified path.\r
+        """\r
+        found = False\r
+        rv = None\r
+        for entry in self:\r
+            try:\r
+                rv = entry.getByPath(path)\r
+                found = True\r
+                break\r
+            except ConfigError:\r
+                pass\r
+        if not found:\r
+            raise ConfigError("unable to resolve %r" % path)\r
+        return rv\r
diff --git a/test/config_0_3_9/logconfig.cfg b/test/config_0_3_9/logconfig.cfg
new file mode 100644 (file)
index 0000000..2845e3c
--- /dev/null
@@ -0,0 +1,65 @@
+# Configuration file for logconfig.py\r
+\r
+# root logger configuration\r
+root:\r
+{\r
+  level     : `DEBUG`\r
+  handlers  : [$handlers.console, $handlers.file]\r
+}\r
+formatters: {\r
+  brief:\r
+  {\r
+    format: '%(levelname)-8s: %(name)s: %(message)s'\r
+  }\r
+  precise:\r
+  {\r
+    format: '%(asctime)s %(name)-15s %(levelname)-8s %(message)s'\r
+  }\r
+}\r
+handlers:\r
+{\r
+  console:\r
+  {\r
+    class : `logconfig.StreamHandler`\r
+    config:\r
+    {\r
+      level   : `INFO`\r
+      stream  : `sys.stdout`\r
+      formatter: $formatters.brief\r
+    }\r
+  }\r
+  file:\r
+  {\r
+    class : `logconfig.RotatingFileHandler`\r
+    config:\r
+    {\r
+      name: 'logconfig.log'\r
+      maxBytes: 1024\r
+      backupCount: 3\r
+      formatter: $formatters.precise\r
+    }\r
+  }\r
+  debugfile:\r
+  {\r
+    class : `logconfig.FileHandler`\r
+    config:\r
+    {\r
+      name: 'logconfig-detail.log'\r
+      mode: 'a'\r
+      formatter: $formatters.precise\r
+    }\r
+  }\r
+}\r
+loggers:\r
+{\r
+  area1:\r
+  {\r
+    level : `ERROR`\r
+    handlers: [$handlers.debugfile]\r
+  }\r
+  area2:\r
+  {\r
+    level : `CRITICAL`\r
+    handlers: [$handlers.debugfile]\r
+  }\r
+}
\ No newline at end of file
diff --git a/test/config_0_3_9/logconfig.py b/test/config_0_3_9/logconfig.py
new file mode 100644 (file)
index 0000000..44ae1ed
--- /dev/null
@@ -0,0 +1,138 @@
+#!/usr/bin/env python\r
+#\r
+# Copyright 2001-2004 by Vinay Sajip. All Rights Reserved.\r
+#\r
+# Permission to use, copy, modify, and distribute this software and its\r
+# documentation for any purpose and without fee is hereby granted,\r
+# provided that the above copyright notice appear in all copies and that\r
+# both that copyright notice and this permission notice appear in\r
+# supporting documentation, and that the name of Vinay Sajip\r
+# not be used in advertising or publicity pertaining to distribution\r
+# of the software without specific, written prior permission.\r
+# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING\r
+# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL\r
+# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR\r
+# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER\r
+# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT\r
+# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\r
+#\r
+# This file is part of the Python config distribution. See\r
+# http://www.red-dove.com/python_config.html\r
+#\r
+"""\r
+A test for the config module through seeing how to use it to configure logging.\r
+\r
+Copyright (C) 2004 Vinay Sajip. All Rights Reserved.\r
+"""\r
+\r
+from config import Config\r
+from optparse import OptionParser, get_prog_name\r
+from random import choice\r
+import logging\r
+import logging.handlers\r
+import sys\r
+\r
+class Usage(Exception):\r
+    pass\r
+\r
+class BaseHandler:\r
+    def __init__(self, config):\r
+        if 'level' in config:\r
+            self.setLevel(config.level)\r
+        if 'formatter' in config:\r
+            self.setFormatter(config.formatter)\r
+\r
+class StreamHandler(logging.StreamHandler, BaseHandler):\r
+    def __init__(self, config):\r
+        stream = config.get('stream')\r
+        logging.StreamHandler.__init__(self, stream)\r
+        BaseHandler.__init__(self, config)\r
+\r
+class RotatingFileHandler(logging.handlers.RotatingFileHandler, BaseHandler):\r
+    def __init__(self, config):\r
+        name = config.get('name')\r
+        if name is None:\r
+            raise ValueError('RotatingFileHandler: name not specified')\r
+        mode = config.get('mode', 'a')\r
+        maxBytes = config.get('maxBytes', 0)\r
+        backupCount = config.get('backupCount', 0)\r
+        logging.handlers.RotatingFileHandler.__init__(self, name, mode, maxBytes, backupCount)\r
+        BaseHandler.__init__(self, config)\r
+\r
+class FileHandler(logging.FileHandler, BaseHandler):\r
+    def __init__(self, config):\r
+        name = config.get('name')\r
+        if name is None:\r
+            raise ValueError('FileHandler: name not specified')\r
+        mode = config.get('mode', 'a')\r
+        logging.FileHandler.__init__(self, name, mode)\r
+        BaseHandler.__init__(self, config)\r
+\r
+def configLogger(logger, config):\r
+    for handler in logger.handlers:\r
+        logger.removeHandler(handler)\r
+    if 'level' in config:\r
+        logger.setLevel(config.level)\r
+    if 'handlers' in config:\r
+        for handler in config.handlers:\r
+            logger.addHandler(handler)\r
+\r
+def fileConfig(fname, *args, **kwargs):\r
+    cfg = Config(fname)\r
+    cfg.addNamespace(logging)\r
+    cfg.addNamespace(sys.modules[StreamHandler.__module__], 'logconfig')\r
+\r
+    for name in cfg.formatters.keys():\r
+        formatterConfig = cfg.formatters[name]\r
+        fmt = formatterConfig.get('format')\r
+        datefmt = formatterConfig.get('datefmt')\r
+        formatter = logging.Formatter(fmt, datefmt)\r
+        cfg.formatters[name] = formatter\r
+\r
+    for name in cfg.handlers.keys():\r
+        klass = cfg.handlers[name].get('class')\r
+        config = cfg.handlers[name].get('config')\r
+        cfg.handlers[name] = klass(config)\r
+\r
+    for name in cfg.loggers.keys():\r
+        loggerConfig = cfg.loggers[name]\r
+        logger = logging.getLogger(name)\r
+        configLogger(logger, loggerConfig)\r
+\r
+    if 'root' in cfg:\r
+        configLogger(logging.getLogger(''), cfg.root)\r
+\r
+def testConfig():\r
+    levels = [logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL]\r
+    loggers = ['', 'area1', 'area2']\r
+    for i in xrange(1000):\r
+        logger = logging.getLogger(choice(loggers))\r
+        level = choice(levels)\r
+        logger.log(level, "Message number %d", i)\r
+\r
+def main(args=None):\r
+    rv = 0\r
+    if args is None:\r
+        args = sys.argv[1:]\r
+    parser = OptionParser(usage="usage: %prog [options] CONFIG-FILE")\r
+\r
+    (options, args) = parser.parse_args(args)\r
+    try:\r
+        if len(args) == 0:\r
+            raise Usage("No configuration file specified")\r
+        fileConfig(args[0])\r
+        testConfig()\r
+    except Usage, e:\r
+        parser.print_help()\r
+        print "\n%s: error: %s" % (get_prog_name(), e)\r
+        rv = 1\r
+    except Exception, e:\r
+        print "\n%s: error: %s" % (get_prog_name(), e)\r
+        typ, val, tb = sys.exc_info()\r
+        import traceback\r
+        traceback.print_tb(tb)\r
+        rv = 2\r
+    return rv\r
+\r
+if __name__ == "__main__":\r
+    sys.exit(main())\r
diff --git a/test/config_0_3_9/setup.py b/test/config_0_3_9/setup.py
new file mode 100644 (file)
index 0000000..9c7dfab
--- /dev/null
@@ -0,0 +1,20 @@
+from distutils.core import setup
+
+setup(name = "config",
+   description="A hierarchical, easy-to-use, powerful configuration module for Python",
+   long_description = """This module allows a hierarchical configuration scheme with support for mappings
+and sequences, cross-references between one part of the configuration and
+another, the ability to flexibly access real Python objects without full-blown
+eval(), an include facility, simple expression evaluation and the ability to
+change, save, cascade and merge configurations. Interfaces easily with
+environment variables and command-line options. It has been developed on python
+2.3 but should work on version 2.2 or greater.""",
+   license="""Copyright (C) 2004-2010 by Vinay Sajip. All Rights Reserved. See LICENSE for license.""",
+            version = "0.3.9",
+            author = "Vinay Sajip",
+            author_email = "vinay_sajip@red-dove.com",
+            maintainer = "Vinay Sajip",
+            maintainer_email = "vinay_sajip@red-dove.com",
+            url = "http://www.red-dove.com/python_config.html",
+            py_modules = ["config"],
+            )
diff --git a/test/config_0_3_9/styles.json b/test/config_0_3_9/styles.json
new file mode 100644 (file)
index 0000000..259697e
--- /dev/null
@@ -0,0 +1,554 @@
+{
+  "embeddedFonts" : [ ],
+  "pageSetup" : {
+    "size": "A4",
+    "width": null,
+    "height": null,
+    "margin-top": "2cm",
+    "margin-bottom": "2cm",
+    "margin-left": "2cm",
+    "margin-right": "2cm",
+    "margin-gutter": "0cm",
+    "spacing-header": "5mm",
+    "spacing-footer": "5mm",
+    "firstTemplate": "oneColumn"
+  },
+  "pageTemplates" : {
+    "coverPage": {
+        "frames": [
+            ["0cm", "0cm", "100%", "100%"]
+        ],
+        "showHeader" : false,
+        "showFooter" : false
+    },
+    "oneColumn": {
+        "frames": [
+            ["0cm", "0cm", "100%", "100%"]
+        ],
+        "showHeader" : true,
+        "showFooter" : true
+    },
+    "twoColumn": {
+        "frames": [
+            ["0cm", "0cm", "49%", "100%"],
+            ["51%", "0cm", "49%", "100%"]
+        ],
+        "showHeader" : true,
+        "showFooter" : true
+    },
+    "threeColumn": {
+        "frames": [
+            ["2%", "0cm", "29.333%", "100%"],
+            ["35.333%", "0cm", "29.333%", "100%"],
+            ["68.666%", "0cm", "29.333%", "100%"]
+        ],
+        "showHeader" : true,
+        "showFooter" : true
+    },
+    "cutePage": {
+        "frames": [
+            ["0%", "0%", "100%", "100%"]
+        ],
+        "showHeader" : true,
+        "showFooter" : true,
+        "defaultFooter" : "###Page###",
+        "defaultHeader" : "###Section###"
+    }
+  },
+  "fontsAlias" : {
+    "stdFont": "Helvetica",     
+    "stdBold": "Helvetica-Bold",
+    "stdItalic": "Helvetica-Oblique",
+    "stdBoldItalic": "Helvetica-BoldOblique",
+    "stdSans": "Helvetica",
+    "stdSansBold": "Helvetica-Bold",
+    "stdSansItalic": "Helvetica-Oblique",
+    "stdSansBoldItalic": "Helvetica-BoldOblique",
+    "stdMono": "Courier",
+    "stdMonoItalic": "Courier-Oblique",
+    "stdMonoBold": "Courier-Bold",
+    "stdMonoBoldItalic": "Courier-BoldOblique",
+    "stdSerif": "Times-Roman"
+  },
+  "linkColor" : "navy",
+  "styles" : [
+    [ "base" , {
+      "parent": null,
+      "fontName": "stdFont",
+      "fontSize":10,
+      "leading":12,
+      "leftIndent":0,
+      "rightIndent":0,
+      "firstLineIndent":0,
+      "alignment":"TA_LEFT",
+      "spaceBefore":0,
+      "spaceAfter":0,
+      "bulletFontName":"stdFont",
+      "bulletFontSize":10,
+      "bulletIndent":0,
+      "textColor": "black",
+      "backColor": null,
+      "wordWrap": null,
+      "borderWidth": 0,
+      "borderPadding": 0,
+      "borderColor": null,
+      "borderRadius": null,
+      "allowWidows": false,
+      "allowOrphans": false,
+      "hyphenation": false,
+      "kerning": false
+    }] ,
+    ["normal" , {
+      "parent": "base"
+    }],
+    ["title_reference" , {
+      "parent": "normal",
+      "fontName": "stdItalic"
+    }],
+    ["bodytext" , {
+      "parent": "normal",
+      "spaceBefore": 6,
+      "alignment": "TA_JUSTIFY",
+      "hyphenation": true
+    }],
+    ["toc" , {
+      "parent": "normal"
+    }],
+    ["blockquote" , {
+      "parent": "bodytext",
+      "leftIndent": 20
+    }],
+    ["lineblock" , {
+      "parent": "bodytext"
+    }],
+    ["line" , {
+      "parent": "lineblock",
+      "spaceBefore": 0
+    }],
+    ["toc1" , {
+      "parent": "toc",
+      "fontName": "stdBold"
+    }],
+    ["toc2" , {
+      "parent": "toc",
+      "leftIndent": 20
+    }],
+    ["toc3" , {
+      "parent": "toc",
+      "leftIndent": 40
+    }],
+    ["toc4" , {
+      "parent": "toc",
+      "leftIndent": 60
+    }],
+    ["toc5" , {
+      "parent": "toc",
+      "leftIndent": 80
+    }],
+    ["toc6" , {
+      "parent": "toc",
+      "leftIndent": 100
+    }],
+    ["toc7" , {
+      "parent": "toc",
+      "leftIndent": 100
+    }],
+    ["toc8" , {
+      "parent": "toc",
+      "leftIndent": 100
+    }],
+    ["toc9" , {
+      "parent": "toc",
+      "leftIndent": 100
+    }],
+    ["toc10" , {
+      "parent": "toc",
+      "leftIndent": 100
+    }],
+    ["toc11" , {
+      "parent": "toc",
+      "leftIndent": 100
+    }],
+    ["toc12" , {
+      "parent": "toc",
+      "leftIndent": 100
+    }],
+    ["toc13" , {
+      "parent": "toc",
+      "leftIndent": 100
+    }],
+    ["toc14" , {
+      "parent": "toc",
+      "leftIndent": 100
+    }],
+    ["toc15" , {
+      "parent": "toc",
+      "leftIndent": 100
+    }],
+    ["footer" , {
+      "parent": "normal",
+      "alignment": "TA_CENTER"
+    }],
+    ["header" , {
+      "parent": "normal",
+      "alignment": "TA_CENTER"
+    }],
+    ["attribution" , {
+      "parent": "bodytext",
+      "alignment": "TA_RIGHT"
+    }],
+    ["figure" , {
+      "parent": "bodytext",
+      "alignment": "TA_CENTER"
+    }],
+    ["figure-caption" , {
+      "parent": "bodytext",
+      "fontName": "stdItalic",
+      "alignment": "TA_CENTER"
+    }],
+    ["figure-legend" , {
+      "parent": "bodytext",
+      "alignment": "TA_CENTER"
+    }],
+    ["bullet_list", {
+      "parent": "bodytext",
+      "commands": [
+            [ "VALIGN", [ 0, 0 ], [ -1, -1 ], "TOP" ],
+            [ "RIGHTPADDING", [ 0, 0 ], [ 1, -1 ], 0 ] 
+        ], 
+        "colWidths": ["20",null]
+    }],
+    ["bullet_list_item" , {
+      "parent": "bodytext"
+    }],
+    ["item_list", { 
+      "parent": "bodytext",
+      "commands": [
+            [ "VALIGN", [ 0, 0 ], [ -1, -1 ], "TOP" ], 
+            [ "RIGHTPADDING", [ 0, 0 ], [ 1, -1 ], 0 ] 
+        ],
+        "colWidths": ["20pt",null]
+    }],
+    ["item_list_item" , {
+      "parent": "bodytext"
+    }],
+    ["definition_list_term" , {
+      "parent": "normal",
+      "fontName": "stdBold",
+      "spaceBefore": 4,
+      "spaceAfter": 0,
+      "keepWithNext": true
+    }],
+    ["definition_list_classifier" , {
+      "parent": "normal",
+      "fontName": "stdItalic"
+    }],
+    ["definition" , {
+      "parent": "bodytext",
+      "firstLineIndent": 0,
+      "bulletIndent": 0,
+      "spaceBefore": 0
+    }],
+    ["fieldname" , {
+      "parent": "bodytext",
+      "alignment": "TA_RIGHT",
+      "fontName": "stdBold"
+    }],
+    ["fieldvalue" , {
+      "parent": "bodytext"
+    }],
+    ["rubric" , {
+      "parent": "bodytext",
+      "textColor": "darkred",
+      "alignment": "TA_CENTER"
+    }],
+    ["italic" , {
+      "parent": "bodytext",
+      "fontName": "stdItalic"
+    }],
+    ["heading" , {
+      "parent": "normal",
+      "keepWithNext": true,
+      "spaceBefore": 12,
+      "spaceAfter": 6
+    }],
+    ["title" , {
+      "parent": "heading",
+      "fontName": "stdBold",
+      "fontSize": "200%",
+      "alignment": "TA_CENTER",
+      "keepWithNext": false,
+      "spaceAfter": 10
+    }],
+    ["subtitle" , {
+      "parent": "title",
+      "spaceBefore": 12,
+      "fontSize": "75%"
+    }],
+    ["heading1" , {
+      "parent": "heading",
+      "fontName": "stdBold",
+      "fontSize": "175%"
+    }],
+    ["heading2" , {
+      "parent": "heading",
+      "fontName": "stdBold",
+      "fontSize": "150%"
+    }],
+    ["heading3" , {
+      "parent": "heading",
+      "fontName": "stdBoldItalic",
+      "fontSize": "125%"
+    }],
+    ["heading4" , {
+      "parent": "heading",
+      "fontName": "stdBoldItalic"
+    }],
+    ["heading5" , {
+      "parent": "heading",
+      "fontName": "stdBoldItalic"
+    }],
+    ["heading6" , {
+      "parent": "heading",
+      "fontName": "stdBoldItalic"
+    }],
+    ["topic-title" , {
+      "parent": "heading3"
+    }],
+    ["sidebar-title" , {
+      "parent": "heading3"
+    }],
+    ["sidebar-subtitle" , {
+      "parent": "heading4"
+    }],
+    ["sidebar" , {
+      "float": "none",
+      "width": "100%",
+      "parent": "normal",
+      "backColor": "beige",
+      "borderColor": "darkgray",
+      "borderPadding": 8,
+      "borderWidth": 0.5
+    }],
+    ["admonition" , {
+      "parent": "normal",
+      "spaceBefore": 12,
+      "spaceAfter": 6,
+      "borderPadding": [16,16,16,16],
+      "backColor": "beige",
+      "borderColor": "darkgray",
+      "borderWidth": 0.5,
+      "commands":[
+            [ "VALIGN", [ 0, 0 ], [ -1, -1 ], "TOP" ]
+      ]
+    }],
+    ["attention" , {
+      "parent": "admonition"
+    }],
+    ["caution" , {
+      "parent": "admonition"
+    }],
+    ["danger" , {
+      "parent": "admonition"
+    }],
+    ["error" , {
+      "parent": "admonition"
+    }],
+    ["hint" , {
+      "parent": "admonition"
+    }],
+    ["important" , {
+      "parent": "admonition"
+    }],
+    ["note" , {
+      "parent": "admonition"
+    }],
+    ["tip" , {
+      "parent": "admonition"
+    }],
+    ["warning" , {
+      "parent": "admonition"
+    }],
+    ["admonition-title" , {
+      "parent": "heading3"
+    }],
+    ["admonition-heading" , {
+      "parent": "heading3"
+    }],
+    ["attention-heading" , {
+      "parent": "admonition-heading"
+    }],
+    ["caution-heading" , {
+      "parent": "admonition-heading"
+    }],
+    ["danger-heading" , {
+      "parent": "admonition-heading"
+    }],
+    ["error-heading" , {
+      "parent": "admonition-heading"
+    }],
+    ["hint-heading" , {
+      "parent": "admonition-heading"
+    }],
+    ["important-heading" , {
+      "parent": "admonition-heading"
+    }],
+    ["note-heading" , {
+      "parent": "admonition-heading"
+    }],
+    ["tip-heading" , {
+      "parent": "admonition-heading"
+    }],
+    ["warning-heading" , {
+      "parent": "admonition-heading"
+    }],
+    ["literal" , {
+      "parent": "normal",
+      "fontName": "stdMono",
+      "firstLineIndent": 0,
+      "hyphenation": false
+    }],
+    ["aafigure" , {
+      "parent": "literal"
+    }],
+    ["table" , {
+      "spaceBefore":6,
+      "spaceAfter":0,
+      "alignment": "TA_CENTER",
+      "commands": [
+            [ "VALIGN", [ 0, 0 ], [ -1, -1 ], "TOP" ], 
+            [ "INNERGRID", [ 0, 0 ], [ -1, -1 ], 0.25, "black" ], 
+            [ "ROWBACKGROUNDS", [0, 0], [-1, -1], ["white","#E0E0E0"]],
+            [ "BOX", [ 0, 0 ], [ -1, -1 ], 0.25, "black" ]
+      ]
+    }],
+    ["table-title" , {
+      "parent" : "heading4",
+      "keepWithNext": false,
+      "alignment" : "TA_CENTER"
+    }],
+    ["table-heading" , {
+      "parent" : "heading",
+      "backColor" : "beige",
+      "alignment" : "TA_CENTER",
+      "valign" : "BOTTOM",
+      "borderPadding" : 0
+    }],
+    ["table-body", {
+      "parent" : "normal"
+    }],
+    ["dedication" , {
+      "parent" : "normal"
+    }],
+    ["abstract" , {
+      "parent" : "normal"
+    }],
+    ["contents" , {
+      "parent" : "normal"
+    }],
+    ["tableofcontents" , {
+      "parent" : "normal"
+    }],
+    ["code" , {
+      "parent": "literal",
+      "leftIndent": 0,
+      "spaceBefore": 8,
+      "spaceAfter": 8,
+      "backColor": "beige",
+      "borderColor": "darkgray",
+      "borderWidth": 0.5,
+      "borderPadding": 6
+    }],
+    ["pygments-n" , {"parent": "code"}],
+    ["pygments-nx" , {"parent": "code"}],
+    ["pygments-p" , {"parent": "code"}],
+    ["pygments-hll", {"parent": "code", "backColor": "#ffffcc"}],
+    ["pygments-c", {"textColor": "#008800", "parent": "code"}],
+    ["pygments-err", {"parent": "code"}],
+    ["pygments-k", {"textColor": "#AA22FF", "parent": "code"}],
+    ["pygments-o", {"textColor": "#666666", "parent": "code"}],
+    ["pygments-cm", {"textColor": "#008800", "parent": "code"}],
+    ["pygments-cp", {"textColor": "#008800", "parent": "code"}],
+    ["pygments-c1", {"textColor": "#008800", "parent": "code"}],
+    ["pygments-cs", {"textColor": "#008800", "parent": "code"}],
+    ["pygments-gd", {"textColor": "#A00000", "parent": "code"}],
+    ["pygments-ge", {"parent": "code"}],
+    ["pygments-gr", {"textColor": "#FF0000", "parent": "code"}],
+    ["pygments-gh", {"textColor": "#000080", "parent": "code"}],
+    ["pygments-gi", {"textColor": "#00A000", "parent": "code"}],
+    ["pygments-go", {"textColor": "#808080", "parent": "code"}],
+    ["pygments-gp", {"textColor": "#000080", "parent": "code"}],
+    ["pygments-gs", {"parent": "code"}],
+    ["pygments-gu", {"textColor": "#800080", "parent": "code"}],
+    ["pygments-gt", {"textColor": "#0040D0", "parent": "code"}],
+    ["pygments-kc", {"textColor": "#AA22FF", "parent": "code"}],
+    ["pygments-kd", {"textColor": "#AA22FF", "parent": "code"}],
+    ["pygments-kn", {"textColor": "#AA22FF", "parent": "code"}],
+    ["pygments-kp", {"textColor": "#AA22FF", "parent": "code"}],
+    ["pygments-kr", {"textColor": "#AA22FF", "parent": "code"}],
+    ["pygments-kt", {"textColor": "#00BB00", "parent": "code"}],
+    ["pygments-m", {"textColor": "#666666", "parent": "code"}],
+    ["pygments-s", {"textColor": "#BB4444", "parent": "code"}],
+    ["pygments-na", {"textColor": "#BB4444", "parent": "code"}],
+    ["pygments-nb", {"textColor": "#AA22FF", "parent": "code"}],
+    ["pygments-nc", {"textColor": "#0000FF", "parent": "code"}],
+    ["pygments-no", {"textColor": "#880000", "parent": "code"}],
+    ["pygments-nd", {"textColor": "#AA22FF", "parent": "code"}],
+    ["pygments-ni", {"textColor": "#999999", "parent": "code"}],
+    ["pygments-ne", {"textColor": "#D2413A", "parent": "code"}],
+    ["pygments-nf", {"textColor": "#00A000", "parent": "code"}],
+    ["pygments-nl", {"textColor": "#A0A000", "parent": "code"}],
+    ["pygments-nn", {"textColor": "#0000FF", "parent": "code"}],
+    ["pygments-nt", {"textColor": "#008000", "parent": "code"}],
+    ["pygments-nv", {"textColor": "#B8860B", "parent": "code"}],
+    ["pygments-ow", {"textColor": "#AA22FF", "parent": "code"}],
+    ["pygments-w", {"textColor": "#bbbbbb", "parent": "code"}],
+    ["pygments-mf", {"textColor": "#666666", "parent": "code"}],
+    ["pygments-mh", {"textColor": "#666666", "parent": "code"}],
+    ["pygments-mi", {"textColor": "#666666", "parent": "code"}],
+    ["pygments-mo", {"textColor": "#666666", "parent": "code"}],
+    ["pygments-sb", {"textColor": "#BB4444", "parent": "code"}],
+    ["pygments-sc", {"textColor": "#BB4444", "parent": "code"}],
+    ["pygments-sd", {"textColor": "#BB4444", "parent": "code"}],
+    ["pygments-s2", {"textColor": "#BB4444", "parent": "code"}],
+    ["pygments-se", {"textColor": "#BB6622", "parent": "code"}],
+    ["pygments-sh", {"textColor": "#BB4444", "parent": "code"}],
+    ["pygments-si", {"textColor": "#BB6688", "parent": "code"}],
+    ["pygments-sx", {"textColor": "#008000", "parent": "code"}],
+    ["pygments-sr", {"textColor": "#BB6688", "parent": "code"}],
+    ["pygments-s1", {"textColor": "#BB4444", "parent": "code"}],
+    ["pygments-ss", {"textColor": "#B8860B", "parent": "code"}],
+    ["pygments-bp", {"textColor": "#AA22FF", "parent": "code"}],
+    ["pygments-vc", {"textColor": "#B8860B", "parent": "code"}],
+    ["pygments-vg", {"textColor": "#B8860B", "parent": "code"}],
+    ["pygments-vi", {"textColor": "#B8860B", "parent": "code"}],
+    ["pygments-il", {"textColor": "#666666", "parent": "code"}],
+    
+     [ "endnote", {
+         "parent": "bodytext",
+         "commands": [
+            [ "VALIGN", [ 0, 0 ], [ -1, -1 ], "TOP" ],
+            [ "TOPPADDING", [ 0, 0 ], [ -1, -1 ], 0 ], 
+            [ "BOTTOMPADDING", [ 0, 0 ], [ -1, -1 ], 0 ], 
+            [ "RIGHTPADDING", [ 0, 0 ], [ 1, -1 ], 0 ] 
+        ], 
+        "colWidths": ["3cm",null]
+    }],
+    [ "field_list", {
+         "parent": "bodytext",
+         "commands": [
+            [ "VALIGN", [ 0, 0 ], [ -1, -1 ], "TOP" ], 
+            [ "TOPPADDING", [ 0, 0 ], [ -1, -1 ], 0 ]
+        ], 
+        "colWidths": ["3cm",null],
+        "spaceBefore": 6
+    }],
+    [ "option_list", {
+         "commands": [
+            [ "VALIGN", [ 0, 0 ], [ -1, -1 ], "TOP" ], 
+            [ "TOPPADDING", [ 0, 0 ], [ -1, -1 ], 0 ]
+        ],
+        "colWidths": [null,null]
+    }]
+  ]
+}
diff --git a/test/config_0_3_9/test_config.py b/test/config_0_3_9/test_config.py
new file mode 100644 (file)
index 0000000..393be86
--- /dev/null
@@ -0,0 +1,439 @@
+# Copyright 2004-2010 by Vinay Sajip. All Rights Reserved.\r
+#\r
+# Permission to use, copy, modify, and distribute this software and its\r
+# documentation for any purpose and without fee is hereby granted,\r
+# provided that the above copyright notice appear in all copies and that\r
+# both that copyright notice and this permission notice appear in\r
+# supporting documentation, and that the name of Vinay Sajip\r
+# not be used in advertising or publicity pertaining to distribution\r
+# of the software without specific, written prior permission.\r
+# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING\r
+# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL\r
+# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR\r
+# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER\r
+# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT\r
+# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\r
+\r
+"""\r
+Test harness for the configuration module 'config' for Python.\r
+"""\r
+\r
+import unittest\r
+# import test_support\r
+import config\r
+from config import Config, ConfigMerger, ConfigList\r
+from config import ConfigError, ConfigFormatError, ConfigResolutionError\r
+import logging\r
+from StringIO import StringIO\r
+\r
+STREAMS = {\r
+    "simple_1" :\r
+"""\r
+message: 'Hello, world!'\r
+""",\r
+    "malformed_1" :\r
+"""\r
+123\r
+""",\r
+    "malformed_2" :\r
+"""\r
+[ 123, 'abc' ]\r
+""",\r
+    "malformed_3" :\r
+"""\r
+{ a : 7, b : 1.3, c : 'test' }\r
+""",\r
+    "malformed_4" :\r
+"""\r
+test: $a [7] # note space before bracket\r
+""",\r
+    "malformed_5" :\r
+"""\r
+test: 'abc'\r
+test: 'def'\r
+""",\r
+    "wellformed_1" :\r
+"""\r
+test: $a[7] # note no space before bracket\r
+""",\r
+    "boolean_1":\r
+"""\r
+test : False\r
+another_test: True\r
+""",\r
+    "boolean_2":\r
+"""\r
+test : false\r
+another_test: true\r
+""",\r
+    "none_1":\r
+"""\r
+test : None\r
+""",\r
+    "none_2":\r
+"""\r
+test : none\r
+""",\r
+    "number_1":\r
+"""\r
+root: 1\r
+stream: 1.7\r
+neg: -1\r
+negfloat: -2.0\r
+posexponent: 2.0999999e-08\r
+negexponent: -2.0999999e-08\r
+exponent: 2.0999999e08\r
+""",\r
+    "sequence_1":\r
+"""\r
+mixed: [ "VALIGN", [ 0, 0 ], [ -1, -1 ], "TOP" ]\r
+simple: [1, 2]\r
+nested: [1, [2, 3], [4, [5, 6]]]\r
+""",\r
+    "include_1":\r
+"""\r
+included: @'include_2'\r
+""",\r
+    "include_2":\r
+"""\r
+test: 123\r
+another_test: 'abc'\r
+""",\r
+    "expr_1":\r
+"""\r
+value1 : 10\r
+value2 : 5\r
+value3 : 'abc'\r
+value4 : 'ghi'\r
+value5 : 0\r
+value6 : { 'a' : $value1, 'b': $value2 }\r
+derived1 : $value1 + $value2\r
+derived2 : $value1 - $value2\r
+derived3 : $value1 * $value2\r
+derived4 : $value1 / $value2\r
+derived5 : $value1 % $value2\r
+derived6 : $value3 + $value4\r
+derived7 : $value3 + 'def' + $value4\r
+derived8 : $value3 - $value4 # meaningless\r
+derived9 : $value1 / $value5    # div by zero\r
+derived10 : $value1 % $value5   # div by zero\r
+derived11 : $value17    # doesn't exist\r
+derived12 : $value6.a + $value6.b\r
+""",\r
+    "eval_1":\r
+"""\r
+stderr : `sys.stderr`\r
+stdout : `sys.stdout`\r
+stdin : `sys.stdin`\r
+debug : `debug`\r
+DEBUG : `DEBUG`\r
+derived: $DEBUG * 10\r
+""",\r
+    "merge_1":\r
+"""\r
+value1: True\r
+value3: [1, 2, 3]\r
+value5: [ 7 ]\r
+value6: { 'a' : 1, 'c' : 3 }\r
+""",\r
+    "merge_2":\r
+"""\r
+value2: False\r
+value4: [4, 5, 6]\r
+value5: ['abc']\r
+value6: { 'b' : 2, 'd' : 4 }\r
+""",\r
+    "merge_3":\r
+"""\r
+value1: True\r
+value2: 3\r
+value3: [1, 3, 5]\r
+value4: [1, 3, 5]\r
+""",\r
+    "merge_4":\r
+"""\r
+value1: False\r
+value2: 4\r
+value3: [2, 4, 6]\r
+value4: [2, 4, 6]\r
+""",\r
+    "list_1":\r
+"""\r
+verbosity : 1\r
+""",\r
+    "list_2":\r
+"""\r
+verbosity : 2\r
+program_value: 4\r
+""",\r
+    "list_3":\r
+"""\r
+verbosity : 3\r
+suite_value: 5\r
+""",\r
+    "get_1":\r
+"""\r
+value1 : 123\r
+value2 : 'abcd'\r
+value3 : True\r
+value4 : None\r
+value5:\r
+{\r
+    value1 : 123\r
+    value2 : 'abcd'\r
+    value3 : True\r
+    value4 : None\r
+}\r
+""",\r
+    "multiline_1":\r
+"""\r
+value1: '''Value One\r
+Value Two\r
+'''\r
+value2: \"\"\"Value Three\r
+Value Four\"\"\"\r
+"""\r
+}\r
+\r
+def makeStream(name):\r
+    s = StringIO(STREAMS[name])\r
+    s.name = name\r
+    return s\r
+\r
+class OutStream(StringIO):\r
+    def close(self):\r
+        self.value = self.getvalue()\r
+        StringIO.close(self)\r
+\r
+class TestConfig(unittest.TestCase):\r
+\r
+    def setUp(self):\r
+        self.cfg = Config(None)\r
+\r
+    def tearDown(self):\r
+        del self.cfg\r
+\r
+    def testCreation(self):\r
+        self.assertEqual(0, len(self.cfg))  # should be empty\r
+\r
+    def testSimple(self):\r
+        self.cfg.load(makeStream("simple_1"))\r
+        self.failUnless('message' in self.cfg)\r
+        self.failIf('root' in self.cfg)\r
+        self.failIf('stream' in self.cfg)\r
+        self.failIf('load' in self.cfg)\r
+        self.failIf('save' in self.cfg)\r
+\r
+    def testValueOnly(self):\r
+        self.assertRaises(ConfigError, self.cfg.load,\r
+           makeStream("malformed_1"))\r
+        self.assertRaises(ConfigError, self.cfg.load,\r
+           makeStream("malformed_2"))\r
+        self.assertRaises(ConfigError, self.cfg.load,\r
+           makeStream("malformed_3"))\r
+\r
+    def testBadBracket(self):\r
+        self.assertRaises(ConfigError, self.cfg.load,\r
+           makeStream("malformed_4"))\r
+\r
+    def testDuplicate(self):\r
+        self.assertRaises(ConfigError, self.cfg.load,\r
+           makeStream("malformed_5"))\r
+\r
+    def testGoodBracket(self):\r
+        self.cfg.load(makeStream("wellformed_1"))\r
+\r
+    def testBoolean(self):\r
+        self.cfg.load(makeStream("boolean_1"))\r
+        self.assertEqual(True, self.cfg.another_test)\r
+        self.assertEqual(False, self.cfg.test)\r
+\r
+    def testNotBoolean(self):\r
+        self.cfg.load(makeStream("boolean_2"))\r
+        self.assertEqual('true', self.cfg.another_test)\r
+        self.assertEqual('false', self.cfg.test)\r
+\r
+    def testNone(self):\r
+        self.cfg.load(makeStream("none_1"))\r
+        self.assertEqual(None, self.cfg.test)\r
+\r
+    def testNotNone(self):\r
+        self.cfg.load(makeStream("none_2"))\r
+        self.assertEqual('none', self.cfg.test)\r
+\r
+    def testNumber(self):\r
+        self.cfg.load(makeStream("number_1"))\r
+        self.assertEqual(1, self.cfg.root)\r
+        self.assertEqual(1.7, self.cfg.stream)\r
+        self.assertEqual(-1, self.cfg.neg)\r
+        self.assertEqual(-2.0, self.cfg.negfloat)\r
+        self.assertAlmostEqual(-2.0999999e-08, self.cfg.negexponent)\r
+        self.assertAlmostEqual(2.0999999e-08, self.cfg.posexponent)\r
+        self.assertAlmostEqual(2.0999999e08, self.cfg.exponent)\r
+\r
+    def testChange(self):\r
+        self.cfg.load(makeStream("simple_1"))\r
+        self.cfg.message = 'Goodbye, cruel world!'\r
+        self.assertEqual('Goodbye, cruel world!', self.cfg.message)\r
+\r
+    def testSave(self):\r
+        self.cfg.load(makeStream("simple_1"))\r
+        self.cfg.message = 'Goodbye, cruel world!'\r
+        out = OutStream()\r
+        self.cfg.save(out)\r
+        self.assertEqual("message : 'Goodbye, cruel world!'" + config.NEWLINE,\r
+           out.value)\r
+\r
+    def testInclude(self):\r
+        config.streamOpener = makeStream\r
+        self.cfg = Config("include_1")\r
+        config.streamOpener = config.defaultStreamOpener\r
+        out = OutStream()\r
+        self.cfg.save(out)\r
+        s = "included :%s{%s  test : 123%s  another_test : 'abc'%s}%s" % (5 *\r
+           (config.NEWLINE,))\r
+        self.assertEqual(s, out.value)\r
+\r
+    def testExpression(self):\r
+        self.cfg.load(makeStream("expr_1"))\r
+        self.assertEqual(15, self.cfg.derived1)\r
+        self.assertEqual(5, self.cfg.derived2)\r
+        self.assertEqual(50, self.cfg.derived3)\r
+        self.assertEqual(2, self.cfg.derived4)\r
+        self.assertEqual(0, self.cfg.derived5)\r
+        self.assertEqual('abcghi', self.cfg.derived6)\r
+        self.assertEqual('abcdefghi', self.cfg.derived7)\r
+        self.assertRaises(TypeError, lambda x: x.derived8, self.cfg)\r
+        self.assertRaises(ZeroDivisionError, lambda x: x.derived9, self.cfg)\r
+        self.assertRaises(ZeroDivisionError, lambda x: x.derived10, self.cfg)\r
+        self.assertRaises(ConfigResolutionError,\r
+           lambda x: x.derived11, self.cfg)\r
+        self.assertEqual(15, self.cfg.derived12)\r
+\r
+    def testEval(self):\r
+        import sys, logging\r
+        self.cfg.load(makeStream("eval_1"))\r
+        self.assertEqual(sys.stderr, self.cfg.stderr)\r
+        self.assertEqual(sys.stdout, self.cfg.stdout)\r
+        self.assertEqual(sys.stdin, self.cfg.stdin)\r
+        self.assertRaises(ConfigResolutionError, lambda x: x.debug, self.cfg)\r
+        self.cfg.addNamespace(logging.Logger)\r
+        self.assertEqual(logging.Logger.debug.im_func, self.cfg.debug)\r
+        self.assertRaises(ConfigResolutionError, lambda x: x.DEBUG, self.cfg)\r
+        self.cfg.addNamespace(logging)\r
+        self.assertEqual(logging.DEBUG, self.cfg.DEBUG)\r
+        self.cfg.removeNamespace(logging.Logger)\r
+        self.assertEqual(logging.debug, self.cfg.debug)\r
+        self.assertEqual(logging.DEBUG * 10, self.cfg.derived)\r
+\r
+    def testFunctions(self):\r
+        makePath = config.makePath\r
+        isWord = config.isWord\r
+        self.assertEqual('suffix', makePath('', 'suffix'))\r
+        self.assertEqual('suffix', makePath(None, 'suffix'))\r
+        self.assertEqual('prefix.suffix', makePath('prefix', 'suffix'))\r
+        self.assertEqual('prefix[1]', makePath('prefix', '[1]'))\r
+        self.failUnless(isWord('a9'))\r
+        self.failUnless(isWord('9a'))    #perverse, but there you go\r
+        self.failIf(isWord(9))\r
+        self.failIf(isWord(None))\r
+        self.failIf(isWord(self))\r
+        self.failIf(isWord(''))\r
+\r
+    def testMerge(self):\r
+        cfg1 = Config()\r
+        cfg1.load(makeStream("merge_1"))\r
+        cfg2 = Config(makeStream("merge_2"))\r
+        ConfigMerger().merge(cfg1, cfg2)\r
+        merged = cfg1\r
+        cfg1 = Config()\r
+        cfg1.load(makeStream("merge_1"))\r
+        for i in xrange(0, 5):\r
+            key = 'value%d' % (i + 1,)\r
+            self.failUnless(key in merged)\r
+        self.assertEqual(len(cfg1.value5) + len(cfg2.value5),\r
+           len(merged.value5))\r
+        cfg3 = Config()\r
+        cfg3.load(makeStream("merge_3"))\r
+        cfg4 = Config(makeStream("merge_4"))\r
+        merger = ConfigMerger()\r
+        self.assertRaises(ConfigError, merger.merge, cfg3, cfg4)\r
+\r
+        cfg3 = Config(makeStream("merge_3"))\r
+        cfg4 = Config(makeStream("merge_4"))\r
+        merger = ConfigMerger(config.overwriteMergeResolve)\r
+        merger.merge(cfg3, cfg4)\r
+        self.assertEqual(False, cfg3['value1'])\r
+        self.assertEqual(4, cfg3['value2'])\r
+\r
+        def customMergeResolve(map1, map2, key):\r
+            if key == "value3":\r
+                rv = "overwrite"\r
+            else:\r
+                rv = config.overwriteMergeResolve(map1, map2, key)\r
+            return rv\r
+\r
+        cfg3 = Config(makeStream("merge_3"))\r
+        cfg4 = Config(makeStream("merge_4"))\r
+        merger = ConfigMerger(customMergeResolve)\r
+        merger.merge(cfg3, cfg4)\r
+        self.assertEqual("[2, 4, 6]", str(cfg3.value3))\r
+        self.assertEqual("[1, 3, 5, 2, 4, 6]", str(cfg3.value4))\r
+\r
+    def testList(self):\r
+        list = ConfigList()\r
+        list.append(Config(makeStream("list_1")))\r
+        list.append(Config(makeStream("list_2")))\r
+        list.append(Config(makeStream("list_3")))\r
+        self.assertEqual(1, list.getByPath('verbosity'))\r
+        self.assertEqual(4, list.getByPath('program_value'))\r
+        self.assertEqual(5, list.getByPath('suite_value'))\r
+        self.assertRaises(ConfigError, list.getByPath, 'nonexistent_value')\r
+\r
+    def testGet(self):\r
+        cfg = self.cfg\r
+        cfg.load(makeStream("get_1"))\r
+        self.assertEqual(123, cfg.get('value1'))\r
+        self.assertEqual(123, cfg.get('value1', -123))\r
+        self.assertEqual(-123, cfg.get('value11', -123))\r
+        self.assertEqual('abcd', cfg.get('value2'))\r
+        self.failUnless(cfg.get('value3'))\r
+        self.failIf(cfg.get('value4') is not None)\r
+        self.assertEqual(123, cfg.value5.get('value1'))\r
+        self.assertEqual(123, cfg.value5.get('value1', -123))\r
+        self.assertEqual(-123, cfg.value5.get('value11', -123))\r
+        self.assertEqual('abcd', cfg.value5.get('value2'))\r
+        self.failUnless(cfg.value5.get('value3'))\r
+        self.failIf(cfg.value5.get('value4') is not None)\r
+\r
+    def testMultiline(self):\r
+        cfg = self.cfg\r
+        cfg.load(makeStream("multiline_1"))\r
+        self.assertEqual("Value One\nValue Two\n", cfg.get('value1'))\r
+        self.assertEqual("Value Three\nValue Four", cfg.get('value2'))\r
+\r
+    def testSequence(self):\r
+        cfg = self.cfg\r
+        strm = makeStream("sequence_1")\r
+        cfg.load(strm)\r
+        self.assertEqual(str(cfg.simple), "[1, 2]")\r
+        self.assertEqual(str(cfg.nested), "[1, [2, 3], [4, [5, 6]]]")\r
+        self.assertEqual(str(cfg.mixed), "['VALIGN', [0, 0], [-1, -1], 'TOP']")\r
+\r
+    def testJSON(self):\r
+        data = StringIO('dummy: ' + open('styles.json', 'r').read())\r
+        self.cfg.load(data)\r
+\r
+def init_logging():\r
+    logging.basicConfig(level=logging.DEBUG, filename="test_config.log",\r
+                        filemode="w", format="%(asctime)s %(levelname)-5s %(name)-10s %(message)s")\r
+"""\r
+def test_main():\r
+    init_logging()\r
+    test_support.run_unittest(TestConfig)\r
+"""\r
+\r
+if __name__ == "__main__":\r
+    unittest.main(exit=False)\r
+    pass\r
+    # test_main()\r
diff --git a/test/environ/test_environ.py b/test/environ/test_environ.py
deleted file mode 100755 (executable)
index 3a63fd5..0000000
+++ /dev/null
@@ -1,150 +0,0 @@
-#!/usr/bin/env python
-#-*- coding:utf-8 -*-
-
-#  Copyright (C) 2010-2018  CEA/DEN
-#
-#  This library is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU Lesser General Public
-#  License as published by the Free Software Foundation; either
-#  version 2.1 of the License.
-#
-#  This library is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-#  Lesser General Public License for more details.
-#
-#  You should have received a copy of the GNU Lesser General Public
-#  License along with this library; if not, write to the Free Software
-#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
-
-import os
-import sys
-import unittest
-
-from src.salomeTools import Sat
-
-class TestSource(unittest.TestCase):
-    """Test of the environ command"""
-    
-    def test_010(self):
-        # Test the environ command without any option
-        OK = 'KO'
-        
-        appli = 'appli-test'
-
-        file_env_name = 'env_launch.sh'
-        
-        sat = Sat()
-        sat.config(appli)
-
-        expected_file_path = os.path.join(sat.cfg.APPLICATION.workdir, file_env_name)
-
-        if os.path.exists(expected_file_path):
-            os.remove(expected_file_path)
-
-        sat.environ(appli)
-
-        if os.path.exists(expected_file_path):
-            OK = 'OK'
-        self.assertEqual(OK, 'OK')
-
-    def test_020(self):
-        # Test the environ command with option '--products'
-        OK = 'KO'
-        
-        appli = 'appli-test'
-        product_name = 'PRODUCT_GIT'
-        
-        file_env_name = 'env_launch.sh'
-        
-        sat = Sat()
-        sat.config(appli)
-
-        expected_file_path = os.path.join(sat.cfg.APPLICATION.workdir, file_env_name)
-
-        if os.path.exists(expected_file_path):
-            os.remove(expected_file_path)
-
-        sat.environ(appli + ' --products ' + product_name)
-
-        if os.path.exists(expected_file_path):
-            OK = 'OK'
-        self.assertEqual(OK, 'OK')        
-
-    def test_030(self):
-        # Test the environ command with option --target
-        OK = 'KO'
-        
-        appli = 'appli-test'
-        
-        file_env_name = 'env_launch.sh'
-        
-        sat = Sat()
-        sat.config(appli)
-
-        expected_file_path = os.path.join('.', file_env_name)
-        expected_file_path2 = os.path.join('.', 'env_build.sh')
-
-        if os.path.exists(expected_file_path):
-            os.remove(expected_file_path)
-
-        sat.environ(appli + ' --target .')
-
-        if os.path.exists(expected_file_path):
-            OK = 'OK'
-
-        if os.path.exists(expected_file_path):
-            os.remove(expected_file_path)
-            os.remove(expected_file_path2)
-
-        # pyunit method to compare 2 str
-        self.assertEqual(OK, 'OK') 
-
-    def test_040(self):
-        # Test the environ command with option --prefix
-        OK = 'KO'
-        
-        appli = 'appli-test'
-        prefix = 'TEST'
-        file_env_name = prefix + '_launch.sh'
-        
-        sat = Sat()
-        sat.config(appli)
-
-        expected_file_path = os.path.join(sat.cfg.APPLICATION.workdir, file_env_name)
-
-        if os.path.exists(expected_file_path):
-            os.remove(expected_file_path)
-
-        sat.environ(appli + ' --prefix ' + prefix)
-
-        if os.path.exists(expected_file_path):
-            OK = 'OK'
-        self.assertEqual(OK, 'OK') 
-
-    def test_050(self):
-        # Test the environ command with option --shell
-        OK = 'KO'
-        
-        appli = 'appli-test'
-        shell = 'bat'
-        file_env_name = 'env_launch.bat'
-        
-        sat = Sat()
-        sat.config(appli)
-
-        expected_file_path = os.path.join(sat.cfg.APPLICATION.workdir, file_env_name)
-
-        if os.path.exists(expected_file_path):
-            os.remove(expected_file_path)
-
-        sat.environ(appli + ' --shell ' + shell)
-
-        if os.path.exists(expected_file_path):
-            OK = 'OK'
-        self.assertEqual(OK, 'OK') 
-
-# test launch
-if __name__ == '__main__':
-    unittest.main()
-    pass
diff --git a/test/job/test_job.py b/test/job/test_job.py
deleted file mode 100755 (executable)
index fc23191..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-#!/usr/bin/env python
-#-*- coding:utf-8 -*-
-
-#  Copyright (C) 2010-2018  CEA/DEN
-#
-#  This library is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU Lesser General Public
-#  License as published by the Free Software Foundation; either
-#  version 2.1 of the License.
-#
-#  This library is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-#  Lesser General Public License for more details.
-#
-#  You should have received a copy of the GNU Lesser General Public
-#  License along with this library; if not, write to the Free Software
-#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
-
-import os
-import sys
-import unittest
-
-from src.salomeTools import Sat
-
-class TestCase(unittest.TestCase):
-    """Test the job command"""
-
-    def test_010(self):
-        # Test the job command
-        OK = 'KO'
-        tmp_file = "/tmp/test.txt"
-
-        sat = Sat("-l " + tmp_file)
-        
-        # Execute the job command
-        sat.job("--jobs_config .test --name Job 1" )
-
-        ff = open(tmp_file, "r")
-        log_files = ff.readlines()
-        ff.close()
-        os.remove(tmp_file)
-        log_config = [line.replace("\n", "") for line in log_files if 'config.xml' in line]
-        
-        text = open(log_config[0], "r").read()
-
-        if "nb_proc" in text:
-            OK = 'OK'         
-        self.assertEqual(OK, 'OK')
-
-
-    def test_020(self):
-        # Test the job command with a failing command
-        OK = 'KO'
-        tmp_file = "/tmp/test.txt"
-
-        sat = Sat("-l " + tmp_file)
-        
-        # Execute the job command
-        res = sat.job("--jobs_config .test --name Job 4" )
-
-        if res == 1:
-            OK = 'OK'         
-        # pyunit method to compare 2 str
-        self.assertEqual(OK, 'OK')
-
-    def test_030(self):
-        # Test the job command with a wrong file configuration
-        OK = 'KO'
-        tmp_file = "/tmp/test.txt"
-
-        sat = Sat("-l " + tmp_file)
-        
-        # Execute the job command
-        res = sat.job("--jobs_config NOTEXIST --name Job 4" )
-
-        if res == 1:
-            OK = 'OK'         
-        self.assertEqual(OK, 'OK')
-
-    def test_040(self):
-        # Test the job command without --jobs_config option
-        OK = 'KO'
-        tmp_file = "/tmp/test.txt"
-
-        sat = Sat("-l " + tmp_file)
-        
-        # Execute the job command
-        res = sat.job("--name Job 4" )
-
-        if res == 1:
-            OK = 'OK'         
-        self.assertEqual(OK, 'OK')
-
-    def test_050(self):
-        # Test the job command without --jobs_config option
-        OK = 'KO'
-        tmp_file = "/tmp/test.txt"
-
-        sat = Sat("-l " + tmp_file)
-        
-        # Execute the job command
-        res = sat.job("--jobs_config .test --name NOTEXIST" )
-
-        if res == 1:
-            OK = 'OK'         
-        self.assertEqual(OK, 'OK')
-
-    def test_060(self):
-        # Test the sat -h job     
-        OK = "KO"
-
-        import job
-        
-        if "Executes the commands of the job defined in the jobs configuration file" in job.description():
-            OK = "OK"
-        self.assertEqual(OK, "OK")
-
-# test launch
-if __name__ == '__main__':
-    unittest.main()
-    pass
diff --git a/test/jobs/test_jobs.py b/test/jobs/test_jobs.py
deleted file mode 100755 (executable)
index 1b22378..0000000
+++ /dev/null
@@ -1,159 +0,0 @@
-#!/usr/bin/env python
-#-*- coding:utf-8 -*-
-
-#  Copyright (C) 2010-2018  CEA/DEN
-#
-#  This library is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU Lesser General Public
-#  License as published by the Free Software Foundation; either
-#  version 2.1 of the License.
-#
-#  This library is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-#  Lesser General Public License for more details.
-#
-#  You should have received a copy of the GNU Lesser General Public
-#  License along with this library; if not, write to the Free Software
-#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
-
-import os
-import sys
-import unittest
-
-from src.salomeTools import Sat
-from unittestpy.tools import outRedirection
-
-class TestCase(unittest.TestCase):
-    "Test the jobs command"""
-
-    def test_010(self):
-        # Test the jobs command
-        OK = 'KO'
-        tmp_file = "/tmp/test.txt"
-
-        sat = Sat("-l " + tmp_file)
-        
-        # Execute the jobs command
-        sat.jobs("--name .test --publish" )
-
-        ff = open(tmp_file, "r")
-        log_files = ff.readlines()
-        ff.close()
-        os.remove(tmp_file)
-        log_jobs = [line.replace("\n", "") for line in log_files if 'jobs.xml' in line]
-        
-        text = open(log_jobs[0], "r").read()
-        
-        expected_res = [
-        "Establishing connection with all the machines",
-        "Executing the jobs",
-        "Results for job"
-        ]
-        
-        res = 0
-        for exp_res in expected_res:
-            if exp_res not in text:
-                res += 1
-        
-        if res == 0:
-            OK = 'OK'
-        self.assertEqual(OK, 'OK')
-
-    def test_020(self):
-        # Test the jobs command with option --only_jobs
-        OK = 'KO'
-        tmp_file = "/tmp/test.txt"
-
-        sat = Sat("-l " + tmp_file)
-        
-        # Execute the jobs command
-        sat.jobs("--name .test --publish --only_jobs Job 1" )
-
-        ff = open(tmp_file, "r")
-        log_files = ff.readlines()
-        ff.close()
-        os.remove(tmp_file)
-        log_jobs = [line.replace("\n", "") for line in log_files if 'jobs.xml' in line]
-        
-        text = open(log_jobs[0], "r").read()
-        
-        expected_res = [
-        "Establishing connection with all the machines",
-        "Executing the jobs",
-        "Results for job"
-        ]
-        
-        res = 0
-        for exp_res in expected_res:
-            if exp_res not in text:
-                res += 1
-        
-        if res == 0:
-            OK = 'OK'
-        self.assertEqual(OK, 'OK')
-
-    def test_030(self):
-        # Test the jobs command without --name option
-        OK = 'KO'
-        tmp_file = "/tmp/test.txt"
-
-        sat = Sat("-l " + tmp_file)
-        
-        # Execute the job command
-        res = sat.jobs()
-
-        if res == 1:
-            OK = 'OK'         
-        self.assertEqual(OK, 'OK')
-        
-    def test_040(self):
-        # Test the jobs command with a wrong file configuration
-        OK = 'KO'
-        tmp_file = "/tmp/test.txt"
-
-        sat = Sat("-l " + tmp_file)
-        
-        # Execute the job command
-        res = sat.jobs("--name NOTEXIST" )
-
-        if res == 1:
-            OK = 'OK'         
-        self.assertEqual(OK, 'OK')
-
-    def test_050(self):
-        # Test the display of the right value of 'sat jobs --list'
-        OK = "KO"
-
-        # output redirection
-        my_out = outRedirection()
-
-        # The command to test
-        sat = Sat()
-        sat.jobs('--list')
-
-        # stop output redirection
-        my_out.end_redirection()
-
-        # get results
-        res = my_out.read_results()
-
-        # get results
-        if "ERROR" not in res:
-            OK = "OK"
-        self.assertEqual(OK, "OK")
-
-    def test_060(self):
-        # Test the sat -h jobs       
-        OK = "KO"
-
-        import jobs
-        
-        if "The jobs command launches maintenances that are described in the dedicated jobs configuration file." in jobs.description():
-            OK = "OK"
-        self.assertEqual(OK, "OK")
-
-# test launch
-if __name__ == '__main__':
-    unittest.main()
-    pass
diff --git a/test/log/test_launch_browser.py b/test/log/test_launch_browser.py
deleted file mode 100755 (executable)
index a9c8be4..0000000
+++ /dev/null
@@ -1,294 +0,0 @@
-#!/usr/bin/env python
-#-*- coding:utf-8 -*-
-
-#  Copyright (C) 2010-2018  CEA/DEN
-#
-#  This library is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU Lesser General Public
-#  License as published by the Free Software Foundation; either
-#  version 2.1 of the License.
-#
-#  This library is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-#  Lesser General Public License for more details.
-#
-#  You should have received a copy of the GNU Lesser General Public
-#  License along with this library; if not, write to the Free Software
-#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
-
-import os
-import sys
-import threading
-import time
-import shutil
-import io
-import unittest
-
-from src.salomeTools import Sat
-from unittestpy.tools import check_proc_existence_and_kill_multi
-
-sleep_time = 2
-
-class TestCase(unittest.TestCase):
-    """Test of log command: launch of browser"""
-           
-    def test_010(self):
-        # Test the write of xml log when invoking a command
-        OK = "KO"
-        
-        # launch the command that will write a log
-        sat = Sat()
-        sat.config('appli-test -v USER.browser')
-        
-        # get log file path
-        logDir = sat.cfg.USER.log_dir
-        logPath = os.path.join(logDir, sat.cfg.VARS.datehour + "_" + sat.cfg.VARS.command + ".xml")
-        
-        if os.path.exists(logPath):
-            OK = "OK"
-        self.assertEqual(OK, "OK")
-
-    def test_020(self):
-        # Test the terminal option without application
-        OK = "KO"
-        
-        # launch the command that will write a log
-        sat = Sat()
-        
-        one = u"1"
-        sys.stdin = io.StringIO(one)
-        
-        
-        try:
-            sat.log('-t')
-            OK = "OK"
-            sys.stdin = sys.__stdin__
-        except:
-            sys.stdin = sys.__stdin__
-        self.assertEqual(OK, "OK")
-
-    def test_030(self):
-        # Test the terminal option with application
-        OK = "KO"
-        
-        # launch the command that will write a log
-        sat = Sat()
-              
-        sat.config('appli-test -v VARS.python')
-        
-        one = u"1"
-        sys.stdin = io.StringIO(one)
-        
-        try:
-            sat.log('appli-test -t --last')
-            OK = "OK"
-            sys.stdin = sys.__stdin__
-        except:
-            pass
-        self.assertEqual(OK, "OK")
-
-    def test_040(self):
-        # Test the terminal option with 0 as input
-        OK = "KO"
-        
-        # launch the command that will write a log
-        sat = Sat()
-              
-        sat.config('appli-test -v VARS.python')
-        
-        zero = u"0\n1"
-        sys.stdin = io.StringIO(zero)
-        
-        try:
-            sat.log('--terminal')
-            OK = "OK"
-        finally:
-            sys.stdin = sys.__stdin__
-        self.assertEqual(OK, "OK")
-
-    def test_050(self):
-        # Test the terminal option with input bigger than the number of logs
-        OK = "KO"
-        
-        # launch the command that will write a log
-        sat = Sat()
-              
-        sat.config('appli-test -v VARS.python')
-        
-        nb_logs = len(os.listdir(sat.cfg.USER.log_dir))
-        
-        nb_logs_u = unicode(str(nb_logs) + "\n1")
-        sys.stdin = io.StringIO(nb_logs_u)
-        
-        try:
-            sat.log('--terminal')
-            OK = "OK"
-        finally:
-            sys.stdin = sys.__stdin__
-        self.assertEqual(OK, "OK")
-
-    def test_060(self):
-        # Test the terminal option with input return
-        OK = "KO"
-        
-        # launch the command that will write a log
-        sat = Sat()
-              
-        sat.config('appli-test -v VARS.python')
-        
-        ret = unicode("\n0")
-        sys.stdin = io.StringIO(ret)
-        
-        try:
-            sat.log('--terminal')
-            OK = "OK"
-        finally:
-            sys.stdin = sys.__stdin__
-        self.assertEqual(OK, "OK")
-
-    def test_070(self):
-        # Test the terminal option with input not int
-        OK = "KO"
-        
-        # launch the command that will write a log
-        sat = Sat()
-              
-        sat.config('appli-test -v VARS.python')
-        
-        ret = unicode("blabla\n0")
-        sys.stdin = io.StringIO(ret)
-        
-        try:
-            sat.log('--terminal')
-            OK = "OK"
-        finally:
-            sys.stdin = sys.__stdin__
-        self.assertEqual(OK, "OK")
-
-    def test_080(self):
-        # Test the terminal option and option last
-        OK = "KO"
-        
-        # launch the command that will write a log
-        sat = Sat()
-        
-        try:
-            sat.log('--terminal --last')
-            OK = "OK"
-        finally:
-            sys.stdin = sys.__stdin__
-        
-        # pyunit method to compare 2 str
-        self.assertEqual(OK, "OK")
-    
-    def test_090(self):
-        # Test the option --last
-        OK = "KO"
-        
-        # launch the command that will write a log
-        sat = Sat("-oUSER.browser='konqueror'")
-              
-        sat.config('appli-test -v VARS.python')
-        
-        
-        time.sleep(sleep_time)
-        cmd_log = threading.Thread(target=sat.log, args=('appli-test --last',))
-        cmd_log.start()
-        
-        time.sleep(sleep_time)
-
-        browser = sat.cfg.USER.browser
-        pid = check_proc_existence_and_kill_multi(browser + ".*" + "xml", 10)
-        
-        if pid:
-            OK = "OK"
-        self.assertEqual(OK, "OK")
-    
-    def test_100(self):
-        # Test the option --clean
-        OK = "KO"
-        
-        # launch the command that will write a log
-        sat = Sat()
-               
-        sat.config('-v VARS.user')
-        
-        nb_logs_t0 = len(os.listdir(sat.cfg.USER.log_dir))
-
-        sat.log('--clean 1')
-        
-        nb_logs_t1 = len(os.listdir(sat.cfg.USER.log_dir))
-        
-        if nb_logs_t1-nb_logs_t0 == 0:
-            OK = "OK"
-        self.assertEqual(OK, "OK")
-
-    def test_120(self):
-        # Test the option --clean with big number of files to clean
-        OK = "KO"
-        
-        # launch the command that will write a log
-        sat = Sat()
-               
-        sat.config('-v VARS.user')
-        
-        nb_logs_t0 = len(os.listdir(sat.cfg.USER.log_dir))
-        
-        if os.path.exists(sat.cfg.USER.log_dir + "_save"):
-            shutil.rmtree(sat.cfg.USER.log_dir + "_save")
-        print("TODO: risky !!!copytree!!!", sat.cfg.USER.log_dir, sat.cfg.USER.log_dir + "_save")
-        """
-        shutil.copytree(sat.cfg.USER.log_dir,sat.cfg.USER.log_dir + "_save")
-        
-        sat.log('--clean ' + str(nb_logs_t0))
-        
-        nb_logs_t1 = len(os.listdir(sat.cfg.USER.log_dir))
-        
-        shutil.rmtree(sat.cfg.USER.log_dir)
-        shutil.move(sat.cfg.USER.log_dir + "_save", sat.cfg.USER.log_dir)
-                
-        if nb_logs_t0-nb_logs_t1 > 10:
-            OK = "OK"
-        """
-        self.assertEqual(OK, "OK")
-    
-    """
-    def test_130(self):
-        # Test the option --full
-        OK = "KO"
-
-        sat = Sat("-oUSER.browser='konqueror'")
-        time.sleep(sleep_time)
-        cmd_log = threading.Thread(target=sat.log, args=('--full',))
-        cmd_log.start()
-
-        time.sleep(sleep_time)
-
-        browser = sat.cfg.USER.browser
-        check_proc_existence_and_kill_multi(browser + ".*" + "hat\.xml", 10)
-        
-        # Read and check the hat.xml file contains at least one log file corresponding to log
-        hatFilePath = os.path.join(sat.cfg.USER.log_dir, "hat.xml")
-        xmlHatFile = src.xmlManager.ReadXmlFile(hatFilePath)
-        for field in xmlHatFile.xmlroot:
-            if field.attrib[b'cmd'] == b'log':
-                OK = "OK"
-                break
-        self.assertEqual(OK, "OK")
-    """
-
-    def test_140(self):
-        # Test the sat -h log
-        OK = "KO"
-
-        import log
-        
-        if "Gives access to the logs produced" in log.description():
-            OK = "OK"
-        self.assertEqual(OK, "OK")
-
-# test launch
-if __name__ == '__main__':
-    unittest.main()
-    pass
diff --git a/test/log/test_launch_browser2.py b/test/log/test_launch_browser2.py
deleted file mode 100755 (executable)
index 38a6184..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-#!/usr/bin/env python
-#-*- coding:utf-8 -*-
-
-#  Copyright (C) 2010-2018  CEA/DEN
-#
-#  This library is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU Lesser General Public
-#  License as published by the Free Software Foundation; either
-#  version 2.1 of the License.
-#
-#  This library is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-#  Lesser General Public License for more details.
-#
-#  You should have received a copy of the GNU Lesser General Public
-#  License along with this library; if not, write to the Free Software
-#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
-
-import os
-import sys
-import threading
-import time
-import unittest
-
-from src.salomeTools import Sat
-from unittestpy.tools import check_proc_existence_and_kill_multi
-
-sleep_time = 2
-
-class TestCase(unittest.TestCase):
-    """Test of log command: launch of browser"""
-
-    def test_010(self):
-        # Test the launch of browser when invoking the log command
-        OK = "KO"
-
-        sat = Sat("-oUSER.browser='konqueror'")
-        time.sleep(sleep_time)
-        cmd_log = threading.Thread(target=sat.log, args=('',))
-        cmd_log.start()
-
-        time.sleep(sleep_time)
-        
-        sat.config("")
-        browser = sat.cfg.USER.browser
-        pid = check_proc_existence_and_kill_multi(browser + ".*" + "hat\.xml", 10)
-
-        if pid:
-            OK = "OK"
-        self.assertEqual(OK, "OK")
-
-# test launch
-if __name__ == '__main__':
-    unittest.main()
-    pass
diff --git a/test/prepare/test_clean.py b/test/prepare/test_clean.py
deleted file mode 100755 (executable)
index 08bb54f..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-#!/usr/bin/env python
-#-*- coding:utf-8 -*-
-
-#  Copyright (C) 2010-2018  CEA/DEN
-#
-#  This library is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU Lesser General Public
-#  License as published by the Free Software Foundation; either
-#  version 2.1 of the License.
-#
-#  This library is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-#  Lesser General Public License for more details.
-#
-#  You should have received a copy of the GNU Lesser General Public
-#  License along with this library; if not, write to the Free Software
-#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
-
-import os
-import sys
-import unittest
-
-from src.salomeTools import Sat
-import src.product
-from unittestpy.tools import outRedirection
-
-class TestCase(unittest.TestCase):
-    """Test of the clean command"""
-
-    def test_010(self):
-        # Test the clean command with no arguments (nothing to clean)
-        OK = 'KO'
-
-        appli = 'appli-test'
-
-        sat = Sat()
-
-        # output redirection
-        my_out = outRedirection()
-        
-        sat.clean(appli)
-        
-        # stop output redirection
-        my_out.end_redirection()
-
-        # get results
-        res = my_out.read_results()
-        
-        if "Nothing to suppress" in res:
-            OK = 'OK'
-        self.assertEqual(OK, 'OK')
-
-    def test_020(self):
-        # Test the clean of sources
-        OK = "KO"
-
-        appli = 'appli-test'
-        product_name = "PRODUCT_GIT"
-
-        sat = Sat()      
-        
-        # Make sure the sources exist
-        sat.prepare(appli + " -p " + product_name)
-        
-        # Call the command
-        sat.clean(appli + " -p " + product_name + " --sources", batch=True)
-           
-        expected_src_dir = src.product.get_product_config(sat.cfg, product_name).source_dir
-        
-        if not os.path.exists(expected_src_dir):
-            OK = "OK"
-        self.assertEqual(OK, "OK")
-
-    def test_030(self):
-        # Test the clean of build
-        OK = "KO"
-
-        appli = 'appli-test'
-        product_name = "PRODUCT_GIT"
-
-        sat = Sat()      
-        
-        # Make sure the build exists
-        sat.prepare(appli + " -p " + product_name)
-        sat.configure(appli + " -p " + product_name)
-        
-        # Call the command
-        sat.clean(appli + " -p " + product_name + " --build", batch=True)
-           
-        expected_build_dir = src.product.get_product_config(sat.cfg, product_name).build_dir
-        
-        if not os.path.exists(expected_build_dir):
-            OK = "OK"
-        self.assertEqual(OK, "OK")
-
-    def test_040(self):
-        # Test the clean of install
-        OK = "KO"
-
-        appli = 'appli-test'
-        product_name = "PRODUCT_GIT"
-
-        sat = Sat()      
-        
-        # Make sure the build exists
-        sat.prepare(appli + " -p " + product_name)
-        sat.configure(appli + " -p " + product_name)
-        
-        # Call the command
-        sat.clean(appli + " -p " + product_name + " --install", batch=True)
-           
-        expected_install_dir = src.product.get_product_config(sat.cfg, product_name).install_dir
-        
-        if not os.path.exists(expected_install_dir):
-            OK = "OK"
-        self.assertEqual(OK, "OK")
-
-    def test_050(self):
-        # Test the clean of all (build, src, install)
-        OK = "KO"
-
-        appli = 'appli-test'
-        product_name = "PRODUCT_GIT"
-
-        sat = Sat()      
-        
-        # Make sure the build exists
-        sat.prepare(appli + " -p " + product_name)
-        sat.compile(appli + " -p " + product_name)
-        
-        # Call the command
-        sat.clean(appli + " -p " + product_name + " --all", batch=True)
-           
-        expected_install_dir = src.product.get_product_config(sat.cfg, product_name).install_dir
-        expected_build_dir = src.product.get_product_config(sat.cfg, product_name).build_dir
-        expected_src_dir = src.product.get_product_config(sat.cfg, product_name).source_dir
-        
-        if not os.path.exists(expected_install_dir) and not os.path.exists(expected_build_dir) and not os.path.exists(expected_src_dir):
-            OK = "OK"
-        self.assertEqual(OK, "OK")
-
-    def test_060(self):
-        # Test the clean with sources_without_dev option
-        OK = "KO"
-
-        appli = 'appli-test'
-        product_name = "PRODUCT_GIT"
-        product_name2 = "PRODUCT_DEV"
-
-        sat = Sat()      
-        
-        # Make sure the build exists
-        sat.prepare(appli + " -p " + product_name + "," + product_name2)
-        
-        # Call the command
-        sat.clean(appli + " -p " + product_name + " --sources_without_dev", batch=True)
-           
-        expected_src_dir = src.product.get_product_config(sat.cfg, product_name).source_dir
-        expected_src_dir2 = src.product.get_product_config(sat.cfg, product_name2).source_dir
-        
-        if not os.path.exists(expected_src_dir) and os.path.exists(expected_src_dir2):
-            OK = "OK"
-        self.assertEqual(OK, "OK")
-
-
-    def test_070(self):
-        # Test the sat -h clean
-        OK = "KO"
-
-        import clean
-        
-        if "The clean command suppress the source, build, or install" in clean.description():
-            OK = "OK"
-        self.assertEqual(OK, "OK")
-
-# test launch
-if __name__ == '__main__':
-    unittest.main()
-    pass
diff --git a/test/prepare/test_patch.py b/test/prepare/test_patch.py
deleted file mode 100755 (executable)
index 1dc24d4..0000000
+++ /dev/null
@@ -1,167 +0,0 @@
-#!/usr/bin/env python
-#-*- coding:utf-8 -*-
-
-#  Copyright (C) 2010-2018  CEA/DEN
-#
-#  This library is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU Lesser General Public
-#  License as published by the Free Software Foundation; either
-#  version 2.1 of the License.
-#
-#  This library is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-#  Lesser General Public License for more details.
-#
-#  You should have received a copy of the GNU Lesser General Public
-#  License along with this library; if not, write to the Free Software
-#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
-
-import os
-import sys
-import shutil
-import unittest
-
-from src.salomeTools import Sat
-import src.product
-from unittestpy.tools import outRedirection
-
-class TestCase(unittest.TestCase):
-    """Test of the patch command"""
-
-    def test_010(self):
-        # Test the patch command with a product in dev mode
-        OK = 'KO'
-
-        appli = 'appli-test'
-        product_name = 'PRODUCT_DEV'
-
-        sat = Sat("-oUSER.output_level=2")
-               
-        sat.config(appli)
-        
-        expected_src_dir = src.product.get_product_config(sat.cfg, product_name).source_dir
-        expected_file_path = os.path.join(expected_src_dir, 'my_test_file.txt')
-        expected_text = 'HELLO WORLD\n'
-        
-        if os.path.exists(expected_src_dir):
-            shutil.rmtree(expected_src_dir)
-        
-        sat.source(appli + ' --product ' + product_name)
-        
-        f = open(expected_file_path, 'r')
-        text = f.readlines()[0]
-        OK1 = 'KO'
-        if text == expected_text:
-            OK1 = 'OK'
-       
-        sat.patch(appli + ' --product ' + product_name)
-        
-        new_expected_text = 'HELLO WORLD MODIFIED\n'
-        f = open(expected_file_path, 'r')
-        text = f.readlines()[0]
-        
-        OK2 = 'KO'
-        if text == new_expected_text:
-            OK2 = 'OK'         
-
-        if (OK1, OK2)==('OK', 'OK'):
-            OK = 'OK'
-        self.assertEqual(OK, 'OK')
-
-    def test_020(self):
-        # Test the patch command with a product with no sources found
-        OK = 'KO'
-
-        appli = 'appli-test'
-        product_name = 'PRODUCT_DEV'
-
-        sat = Sat('')
-        sat.config(appli)
-        
-        expected_src_dir = src.product.get_product_config(sat.cfg, product_name).source_dir
-        
-        if os.path.exists(expected_src_dir):
-            shutil.rmtree(expected_src_dir)
-               
-        # output redirection
-        my_out = outRedirection()
-        
-        sat.patch(appli + ' --product ' + product_name)
-        
-        # stop output redirection
-        my_out.end_redirection()
-
-        # get results
-        res = my_out.read_results()
-        
-        if "No sources found for the " + product_name +" product" in res:
-            OK = 'OK'
-        self.assertEqual(OK, 'OK')
-
-    def test_030(self):
-        # Test the patch command with a product without patch
-        OK = 'KO'
-
-        appli = 'appli-test'
-        product_name = 'PRODUCT_ARCHIVE'
-
-        sat = Sat('-v4')
-                      
-        sat.source(appli + ' --product ' + product_name)
-               
-        # output redirection
-        my_out = outRedirection()
-        
-        sat.patch(appli + ' --product ' + product_name)
-        
-        # stop output redirection
-        my_out.end_redirection()
-
-        # get results
-        res = my_out.read_results()
-        
-        if "No patch for the " + product_name +" product" in res:
-            OK = 'OK'
-        self.assertEqual(OK, 'OK')
-
-    def test_040(self):
-        # Test the patch command with a product with a not valid patch
-        OK = 'KO'
-
-        appli = 'appli-test'
-        product_name = 'PRODUCT_DEV'
-
-        sat = Sat("-oPRODUCTS.PRODUCT_DEV.default.patches=['/']")
-                      
-        sat.source(appli + ' --product ' + product_name)
-               
-        # output redirection
-        my_out = outRedirection()
-        
-        sat.patch(appli + ' --product ' + product_name)
-        
-        # stop output redirection
-        my_out.end_redirection()
-
-        # get results
-        res = my_out.read_results()
-        
-        if "Not a valid patch" in res:
-            OK = 'OK'
-        self.assertEqual(OK, 'OK')
-
-    def test_050(self):
-        # Test the sat -h patch
-        OK = "KO"
-
-        import patch
-        
-        if "The patch command apply the patches on the sources of" in patch.description():
-            OK = "OK"
-        self.assertEqual(OK, "OK")
-
-# test launch
-if __name__ == '__main__':
-    unittest.main()
-    pass
diff --git a/test/prepare/test_prepare.py b/test/prepare/test_prepare.py
deleted file mode 100755 (executable)
index 3340547..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-#!/usr/bin/env python
-#-*- coding:utf-8 -*-
-
-#  Copyright (C) 2010-2018  CEA/DEN
-#
-#  This library is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU Lesser General Public
-#  License as published by the Free Software Foundation; either
-#  version 2.1 of the License.
-#
-#  This library is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-#  Lesser General Public License for more details.
-#
-#  You should have received a copy of the GNU Lesser General Public
-#  License along with this library; if not, write to the Free Software
-#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
-
-import os
-import sys
-import shutil
-import unittest
-
-import src
-from src.salomeTools import Sat
-
-class TestCase(unittest.TestCase):
-    """Test of the prepare command"""
-
-    def test_010(self):
-        # Test the prepare command with a product in dev mode
-        OK = 'KO'
-
-        appli = 'appli-test'
-        product_name = 'PRODUCT_DEV'
-
-        sat = Sat()
-               
-        sat.config(appli)
-        
-        expected_src_dir = src.product.get_product_config(sat.cfg, product_name).source_dir
-        expected_file_path = os.path.join(expected_src_dir, 'my_test_file.txt')
-        expected_text = 'HELLO WORLD\n'
-        
-        if os.path.exists(expected_src_dir):
-            shutil.rmtree(expected_src_dir)
-        
-        sat.prepare(appli + ' --product ' + product_name)
-        
-        f = open(expected_file_path, 'r')
-        text = f.readlines()[0]
-        if text == expected_text:
-            OK = 'OK'
-        self.assertEqual(OK, 'OK')
-
-    def test_020(self):
-        # Test the prepare command with all products
-        OK = 'KO'
-
-        appli = 'appli-test'
-        product_name = 'PRODUCT_DEV'
-
-        sat = Sat()
-        sat.config(appli)
-        
-        expected_src_dir = src.product.get_product_config(sat.cfg, product_name).source_dir
-        expected_file_path = os.path.join(expected_src_dir, 'my_test_file.txt')
-        expected_text = 'HELLO WORLD\n'
-        
-        if os.path.exists(expected_src_dir):
-            shutil.rmtree(expected_src_dir)
-        
-        sat.prepare(appli)
-        
-        f = open(expected_file_path, 'r')
-        text = f.readlines()[0]
-        if text == expected_text:
-            OK = 'OK'
-        self.assertEqual(OK, 'OK')
-
-    def test_030(self):
-        # Test the prepare command with all products
-        OK = 'KO'
-
-        appli = 'appli-test'
-
-        sat = Sat()
-        sat.config(appli)
-       
-        try:
-            sat.prepare(appli + " --force --force_patch")
-            OK = 'OK'
-        except:
-            pass
-        self.assertEqual(OK, 'OK')
-
-    def test_040(self):
-        # Test the sat -h prepare
-        OK = "KO"
-
-        import prepare
-        
-        if "The prepare command gets the sources" in prepare.description():
-            OK = "OK"
-        self.assertEqual(OK, "OK")
-
-# test launch
-if __name__ == '__main__':
-    unittest.main()
-    pass
diff --git a/test/prepare/test_source.py b/test/prepare/test_source.py
deleted file mode 100755 (executable)
index f7a053d..0000000
+++ /dev/null
@@ -1,175 +0,0 @@
-#!/usr/bin/env python
-#-*- coding:utf-8 -*-
-
-#  Copyright (C) 2010-2018  CEA/DEN
-#
-#  This library is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU Lesser General Public
-#  License as published by the Free Software Foundation; either
-#  version 2.1 of the License.
-#
-#  This library is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-#  Lesser General Public License for more details.
-#
-#  You should have received a copy of the GNU Lesser General Public
-#  License along with this library; if not, write to the Free Software
-#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
-
-import os
-import sys
-import unittest
-
-from src.salomeTools import Sat
-import src.product
-from unittestpy.tools import outRedirection
-
-class TestCase(unittest.TestCase):
-    """Test of the source command"""
-    
-    def test_010(self):
-        # Test the source command with archive product
-        appli = 'appli-test'
-        product_name = 'PRODUCT_ARCHIVE'
-
-        sat = Sat()
-        sat.source(appli + ' --product ' + product_name)
-
-        expected_src_dir = src.product.get_product_config(sat.cfg, product_name).source_dir
-        expected_file_path = os.path.join(expected_src_dir, 'my_test_file.txt')
-        expected_text = 'HELLO WORLD\n'
-
-        f = open(expected_file_path, 'r')
-        text = f.read()
-        self.assertEqual(text, expected_text)
-        
-    def test_020(self):
-        # Test the source command with git product
-        appli = 'appli-test'
-        product_name = 'PRODUCT_GIT'
-
-        sat = Sat()
-        sat.source(appli + ' --product ' + product_name)
-
-        expected_src_dir = src.product.get_product_config(sat.cfg, product_name).source_dir
-        expected_file_path = os.path.join(expected_src_dir, 'my_test_file.txt')
-        expected_text = 'HELLO WORLD\n'
-
-        f = open(expected_file_path, 'r')
-        text = f.read()
-        self.assertEqual(text, expected_text)
-
-    def test_030(self):
-        # Test the source command with cvs product
-        appli = 'appli-test'
-        product_name = 'PRODUCT_CVS'
-
-        sat = Sat()
-        sat.source(appli + ' --product ' + product_name)
-
-        expected_src_dir = src.product.get_product_config(sat.cfg, product_name).source_dir
-        expected_file_path = os.path.join(expected_src_dir, 'README.FIRST.txt')
-        expected_text = 'Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE\n'
-
-        f = open(expected_file_path, 'r')
-        text = f.readlines()[0]
-
-        # pyunit method to compare 2 str
-        self.assertEqual(text, expected_text)
-    
-    """
-    def test_040(self):
-        # Test the source command with svn product
-        OK = 'KO'
-        
-        appli = 'appli-test'
-        product_name = 'PRODUCT_SVN'
-
-        sat = Sat()
-        sat.source(appli + ' --product ' + product_name)
-
-        expected_src_dir = src.product.get_product_config(sat.cfg, product_name).source_dir
-        expected_file_path = os.path.join(expected_src_dir, 'scripts', 'README')
-        expected_text = 'this directory contains scripts used by salomeTool'
-
-        f = open(expected_file_path, 'r')
-        text = f.readlines()[0]
-        
-        if expected_text in text:
-            OK = 'OK'
-         
-        # pyunit method to compare 2 str
-        self.assertEqual(OK, 'OK')
-    """
-
-    def test_050(self):
-        # Test the source command with native product
-        OK = 'KO'
-        
-        appli = 'appli-test'
-        product_name = 'PRODUCT_NATIVE'
-
-        sat = Sat()
-        sat.source(appli + ' --product ' + product_name)
-
-        expected_src_dir = os.path.join(sat.cfg.APPLICATION.workdir, 'SOURCES', product_name)
-        if not os.path.exists(expected_src_dir):
-            OK = 'OK'
-        self.assertEqual(OK, 'OK')
-
-    def test_060(self):
-        # Test the source command with fixed product
-        OK = 'KO'
-        
-        appli = 'appli-test'
-        product_name = 'PRODUCT_FIXED'
-
-        sat = Sat()
-        sat.source(appli + ' --product ' + product_name)
-
-        expected_src_dir = src.product.get_product_config(sat.cfg, product_name).install_dir
-
-        if os.path.exists(expected_src_dir):
-            OK = 'OK'
-        self.assertEqual(OK, 'OK')
-
-    """
-    def test_070(self):
-        # Test the source command with unknown product
-        OK = 'KO'
-
-        # output redirection
-        my_out = outRedirection()
-
-        appli = 'appli-test'
-        product_name = 'PRODUCT_UNKNOWN'
-
-        sat = Sat()
-        sat.source(appli + ' --product ' + product_name)
-
-        # stop output redirection
-        my_out.end_redirection()
-
-        # get results
-        res = my_out.read_results()
-
-        if "Unknown get source method" in res:
-            OK = 'OK'
-        self.assertEqual(OK, 'OK')
-    """
-
-    def test_080(self):
-        # Test the sat -h source
-        OK = "KO"
-
-        import source
-        
-        if "gets the sources of the application" in source.description():
-            OK = "OK"
-        self.assertEqual(OK, "OK")
-
-# test launch
-if __name__ == '__main__':
-    unittest.main()
-    pass
diff --git a/test/run_all.sh b/test/run_all.sh
deleted file mode 100755 (executable)
index 5905725..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-#!/usr/bin/env bash
-#-*- coding:utf-8 -*-
-
-#  Copyright (C) 2010-2018  CEA/DEN
-#
-#  This library is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU Lesser General Public
-#  License as published by the Free Software Foundation; either
-#  version 2.1 of the License.
-#
-#  This library is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-#  Lesser General Public License for more details.
-#
-#  You should have received a copy of the GNU Lesser General Public
-#  License along with this library; if not, write to the Free Software
-#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
-
-echo "TODO: OBSOLETE: to set as python script, may be"
-echo "Begin date:"
-date
-echo
-echo "Remove old results ... "
-rm -rf .coverage htmlcov
-echo "Done"
-echo
-echo "****************************"
-coverage run --source=../commands/config.py    config/option_value.py > test_res.html
-coverage run --source=../commands/config.py -a config/option_value_2.py >> test_res.html
-coverage run --source=../commands/config.py -a config/create_user_pyconf.py >> test_res.html
-coverage run --source=../commands/config.py -a config/option_copy.py >> test_res.html
-coverage run --source=../commands/config.py -a config/option_edit.py >> test_res.html
-coverage run --source=../commands/config.py,../commands/log.py,../src/xmlManager.py,../src/logger.py -a log/launch_browser.py >> test_res.html
-coverage run --source=../commands/config.py,../commands/log.py,../src/xmlManager.py,../src/logger.py -a log/launch_browser2.py >> test_res.html
-coverage run --source=../commands/config.py,../commands/source.py,../commands/patch.py,../commands/prepare.py -a prepare/test_source.py >> test_res.html
-coverage run --source=../commands/config.py,../commands/source.py,../commands/patch.py,../commands/prepare.py -a prepare/test_patch.py >> test_res.html
-coverage run --source=../commands/config.py,../commands/source.py,../commands/patch.py,../commands/prepare.py -a prepare/test_prepare.py >> test_res.html
-coverage run --source=../commands/config.py,../commands/source.py,../commands/patch.py,../commands/prepare.py,../commands/clean.py -a prepare/test_clean.py >> test_res.html
-coverage run --source=../commands/config.py,../commands/environ.py -a environ/test_environ.py >> test_res.html
-coverage run --source=../commands/config.py,../commands/configure.py,../commands/environ.py -a compilation/test_configure.py >> test_res.html
-coverage run --source=../commands/config.py,../commands/make.py,../commands/environ.py -a compilation/test_make.py >> test_res.html
-coverage run --source=../commands/config.py,../commands/makeinstall.py,../commands/environ.py -a compilation/test_makeinstall.py >> test_res.html
-coverage run --source=../commands/config.py,../commands/compile.py,../commands/configure.py,../commands/make.py,../commands/makeinstall.py,../commands/environ.py -a compilation/test_compilation.py >> test_res.html
-coverage run --source=../commands/shell.py -a shell/test_shell.py >> test_res.html
-coverage run --source=../commands/job.py -a job/test_job.py >> test_res.html
-coverage run --source=../commands/jobs.py -a jobs/test_jobs.py >> test_res.html
-coverage run --source=../commands/test.py,../src/test_module.py,../src/fork.py -a test/test_command.py >> test_res.html
-echo "****************************"
-echo
-echo "building html coverage"
-coverage html
-echo "Done"
-echo
-echo "End date:"
-date
-echo
-
-#firefox test_res.html htmlcov/index.html
diff --git a/test/shell/test_shell.py b/test/shell/test_shell.py
deleted file mode 100755 (executable)
index 80f579e..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-#!/usr/bin/env python
-#-*- coding:utf-8 -*-
-
-#  Copyright (C) 2010-2018  CEA/DEN
-#
-#  This library is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU Lesser General Public
-#  License as published by the Free Software Foundation; either
-#  version 2.1 of the License.
-#
-#  This library is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-#  Lesser General Public License for more details.
-#
-#  You should have received a copy of the GNU Lesser General Public
-#  License along with this library; if not, write to the Free Software
-#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
-
-import os
-import sys
-import unittest
-
-from src.salomeTools import Sat
-
-class TestCase(unittest.TestCase):
-    """Test of the shell command"""
-
-    def test_010(self):
-        # Test the shell command with the --command option
-        OK = 'KO'
-        tmp_file = "/tmp/test.txt"
-
-        sat = Sat("-l " + tmp_file)
-        
-        sat.config()
-        sat_way = sat.cfg.VARS.salometoolsway
-        
-        # Execute the shell command
-        sat.shell("--command ls " + sat_way)
-
-        ff = open(tmp_file, "r")
-        log_files = ff.readlines()
-        ff.close()
-        os.remove(tmp_file)
-        log_files = [line.replace("\n", "") for line in log_files]
-        
-        text = open(log_files[2], "r").read()
-
-        if "salomeTools.py" in text:
-            OK = 'OK'         
-        self.assertEqual(OK, 'OK')
-
-    def test_020(self):
-        # Test the shell command with the --command option with a failing command
-        OK = 'KO'
-        tmp_file = "/tmp/test.txt"
-
-        sat = Sat("-l " + tmp_file)
-        
-        sat.config()
-        
-        # Execute the shell command
-        res = sat.shell("--command i_fail")
-
-        ff = open(tmp_file, "r")
-        log_files = ff.readlines()
-        ff.close()
-        os.remove(tmp_file)
-        log_files = [line.replace("\n", "") for line in log_files]
-        
-        text = open(log_files[2], "r").read()
-
-        if "i_fail" in text and res == 1:
-            OK = 'OK'         
-        self.assertEqual(OK, 'OK')
-
-    def test_030(self):
-        # Test the sat -h shell
-        OK = "KO"
-
-        import shell
-        
-        if "Executes the shell command passed as argument" in shell.description():
-            OK = "OK"
-        self.assertEqual(OK, "OK")
-
-# test launch
-if __name__ == '__main__':
-    unittest.main()
-    pass
diff --git a/test/test/test_command.py b/test/test/test_command.py
deleted file mode 100755 (executable)
index 136df62..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-#!/usr/bin/env python
-#-*- coding:utf-8 -*-
-
-#  Copyright (C) 2010-2018  CEA/DEN
-#
-#  This library is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU Lesser General Public
-#  License as published by the Free Software Foundation; either
-#  version 2.1 of the License.
-#
-#  This library is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-#  Lesser General Public License for more details.
-#
-#  You should have received a copy of the GNU Lesser General Public
-#  License along with this library; if not, write to the Free Software
-#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
-
-import os
-import sys
-import unittest
-
-from src.salomeTools import Sat
-
-class TestTest(unittest.TestCase):
-    """Test of the test command"""
-
-    def test_010(self):
-        # Test the test command
-        OK = 'KO'
-        tmp_file = "/tmp/test.txt"
-        application = "SALOME-7.8.0"
-
-        sat = Sat("-l " + tmp_file)
-        
-        # Execute the job command
-        sat.test(application + " --grid GEOM --session light" )
-
-        ff = open(tmp_file, "r")
-        log_files = ff.readlines()
-        ff.close()
-        os.remove(tmp_file)
-        log_testboard = [line.replace("\n", "") for line in log_files if 'testboard.xml' in line]
-        
-        text = open(log_testboard[0], "r").read()
-
-        if '<session name="light">' in text:
-            OK = 'OK'         
-        self.assertEqual(OK, 'OK')
-
-    def test_020(self):
-        # Test the test command with PY type
-        OK = 'KO'
-        tmp_file = "/tmp/test.txt"
-        application = "SALOME-7.8.0"
-
-        sat = Sat("-l " + tmp_file)
-        
-        # Execute the job command
-        sat.test(application + " --grid MED --session PY_test_withKernel" )
-
-        ff = open(tmp_file, "r")
-        log_files = ff.readlines()
-        ff.close()
-        os.remove(tmp_file)
-        log_testboard = [line.replace("\n", "") for line in log_files if 'testboard.xml' in line]
-        
-        text = open(log_testboard[0], "r").read()
-
-        if '<session name="PY_test_withKernel">' in text:
-            OK = 'OK'         
-        self.assertEqual(OK, 'OK')
-
-    def test_030(self):
-        # Test the sat -h test
-        OK = "KO"
-
-        import test
-        
-        if "The test command runs a test base on a SALOME installation" in test.description():
-            OK = "OK"
-        self.assertEqual(OK, "OK")
-
-# test launch
-if __name__ == '__main__':
-    unittest.main()
-    pass
diff --git a/test/test_020_debug.py b/test/test_020_debug.py
new file mode 100755 (executable)
index 0000000..27e46ef
--- /dev/null
@@ -0,0 +1,126 @@
+#!/usr/bin/env python
+#-*- coding:utf-8 -*-
+
+#  Copyright (C) 2010-2018  CEA/DEN
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2.1 of the License.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+import os
+import sys
+import unittest
+
+import src.debug as DBG # Easy print stderr (for DEBUG only)
+import src.pyconf as PYF # 0.3.7
+import config_0_3_9.config as PYF9 # TODO 0.3.9
+
+_EXAMPLES = {
+1 : """\
+  messages:
+  [
+    {
+      stream : "sys.stderr" # modified
+      message: 111 # modified
+      name: 'Harry'
+    }
+    {
+      stream : $messages[0].stream
+      message: 1.23e4 # modified do not work 0.3.7
+      name: 'Ruud'
+    }
+    {
+      stream : "HELLO " + $messages[0].stream
+      message: 'Bienvenue'
+      name: "Yves"
+    }
+  ]
+""",
+
+2 : """\
+  aa: 111
+  bb: $aa + 222
+""",
+
+3 : """\
+  aa: Yves
+  bb: "Herve" # avoid Hervé -> 'utf8' codec can't decode byte
+""",
+
+4 : """\
+  aa: Yves
+  bb: "Hervé" # avoid Hervé -> 'utf8' codec can't decode byte
+""",
+
+
+}
+
+
+class TestCase(unittest.TestCase):
+  "Test the debug.py"""
+  
+  def test_000(self):
+    # one shot setUp() for this TestCase
+    # DBG.push_debug(True)
+    # SAT.setNotLocale() # test english
+    return
+    
+  def test_005(self):
+    res = DBG.getLocalEnv()
+    self.assertTrue(len(res.split()) > 0)
+    self.assertTrue("USER :" in res)
+    self.assertTrue("LANG :" in res)
+       
+  def test_010(self):
+    inStream = DBG.InStream(_EXAMPLES[1])
+    self.assertEqual(inStream.getvalue(), _EXAMPLES[1])
+    cfg = PYF.Config(inStream)
+    self.assertEqual(len(cfg.messages), 3)
+    outStream = DBG.OutStream()
+    DBG.saveConfigStd(cfg, outStream)
+    res = outStream.value
+    DBG.write("test_010 cfg std", res)
+    self.assertTrue("messages :" in res)
+    self.assertTrue("'sys.stderr'" in res)
+    
+  def test_020(self):
+    inStream = DBG.InStream(_EXAMPLES[2])
+    cfg = PYF.Config(inStream)
+    res = DBG.getStrConfigDbg(cfg)
+    DBG.write("test_020 cfg dbg", res)
+    ress = res.split("\n")
+    self.assertTrue(".aa : '111'" in ress[0])
+    self.assertTrue(".bb : $aa + 222 --> '333'" in ress[1])
+    
+  def test_025(self):
+    inStream = DBG.InStream(_EXAMPLES[1])
+    cfg = PYF.Config(inStream)
+    outStream = DBG.OutStream()
+    DBG.saveConfigDbg(cfg, outStream)
+    res = outStream.value
+    DBG.write("test_025 cfg dbg", res)
+    for i in range(len(cfg.messages)):
+      self.assertTrue("messages[%i].name" % i in res)
+    self.assertTrue("--> 'HELLO sys.stderr'" in res)
+
+      
+  def test_999(self):
+    # one shot tearDown() for this TestCase
+    # SAT.setLocale() # end test english
+    # DBG.pop_debug()
+    return
+    
+if __name__ == '__main__':
+    unittest.main(exit=False)
+    pass
+
diff --git a/test/test_025_pyconf.py b/test/test_025_pyconf.py
new file mode 100755 (executable)
index 0000000..8d1107f
--- /dev/null
@@ -0,0 +1,151 @@
+#!/usr/bin/env python
+#-*- coding:utf-8 -*-
+
+#  Copyright (C) 2010-2018  CEA/DEN
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2.1 of the License.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+import os
+import sys
+import unittest
+
+import src.debug as DBG # Easy print stderr (for DEBUG only)
+import src.pyconf as PYF # 0.3.7
+import config_0_3_9.config as PYF9 # TODO 0.3.9
+
+_EXAMPLES = {
+1 : """\
+  messages:
+  [
+    {
+      stream : "sys.stderr" # modified
+      message: 'Welcome'
+      name: 'Harry'
+    }
+    {
+      stream : "sys.stdout" # modified
+      message: 'Welkom'
+      name: 'Ruud'
+    }
+    {
+      stream : $messages[0].stream
+      message: 'Bienvenue'
+      name: "Yves"
+    }
+  ]
+""",
+
+2 : """\
+  aa: 111
+  bb: $aa + 222
+""",
+
+3 : """\
+  aa: Yves
+  bb: "Herve" # avoid Hervé -> 'utf8' codec can't decode byte
+""",
+
+4 : """\
+  aa: Yves
+  bb: "Hervé" # avoid Hervé -> 'utf8' codec can't decode byte
+""",
+
+
+}
+
+
+class TestCase(unittest.TestCase):
+  "Test the pyconf.py"""
+  
+  def test_000(self):
+    # one shot setUp() for this TestCase
+    # DBG.push_debug(True)
+    # SAT.setNotLocale() # test english
+    return
+
+  def test_010(self):
+    # pyconf.py doc example 0.3.7
+    # https://www.red-dove.com/config-doc/ is 0.3.9 !
+    # which, when run, would yield the console output:
+
+    expected = """\
+Welcome, Harry
+Welkom, Ruud
+Bienvenue, Yves
+"""
+    inStream = DBG.InStream(_EXAMPLES[1])
+    cfg = PYF.Config(inStream)
+    res = ''
+    for m in cfg.messages:
+        res += '%s, %s\n' % (m.message, m.name)
+    self.assertEqual(res, expected)
+    outStream = DBG.OutStream()
+    cfg.__save__(outStream) # sat renamed save() in __save__()
+    res = outStream.value
+    DBG.write("test_010 cfg", res)
+    self.assertTrue("name : 'Harry'" in res)
+    self.assertTrue("name : 'Ruud'" in res)
+    self.assertTrue("name : 'Yves'" in res)
+        
+  def test_020(self):
+    cfg = PYF.Config()
+    self.assertEqual(str(cfg), '{}')
+    self.assertEqual(cfg.__repr__(), '{}')
+    cfg.aa = "1111"
+    self.assertEqual(str(cfg), "{'aa': '1111'}")
+    cfg.bb = 2222
+    self.assertTrue("'bb': 2222" in str(cfg))
+    self.assertTrue("'aa': '1111'" in str(cfg))
+    cfg.cc = 3333.
+    self.assertTrue("'cc': 3333." in str(cfg))
+    
+  def test_030(self):
+    inStream = DBG.InStream(_EXAMPLES[2])
+    cfg = PYF.Config(inStream)
+    self.assertEqual(str(cfg),  "{'aa': 111, 'bb': $aa + 222}")
+    self.assertEqual(cfg.aa, 111)
+    self.assertEqual(cfg.bb, 333)
+      
+  def test_040(self):
+    inStream = DBG.InStream(_EXAMPLES[3])
+    cfg = PYF.Config(inStream)
+    self.assertEqual(cfg.aa, "Yves")
+    self.assertEqual(cfg.bb, "Herve")
+    self.assertEqual(type(cfg.bb), str)
+    cfg.bb = "Hervé" # try this
+    self.assertEqual(type(cfg.bb), str)
+    self.assertEqual(cfg.bb, "Hervé")
+    
+  def test_045(self):
+    """TODO: make Hervé valid with pyconf.py as 0.3.9"""
+    inStream = DBG.InStream(_EXAMPLES[4])
+    cfg = PYF9.Config(inStream)
+    outStream = DBG.OutStream()
+    cfg.save(outStream) # sat renamed save() in __save__()
+    res = outStream.value
+    DBG.write("test_045 cfg", res)
+    self.assertTrue("aa : 'Yves'" in res)
+    self.assertTrue(r"bb : 'Herv\xc3\xa9'" in res)
+    self.assertEqual(cfg.bb, "Hervé")
+      
+  def test_999(self):
+    # one shot tearDown() for this TestCase
+    # SAT.setLocale() # end test english
+    # DBG.pop_debug()
+    return
+    
+if __name__ == '__main__':
+    unittest.main(exit=False)
+    pass
diff --git a/test/test_030_pyconf_0_3_9.py b/test/test_030_pyconf_0_3_9.py
new file mode 100755 (executable)
index 0000000..209d622
--- /dev/null
@@ -0,0 +1,455 @@
+#!/usr/bin/env python
+#-*- coding:utf-8 -*-
+
+# Copyright 2004-2010 by Vinay Sajip. All Rights Reserved.
+#
+# Permission to use, copy, modify, and distribute this software and its
+# documentation for any purpose and without fee is hereby granted,
+# provided that the above copyright notice appear in all copies and that
+# both that copyright notice and this permission notice appear in
+# supporting documentation, and that the name of Vinay Sajip
+# not be used in advertising or publicity pertaining to distribution
+# of the software without specific, written prior permission.
+# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+"""
+Test harness for the configuration module 'config' for Python.
+
+from test_config 0.3.9 modified to test 0.3.7.1
+this test obviously have FAILED (errors=6), 
+TODO, fix upgrading 0.3.9, or not.
+"""
+
+import unittest
+# import test_support
+import src.pyconf as config
+from src.pyconf import Config, ConfigMerger, ConfigList
+from src.pyconf import ConfigError, ConfigFormatError, ConfigResolutionError
+import logging
+from StringIO import StringIO
+
+STREAMS = {
+    "simple_1" :
+"""
+message: 'Hello, world!'
+""",
+    "malformed_1" :
+"""
+123
+""",
+    "malformed_2" :
+"""
+[ 123, 'abc' ]
+""",
+    "malformed_3" :
+"""
+{ a : 7, b : 1.3, c : 'test' }
+""",
+    "malformed_4" :
+"""
+test: $a [7] # note space before bracket
+""",
+    "malformed_5" :
+"""
+test: 'abc'
+test: 'def'
+""",
+    "wellformed_1" :
+"""
+test: $a[7] # note no space before bracket
+""",
+    "boolean_1":
+"""
+test : False
+another_test: True
+""",
+    "boolean_2":
+"""
+test : false
+another_test: true
+""",
+    "none_1":
+"""
+test : None
+""",
+    "none_2":
+"""
+test : none
+""",
+    "number_1":
+"""
+root: 1
+stream: 1.7
+neg: -1
+negfloat: -2.0
+posexponent: 2.0999999e-08
+negexponent: -2.0999999e-08
+exponent: 2.0999999e08
+""",
+    "sequence_1":
+"""
+mixed: [ "VALIGN", [ 0, 0 ], [ -1, -1 ], "TOP" ]
+simple: [1, 2]
+nested: [1, [2, 3], [4, [5, 6]]]
+""",
+    "include_1":
+"""
+included: @'include_2'
+""",
+    "include_2":
+"""
+test: 123
+another_test: 'abc'
+""",
+    "expr_1":
+"""
+value1 : 10
+value2 : 5
+value3 : 'abc'
+value4 : 'ghi'
+value5 : 0
+value6 : { 'a' : $value1, 'b': $value2 }
+derived1 : $value1 + $value2
+derived2 : $value1 - $value2
+derived3 : $value1 * $value2
+derived4 : $value1 / $value2
+derived5 : $value1 % $value2
+derived6 : $value3 + $value4
+derived7 : $value3 + 'def' + $value4
+derived8 : $value3 - $value4 # meaningless
+derived9 : $value1 / $value5    # div by zero
+derived10 : $value1 % $value5   # div by zero
+derived11 : $value17    # doesn't exist
+derived12 : $value6.a + $value6.b
+""",
+    "eval_1":
+"""
+stderr : `sys.stderr`
+stdout : `sys.stdout`
+stdin : `sys.stdin`
+debug : `debug`
+DEBUG : `DEBUG`
+derived: $DEBUG * 10
+""",
+    "merge_1":
+"""
+value1: True
+value3: [1, 2, 3]
+value5: [ 7 ]
+value6: { 'a' : 1, 'c' : 3 }
+""",
+    "merge_2":
+"""
+value2: False
+value4: [4, 5, 6]
+value5: ['abc']
+value6: { 'b' : 2, 'd' : 4 }
+""",
+    "merge_3":
+"""
+value1: True
+value2: 3
+value3: [1, 3, 5]
+value4: [1, 3, 5]
+""",
+    "merge_4":
+"""
+value1: False
+value2: 4
+value3: [2, 4, 6]
+value4: [2, 4, 6]
+""",
+    "list_1":
+"""
+verbosity : 1
+""",
+    "list_2":
+"""
+verbosity : 2
+program_value: 4
+""",
+    "list_3":
+"""
+verbosity : 3
+suite_value: 5
+""",
+    "get_1":
+"""
+value1 : 123
+value2 : 'abcd'
+value3 : True
+value4 : None
+value5:
+{
+    value1 : 123
+    value2 : 'abcd'
+    value3 : True
+    value4 : None
+}
+""",
+    "multiline_1":
+"""
+value1: '''Value One
+Value Two
+'''
+value2: \"\"\"Value Three
+Value Four\"\"\"
+"""
+}
+
+def makeStream(name):
+    s = StringIO(STREAMS[name])
+    s.name = name
+    return s
+
+class OutStream(StringIO):
+    def close(self):
+        self.value = self.getvalue()
+        StringIO.close(self)
+
+class TestConfig(unittest.TestCase):
+
+    def setUp(self):
+        self.cfg = Config(None)
+
+    def tearDown(self):
+        del self.cfg
+
+    def testCreation(self):
+        self.assertEqual(0, len(self.cfg))  # should be empty
+
+    def testSimple(self):
+        self.cfg.load(makeStream("simple_1"))
+        self.failUnless('message' in self.cfg)
+        self.failIf('root' in self.cfg)
+        self.failIf('stream' in self.cfg)
+        self.failIf('load' in self.cfg)
+        self.failIf('save' in self.cfg)
+
+    def testValueOnly(self):
+        self.assertRaises(ConfigError, self.cfg.load,
+           makeStream("malformed_1"))
+        self.assertRaises(ConfigError, self.cfg.load,
+           makeStream("malformed_2"))
+        self.assertRaises(ConfigError, self.cfg.load,
+           makeStream("malformed_3"))
+
+    def testBadBracket(self):
+        self.assertRaises(ConfigError, self.cfg.load,
+           makeStream("malformed_4"))
+
+    def testDuplicate(self):
+        self.assertRaises(ConfigError, self.cfg.load,
+           makeStream("malformed_5"))
+
+    def testGoodBracket(self):
+        self.cfg.load(makeStream("wellformed_1"))
+
+    def testBoolean(self):
+        self.cfg.load(makeStream("boolean_1"))
+        self.assertEqual(True, self.cfg.another_test)
+        self.assertEqual(False, self.cfg.test)
+
+    def testNotBoolean(self):
+        self.cfg.load(makeStream("boolean_2"))
+        self.assertEqual('true', self.cfg.another_test)
+        self.assertEqual('false', self.cfg.test)
+
+    def testNone(self):
+        self.cfg.load(makeStream("none_1"))
+        self.assertEqual(None, self.cfg.test)
+
+    def testNotNone(self):
+        self.cfg.load(makeStream("none_2"))
+        self.assertEqual('none', self.cfg.test)
+
+    def testNumber(self):
+        self.cfg.load(makeStream("number_1"))
+        self.assertEqual(1, self.cfg.root)
+        self.assertEqual(1.7, self.cfg.stream)
+        self.assertEqual(-1, self.cfg.neg)
+        self.assertEqual(-2.0, self.cfg.negfloat)
+        self.assertAlmostEqual(-2.0999999e-08, self.cfg.negexponent)
+        self.assertAlmostEqual(2.0999999e-08, self.cfg.posexponent)
+        self.assertAlmostEqual(2.0999999e08, self.cfg.exponent)
+
+    def testChange(self):
+        self.cfg.load(makeStream("simple_1"))
+        self.cfg.message = 'Goodbye, cruel world!'
+        self.assertEqual('Goodbye, cruel world!', self.cfg.message)
+
+    def testSave(self):
+        self.cfg.load(makeStream("simple_1"))
+        self.cfg.message = 'Goodbye, cruel world!'
+        out = OutStream()
+        self.cfg.save(out)
+        self.assertEqual("message : 'Goodbye, cruel world!'" + config.NEWLINE,
+           out.value)
+
+    def testInclude(self):
+        config.streamOpener = makeStream
+        self.cfg = Config("include_1")
+        config.streamOpener = config.defaultStreamOpener
+        out = OutStream()
+        self.cfg.save(out)
+        s = "included :%s{%s  test : 123%s  another_test : 'abc'%s}%s" % (5 *
+           (config.NEWLINE,))
+        self.assertEqual(s, out.value)
+
+    def testExpression(self):
+        self.cfg.load(makeStream("expr_1"))
+        self.assertEqual(15, self.cfg.derived1)
+        self.assertEqual(5, self.cfg.derived2)
+        self.assertEqual(50, self.cfg.derived3)
+        self.assertEqual(2, self.cfg.derived4)
+        self.assertEqual(0, self.cfg.derived5)
+        self.assertEqual('abcghi', self.cfg.derived6)
+        self.assertEqual('abcdefghi', self.cfg.derived7)
+        self.assertRaises(TypeError, lambda x: x.derived8, self.cfg)
+        self.assertRaises(ZeroDivisionError, lambda x: x.derived9, self.cfg)
+        self.assertRaises(ZeroDivisionError, lambda x: x.derived10, self.cfg)
+        self.assertRaises(ConfigResolutionError,
+           lambda x: x.derived11, self.cfg)
+        self.assertEqual(15, self.cfg.derived12)
+
+    def testEval(self):
+        import sys, logging
+        self.cfg.load(makeStream("eval_1"))
+        self.assertEqual(sys.stderr, self.cfg.stderr)
+        self.assertEqual(sys.stdout, self.cfg.stdout)
+        self.assertEqual(sys.stdin, self.cfg.stdin)
+        self.assertRaises(ConfigResolutionError, lambda x: x.debug, self.cfg)
+        self.cfg.addNamespace(logging.Logger)
+        self.assertEqual(logging.Logger.debug.im_func, self.cfg.debug)
+        self.assertRaises(ConfigResolutionError, lambda x: x.DEBUG, self.cfg)
+        self.cfg.addNamespace(logging)
+        self.assertEqual(logging.DEBUG, self.cfg.DEBUG)
+        self.cfg.removeNamespace(logging.Logger)
+        self.assertEqual(logging.debug, self.cfg.debug)
+        self.assertEqual(logging.DEBUG * 10, self.cfg.derived)
+
+    def testFunctions(self):
+        makePath = config.makePath
+        isWord = config.isWord
+        self.assertEqual('suffix', makePath('', 'suffix'))
+        self.assertEqual('suffix', makePath(None, 'suffix'))
+        self.assertEqual('prefix.suffix', makePath('prefix', 'suffix'))
+        self.assertEqual('prefix[1]', makePath('prefix', '[1]'))
+        self.failUnless(isWord('a9'))
+        self.failUnless(isWord('9a'))    #perverse, but there you go
+        self.failIf(isWord(9))
+        self.failIf(isWord(None))
+        self.failIf(isWord(self))
+        self.failIf(isWord(''))
+
+    def testMerge(self):
+        cfg1 = Config()
+        cfg1.load(makeStream("merge_1"))
+        cfg2 = Config(makeStream("merge_2"))
+        ConfigMerger().merge(cfg1, cfg2)
+        merged = cfg1
+        cfg1 = Config()
+        cfg1.load(makeStream("merge_1"))
+        for i in xrange(0, 5):
+            key = 'value%d' % (i + 1,)
+            self.failUnless(key in merged)
+        self.assertEqual(len(cfg1.value5) + len(cfg2.value5),
+           len(merged.value5))
+        cfg3 = Config()
+        cfg3.load(makeStream("merge_3"))
+        cfg4 = Config(makeStream("merge_4"))
+        merger = ConfigMerger()
+        self.assertRaises(ConfigError, merger.merge, cfg3, cfg4)
+
+        cfg3 = Config(makeStream("merge_3"))
+        cfg4 = Config(makeStream("merge_4"))
+        merger = ConfigMerger(config.overwriteMergeResolve)
+        merger.merge(cfg3, cfg4)
+        self.assertEqual(False, cfg3['value1'])
+        self.assertEqual(4, cfg3['value2'])
+
+        def customMergeResolve(map1, map2, key):
+            if key == "value3":
+                rv = "overwrite"
+            else:
+                rv = config.overwriteMergeResolve(map1, map2, key)
+            return rv
+
+        cfg3 = Config(makeStream("merge_3"))
+        cfg4 = Config(makeStream("merge_4"))
+        merger = ConfigMerger(customMergeResolve)
+        merger.merge(cfg3, cfg4)
+        self.assertEqual("[2, 4, 6]", str(cfg3.value3))
+        self.assertEqual("[1, 3, 5, 2, 4, 6]", str(cfg3.value4))
+
+    def testList(self):
+        list = ConfigList()
+        list.append(Config(makeStream("list_1")))
+        list.append(Config(makeStream("list_2")))
+        list.append(Config(makeStream("list_3")))
+        self.assertEqual(1, list.getByPath('verbosity'))
+        self.assertEqual(4, list.getByPath('program_value'))
+        self.assertEqual(5, list.getByPath('suite_value'))
+        self.assertRaises(ConfigError, list.getByPath, 'nonexistent_value')
+
+    def testGet(self):
+        cfg = self.cfg
+        cfg.load(makeStream("get_1"))
+        self.assertEqual(123, cfg.get('value1'))
+        self.assertEqual(123, cfg.get('value1', -123))
+        self.assertEqual(-123, cfg.get('value11', -123))
+        self.assertEqual('abcd', cfg.get('value2'))
+        self.failUnless(cfg.get('value3'))
+        self.failIf(cfg.get('value4') is not None)
+        self.assertEqual(123, cfg.value5.get('value1'))
+        self.assertEqual(123, cfg.value5.get('value1', -123))
+        self.assertEqual(-123, cfg.value5.get('value11', -123))
+        self.assertEqual('abcd', cfg.value5.get('value2'))
+        self.failUnless(cfg.value5.get('value3'))
+        self.failIf(cfg.value5.get('value4') is not None)
+
+    def testMultiline(self):
+        cfg = self.cfg
+        cfg.load(makeStream("multiline_1"))
+        self.assertEqual("Value One\nValue Two\n", cfg.get('value1'))
+        self.assertEqual("Value Three\nValue Four", cfg.get('value2'))
+
+    def testSequence(self):
+        cfg = self.cfg
+        strm = makeStream("sequence_1")
+        cfg.load(strm)
+        self.assertEqual(str(cfg.simple), "[1, 2]")
+        self.assertEqual(str(cfg.nested), "[1, [2, 3], [4, [5, 6]]]")
+        self.assertEqual(str(cfg.mixed), "['VALIGN', [0, 0], [-1, -1], 'TOP']")
+
+    def testJSON(self):
+        data = StringIO('dummy: ' + open('styles.json', 'r').read())
+        self.cfg.load(data)
+
+def init_logging():
+    logging.basicConfig(level=logging.DEBUG, filename="test_config.log",
+                        filemode="w", format="%(asctime)s %(levelname)-5s %(name)-10s %(message)s")
+"""
+def test_main():
+    init_logging()
+    test_support.run_unittest(TestConfig)
+"""
+
+if __name__ == "__main__":
+    # test_main()
+    unittest.main(exit=False)
+    import sys
+    sys.stderr.write("""
+                     
+###########################################################
+WARNING: this test obviously have 'FAILED  (errors=6)', 
+TODO:    fix upgrading 0.3.9, (or not).
+###########################################################
+""")
+    pass
+  
diff --git a/test/test_100_satHelp.py b/test/test_100_satHelp.py
new file mode 100755 (executable)
index 0000000..0ffef0e
--- /dev/null
@@ -0,0 +1,120 @@
+#!/usr/bin/env python
+#-*- coding:utf-8 -*-
+
+#  Copyright (C) 2010-2018  CEA/DEN
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2.1 of the License.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+import os
+import sys
+import unittest
+
+import src.salomeTools as SAT
+import src.debug as DBG # Easy print stderr (for DEBUG only)
+import src.loggingSat as LOG
+
+class TestCase(unittest.TestCase):
+  "Test the sat --help commands"""
+  
+  logger = LOG.getUnittestLogger()
+  debug = False
+  
+  def tearDown(self):
+    # print "tearDown", __file__
+    # assure self.logger clear for next test
+    logs = self.logger.getLogsAndClear()
+    # using assertNotIn() is too much verbose
+    self.assertFalse("ERROR" in logs)
+    self.assertFalse("CRITICAL" in logs)
+  
+  def test_000(self):
+    # one shot setUp() for this TestCase
+    if self.debug: DBG.push_debug(True)
+    SAT.setNotLocale() # test english
+
+  def test_999(self):
+    # one shot tearDown() for this TestCase
+    SAT.setLocale() # end test english
+    if self.debug: DBG.pop_debug()
+
+  def test_010(self):
+    cmd = "sat --help"
+    stdout, stderr = SAT.launchSat(cmd)
+    DBG.write("test_010 stdout", stdout)
+    DBG.write("test_010 stderr", stderr)
+    self.assertEqual(stderr, "")
+    self.assertTrue(" - config" in stdout)
+    self.assertTrue(" - prepare" in stdout)
+    self.assertTrue(" - compile" in stdout)
+
+  def test_011(self):
+    cmd = "--help"
+    s = SAT.Sat(self.logger)
+    returnCode = s.execute_cli(cmd)
+    self.assertTrue(returnCode.isOk())
+    logs = self.logger.getLogs()
+    DBG.write("test_011 logger", logs)
+    self.assertTrue(" - config" in logs)
+    self.assertTrue(" - prepare" in logs)
+    self.assertTrue(" - compile" in logs)
+    
+  def test_030(self):
+    cmd = "sat config --help"
+    stdout, stderr = SAT.launchSat(cmd)
+    DBG.write("test_030 stdout", stdout)
+    self.assertEqual(stderr, "")
+    self.assertTrue("--value" in stdout)
+
+  def test_031(self):
+    cmd = "config --help"
+    s = SAT.Sat(self.logger)
+    returnCode = s.execute_cli(cmd)
+    self.assertTrue(returnCode.isOk())
+    logs = self.logger.getLogs()
+    DBG.write("test_031 logger", logs)
+    self.assertTrue("--value" in logs)
+    
+  def xxtest_040(self):
+    cmd = "config --list"
+    s = SAT.Sat(self.logger)
+    returnCode = s.execute_cli(cmd)
+    self.assertTrue(returnCode.isOk())
+    logs = self.logger.getLogs()
+    self.assertTrue("--value" in logs)
+
+  def test_050(self):
+    cmds = SAT.getCommandsList()
+    DBG.write("test_050 getCommandsList", cmds)
+    for c in cmds:
+      cmd = "sat %s --help" % c
+      stdout, stderr = SAT.launchSat(cmd)
+      self.assertEqual(stderr, "")
+      self.assertTrue(c in stdout)
+      self.assertTrue("Available options" in stdout)
+      
+  def test_051(self):
+    cmds = SAT.getCommandsList()
+    for c in cmds:
+      cmd = "%s --help" % c
+      s = SAT.Sat(self.logger)
+      returnCode = s.execute_cli(cmd)
+      self.assertTrue(returnCode.isOk())
+      logs = self.logger.getLogsAndClear()
+      DBG.write(cmd, logs, True)
+      self.assertTrue("Available options" in logs)
+                
+if __name__ == '__main__':
+    unittest.main(exit=False)
+    pass
diff --git a/test/test_500_APPLI_TEST.py b/test/test_500_APPLI_TEST.py
new file mode 100755 (executable)
index 0000000..dcb58c7
--- /dev/null
@@ -0,0 +1,63 @@
+#!/usr/bin/env python
+#-*- coding:utf-8 -*-
+
+#  Copyright (C) 2010-2018  CEA/DEN
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2.1 of the License.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+import os
+import sys
+import unittest
+
+import src.salomeTools as SAT
+import src.debug as DBG # Easy print stderr (for DEBUG only)
+import src.loggingSat as LOG
+
+class TestCase(unittest.TestCase):
+  "Test the sat commands on APPLI_TEST configuration pyconf etc. files"""
+  
+  logger = LOG.getUnittestLogger()
+  debug = False
+  
+  def tearDown(self):
+    # print "tearDown", __file__
+    # assure self.logger clear for next test
+    logs = self.logger.getLogsAndClear()
+    # using assertNotIn() is too much verbose
+    self.assertFalse("ERROR" in logs)
+    self.assertFalse("CRITICAL" in logs)
+
+  def test_000(self):
+    # one shot setUp() for this TestCase
+    if self.debug: DBG.push_debug(True)
+    SAT.setNotLocale() # test english
+    return
+
+  def test_999(self):
+    # one shot tearDown() for this TestCase
+    SAT.setLocale() # end test english
+    if self.debug: DBG.pop_debug()
+
+  def test_010(self):
+    cmd = "-v 5 config -l"
+    s = SAT.Sat(self.logger)
+    DBG.write("s.getConfig()", s.getConfig()) #none
+    DBG.write("s.__dict__", s.__dict__) # have 
+    returnCode = s.execute_cli(cmd)
+    self.assertTrue(returnCode.isOk())
+
+if __name__ == '__main__':
+    unittest.main(exit=False)
+    pass
diff --git a/test/test_sat5_0/__init__.py b/test/test_sat5_0/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/test/test_sat5_0/compilation/test_compilation.py b/test/test_sat5_0/compilation/test_compilation.py
new file mode 100755 (executable)
index 0000000..79192ad
--- /dev/null
@@ -0,0 +1,227 @@
+#!/usr/bin/env python
+#-*- coding:utf-8 -*-
+
+#  Copyright (C) 2010-2018  CEA/DEN
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2.1 of the License.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+import os
+import sys
+import unittest
+
+import src.product
+from src.salomeTools import Sat
+
+class TestCase(unittest.TestCase):
+    """Test of the compile command"""
+
+    def test_010(self):
+        # Test the compile command with '--products' option
+        OK = 'KO'
+
+        appli = 'appli-test'
+        product_name = 'PRODUCT_GIT'
+
+        sat = Sat()
+                            
+        sat.prepare(appli + ' --product ' + product_name)
+        expected_install_dir = src.product.get_product_config(sat.cfg, product_name).install_dir
+        expected_file_path = os.path.join(expected_install_dir, 'bin/hello')
+
+        sat.clean(appli + ' --build --install --product ' + product_name, batch=True)
+        sat.compile(appli + ' --product ' + product_name)
+        
+        if os.path.exists(expected_file_path):
+            OK = 'OK'         
+        # pyunit method to compare 2 str
+        self.assertEqual(OK, 'OK')
+
+    def test_020(self):
+        # Test the configure command with '--fathers' option
+        OK = 'KO'
+
+        appli = 'appli-test'
+        product_name = 'PRODUCT_GIT'
+        product_name2 = 'PRODUCT_ARCHIVE'
+
+        sat = Sat()
+                            
+        sat.prepare(appli + ' --product ' + product_name +"," +product_name2)
+        expected_install_dir = src.product.get_product_config(sat.cfg, product_name).install_dir
+        expected_file_path = os.path.join(expected_install_dir, 'bin/hello')
+        expected_install_dir2 = src.product.get_product_config(sat.cfg, product_name2).install_dir
+        expected_file_path2 = os.path.join(expected_install_dir2, 'bin/hello-archive')
+        
+        sat.clean(appli + ' --build --install --product ' + product_name +"," +product_name2, batch=True)
+        sat.compile(appli + ' --with_fathers --product ' + product_name)
+        
+        if os.path.exists(expected_file_path) and os.path.exists(expected_file_path2):
+            OK = 'OK'         
+        # pyunit method to compare 2 str
+        self.assertEqual(OK, 'OK')
+        
+    def test_030(self):
+        # Test the configure command with '--children' option
+        OK = 'KO'
+
+        appli = 'appli-test'
+        product_name = 'PRODUCT_GIT'
+        product_name2 = 'PRODUCT_ARCHIVE'
+
+        sat = Sat()
+                            
+        sat.prepare(appli + ' --product ' + product_name +"," +product_name2)
+        expected_install_dir = src.product.get_product_config(sat.cfg, product_name).install_dir
+        expected_file_path = os.path.join(expected_install_dir, 'bin/hello')
+        expected_install_dir2 = src.product.get_product_config(sat.cfg, product_name2).install_dir
+        expected_file_path2 = os.path.join(expected_install_dir2, 'bin/hello-archive')
+
+        sat.clean(appli + ' --build --install --product ' + product_name +"," +product_name2, batch=True)
+        sat.compile(appli + ' --with_children --product ' + product_name2)
+        
+        if os.path.exists(expected_file_path) and os.path.exists(expected_file_path2):
+            OK = 'OK'         
+        # pyunit method to compare 2 str
+        self.assertEqual(OK, 'OK')
+
+    def test_040(self):
+        # Test the configure command with '--clean_all' option
+        OK = 'KO'
+
+        appli = 'appli-test'
+        product_name = 'PRODUCT_GIT'
+        product_name2 = 'PRODUCT_ARCHIVE'
+
+        sat = Sat()
+                            
+        sat.prepare(appli + ' --product ' + product_name +"," +product_name2)
+        expected_install_dir = src.product.get_product_config(sat.cfg, product_name).install_dir
+        expected_file_path = os.path.join(expected_install_dir, 'bin/hello')
+        expected_install_dir2 = src.product.get_product_config(sat.cfg, product_name2).install_dir
+        expected_file_path2 = os.path.join(expected_install_dir2, 'bin/hello-archive')
+
+        sat.compile(appli + ' --with_children --product ' + product_name2)
+        
+        sat.compile(appli + ' --clean_all --with_children --product ' + product_name2, batch=True)
+        
+        if os.path.exists(expected_file_path) and os.path.exists(expected_file_path2):
+            OK = 'OK'         
+        # pyunit method to compare 2 str
+        self.assertEqual(OK, 'OK')
+
+    def test_050(self):
+        # Test the configure command with '--clean_install' option
+        OK = 'KO'
+
+        appli = 'appli-test'
+        product_name = 'PRODUCT_GIT'
+        product_name2 = 'PRODUCT_ARCHIVE'
+
+        sat = Sat()
+                            
+        sat.prepare(appli + ' --product ' + product_name +"," +product_name2)
+        expected_install_dir = src.product.get_product_config(sat.cfg, product_name).install_dir
+        expected_file_path = os.path.join(expected_install_dir, 'bin/hello')
+        expected_install_dir2 = src.product.get_product_config(sat.cfg, product_name2).install_dir
+        expected_file_path2 = os.path.join(expected_install_dir2, 'bin/hello-archive')
+
+        sat.compile(appli + ' --with_children --product ' + product_name2)
+        
+        sat.compile(appli + ' --clean_install --with_children --product ' + product_name2, batch=True)
+        
+        if os.path.exists(expected_file_path) and os.path.exists(expected_file_path2):
+            OK = 'OK'         
+        # pyunit method to compare 2 str
+        self.assertEqual(OK, 'OK')
+
+    def test_060(self):
+        # Test the configure command with '--make_flags' option
+        OK = 'KO'
+
+        appli = 'appli-test'
+        product_name = 'PRODUCT_GIT'
+
+        sat = Sat()
+                            
+        sat.prepare(appli + ' --product ' + product_name)
+        expected_install_dir = src.product.get_product_config(sat.cfg, product_name).install_dir
+        expected_file_path = os.path.join(expected_install_dir, 'bin/hello')
+
+        sat.clean(appli + ' --build --install --product ' + product_name, batch=True)
+        sat.compile(appli + ' --make_flags 3 --product ' + product_name)
+               
+        if os.path.exists(expected_file_path):
+            OK = 'OK'         
+        # pyunit method to compare 2 str
+        self.assertEqual(OK, 'OK')
+
+    def test_070(self):
+        # Test the configure command with '--show' option
+        OK = 'KO'
+
+        appli = 'appli-test'
+        product_name = 'PRODUCT_GIT'
+
+        sat = Sat()
+                            
+        sat.prepare(appli + ' --product ' + product_name)
+        expected_install_dir = src.product.get_product_config(sat.cfg, product_name).install_dir
+        expected_file_path = os.path.join(expected_install_dir, 'bin/hello')
+
+        sat.clean(appli + ' --build --install --product ' + product_name, batch=True)
+        sat.compile(appli + ' --show --product ' + product_name)
+               
+        if not(os.path.exists(expected_file_path)):
+            OK = 'OK'         
+        # pyunit method to compare 2 str
+        self.assertEqual(OK, 'OK')
+
+    def test_080(self):
+        # Test the configure command with '--stop_first_fail' option
+        OK = 'KO'
+
+        appli = 'appli-test'
+
+        sat = Sat()
+                            
+        sat.prepare(appli + ' --product PRODUCT_CVS,Python')
+        expected_install_dir = src.product.get_product_config(sat.cfg, "PRODUCT_CVS").install_dir
+
+        sat.clean(appli + ' --build --install --product PRODUCT_CVS', batch=True)
+        sat.compile(appli + ' --stop_first_fail --product PRODUCT_CVS,Python')
+               
+        if not(os.path.exists(expected_install_dir)):
+            OK = 'OK'         
+        # pyunit method to compare 2 str
+        self.assertEqual(OK, 'OK')
+
+    def test_090(self):
+        # Test the 'sat -h compile' command to get description       
+
+        OK = "KO"
+
+        import compile
+        
+        if "The compile command constructs the products" in compile.description():
+            OK = "OK"
+
+        # pyunit method to compare 2 str
+        self.assertEqual(OK, "OK")
+
+# test launch
+if __name__ == '__main__':
+    unittest.main()
+    pass
+
diff --git a/test/test_sat5_0/compilation/test_configure.py b/test/test_sat5_0/compilation/test_configure.py
new file mode 100755 (executable)
index 0000000..9d995a2
--- /dev/null
@@ -0,0 +1,110 @@
+#!/usr/bin/env python
+#-*- coding:utf-8 -*-
+
+#  Copyright (C) 2010-2018  CEA/DEN
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2.1 of the License.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+import os
+import sys
+import unittest
+
+import src.product
+from src.salomeTools import Sat
+
+class TestCase(unittest.TestCase):
+    """Test of the configure command"""
+
+    def setUp(self):
+        print("setUp")
+
+    def tearDown(self):
+        print("tearDown")
+
+    def test_010(self):
+        # Test the configure command with a product in cmake
+        OK = 'KO'
+
+        appli = 'appli-test'
+        product_name = 'PRODUCT_GIT'
+
+        sat = Sat()
+                            
+        sat.prepare(appli + ' --product ' + product_name)
+        expected_build_dir = src.product.get_product_config(sat.cfg, product_name).build_dir
+        expected_file_path = os.path.join(expected_build_dir, 'CMakeCache.txt')
+       
+        sat.configure(appli + ' --product ' + product_name)
+        
+        if os.path.exists(os.path.join(expected_build_dir, expected_file_path)):
+            OK = 'OK'         
+        # pyunit method to compare 2 str
+        self.assertEqual(OK, 'OK')
+
+    def test_020(self):
+        # Test the configure command with a product in autotools
+        OK = 'KO'
+
+        appli = 'appli-test'
+        product_name = 'PRODUCT_CVS'
+
+        sat = Sat()
+                            
+        sat.prepare(appli + ' --product ' + product_name)
+        expected_build_dir = src.product.get_product_config(sat.cfg, product_name).build_dir
+        expected_file_path = os.path.join(expected_build_dir, 'config.log')
+       
+        sat.configure(appli + ' --product ' + product_name)
+        
+        if os.path.exists(os.path.join(expected_build_dir, expected_file_path)):
+            OK = 'OK'         
+        # pyunit method to compare 2 str
+        self.assertEqual(OK, 'OK')
+
+    def test_030(self):
+        # Test the configure command with a product in script mode
+        OK = 'KO'
+
+        appli = 'appli-test'
+        product_name = 'Python'
+
+        sat = Sat()
+                            
+        sat.prepare(appli + ' --product ' + product_name)
+        expected_build_dir = src.product.get_product_config(sat.cfg, product_name).build_dir
+      
+        sat.configure(appli + ' --product ' + product_name)
+        
+        if os.path.exists(expected_build_dir):
+            OK = 'OK'         
+        # pyunit method to compare 2 str
+        self.assertEqual(OK, 'OK')
+
+    def test_040(self):
+        # Test the 'sat -h configure'
+        OK = "KO"
+
+        import configure
+        
+        if "The configure command executes in the build directory" in configure.description():
+            OK = "OK"
+
+        # pyunit method to compare 2 str
+        self.assertEqual(OK, "OK")
+
+# test launch
+if __name__ == '__main__':
+    unittest.main()
+    pass
diff --git a/test/test_sat5_0/compilation/test_make.py b/test/test_sat5_0/compilation/test_make.py
new file mode 100755 (executable)
index 0000000..c956965
--- /dev/null
@@ -0,0 +1,106 @@
+#!/usr/bin/env python
+#-*- coding:utf-8 -*-
+
+#  Copyright (C) 2010-2018  CEA/DEN
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2.1 of the License.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+import os
+import sys
+import unittest
+
+import src.product
+from src.salomeTools import Sat
+
+class TestCase(unittest.TestCase):
+    """Test of the make command"""
+
+    def test_010(self):
+        # Test the configure command without any option
+        OK = 'KO'
+
+        appli = 'appli-test'
+        product_name = 'PRODUCT_GIT'
+
+        sat = Sat()
+                            
+        sat.prepare(appli + ' --product ' + product_name)
+        expected_build_dir = src.product.get_product_config(sat.cfg, product_name).build_dir
+        expected_file_path = os.path.join(expected_build_dir, 'hello')
+       
+        sat.configure(appli + ' --product ' + product_name)        
+        sat.make(appli + ' --product ' + product_name)
+        
+        if os.path.exists(os.path.join(expected_build_dir, expected_file_path)):
+            OK = 'OK'         
+        # pyunit method to compare 2 str
+        self.assertEqual(OK, 'OK')
+
+    def test_020(self):
+        # Test the make command with an option
+        OK = 'KO'
+        appli = 'appli-test'
+        product_name = 'PRODUCT_GIT'
+
+        sat = Sat()
+                            
+        sat.prepare(appli + ' --product ' + product_name)
+        expected_build_dir = src.product.get_product_config(sat.cfg, product_name).build_dir
+        expected_file_path = os.path.join(expected_build_dir, 'hello')
+       
+        sat.configure(appli + ' --product ' + product_name)   
+        sat.make(appli + ' --product ' + product_name + ' --option -j3')
+        
+        if os.path.exists(os.path.join(expected_build_dir, expected_file_path)):
+            OK = 'OK'         
+        # pyunit method to compare 2 str
+        self.assertEqual(OK, 'OK')
+
+    def test_030(self):
+        # Test the make command with a product in script mode
+        OK = 'KO'
+
+        appli = 'appli-test'
+        product_name = 'Python'
+
+        sat = Sat()
+                            
+        sat.prepare(appli + ' --product ' + product_name)
+        expected_install_dir = src.product.get_product_config(sat.cfg, product_name).install_dir
+        expected_file = "bin/python2.7"
+        
+        sat.make(appli + ' --product ' + product_name)
+        
+        if os.path.exists(os.path.join(expected_install_dir, expected_file)):
+            OK = 'OK'         
+        # pyunit method to compare 2 str
+        self.assertEqual(OK, 'OK')
+
+    def test_040(self):
+        # Test the sat -h make 
+        OK = "KO"
+
+        import make
+        
+        if "The make command executes the \"make\" command" in make.description():
+            OK = "OK"
+
+        # pyunit method to compare 2 str
+        self.assertEqual(OK, "OK")
+
+# test launch
+if __name__ == '__main__':
+    unittest.main()
+    pass
diff --git a/test/test_sat5_0/compilation/test_makeinstall.py b/test/test_sat5_0/compilation/test_makeinstall.py
new file mode 100755 (executable)
index 0000000..62aba79
--- /dev/null
@@ -0,0 +1,69 @@
+#!/usr/bin/env python
+#-*- coding:utf-8 -*-
+
+#  Copyright (C) 2010-2018  CEA/DEN
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2.1 of the License.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+import os
+import sys
+import unittest
+
+import src.product
+from src.salomeTools import Sat
+
+class TestMakeinstall(unittest.TestCase):
+    """Test of the makeinstall command"""
+
+    def test_010(self):
+        # Test the configure-make-makeinstall command without any option
+        OK = 'KO'
+
+        appli = 'appli-test'
+        product_name = 'PRODUCT_GIT'
+
+        sat = Sat()
+                            
+        sat.prepare(appli + ' --product ' + product_name)
+        expected_install_dir = src.product.get_product_config(sat.cfg, product_name).install_dir
+        expected_file_path = os.path.join(expected_install_dir, 'bin/hello')
+       
+        sat.configure(appli + ' --product ' + product_name)
+        
+        sat.make(appli + ' --product ' + product_name)
+        
+        sat.makeinstall(appli + ' --product ' + product_name)
+        
+        if os.path.exists(expected_file_path):
+            OK = 'OK'         
+        # pyunit method to compare 2 str
+        self.assertEqual(OK, 'OK')
+
+    def test_020(self):
+        # Test the sat -h make
+        OK = "KO"
+
+        import makeinstall
+        
+        if "The makeinstall command executes the 'make install' command" in makeinstall.description():
+            OK = "OK"
+
+        # pyunit method to compare 2 str
+        self.assertEqual(OK, "OK")
+
+# test launch
+if __name__ == '__main__':
+    unittest.main()
+    pass
diff --git a/test/test_sat5_0/config/test_create_user_pyconf.py b/test/test_sat5_0/config/test_create_user_pyconf.py
new file mode 100755 (executable)
index 0000000..df1c0b0
--- /dev/null
@@ -0,0 +1,119 @@
+#!/usr/bin/env python
+#-*- coding:utf-8 -*-
+
+#  Copyright (C) 2010-2018  CEA/DEN
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2.1 of the License.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+import os
+import sys
+import shutil
+import unittest
+
+from src.salomeTools import Sat
+
+class TestCase(unittest.TestCase):
+    """Test create file .pyconf"""
+    
+    def test_010(self):
+        # Test creation of ~/.salomeTools/salomeTools.pyconf
+        res = "KO"
+        user_dir = os.path.expanduser(os.path.join('~','.salomeTools'))
+        user_dir_save = os.path.expanduser(os.path.join('~','.salomeTools_save'))
+        if os.path.exists(user_dir_save):
+            shutil.rmtree(user_dir_save)
+        if os.path.exists(user_dir):
+            shutil.move(user_dir, user_dir_save)
+               
+        # The command to test
+        sat = Sat('')
+        sat.config('-v .')
+
+        expected_file = os.path.expanduser(os.path.join('~','.salomeTools', 'salomeTools.pyconf'))
+
+        if os.path.exists(expected_file):
+            res = "OK"
+
+        shutil.rmtree(user_dir)
+        shutil.move(user_dir_save, user_dir)
+        self.assertEqual(res, "OK")
+
+    def test_020(self):
+        # Test override VARS
+        OK = "KO"
+        
+        # The command to test
+        sat = Sat("-oVARS.user='user_test'")
+        sat.config()
+
+        if sat.cfg.VARS.user == 'user_test':
+            OK = "OK"
+        self.assertEqual(OK, "OK")
+
+    def test_030(self):
+        # Test override INTERNAL
+        OK = "KO"
+        
+        # The command to test
+        sat = Sat("-oINTERNAL.sat_version='V0'")
+        sat.config()
+
+        if sat.cfg.INTERNAL.sat_version == 'V0':
+            OK = "OK"
+        self.assertEqual(OK, "OK")
+
+    """
+    def test_040(self):
+        # Test override SITE
+        OK = "KO"
+        
+        # The command to test
+        sat = Sat("-oSITE.jobs.config_path='/tmp'")
+        sat.config()
+
+        if sat.cfg.SITE.jobs.config_path == '/tmp':
+            OK = "OK"
+
+        self.assertEqual(OK, "OK")
+    """
+
+    def test_050(self):
+        # Test override APPLICATION
+        OK = "KO"
+        
+        # The command to test
+        sat = Sat("-oAPPLICATION.out_dir='/tmp'")
+        sat.config('appli-test')
+
+        if sat.cfg.APPLICATION.out_dir == '/tmp':
+            OK = "OK"
+        self.assertEqual(OK, "OK")
+
+    def test_060(self):
+        # Test override PRODUCTS
+        OK = "KO"
+        
+        # The command to test
+        sat = Sat("-oPRODUCTS.PRODUCT_GIT.default.name='test'")
+        sat.config('')
+
+        if sat.cfg.PRODUCTS.PRODUCT_GIT.default.name == 'test':
+            OK = "OK"
+        self.assertEqual(OK, "OK")
+
+# test launch
+if __name__ == '__main__':
+    unittest.main()
+    pass
diff --git a/test/test_sat5_0/config/test_option_copy.py b/test/test_sat5_0/config/test_option_copy.py
new file mode 100755 (executable)
index 0000000..bb7fe0b
--- /dev/null
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+#-*- coding:utf-8 -*-
+
+#  Copyright (C) 2010-2018  CEA/DEN
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2.1 of the License.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+import os
+import sys
+import unittest
+
+from src.salomeTools import Sat
+
+class TestCase(unittest.TestCase):
+    """sat config --copy"""
+    
+    def test_010(self):
+        # Test the copy of a pyconf
+        res = "KO"
+        appli_to_copy = "appli-test"
+
+        expected_file = os.path.expanduser(os.path.join('~','.salomeTools', 'Applications', 'LOCAL_' + appli_to_copy + '.pyconf'))
+        if os.path.exists(expected_file):
+            os.remove(expected_file)
+               
+        # The command to test
+        sat = Sat('')
+        sat.config('appli-test -c')
+
+        if os.path.exists(expected_file):
+            res = "OK"
+            os.remove(expected_file)
+        self.assertEqual(res, "OK")
+
+# test launch
+if __name__ == '__main__':
+    unittest.main()
+    pass
diff --git a/test/test_sat5_0/config/test_option_edit.py b/test/test_sat5_0/config/test_option_edit.py
new file mode 100755 (executable)
index 0000000..c6674e9
--- /dev/null
@@ -0,0 +1,73 @@
+#!/usr/bin/env python
+#-*- coding:utf-8 -*-
+
+#  Copyright (C) 2010-2018  CEA/DEN
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2.1 of the License.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+import os
+import sys
+import threading
+import time
+import unittest
+
+from src.salomeTools import Sat
+from unittestpy.tools import check_proc_existence_and_kill_multi
+
+sleep_time = 2
+
+class TestCase(unittest.TestCase):
+    """sat config --edit"""
+    
+    def test_010(self):
+        # Test the launch of the editor when invoking the config -e
+        OK = "KO"
+
+        sat = Sat("-oUSER.editor='cooledit'")
+        sat.config()
+        cmd_config = threading.Thread(target=sat.config, args=('-e',))
+        cmd_config.start()
+
+        time.sleep(sleep_time)
+
+        editor = sat.cfg.USER.editor
+        pid = check_proc_existence_and_kill_multi(editor + ".*" + "salomeTools\.pyconf", 10)
+
+        if pid:
+            OK = "OK"
+        self.assertEqual(OK, "OK")
+
+    def test_020(self):
+        # Test the launch of the editor when invoking the config -e appli-test
+        OK = "KO"
+
+        sat = Sat("-oUSER.editor='cooledit'")
+        sat.config()
+        cmd_config = threading.Thread(target=sat.config, args=('appli-test -e',))
+        cmd_config.start()
+
+        time.sleep(sleep_time)
+
+        editor = sat.cfg.USER.editor
+        pid = check_proc_existence_and_kill_multi(editor + ".*" + "appli-test\.pyconf", 10)
+
+        if pid:
+            OK = "OK"
+        self.assertEqual(OK, "OK")
+# test launch
+if __name__ == '__main__':
+    unittest.main()
+    pass
diff --git a/test/test_sat5_0/config/test_option_value.py b/test/test_sat5_0/config/test_option_value.py
new file mode 100755 (executable)
index 0000000..50a7d84
--- /dev/null
@@ -0,0 +1,109 @@
+#!/usr/bin/env python
+#-*- coding:utf-8 -*-
+
+#  Copyright (C) 2010-2018  CEA/DEN
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2.1 of the License.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+import os
+import sys
+import platform
+import unittest
+
+from src.salomeTools import Sat
+from unittestpy.tools import outRedirection
+
+class TestCase(unittest.TestCase):
+    """sat config --value"""
+    
+    def test_010(self):
+        # Test the display of the right value of "sat config -v VARS.hostname"
+        OK = "KO"
+
+        # output redirection
+        my_out = outRedirection()
+
+        # The command to test
+        sat = Sat()
+        sat.config('-v VARS.hostname')
+
+        # stop output redirection
+        my_out.end_redirection()
+
+        # get results
+        res = my_out.read_results()
+
+        if platform.node() in res:
+            OK = "OK"
+        self.assertEqual(OK, "OK")
+
+    def test_020(self):
+        # Test the display of the right value of "sat config -l"
+        OK = "KO"
+
+        # output redirection
+        my_out = outRedirection()
+
+        # The command to test
+        sat = Sat()
+        sat.config('-l')
+
+        # stop output redirection
+        my_out.end_redirection()
+
+        # get results
+        res = my_out.read_results()
+
+        # get results
+        if "ERROR" not in res:
+            OK = "OK"
+        self.assertEqual(OK, "OK")
+    
+    """    
+    def test_030(self):
+        # Test the exception when salomeTools.pyconf has errors           
+        OK = "KO"
+        
+        # The command to test
+        sat = Sat()
+        sat.config()
+        
+        salomeToolspyconfPath = os.path.join(sat.cfg.VARS.srcDir, "internal_config", "salomeTools.pyconf")
+        salomeToolspyconfPath_save = os.path.join(sat.cfg.VARS.srcDir, "internal_config", "salomeTools.pyconf_save")
+        if os.path.exists(salomeToolspyconfPath_save):
+            os.remove(salomeToolspyconfPath_save)
+        shutil.copyfile(salomeToolspyconfPath, salomeToolspyconfPath_save)
+        f_read = open(salomeToolspyconfPath, 'r')
+        text = f_read.read()
+        f_read.close()
+        os.remove(salomeToolspyconfPath)
+        f_write = open(salomeToolspyconfPath, 'w')
+        f_write.write(text.replace(':', ''))
+        f_write.close()
+        
+        try:
+            sat.config()
+        except TypeError:
+            OK = "OK"
+        finally:
+            shutil.copyfile(salomeToolspyconfPath_save, salomeToolspyconfPath)
+            os.remove(salomeToolspyconfPath_save)
+        self.assertEqual(OK, "OK")
+    """       
+        
+# test launch
+if __name__ == '__main__':
+    unittest.main()
+    pass
diff --git a/test/test_sat5_0/config/test_option_value_2.py b/test/test_sat5_0/config/test_option_value_2.py
new file mode 100755 (executable)
index 0000000..c11fee1
--- /dev/null
@@ -0,0 +1,103 @@
+#!/usr/bin/env python
+#-*- coding:utf-8 -*-
+
+#  Copyright (C) 2010-2018  CEA/DEN
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2.1 of the License.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+import os
+import sys
+import platform
+import unittest
+
+from src.salomeTools import Sat
+from unittestpy.tools import outRedirection
+
+class TestCase(unittest.TestCase):
+    """sat config -v VARS.python"""
+    
+    def test_010(self):
+        # Test the display of the right value of 'sat config -v VARS.python'
+        OK = 'KO'
+
+        # output redirection
+        my_out = outRedirection()
+
+        # The command to test
+        sat = Sat('')
+        sat.config('-v VARS.python')
+
+        # stop output redirection
+        my_out.end_redirection()
+
+        # get results
+        res = my_out.read_results()
+        
+        
+        if platform.python_version() in res:
+            OK = 'OK'
+        self.assertEqual(OK, 'OK')
+
+    def test_020(self):
+        # Test the display of the right value of 'sat config -s'
+        OK = 'KO'
+
+        # output redirection
+        my_out = outRedirection()
+
+        # The command to test
+        sat = Sat('')
+        sat.config('-s')
+
+        # stop output redirection
+        my_out.end_redirection()
+
+        # get results
+        res = my_out.read_results()
+        
+        
+        if 'INTERNAL' in res:
+            OK = 'OK'
+        self.assertEqual(OK, 'OK')
+        
+    def test_030(self):
+        # Test the display of the right value of 'sat config --info'
+        application = 'appli-test'
+        product = 'PRODUCT_DEV'
+        
+        OK = 'KO'
+
+        # output redirection
+        my_out = outRedirection()
+
+        # The command to test
+        sat = Sat('')
+        sat.config(application + ' --info ' + product)
+
+        # stop output redirection
+        my_out.end_redirection()
+
+        # get results
+        res = my_out.read_results()
+        
+        
+        if 'compilation method = cmake' in res:
+            OK = 'OK'
+        self.assertEqual(OK, 'OK')
+
+# test launch
+if __name__ == '__main__':
+    unittest.main()
+    pass
diff --git a/test/test_sat5_0/environ/test_environ.py b/test/test_sat5_0/environ/test_environ.py
new file mode 100755 (executable)
index 0000000..3a63fd5
--- /dev/null
@@ -0,0 +1,150 @@
+#!/usr/bin/env python
+#-*- coding:utf-8 -*-
+
+#  Copyright (C) 2010-2018  CEA/DEN
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2.1 of the License.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+import os
+import sys
+import unittest
+
+from src.salomeTools import Sat
+
+class TestSource(unittest.TestCase):
+    """Test of the environ command"""
+    
+    def test_010(self):
+        # Test the environ command without any option
+        OK = 'KO'
+        
+        appli = 'appli-test'
+
+        file_env_name = 'env_launch.sh'
+        
+        sat = Sat()
+        sat.config(appli)
+
+        expected_file_path = os.path.join(sat.cfg.APPLICATION.workdir, file_env_name)
+
+        if os.path.exists(expected_file_path):
+            os.remove(expected_file_path)
+
+        sat.environ(appli)
+
+        if os.path.exists(expected_file_path):
+            OK = 'OK'
+        self.assertEqual(OK, 'OK')
+
+    def test_020(self):
+        # Test the environ command with option '--products'
+        OK = 'KO'
+        
+        appli = 'appli-test'
+        product_name = 'PRODUCT_GIT'
+        
+        file_env_name = 'env_launch.sh'
+        
+        sat = Sat()
+        sat.config(appli)
+
+        expected_file_path = os.path.join(sat.cfg.APPLICATION.workdir, file_env_name)
+
+        if os.path.exists(expected_file_path):
+            os.remove(expected_file_path)
+
+        sat.environ(appli + ' --products ' + product_name)
+
+        if os.path.exists(expected_file_path):
+            OK = 'OK'
+        self.assertEqual(OK, 'OK')        
+
+    def test_030(self):
+        # Test the environ command with option --target
+        OK = 'KO'
+        
+        appli = 'appli-test'
+        
+        file_env_name = 'env_launch.sh'
+        
+        sat = Sat()
+        sat.config(appli)
+
+        expected_file_path = os.path.join('.', file_env_name)
+        expected_file_path2 = os.path.join('.', 'env_build.sh')
+
+        if os.path.exists(expected_file_path):
+            os.remove(expected_file_path)
+
+        sat.environ(appli + ' --target .')
+
+        if os.path.exists(expected_file_path):
+            OK = 'OK'
+
+        if os.path.exists(expected_file_path):
+            os.remove(expected_file_path)
+            os.remove(expected_file_path2)
+
+        # pyunit method to compare 2 str
+        self.assertEqual(OK, 'OK') 
+
+    def test_040(self):
+        # Test the environ command with option --prefix
+        OK = 'KO'
+        
+        appli = 'appli-test'
+        prefix = 'TEST'
+        file_env_name = prefix + '_launch.sh'
+        
+        sat = Sat()
+        sat.config(appli)
+
+        expected_file_path = os.path.join(sat.cfg.APPLICATION.workdir, file_env_name)
+
+        if os.path.exists(expected_file_path):
+            os.remove(expected_file_path)
+
+        sat.environ(appli + ' --prefix ' + prefix)
+
+        if os.path.exists(expected_file_path):
+            OK = 'OK'
+        self.assertEqual(OK, 'OK') 
+
+    def test_050(self):
+        # Test the environ command with option --shell
+        OK = 'KO'
+        
+        appli = 'appli-test'
+        shell = 'bat'
+        file_env_name = 'env_launch.bat'
+        
+        sat = Sat()
+        sat.config(appli)
+
+        expected_file_path = os.path.join(sat.cfg.APPLICATION.workdir, file_env_name)
+
+        if os.path.exists(expected_file_path):
+            os.remove(expected_file_path)
+
+        sat.environ(appli + ' --shell ' + shell)
+
+        if os.path.exists(expected_file_path):
+            OK = 'OK'
+        self.assertEqual(OK, 'OK') 
+
+# test launch
+if __name__ == '__main__':
+    unittest.main()
+    pass
diff --git a/test/test_sat5_0/job/test_job.py b/test/test_sat5_0/job/test_job.py
new file mode 100755 (executable)
index 0000000..fc23191
--- /dev/null
@@ -0,0 +1,122 @@
+#!/usr/bin/env python
+#-*- coding:utf-8 -*-
+
+#  Copyright (C) 2010-2018  CEA/DEN
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2.1 of the License.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+import os
+import sys
+import unittest
+
+from src.salomeTools import Sat
+
+class TestCase(unittest.TestCase):
+    """Test the job command"""
+
+    def test_010(self):
+        # Test the job command
+        OK = 'KO'
+        tmp_file = "/tmp/test.txt"
+
+        sat = Sat("-l " + tmp_file)
+        
+        # Execute the job command
+        sat.job("--jobs_config .test --name Job 1" )
+
+        ff = open(tmp_file, "r")
+        log_files = ff.readlines()
+        ff.close()
+        os.remove(tmp_file)
+        log_config = [line.replace("\n", "") for line in log_files if 'config.xml' in line]
+        
+        text = open(log_config[0], "r").read()
+
+        if "nb_proc" in text:
+            OK = 'OK'         
+        self.assertEqual(OK, 'OK')
+
+
+    def test_020(self):
+        # Test the job command with a failing command
+        OK = 'KO'
+        tmp_file = "/tmp/test.txt"
+
+        sat = Sat("-l " + tmp_file)
+        
+        # Execute the job command
+        res = sat.job("--jobs_config .test --name Job 4" )
+
+        if res == 1:
+            OK = 'OK'         
+        # pyunit method to compare 2 str
+        self.assertEqual(OK, 'OK')
+
+    def test_030(self):
+        # Test the job command with a wrong file configuration
+        OK = 'KO'
+        tmp_file = "/tmp/test.txt"
+
+        sat = Sat("-l " + tmp_file)
+        
+        # Execute the job command
+        res = sat.job("--jobs_config NOTEXIST --name Job 4" )
+
+        if res == 1:
+            OK = 'OK'         
+        self.assertEqual(OK, 'OK')
+
+    def test_040(self):
+        # Test the job command without --jobs_config option
+        OK = 'KO'
+        tmp_file = "/tmp/test.txt"
+
+        sat = Sat("-l " + tmp_file)
+        
+        # Execute the job command
+        res = sat.job("--name Job 4" )
+
+        if res == 1:
+            OK = 'OK'         
+        self.assertEqual(OK, 'OK')
+
+    def test_050(self):
+        # Test the job command without --jobs_config option
+        OK = 'KO'
+        tmp_file = "/tmp/test.txt"
+
+        sat = Sat("-l " + tmp_file)
+        
+        # Execute the job command
+        res = sat.job("--jobs_config .test --name NOTEXIST" )
+
+        if res == 1:
+            OK = 'OK'         
+        self.assertEqual(OK, 'OK')
+
+    def test_060(self):
+        # Test the sat -h job     
+        OK = "KO"
+
+        import job
+        
+        if "Executes the commands of the job defined in the jobs configuration file" in job.description():
+            OK = "OK"
+        self.assertEqual(OK, "OK")
+
+# test launch
+if __name__ == '__main__':
+    unittest.main()
+    pass
diff --git a/test/test_sat5_0/jobs/test_jobs.py b/test/test_sat5_0/jobs/test_jobs.py
new file mode 100755 (executable)
index 0000000..1b22378
--- /dev/null
@@ -0,0 +1,159 @@
+#!/usr/bin/env python
+#-*- coding:utf-8 -*-
+
+#  Copyright (C) 2010-2018  CEA/DEN
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2.1 of the License.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+import os
+import sys
+import unittest
+
+from src.salomeTools import Sat
+from unittestpy.tools import outRedirection
+
+class TestCase(unittest.TestCase):
+    "Test the jobs command"""
+
+    def test_010(self):
+        # Test the jobs command
+        OK = 'KO'
+        tmp_file = "/tmp/test.txt"
+
+        sat = Sat("-l " + tmp_file)
+        
+        # Execute the jobs command
+        sat.jobs("--name .test --publish" )
+
+        ff = open(tmp_file, "r")
+        log_files = ff.readlines()
+        ff.close()
+        os.remove(tmp_file)
+        log_jobs = [line.replace("\n", "") for line in log_files if 'jobs.xml' in line]
+        
+        text = open(log_jobs[0], "r").read()
+        
+        expected_res = [
+        "Establishing connection with all the machines",
+        "Executing the jobs",
+        "Results for job"
+        ]
+        
+        res = 0
+        for exp_res in expected_res:
+            if exp_res not in text:
+                res += 1
+        
+        if res == 0:
+            OK = 'OK'
+        self.assertEqual(OK, 'OK')
+
+    def test_020(self):
+        # Test the jobs command with option --only_jobs
+        OK = 'KO'
+        tmp_file = "/tmp/test.txt"
+
+        sat = Sat("-l " + tmp_file)
+        
+        # Execute the jobs command
+        sat.jobs("--name .test --publish --only_jobs Job 1" )
+
+        ff = open(tmp_file, "r")
+        log_files = ff.readlines()
+        ff.close()
+        os.remove(tmp_file)
+        log_jobs = [line.replace("\n", "") for line in log_files if 'jobs.xml' in line]
+        
+        text = open(log_jobs[0], "r").read()
+        
+        expected_res = [
+        "Establishing connection with all the machines",
+        "Executing the jobs",
+        "Results for job"
+        ]
+        
+        res = 0
+        for exp_res in expected_res:
+            if exp_res not in text:
+                res += 1
+        
+        if res == 0:
+            OK = 'OK'
+        self.assertEqual(OK, 'OK')
+
+    def test_030(self):
+        # Test the jobs command without --name option
+        OK = 'KO'
+        tmp_file = "/tmp/test.txt"
+
+        sat = Sat("-l " + tmp_file)
+        
+        # Execute the job command
+        res = sat.jobs()
+
+        if res == 1:
+            OK = 'OK'         
+        self.assertEqual(OK, 'OK')
+        
+    def test_040(self):
+        # Test the jobs command with a wrong file configuration
+        OK = 'KO'
+        tmp_file = "/tmp/test.txt"
+
+        sat = Sat("-l " + tmp_file)
+        
+        # Execute the job command
+        res = sat.jobs("--name NOTEXIST" )
+
+        if res == 1:
+            OK = 'OK'         
+        self.assertEqual(OK, 'OK')
+
+    def test_050(self):
+        # Test the display of the right value of 'sat jobs --list'
+        OK = "KO"
+
+        # output redirection
+        my_out = outRedirection()
+
+        # The command to test
+        sat = Sat()
+        sat.jobs('--list')
+
+        # stop output redirection
+        my_out.end_redirection()
+
+        # get results
+        res = my_out.read_results()
+
+        # get results
+        if "ERROR" not in res:
+            OK = "OK"
+        self.assertEqual(OK, "OK")
+
+    def test_060(self):
+        # Test the sat -h jobs       
+        OK = "KO"
+
+        import jobs
+        
+        if "The jobs command launches maintenances that are described in the dedicated jobs configuration file." in jobs.description():
+            OK = "OK"
+        self.assertEqual(OK, "OK")
+
+# test launch
+if __name__ == '__main__':
+    unittest.main()
+    pass
diff --git a/test/test_sat5_0/log/test_launch_browser.py b/test/test_sat5_0/log/test_launch_browser.py
new file mode 100755 (executable)
index 0000000..a9c8be4
--- /dev/null
@@ -0,0 +1,294 @@
+#!/usr/bin/env python
+#-*- coding:utf-8 -*-
+
+#  Copyright (C) 2010-2018  CEA/DEN
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2.1 of the License.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+import os
+import sys
+import threading
+import time
+import shutil
+import io
+import unittest
+
+from src.salomeTools import Sat
+from unittestpy.tools import check_proc_existence_and_kill_multi
+
+sleep_time = 2
+
+class TestCase(unittest.TestCase):
+    """Test of log command: launch of browser"""
+           
+    def test_010(self):
+        # Test the write of xml log when invoking a command
+        OK = "KO"
+        
+        # launch the command that will write a log
+        sat = Sat()
+        sat.config('appli-test -v USER.browser')
+        
+        # get log file path
+        logDir = sat.cfg.USER.log_dir
+        logPath = os.path.join(logDir, sat.cfg.VARS.datehour + "_" + sat.cfg.VARS.command + ".xml")
+        
+        if os.path.exists(logPath):
+            OK = "OK"
+        self.assertEqual(OK, "OK")
+
+    def test_020(self):
+        # Test the terminal option without application
+        OK = "KO"
+        
+        # launch the command that will write a log
+        sat = Sat()
+        
+        one = u"1"
+        sys.stdin = io.StringIO(one)
+        
+        
+        try:
+            sat.log('-t')
+            OK = "OK"
+            sys.stdin = sys.__stdin__
+        except:
+            sys.stdin = sys.__stdin__
+        self.assertEqual(OK, "OK")
+
+    def test_030(self):
+        # Test the terminal option with application
+        OK = "KO"
+        
+        # launch the command that will write a log
+        sat = Sat()
+              
+        sat.config('appli-test -v VARS.python')
+        
+        one = u"1"
+        sys.stdin = io.StringIO(one)
+        
+        try:
+            sat.log('appli-test -t --last')
+            OK = "OK"
+            sys.stdin = sys.__stdin__
+        except:
+            pass
+        self.assertEqual(OK, "OK")
+
+    def test_040(self):
+        # Test the terminal option with 0 as input
+        OK = "KO"
+        
+        # launch the command that will write a log
+        sat = Sat()
+              
+        sat.config('appli-test -v VARS.python')
+        
+        zero = u"0\n1"
+        sys.stdin = io.StringIO(zero)
+        
+        try:
+            sat.log('--terminal')
+            OK = "OK"
+        finally:
+            sys.stdin = sys.__stdin__
+        self.assertEqual(OK, "OK")
+
+    def test_050(self):
+        # Test the terminal option with input bigger than the number of logs
+        OK = "KO"
+        
+        # launch the command that will write a log
+        sat = Sat()
+              
+        sat.config('appli-test -v VARS.python')
+        
+        nb_logs = len(os.listdir(sat.cfg.USER.log_dir))
+        
+        nb_logs_u = unicode(str(nb_logs) + "\n1")
+        sys.stdin = io.StringIO(nb_logs_u)
+        
+        try:
+            sat.log('--terminal')
+            OK = "OK"
+        finally:
+            sys.stdin = sys.__stdin__
+        self.assertEqual(OK, "OK")
+
+    def test_060(self):
+        # Test the terminal option with input return
+        OK = "KO"
+        
+        # launch the command that will write a log
+        sat = Sat()
+              
+        sat.config('appli-test -v VARS.python')
+        
+        ret = unicode("\n0")
+        sys.stdin = io.StringIO(ret)
+        
+        try:
+            sat.log('--terminal')
+            OK = "OK"
+        finally:
+            sys.stdin = sys.__stdin__
+        self.assertEqual(OK, "OK")
+
+    def test_070(self):
+        # Test the terminal option with input not int
+        OK = "KO"
+        
+        # launch the command that will write a log
+        sat = Sat()
+              
+        sat.config('appli-test -v VARS.python')
+        
+        ret = unicode("blabla\n0")
+        sys.stdin = io.StringIO(ret)
+        
+        try:
+            sat.log('--terminal')
+            OK = "OK"
+        finally:
+            sys.stdin = sys.__stdin__
+        self.assertEqual(OK, "OK")
+
+    def test_080(self):
+        # Test the terminal option and option last
+        OK = "KO"
+        
+        # launch the command that will write a log
+        sat = Sat()
+        
+        try:
+            sat.log('--terminal --last')
+            OK = "OK"
+        finally:
+            sys.stdin = sys.__stdin__
+        
+        # pyunit method to compare 2 str
+        self.assertEqual(OK, "OK")
+    
+    def test_090(self):
+        # Test the option --last
+        OK = "KO"
+        
+        # launch the command that will write a log
+        sat = Sat("-oUSER.browser='konqueror'")
+              
+        sat.config('appli-test -v VARS.python')
+        
+        
+        time.sleep(sleep_time)
+        cmd_log = threading.Thread(target=sat.log, args=('appli-test --last',))
+        cmd_log.start()
+        
+        time.sleep(sleep_time)
+
+        browser = sat.cfg.USER.browser
+        pid = check_proc_existence_and_kill_multi(browser + ".*" + "xml", 10)
+        
+        if pid:
+            OK = "OK"
+        self.assertEqual(OK, "OK")
+    
+    def test_100(self):
+        # Test the option --clean
+        OK = "KO"
+        
+        # launch the command that will write a log
+        sat = Sat()
+               
+        sat.config('-v VARS.user')
+        
+        nb_logs_t0 = len(os.listdir(sat.cfg.USER.log_dir))
+
+        sat.log('--clean 1')
+        
+        nb_logs_t1 = len(os.listdir(sat.cfg.USER.log_dir))
+        
+        if nb_logs_t1-nb_logs_t0 == 0:
+            OK = "OK"
+        self.assertEqual(OK, "OK")
+
+    def test_120(self):
+        # Test the option --clean with big number of files to clean
+        OK = "KO"
+        
+        # launch the command that will write a log
+        sat = Sat()
+               
+        sat.config('-v VARS.user')
+        
+        nb_logs_t0 = len(os.listdir(sat.cfg.USER.log_dir))
+        
+        if os.path.exists(sat.cfg.USER.log_dir + "_save"):
+            shutil.rmtree(sat.cfg.USER.log_dir + "_save")
+        print("TODO: risky !!!copytree!!!", sat.cfg.USER.log_dir, sat.cfg.USER.log_dir + "_save")
+        """
+        shutil.copytree(sat.cfg.USER.log_dir,sat.cfg.USER.log_dir + "_save")
+        
+        sat.log('--clean ' + str(nb_logs_t0))
+        
+        nb_logs_t1 = len(os.listdir(sat.cfg.USER.log_dir))
+        
+        shutil.rmtree(sat.cfg.USER.log_dir)
+        shutil.move(sat.cfg.USER.log_dir + "_save", sat.cfg.USER.log_dir)
+                
+        if nb_logs_t0-nb_logs_t1 > 10:
+            OK = "OK"
+        """
+        self.assertEqual(OK, "OK")
+    
+    """
+    def test_130(self):
+        # Test the option --full
+        OK = "KO"
+
+        sat = Sat("-oUSER.browser='konqueror'")
+        time.sleep(sleep_time)
+        cmd_log = threading.Thread(target=sat.log, args=('--full',))
+        cmd_log.start()
+
+        time.sleep(sleep_time)
+
+        browser = sat.cfg.USER.browser
+        check_proc_existence_and_kill_multi(browser + ".*" + "hat\.xml", 10)
+        
+        # Read and check the hat.xml file contains at least one log file corresponding to log
+        hatFilePath = os.path.join(sat.cfg.USER.log_dir, "hat.xml")
+        xmlHatFile = src.xmlManager.ReadXmlFile(hatFilePath)
+        for field in xmlHatFile.xmlroot:
+            if field.attrib[b'cmd'] == b'log':
+                OK = "OK"
+                break
+        self.assertEqual(OK, "OK")
+    """
+
+    def test_140(self):
+        # Test the sat -h log
+        OK = "KO"
+
+        import log
+        
+        if "Gives access to the logs produced" in log.description():
+            OK = "OK"
+        self.assertEqual(OK, "OK")
+
+# test launch
+if __name__ == '__main__':
+    unittest.main()
+    pass
diff --git a/test/test_sat5_0/log/test_launch_browser2.py b/test/test_sat5_0/log/test_launch_browser2.py
new file mode 100755 (executable)
index 0000000..38a6184
--- /dev/null
@@ -0,0 +1,56 @@
+#!/usr/bin/env python
+#-*- coding:utf-8 -*-
+
+#  Copyright (C) 2010-2018  CEA/DEN
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2.1 of the License.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+import os
+import sys
+import threading
+import time
+import unittest
+
+from src.salomeTools import Sat
+from unittestpy.tools import check_proc_existence_and_kill_multi
+
+sleep_time = 2
+
+class TestCase(unittest.TestCase):
+    """Test of log command: launch of browser"""
+
+    def test_010(self):
+        # Test the launch of browser when invoking the log command
+        OK = "KO"
+
+        sat = Sat("-oUSER.browser='konqueror'")
+        time.sleep(sleep_time)
+        cmd_log = threading.Thread(target=sat.log, args=('',))
+        cmd_log.start()
+
+        time.sleep(sleep_time)
+        
+        sat.config("")
+        browser = sat.cfg.USER.browser
+        pid = check_proc_existence_and_kill_multi(browser + ".*" + "hat\.xml", 10)
+
+        if pid:
+            OK = "OK"
+        self.assertEqual(OK, "OK")
+
+# test launch
+if __name__ == '__main__':
+    unittest.main()
+    pass
diff --git a/test/test_sat5_0/prepare/test_clean.py b/test/test_sat5_0/prepare/test_clean.py
new file mode 100755 (executable)
index 0000000..08bb54f
--- /dev/null
@@ -0,0 +1,180 @@
+#!/usr/bin/env python
+#-*- coding:utf-8 -*-
+
+#  Copyright (C) 2010-2018  CEA/DEN
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2.1 of the License.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+import os
+import sys
+import unittest
+
+from src.salomeTools import Sat
+import src.product
+from unittestpy.tools import outRedirection
+
+class TestCase(unittest.TestCase):
+    """Test of the clean command"""
+
+    def test_010(self):
+        # Test the clean command with no arguments (nothing to clean)
+        OK = 'KO'
+
+        appli = 'appli-test'
+
+        sat = Sat()
+
+        # output redirection
+        my_out = outRedirection()
+        
+        sat.clean(appli)
+        
+        # stop output redirection
+        my_out.end_redirection()
+
+        # get results
+        res = my_out.read_results()
+        
+        if "Nothing to suppress" in res:
+            OK = 'OK'
+        self.assertEqual(OK, 'OK')
+
+    def test_020(self):
+        # Test the clean of sources
+        OK = "KO"
+
+        appli = 'appli-test'
+        product_name = "PRODUCT_GIT"
+
+        sat = Sat()      
+        
+        # Make sure the sources exist
+        sat.prepare(appli + " -p " + product_name)
+        
+        # Call the command
+        sat.clean(appli + " -p " + product_name + " --sources", batch=True)
+           
+        expected_src_dir = src.product.get_product_config(sat.cfg, product_name).source_dir
+        
+        if not os.path.exists(expected_src_dir):
+            OK = "OK"
+        self.assertEqual(OK, "OK")
+
+    def test_030(self):
+        # Test the clean of build
+        OK = "KO"
+
+        appli = 'appli-test'
+        product_name = "PRODUCT_GIT"
+
+        sat = Sat()      
+        
+        # Make sure the build exists
+        sat.prepare(appli + " -p " + product_name)
+        sat.configure(appli + " -p " + product_name)
+        
+        # Call the command
+        sat.clean(appli + " -p " + product_name + " --build", batch=True)
+           
+        expected_build_dir = src.product.get_product_config(sat.cfg, product_name).build_dir
+        
+        if not os.path.exists(expected_build_dir):
+            OK = "OK"
+        self.assertEqual(OK, "OK")
+
+    def test_040(self):
+        # Test the clean of install
+        OK = "KO"
+
+        appli = 'appli-test'
+        product_name = "PRODUCT_GIT"
+
+        sat = Sat()      
+        
+        # Make sure the build exists
+        sat.prepare(appli + " -p " + product_name)
+        sat.configure(appli + " -p " + product_name)
+        
+        # Call the command
+        sat.clean(appli + " -p " + product_name + " --install", batch=True)
+           
+        expected_install_dir = src.product.get_product_config(sat.cfg, product_name).install_dir
+        
+        if not os.path.exists(expected_install_dir):
+            OK = "OK"
+        self.assertEqual(OK, "OK")
+
+    def test_050(self):
+        # Test the clean of all (build, src, install)
+        OK = "KO"
+
+        appli = 'appli-test'
+        product_name = "PRODUCT_GIT"
+
+        sat = Sat()      
+        
+        # Make sure the build exists
+        sat.prepare(appli + " -p " + product_name)
+        sat.compile(appli + " -p " + product_name)
+        
+        # Call the command
+        sat.clean(appli + " -p " + product_name + " --all", batch=True)
+           
+        expected_install_dir = src.product.get_product_config(sat.cfg, product_name).install_dir
+        expected_build_dir = src.product.get_product_config(sat.cfg, product_name).build_dir
+        expected_src_dir = src.product.get_product_config(sat.cfg, product_name).source_dir
+        
+        if not os.path.exists(expected_install_dir) and not os.path.exists(expected_build_dir) and not os.path.exists(expected_src_dir):
+            OK = "OK"
+        self.assertEqual(OK, "OK")
+
+    def test_060(self):
+        # Test the clean with sources_without_dev option
+        OK = "KO"
+
+        appli = 'appli-test'
+        product_name = "PRODUCT_GIT"
+        product_name2 = "PRODUCT_DEV"
+
+        sat = Sat()      
+        
+        # Make sure the build exists
+        sat.prepare(appli + " -p " + product_name + "," + product_name2)
+        
+        # Call the command
+        sat.clean(appli + " -p " + product_name + " --sources_without_dev", batch=True)
+           
+        expected_src_dir = src.product.get_product_config(sat.cfg, product_name).source_dir
+        expected_src_dir2 = src.product.get_product_config(sat.cfg, product_name2).source_dir
+        
+        if not os.path.exists(expected_src_dir) and os.path.exists(expected_src_dir2):
+            OK = "OK"
+        self.assertEqual(OK, "OK")
+
+
+    def test_070(self):
+        # Test the sat -h clean
+        OK = "KO"
+
+        import clean
+        
+        if "The clean command suppress the source, build, or install" in clean.description():
+            OK = "OK"
+        self.assertEqual(OK, "OK")
+
+# test launch
+if __name__ == '__main__':
+    unittest.main()
+    pass
diff --git a/test/test_sat5_0/prepare/test_patch.py b/test/test_sat5_0/prepare/test_patch.py
new file mode 100755 (executable)
index 0000000..1dc24d4
--- /dev/null
@@ -0,0 +1,167 @@
+#!/usr/bin/env python
+#-*- coding:utf-8 -*-
+
+#  Copyright (C) 2010-2018  CEA/DEN
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2.1 of the License.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+import os
+import sys
+import shutil
+import unittest
+
+from src.salomeTools import Sat
+import src.product
+from unittestpy.tools import outRedirection
+
+class TestCase(unittest.TestCase):
+    """Test of the patch command"""
+
+    def test_010(self):
+        # Test the patch command with a product in dev mode
+        OK = 'KO'
+
+        appli = 'appli-test'
+        product_name = 'PRODUCT_DEV'
+
+        sat = Sat("-oUSER.output_level=2")
+               
+        sat.config(appli)
+        
+        expected_src_dir = src.product.get_product_config(sat.cfg, product_name).source_dir
+        expected_file_path = os.path.join(expected_src_dir, 'my_test_file.txt')
+        expected_text = 'HELLO WORLD\n'
+        
+        if os.path.exists(expected_src_dir):
+            shutil.rmtree(expected_src_dir)
+        
+        sat.source(appli + ' --product ' + product_name)
+        
+        f = open(expected_file_path, 'r')
+        text = f.readlines()[0]
+        OK1 = 'KO'
+        if text == expected_text:
+            OK1 = 'OK'
+       
+        sat.patch(appli + ' --product ' + product_name)
+        
+        new_expected_text = 'HELLO WORLD MODIFIED\n'
+        f = open(expected_file_path, 'r')
+        text = f.readlines()[0]
+        
+        OK2 = 'KO'
+        if text == new_expected_text:
+            OK2 = 'OK'         
+
+        if (OK1, OK2)==('OK', 'OK'):
+            OK = 'OK'
+        self.assertEqual(OK, 'OK')
+
+    def test_020(self):
+        # Test the patch command with a product with no sources found
+        OK = 'KO'
+
+        appli = 'appli-test'
+        product_name = 'PRODUCT_DEV'
+
+        sat = Sat('')
+        sat.config(appli)
+        
+        expected_src_dir = src.product.get_product_config(sat.cfg, product_name).source_dir
+        
+        if os.path.exists(expected_src_dir):
+            shutil.rmtree(expected_src_dir)
+               
+        # output redirection
+        my_out = outRedirection()
+        
+        sat.patch(appli + ' --product ' + product_name)
+        
+        # stop output redirection
+        my_out.end_redirection()
+
+        # get results
+        res = my_out.read_results()
+        
+        if "No sources found for the " + product_name +" product" in res:
+            OK = 'OK'
+        self.assertEqual(OK, 'OK')
+
+    def test_030(self):
+        # Test the patch command with a product without patch
+        OK = 'KO'
+
+        appli = 'appli-test'
+        product_name = 'PRODUCT_ARCHIVE'
+
+        sat = Sat('-v4')
+                      
+        sat.source(appli + ' --product ' + product_name)
+               
+        # output redirection
+        my_out = outRedirection()
+        
+        sat.patch(appli + ' --product ' + product_name)
+        
+        # stop output redirection
+        my_out.end_redirection()
+
+        # get results
+        res = my_out.read_results()
+        
+        if "No patch for the " + product_name +" product" in res:
+            OK = 'OK'
+        self.assertEqual(OK, 'OK')
+
+    def test_040(self):
+        # Test the patch command with a product with a not valid patch
+        OK = 'KO'
+
+        appli = 'appli-test'
+        product_name = 'PRODUCT_DEV'
+
+        sat = Sat("-oPRODUCTS.PRODUCT_DEV.default.patches=['/']")
+                      
+        sat.source(appli + ' --product ' + product_name)
+               
+        # output redirection
+        my_out = outRedirection()
+        
+        sat.patch(appli + ' --product ' + product_name)
+        
+        # stop output redirection
+        my_out.end_redirection()
+
+        # get results
+        res = my_out.read_results()
+        
+        if "Not a valid patch" in res:
+            OK = 'OK'
+        self.assertEqual(OK, 'OK')
+
+    def test_050(self):
+        # Test the sat -h patch
+        OK = "KO"
+
+        import patch
+        
+        if "The patch command apply the patches on the sources of" in patch.description():
+            OK = "OK"
+        self.assertEqual(OK, "OK")
+
+# test launch
+if __name__ == '__main__':
+    unittest.main()
+    pass
diff --git a/test/test_sat5_0/prepare/test_prepare.py b/test/test_sat5_0/prepare/test_prepare.py
new file mode 100755 (executable)
index 0000000..3340547
--- /dev/null
@@ -0,0 +1,111 @@
+#!/usr/bin/env python
+#-*- coding:utf-8 -*-
+
+#  Copyright (C) 2010-2018  CEA/DEN
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2.1 of the License.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+import os
+import sys
+import shutil
+import unittest
+
+import src
+from src.salomeTools import Sat
+
+class TestCase(unittest.TestCase):
+    """Test of the prepare command"""
+
+    def test_010(self):
+        # Test the prepare command with a product in dev mode
+        OK = 'KO'
+
+        appli = 'appli-test'
+        product_name = 'PRODUCT_DEV'
+
+        sat = Sat()
+               
+        sat.config(appli)
+        
+        expected_src_dir = src.product.get_product_config(sat.cfg, product_name).source_dir
+        expected_file_path = os.path.join(expected_src_dir, 'my_test_file.txt')
+        expected_text = 'HELLO WORLD\n'
+        
+        if os.path.exists(expected_src_dir):
+            shutil.rmtree(expected_src_dir)
+        
+        sat.prepare(appli + ' --product ' + product_name)
+        
+        f = open(expected_file_path, 'r')
+        text = f.readlines()[0]
+        if text == expected_text:
+            OK = 'OK'
+        self.assertEqual(OK, 'OK')
+
+    def test_020(self):
+        # Test the prepare command with all products
+        OK = 'KO'
+
+        appli = 'appli-test'
+        product_name = 'PRODUCT_DEV'
+
+        sat = Sat()
+        sat.config(appli)
+        
+        expected_src_dir = src.product.get_product_config(sat.cfg, product_name).source_dir
+        expected_file_path = os.path.join(expected_src_dir, 'my_test_file.txt')
+        expected_text = 'HELLO WORLD\n'
+        
+        if os.path.exists(expected_src_dir):
+            shutil.rmtree(expected_src_dir)
+        
+        sat.prepare(appli)
+        
+        f = open(expected_file_path, 'r')
+        text = f.readlines()[0]
+        if text == expected_text:
+            OK = 'OK'
+        self.assertEqual(OK, 'OK')
+
+    def test_030(self):
+        # Test the prepare command with all products
+        OK = 'KO'
+
+        appli = 'appli-test'
+
+        sat = Sat()
+        sat.config(appli)
+       
+        try:
+            sat.prepare(appli + " --force --force_patch")
+            OK = 'OK'
+        except:
+            pass
+        self.assertEqual(OK, 'OK')
+
+    def test_040(self):
+        # Test the sat -h prepare
+        OK = "KO"
+
+        import prepare
+        
+        if "The prepare command gets the sources" in prepare.description():
+            OK = "OK"
+        self.assertEqual(OK, "OK")
+
+# test launch
+if __name__ == '__main__':
+    unittest.main()
+    pass
diff --git a/test/test_sat5_0/prepare/test_source.py b/test/test_sat5_0/prepare/test_source.py
new file mode 100755 (executable)
index 0000000..f7a053d
--- /dev/null
@@ -0,0 +1,175 @@
+#!/usr/bin/env python
+#-*- coding:utf-8 -*-
+
+#  Copyright (C) 2010-2018  CEA/DEN
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2.1 of the License.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+import os
+import sys
+import unittest
+
+from src.salomeTools import Sat
+import src.product
+from unittestpy.tools import outRedirection
+
+class TestCase(unittest.TestCase):
+    """Test of the source command"""
+    
+    def test_010(self):
+        # Test the source command with archive product
+        appli = 'appli-test'
+        product_name = 'PRODUCT_ARCHIVE'
+
+        sat = Sat()
+        sat.source(appli + ' --product ' + product_name)
+
+        expected_src_dir = src.product.get_product_config(sat.cfg, product_name).source_dir
+        expected_file_path = os.path.join(expected_src_dir, 'my_test_file.txt')
+        expected_text = 'HELLO WORLD\n'
+
+        f = open(expected_file_path, 'r')
+        text = f.read()
+        self.assertEqual(text, expected_text)
+        
+    def test_020(self):
+        # Test the source command with git product
+        appli = 'appli-test'
+        product_name = 'PRODUCT_GIT'
+
+        sat = Sat()
+        sat.source(appli + ' --product ' + product_name)
+
+        expected_src_dir = src.product.get_product_config(sat.cfg, product_name).source_dir
+        expected_file_path = os.path.join(expected_src_dir, 'my_test_file.txt')
+        expected_text = 'HELLO WORLD\n'
+
+        f = open(expected_file_path, 'r')
+        text = f.read()
+        self.assertEqual(text, expected_text)
+
+    def test_030(self):
+        # Test the source command with cvs product
+        appli = 'appli-test'
+        product_name = 'PRODUCT_CVS'
+
+        sat = Sat()
+        sat.source(appli + ' --product ' + product_name)
+
+        expected_src_dir = src.product.get_product_config(sat.cfg, product_name).source_dir
+        expected_file_path = os.path.join(expected_src_dir, 'README.FIRST.txt')
+        expected_text = 'Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE\n'
+
+        f = open(expected_file_path, 'r')
+        text = f.readlines()[0]
+
+        # pyunit method to compare 2 str
+        self.assertEqual(text, expected_text)
+    
+    """
+    def test_040(self):
+        # Test the source command with svn product
+        OK = 'KO'
+        
+        appli = 'appli-test'
+        product_name = 'PRODUCT_SVN'
+
+        sat = Sat()
+        sat.source(appli + ' --product ' + product_name)
+
+        expected_src_dir = src.product.get_product_config(sat.cfg, product_name).source_dir
+        expected_file_path = os.path.join(expected_src_dir, 'scripts', 'README')
+        expected_text = 'this directory contains scripts used by salomeTool'
+
+        f = open(expected_file_path, 'r')
+        text = f.readlines()[0]
+        
+        if expected_text in text:
+            OK = 'OK'
+         
+        # pyunit method to compare 2 str
+        self.assertEqual(OK, 'OK')
+    """
+
+    def test_050(self):
+        # Test the source command with native product
+        OK = 'KO'
+        
+        appli = 'appli-test'
+        product_name = 'PRODUCT_NATIVE'
+
+        sat = Sat()
+        sat.source(appli + ' --product ' + product_name)
+
+        expected_src_dir = os.path.join(sat.cfg.APPLICATION.workdir, 'SOURCES', product_name)
+        if not os.path.exists(expected_src_dir):
+            OK = 'OK'
+        self.assertEqual(OK, 'OK')
+
+    def test_060(self):
+        # Test the source command with fixed product
+        OK = 'KO'
+        
+        appli = 'appli-test'
+        product_name = 'PRODUCT_FIXED'
+
+        sat = Sat()
+        sat.source(appli + ' --product ' + product_name)
+
+        expected_src_dir = src.product.get_product_config(sat.cfg, product_name).install_dir
+
+        if os.path.exists(expected_src_dir):
+            OK = 'OK'
+        self.assertEqual(OK, 'OK')
+
+    """
+    def test_070(self):
+        # Test the source command with unknown product
+        OK = 'KO'
+
+        # output redirection
+        my_out = outRedirection()
+
+        appli = 'appli-test'
+        product_name = 'PRODUCT_UNKNOWN'
+
+        sat = Sat()
+        sat.source(appli + ' --product ' + product_name)
+
+        # stop output redirection
+        my_out.end_redirection()
+
+        # get results
+        res = my_out.read_results()
+
+        if "Unknown get source method" in res:
+            OK = 'OK'
+        self.assertEqual(OK, 'OK')
+    """
+
+    def test_080(self):
+        # Test the sat -h source
+        OK = "KO"
+
+        import source
+        
+        if "gets the sources of the application" in source.description():
+            OK = "OK"
+        self.assertEqual(OK, "OK")
+
+# test launch
+if __name__ == '__main__':
+    unittest.main()
+    pass
diff --git a/test/test_sat5_0/run_all.sh b/test/test_sat5_0/run_all.sh
new file mode 100755 (executable)
index 0000000..5905725
--- /dev/null
@@ -0,0 +1,59 @@
+#!/usr/bin/env bash
+#-*- coding:utf-8 -*-
+
+#  Copyright (C) 2010-2018  CEA/DEN
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2.1 of the License.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+echo "TODO: OBSOLETE: to set as python script, may be"
+echo "Begin date:"
+date
+echo
+echo "Remove old results ... "
+rm -rf .coverage htmlcov
+echo "Done"
+echo
+echo "****************************"
+coverage run --source=../commands/config.py    config/option_value.py > test_res.html
+coverage run --source=../commands/config.py -a config/option_value_2.py >> test_res.html
+coverage run --source=../commands/config.py -a config/create_user_pyconf.py >> test_res.html
+coverage run --source=../commands/config.py -a config/option_copy.py >> test_res.html
+coverage run --source=../commands/config.py -a config/option_edit.py >> test_res.html
+coverage run --source=../commands/config.py,../commands/log.py,../src/xmlManager.py,../src/logger.py -a log/launch_browser.py >> test_res.html
+coverage run --source=../commands/config.py,../commands/log.py,../src/xmlManager.py,../src/logger.py -a log/launch_browser2.py >> test_res.html
+coverage run --source=../commands/config.py,../commands/source.py,../commands/patch.py,../commands/prepare.py -a prepare/test_source.py >> test_res.html
+coverage run --source=../commands/config.py,../commands/source.py,../commands/patch.py,../commands/prepare.py -a prepare/test_patch.py >> test_res.html
+coverage run --source=../commands/config.py,../commands/source.py,../commands/patch.py,../commands/prepare.py -a prepare/test_prepare.py >> test_res.html
+coverage run --source=../commands/config.py,../commands/source.py,../commands/patch.py,../commands/prepare.py,../commands/clean.py -a prepare/test_clean.py >> test_res.html
+coverage run --source=../commands/config.py,../commands/environ.py -a environ/test_environ.py >> test_res.html
+coverage run --source=../commands/config.py,../commands/configure.py,../commands/environ.py -a compilation/test_configure.py >> test_res.html
+coverage run --source=../commands/config.py,../commands/make.py,../commands/environ.py -a compilation/test_make.py >> test_res.html
+coverage run --source=../commands/config.py,../commands/makeinstall.py,../commands/environ.py -a compilation/test_makeinstall.py >> test_res.html
+coverage run --source=../commands/config.py,../commands/compile.py,../commands/configure.py,../commands/make.py,../commands/makeinstall.py,../commands/environ.py -a compilation/test_compilation.py >> test_res.html
+coverage run --source=../commands/shell.py -a shell/test_shell.py >> test_res.html
+coverage run --source=../commands/job.py -a job/test_job.py >> test_res.html
+coverage run --source=../commands/jobs.py -a jobs/test_jobs.py >> test_res.html
+coverage run --source=../commands/test.py,../src/test_module.py,../src/fork.py -a test/test_command.py >> test_res.html
+echo "****************************"
+echo
+echo "building html coverage"
+coverage html
+echo "Done"
+echo
+echo "End date:"
+date
+echo
+
+#firefox test_res.html htmlcov/index.html
diff --git a/test/test_sat5_0/shell/test_shell.py b/test/test_sat5_0/shell/test_shell.py
new file mode 100755 (executable)
index 0000000..80f579e
--- /dev/null
@@ -0,0 +1,91 @@
+#!/usr/bin/env python
+#-*- coding:utf-8 -*-
+
+#  Copyright (C) 2010-2018  CEA/DEN
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2.1 of the License.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+import os
+import sys
+import unittest
+
+from src.salomeTools import Sat
+
+class TestCase(unittest.TestCase):
+    """Test of the shell command"""
+
+    def test_010(self):
+        # Test the shell command with the --command option
+        OK = 'KO'
+        tmp_file = "/tmp/test.txt"
+
+        sat = Sat("-l " + tmp_file)
+        
+        sat.config()
+        sat_way = sat.cfg.VARS.salometoolsway
+        
+        # Execute the shell command
+        sat.shell("--command ls " + sat_way)
+
+        ff = open(tmp_file, "r")
+        log_files = ff.readlines()
+        ff.close()
+        os.remove(tmp_file)
+        log_files = [line.replace("\n", "") for line in log_files]
+        
+        text = open(log_files[2], "r").read()
+
+        if "salomeTools.py" in text:
+            OK = 'OK'         
+        self.assertEqual(OK, 'OK')
+
+    def test_020(self):
+        # Test the shell command with the --command option with a failing command
+        OK = 'KO'
+        tmp_file = "/tmp/test.txt"
+
+        sat = Sat("-l " + tmp_file)
+        
+        sat.config()
+        
+        # Execute the shell command
+        res = sat.shell("--command i_fail")
+
+        ff = open(tmp_file, "r")
+        log_files = ff.readlines()
+        ff.close()
+        os.remove(tmp_file)
+        log_files = [line.replace("\n", "") for line in log_files]
+        
+        text = open(log_files[2], "r").read()
+
+        if "i_fail" in text and res == 1:
+            OK = 'OK'         
+        self.assertEqual(OK, 'OK')
+
+    def test_030(self):
+        # Test the sat -h shell
+        OK = "KO"
+
+        import shell
+        
+        if "Executes the shell command passed as argument" in shell.description():
+            OK = "OK"
+        self.assertEqual(OK, "OK")
+
+# test launch
+if __name__ == '__main__':
+    unittest.main()
+    pass
diff --git a/test/test_sat5_0/test/test_command.py b/test/test_sat5_0/test/test_command.py
new file mode 100755 (executable)
index 0000000..136df62
--- /dev/null
@@ -0,0 +1,88 @@
+#!/usr/bin/env python
+#-*- coding:utf-8 -*-
+
+#  Copyright (C) 2010-2018  CEA/DEN
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2.1 of the License.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+import os
+import sys
+import unittest
+
+from src.salomeTools import Sat
+
+class TestTest(unittest.TestCase):
+    """Test of the test command"""
+
+    def test_010(self):
+        # Test the test command
+        OK = 'KO'
+        tmp_file = "/tmp/test.txt"
+        application = "SALOME-7.8.0"
+
+        sat = Sat("-l " + tmp_file)
+        
+        # Execute the job command
+        sat.test(application + " --grid GEOM --session light" )
+
+        ff = open(tmp_file, "r")
+        log_files = ff.readlines()
+        ff.close()
+        os.remove(tmp_file)
+        log_testboard = [line.replace("\n", "") for line in log_files if 'testboard.xml' in line]
+        
+        text = open(log_testboard[0], "r").read()
+
+        if '<session name="light">' in text:
+            OK = 'OK'         
+        self.assertEqual(OK, 'OK')
+
+    def test_020(self):
+        # Test the test command with PY type
+        OK = 'KO'
+        tmp_file = "/tmp/test.txt"
+        application = "SALOME-7.8.0"
+
+        sat = Sat("-l " + tmp_file)
+        
+        # Execute the job command
+        sat.test(application + " --grid MED --session PY_test_withKernel" )
+
+        ff = open(tmp_file, "r")
+        log_files = ff.readlines()
+        ff.close()
+        os.remove(tmp_file)
+        log_testboard = [line.replace("\n", "") for line in log_files if 'testboard.xml' in line]
+        
+        text = open(log_testboard[0], "r").read()
+
+        if '<session name="PY_test_withKernel">' in text:
+            OK = 'OK'         
+        self.assertEqual(OK, 'OK')
+
+    def test_030(self):
+        # Test the sat -h test
+        OK = "KO"
+
+        import test
+        
+        if "The test command runs a test base on a SALOME installation" in test.description():
+            OK = "OK"
+        self.assertEqual(OK, "OK")
+
+# test launch
+if __name__ == '__main__':
+    unittest.main()
+    pass