test/test_res.html
doc/src/commands/apidoc*
.idea
+.spyderproject
+
# -*- 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
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:
except:
XTST = None
errPrint("""
-WARNING: no XML output available.
+WARNING: no XML output available for unittest.
try 'pip install unittest-xml-reporting'.
""")
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())
###################################################################
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',
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(
)
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
# 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',
_("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)
# 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
# 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)
-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
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:
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),
("<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>", ""),
("<bright>", ""),
("<normal>", ""),
("<reset>", ""),
+ ("<header>", ""),
("<OK>", "OK"),
("<KO>", "KO"),
-)
+) )
def indent(msg, nb, car=" "):
"""indent nb car (spaces) multi lines message except first one"""
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
+
--- /dev/null
+#!/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
_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
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:
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"
import sys
import logging
import pprint as PP
+import src.coloringSat as COLS
_verbose = False
_name = "loggingSat"
_loggerDefaultName = 'SatDefaultLogger'
_loggerUnittestName = 'SatUnittestLogger'
+
def getDefaultLogger():
log("getDefaultLogger %s" % _loggerDefaultName)
return logging.getLogger(_loggerDefaultName)
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):
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):
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")
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:
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
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)
# 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
'''
: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
option['destName'] = destName
option['helpString'] = helpString
option['result'] = default
+
self.options.append(option)
def get_help(self):
# 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" \
% option
return msg
- def print_help(self):
- print(self.get_help())
-
def parse_args(self, argList=None):
'''Method that instantiates the class OptResult
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
# 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)
'''
########################################################################
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__), "..") )
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
# 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):
"""
'.../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
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
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):
"""
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
# 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
+
+
+++ /dev/null
-
-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"
- }
-}
+++ /dev/null
-#!/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
+++ /dev/null
-#TODO
-switch pyconf.py 0.3.7.1 -> 0.3.9, here for test
+++ /dev/null
-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.
+++ /dev/null
-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
+++ /dev/null
-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
+++ /dev/null
-# 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
+++ /dev/null
-# 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
+++ /dev/null
-#!/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
+++ /dev/null
-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"],
- )
+++ /dev/null
-{
- "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]
- }]
- ]
-}
+++ /dev/null
-# 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
+++ /dev/null
-#!/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
-
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
-
--- /dev/null
+
+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"
+ }
+}
--- /dev/null
+#TODO
+switch pyconf.py 0.3.7.1 -> 0.3.9, here for test
+++ /dev/null
-#!/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
-
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
--- /dev/null
+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.
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+# 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
--- /dev/null
+# 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
--- /dev/null
+#!/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
--- /dev/null
+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"],
+ )
--- /dev/null
+{
+ "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]
+ }]
+ ]
+}
--- /dev/null
+# 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
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
+++ /dev/null
-#!/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
--- /dev/null
+#!/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
+
--- /dev/null
+#!/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
--- /dev/null
+#!/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
+
--- /dev/null
+#!/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
--- /dev/null
+#!/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
--- /dev/null
+#!/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
+
--- /dev/null
+#!/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
--- /dev/null
+#!/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
--- /dev/null
+#!/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
--- /dev/null
+#!/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
--- /dev/null
+#!/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
--- /dev/null
+#!/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
--- /dev/null
+#!/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
--- /dev/null
+#!/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
--- /dev/null
+#!/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
--- /dev/null
+#!/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
--- /dev/null
+#!/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
--- /dev/null
+#!/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
--- /dev/null
+#!/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
--- /dev/null
+#!/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
--- /dev/null
+#!/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
--- /dev/null
+#!/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
--- /dev/null
+#!/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
--- /dev/null
+#!/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
--- /dev/null
+#!/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
--- /dev/null
+#!/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