From: Christian Van Wambeke Date: Sun, 1 Apr 2018 18:25:09 +0000 (+0200) Subject: sat --help and logingSat for unittest and begin fix ./test/test_xxx_zzz.py X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=772e86c1c13a8e0e4b0dfd6f68fead7231320625;p=tools%2Fsat.git sat --help and logingSat for unittest and begin fix ./test/test_xxx_zzz.py --- diff --git a/.gitignore b/.gitignore index 86431c4..6bab5df 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,5 @@ test/htmlcov test/test_res.html doc/src/commands/apidoc* .idea +.spyderproject + diff --git a/AllTestLauncherSat.py b/AllTestLauncherSat.py index 59f4fbd..45f2a59 100755 --- a/AllTestLauncherSat.py +++ b/AllTestLauncherSat.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- # %% LICENSE_SALOME_CEA_BEGIN -# Copyright (C) 2008-2016 CEA/DEN +# Copyright (C) 2008-2018 CEA/DEN # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -69,7 +69,7 @@ verboseImport = True satdir = os.path.dirname(os.path.realpath(__file__)) def errPrint(aStr): - """to avoid write in html or xml file log message""" + """stderr to avoid write in html or xml file log message""" sys.stderr.write(aStr + '\n') try: @@ -87,7 +87,7 @@ try: except: XTST = None errPrint(""" -WARNING: no XML output available. +WARNING: no XML output available for unittest. try 'pip install unittest-xml-reporting'. """) @@ -180,8 +180,9 @@ def runOnArgs(args): if done: del sys.path[0] #attention of sys.path appends done = False - errPrint("ERROR: AllTestLauncher: import '%s':" % aFile) - errPrint(" %s\n" % e) + errPrint("""\ +ERROR: AllTestLauncher: import '%s': + %s\n""" % (aFile, e)) continue listfilesForTest = sorted(filesForTest.keys()) @@ -255,7 +256,7 @@ def runFromEnvVar(envVar, fileTestPattern="*Test.py"): ################################################################### def getParser(): - parser = AP.ArgumentParser(description='launch All SAT python tests', argument_default=None) + parser = AP.ArgumentParser(description='launch All salomeTools python tests', argument_default=None) parser.add_argument( '-d', '--debug', @@ -280,7 +281,7 @@ of recursive searching unittest python files parser.add_argument( '-p', '--pattern', help="file pattern for unittest files ['test_*.py'|'*Test.py'...]", - default="test_*.py", + default="test_???_*.py", # as alphabetical ordered test site metavar='filePattern' ) parser.add_argument( @@ -302,12 +303,14 @@ If name = 'stdout' then all-in-one xml output at 'sys.stdout'. For pipe redirect ) return parser -#export PATH=/volatile/wambeke/SAT5/SAT5_S840_MATIX24/salomeTools-5-cvw:${PATH} +#export PATH=satdir:${PATH} ################################################################### if __name__ == '__main__': # Make the src & command package accessible from all code + # as export PATH=satdir:${PATH} sys.path.insert(0, satdir) + errPrint("WARNING: export PATH=%s:${PATH}\n" % satdir) args = getParser().parse_args(sys.argv[1:]) debug = args.debug diff --git a/commands/config.py b/commands/config.py index 515c2a6..07c2cf2 100644 --- a/commands/config.py +++ b/commands/config.py @@ -16,813 +16,45 @@ # 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 parser = src.options.Options() + parser.add_option('h', 'help', 'boolean', 'help', + _("shows help on command.")) parser.add_option('v', 'value', 'string', 'value', _("Optional: print the value of CONFIG_VARIABLE.")) parser.add_option('d', 'debug', 'string', 'debug', @@ -833,43 +65,41 @@ class Command(_BaseCommand): _("Optional: get information on a product.")) parser.add_option('l', 'list', 'boolean', 'list', _("Optional: list all available applications.")) - parser.add_option('', 'show_patchs', 'boolean', 'show_patchs', + parser.add_option('p', 'show_patchs', 'boolean', 'show_patchs', _("Optional: synthetic view of all patches used in the application")) parser.add_option('c', 'copy', 'boolean', 'copy', _("""Optional: copy a config file (.pyconf) to the personal config files directory. - \tWarning: the included files are not copied. - \tIf a name is given the new config file takes the given name.""")) + Warning: the included files are not copied. + If a name is given the new config file takes the given name.""")) parser.add_option('n', 'no_label', 'boolean', 'no_label', _("Internal use: do not print labels, Works only with --value and --list.")) - parser.add_option('', 'completion', 'boolean', 'completion', + parser.add_option('o', 'completion', 'boolean', 'completion', _("Internal use: print only keys, works only with --value.")) parser.add_option('s', 'schema', 'boolean', 'schema', _("Internal use.")) return parser - def description(self): - '''method that is called when salomeTools is called with --help option. - - :return: The text to display for the config command description. - :rtype: str - ''' - return _("""\ -The config command allows manipulation and operation on config files. + def run(self, cmd_arguments): + """method that is called when salomeTools is called with config parameter.""" + argList = self.assumeAsList(cmd_arguments) -example: ->> sat config SALOME-master --info ParaView""") + # print general help and returns + if len(argList) == 0: + self.print_help() + return RCO.ReturnCode("OK", "No arguments, as 'sat %s --help'" % self.name) - - def run(self, args): - '''method that is called when salomeTools is called with config parameter. - ''' + self._options, remaindersArgs = self.parseArguments(argList) + + if self._options.help: + self.print_help() + return RCO.ReturnCode("OK", "Done 'sat %s --help'" % self.name) + + # shortcuts runner = self.getRunner() config = self.getConfig() logger = self.getLogger() + options = self.getOptions() - # Parse the options - (options, argsc) = self.parse_args(args) - # Only useful for completion mechanism : print the keys of the config if options.schema: get_config_children(config, args) diff --git a/sat b/sat index d374a93..eb1cc10 100755 --- a/sat +++ b/sat @@ -17,15 +17,15 @@ # License along with this library; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -'''\ +"""\ This file is the main entry file to use salomeTools, in mode Command Line Argument(s) (CLI) -''' +""" import os import sys -# OKSYS and KOSYS seems equal on linux or windows +# exit OKSYS and KOSYS seems equal on linux or windows OKSYS = 0 # OK KOSYS = 1 # KO @@ -35,27 +35,41 @@ satdir = os.path.dirname(os.path.realpath(__file__)) # Make the src & commands package accessible from all code sys.path.insert(0, satdir) +import src.loggingSat as LOG +import src.debug as DBG # Easy print stderr (for DEBUG only) +logger = LOG.getDefaultLogger() + + ################################# # MAIN ################################# if __name__ == "__main__": - import src.loggingSat as LOG - import src.debug as DBG # Easy print stderr (for DEBUG only)from src.salomeTools import Sat - from src.salomeTools import Sat + from src.salomeTools import Sat # it is time... - _debug = True # Have to be False in production (for DEBUG only) - DBG.push_debug(_debug) - - logger = LOG.getDefaultLogger() - # instantiate the salomeTools class - sat = Sat(logger) - returnCode = sat.execute_cli(sys.argv[1:]) - logger.debug("sat exit code: %s" % returnCode) + _debug = False # Have to be False in production (for programmers DEBUG only) + DBG.push_debug(_debug) # as __main__ with sys.exit so no need pop_debug - sys.exit(returnCode.toSys()) + sat = Sat(logger) # instantiate the salomeTools class + args = sys.argv[1:] # skip useless "sat' + + try: + returnCode = sat.execute_cli(args) + logger.debug("sat exit code: %s" % returnCode) + sys.exit(returnCode.toSys()) + + except Exception as e: + msg = "Exception raised for execute_cli('%s'):\n\n%s" + 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) diff --git a/src/__init__.py b/src/__init__.py index 5ac9804..3cdf701 100644 --- a/src/__init__.py +++ b/src/__init__.py @@ -1,2 +1,4 @@ -import src.pyconf \ No newline at end of file +# https://www.python.org/dev/peps/pep-0396/ +__version__ = "5.1.0" +__name__ = "SalomeTools" \ No newline at end of file diff --git a/src/coloringSat.py b/src/coloringSat.py index 8fc13c6..7d88a9e 100755 --- a/src/coloringSat.py +++ b/src/coloringSat.py @@ -51,11 +51,10 @@ import colorama as CLRM from colorama import Fore as FG from colorama import Style as ST #from colorama import AnsiToWin32 -from ansitowin32 import AnsiToWin32 # debug is os.name == 'nt' ? +from colorama import AnsiToWin32 # debug is os.name == 'nt' ? CLRM.init(wrap=False) # choose NO wrapping - """ from colorama: Available formatting constants are: @@ -65,8 +64,10 @@ Style: DIM, NORMAL, BRIGHT, RESET_ALL n.b. DIM is not assumed in win32 """ -dir(ST) -# order matters for replace + +# dir(ST) + +# order matters for items replaces forward to color _tags = ( ("", FG.BLACK), ("", FG.RED), @@ -79,12 +80,14 @@ _tags = ( ("", ST.BRIGHT), ("", ST.NORMAL), ("", ST.RESET_ALL), + ("
", FG.BLUE), ("", FG.GREEN + ST.BRIGHT + "OK" + ST.RESET_ALL), ("", 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( ( ("", ""), ("", ""), ("", ""), @@ -96,9 +99,10 @@ _tagsNone = ( ("", ""), ("", ""), ("", ""), + ("
", ""), ("", "OK"), ("", "KO"), -) +) ) def indent(msg, nb, car=" "): """indent nb car (spaces) multi lines message except first one""" @@ -176,7 +180,7 @@ if __name__ == "__main__": log("import colorama in %s" % __file__) log("set green and not reset...") log("...and here is not green because appended reset at end of message") - log("dir(FG):\n%s" % dir(FG)) - log("dir(ST):\n%s" % dir(ST)) + log("dir(FG):\n%s ... or ??" % dir(FG)) + log("dir(ST):\n%s ... or ??" % dir(ST)) - \ No newline at end of file + diff --git a/src/configManager.py b/src/configManager.py new file mode 100644 index 0000000..e05eed5 --- /dev/null +++ b/src/configManager.py @@ -0,0 +1,935 @@ +#!/usr/bin/env python +#-*- coding:utf-8 -*- +# Copyright (C) 2010-2012 CEA/DEN +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import os +import platform +import datetime +import shutil +import sys + +import src.debug as DBG +import src.loggingSat as LOG +import src.returnCode as RCO +import src.architecture as ARCH +import src.utilsSat as UTS + + +class ConfigOpener: + '''Class that helps to find an application pyconf + in all the possible directories (pathList) + ''' + def __init__(self, pathList): + '''Initialization + + :param pathList list: The list of paths where to search a pyconf. + ''' + self.pathList = pathList + + def __call__(self, name): + if os.path.isabs(name): + return src.pyconf.ConfigInputStream(open(name, 'rb')) + else: + return src.pyconf.ConfigInputStream( + open(os.path.join( self.get_path(name), name ), 'rb') ) + raise IOError(_("Configuration file '%s' not found") % name) + + def get_path( self, name ): + '''The method that returns the entire path of the pyconf searched + :param name str: The name of the searched pyconf. + ''' + for path in self.pathList: + if os.path.exists(os.path.join(path, name)): + return path + raise IOError(_("Configuration file '%s' not found") % name) + +class ConfigManager: + '''Class that manages the read of all the configuration files of salomeTools + ''' + def __init__(self, datadir=None): + self.logger = LOG.getDefaultLogger() + + + def _create_vars(self, application=None, command=None, datadir=None): + '''Create a dictionary that stores all information about machine, + user, date, repositories, etc... + + :param application str: The application for which salomeTools is called. + :param command str: The command that is called. + :param datadir str: The repository that contain external data + for salomeTools. + :return: The dictionary that stores all information. + :rtype: dict + ''' + var = {} + var['user'] = ARCH.get_user() + var['salometoolsway'] = os.path.dirname( + os.path.dirname(os.path.abspath(__file__))) + var['srcDir'] = os.path.join(var['salometoolsway'], 'src') + var['internal_dir'] = os.path.join(var['srcDir'], 'internal_config') + var['sep']= os.path.sep + + # datadir has a default location + var['datadir'] = os.path.join(var['salometoolsway'], 'data') + if datadir is not None: + var['datadir'] = datadir + + var['personalDir'] = os.path.join(os.path.expanduser('~'), + '.salomeTools') + UTS.ensure_path_exists(var['personalDir']) + + var['personal_applications_dir'] = os.path.join(var['personalDir'], + "Applications") + UTS.ensure_path_exists(var['personal_applications_dir']) + + var['personal_products_dir'] = os.path.join(var['personalDir'], + "products") + UTS.ensure_path_exists(var['personal_products_dir']) + + var['personal_archives_dir'] = os.path.join(var['personalDir'], + "Archives") + UTS.ensure_path_exists(var['personal_archives_dir']) + + var['personal_jobs_dir'] = os.path.join(var['personalDir'], + "Jobs") + UTS.ensure_path_exists(var['personal_jobs_dir']) + + var['personal_machines_dir'] = os.path.join(var['personalDir'], + "Machines") + UTS.ensure_path_exists(var['personal_machines_dir']) + + # read linux distributions dictionary + distrib_cfg = src.pyconf.Config(os.path.join(var['srcDir'], + 'internal_config', + 'distrib.pyconf')) + + # set platform parameters + dist_name = ARCH.get_distribution(codes=distrib_cfg.DISTRIBUTIONS) + dist_version = ARCH.get_distrib_version(dist_name, + codes=distrib_cfg.VERSIONS) + dist = dist_name + dist_version + + var['dist_name'] = dist_name + var['dist_version'] = dist_version + var['dist'] = dist + var['python'] = ARCH.get_python_version() + + var['nb_proc'] = ARCH.get_nb_proc() + node_name = platform.node() + var['node'] = node_name + var['hostname'] = node_name + + # set date parameters + dt = datetime.datetime.now() + var['date'] = dt.strftime('%Y%m%d') + var['datehour'] = dt.strftime('%Y%m%d_%H%M%S') + var['hour'] = dt.strftime('%H%M%S') + + var['command'] = str(command) + var['application'] = str(application) + + # Root dir for temporary files + var['tmp_root'] = os.sep + 'tmp' + os.sep + var['user'] + # particular win case + if ARCH.is_windows() : + var['tmp_root'] = os.path.expanduser('~') + os.sep + 'tmp' + + return var + + def get_command_line_overrides(self, options, sections): + '''get all the overwrites that are in the command line + + :param options: the options from salomeTools class + initialization (like -l5 or --overwrite) + :param sections str: The config section to overwrite. + :return: The list of all the overwrites to apply. + :rtype: list + ''' + # when there are no options or not the overwrite option, + # return an empty list + if options is None or options.overwrite is None: + return [] + + over = [] + for section in sections: + # only overwrite the sections that correspond to the option + over.extend(filter(lambda l: l.startswith(section + "."), + options.overwrite)) + return over + + def get_config(self, application=None, options=None, command=None, + datadir=None): + '''get the config from all the configuration files. + + :param application str: The application for which salomeTools is called. + :param options class Options: The general salomeTools + options (--overwrite or -v5, for example) + :param command str: The command that is called. + :param datadir str: The repository that contain + external data for salomeTools. + :return: The final config. + :rtype: class 'src.pyconf.Config' + ''' + + # create a ConfigMerger to handle merge + merger = src.pyconf.ConfigMerger() #MergeHandler()) + + # create the configuration instance + cfg = src.pyconf.Config() + + # ===================================================================== + # create VARS section + var = self._create_vars(application=application, command=command, + datadir=datadir) + # add VARS to config + cfg.VARS = src.pyconf.Mapping(cfg) + for variable in var: + cfg.VARS[variable] = var[variable] + + # apply overwrite from command line if needed + for rule in self.get_command_line_overrides(options, ["VARS"]): + exec('cfg.' + rule) # this cannot be factorized because of the exec + + # ===================================================================== + # Load INTERNAL config + # read src/internal_config/salomeTools.pyconf + src.pyconf.streamOpener = ConfigOpener([ + os.path.join(cfg.VARS.srcDir, 'internal_config')]) + try: + internal_cfg = src.pyconf.Config(open(os.path.join(cfg.VARS.srcDir, + 'internal_config', 'salomeTools.pyconf'))) + except src.pyconf.ConfigError as e: + raise src.SatException(_("Error in configuration file:" + " salomeTools.pyconf\n %(error)s") % \ + {'error': str(e) }) + + merger.merge(cfg, internal_cfg) + + # apply overwrite from command line if needed + for rule in self.get_command_line_overrides(options, ["INTERNAL"]): + exec('cfg.' + rule) # this cannot be factorized because of the exec + + # ===================================================================== + # Load LOCAL config file + # search only in the data directory + src.pyconf.streamOpener = ConfigOpener([cfg.VARS.datadir]) + try: + local_cfg = src.pyconf.Config(open(os.path.join(cfg.VARS.datadir, + 'local.pyconf')), + PWD = ('LOCAL', cfg.VARS.datadir) ) + except src.pyconf.ConfigError as e: + raise src.SatException(_("Error in configuration file: " + "local.pyconf\n %(error)s") % \ + {'error': str(e) }) + except IOError as error: + e = str(error) + raise src.SatException( e ); + merger.merge(cfg, local_cfg) + + # When the key is "default", put the default value + if cfg.LOCAL.base == "default": + cfg.LOCAL.base = os.path.abspath( + os.path.join(cfg.VARS.salometoolsway, + "..", + "BASE")) + if cfg.LOCAL.workdir == "default": + cfg.LOCAL.workdir = os.path.abspath( + os.path.join(cfg.VARS.salometoolsway, + "..")) + if cfg.LOCAL.log_dir == "default": + cfg.LOCAL.log_dir = os.path.abspath( + os.path.join(cfg.VARS.salometoolsway, + "..", + "LOGS")) + + if cfg.LOCAL.archive_dir == "default": + cfg.LOCAL.archive_dir = os.path.abspath( + os.path.join(cfg.VARS.salometoolsway, + "..", + "ARCHIVES")) + + # apply overwrite from command line if needed + for rule in self.get_command_line_overrides(options, ["LOCAL"]): + exec('cfg.' + rule) # this cannot be factorized because of the exec + + # ===================================================================== + # Load the PROJECTS + projects_cfg = src.pyconf.Config() + projects_cfg.addMapping("PROJECTS", + src.pyconf.Mapping(projects_cfg), + "The projects\n") + projects_cfg.PROJECTS.addMapping("projects", + src.pyconf.Mapping(cfg.PROJECTS), + "The projects definition\n") + + for project_pyconf_path in cfg.PROJECTS.project_file_paths: + if not os.path.exists(project_pyconf_path): + msg = _("Cannot find project file %s, 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 += "
%s: " % 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("
%s: ERROR %s\n" % (vname, str(e))) + return + + # in this case, display only the value + if show_label: + stream.write(tab_level) + stream.write("" % 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 diff --git a/src/debug.py b/src/debug.py index dbf7e67..9a9056d 100644 --- a/src/debug.py +++ b/src/debug.py @@ -38,6 +38,10 @@ import pprint as PP _debug = [False] #support push/pop for temporary activate debug outputs +_user = os.environ['USER'] +_developpers = ["christian", "wambeke", ] # crouzet, kloss ... + + def indent(text, amount=2, ch=' '): """indent multi lines message""" padding = amount * ch @@ -46,8 +50,10 @@ def indent(text, amount=2, ch=' '): def write(title, var="", force=None, fmt="\n#### DEBUG: %s:\n%s\n"): """write sys.stderr a message if _debug[-1]==True or optionaly force=True""" if _debug[-1] or force: - if 'src.pyconf.Config' in str(type(var)): + if 'pyconf.Config' in str(type(var)): sys.stderr.write(fmt % (title, indent(getStrConfigDbg(var)))) + if 'loggingSat.UnittestStream' in str(type(var)): + sys.stderr.write(fmt % (title, indent(var.getLogs()))) elif type(var) is not str: sys.stderr.write(fmt % (title, indent(PP.pformat(var)))) else: diff --git a/src/i18n/fr/LC_MESSAGES/salomeTools.po b/src/i18n/fr/LC_MESSAGES/salomeTools.po index 1101bdf..692522d 100644 --- a/src/i18n/fr/LC_MESSAGES/salomeTools.po +++ b/src/i18n/fr/LC_MESSAGES/salomeTools.po @@ -42,46 +42,38 @@ msgid "batch mode (no question)." msgstr "mode batch (pas de question)." msgid "all traces in the terminal (for example compilation logs)." -msgstr "toutes traces dans le terminal (par exemple: log de compilation)" +msgstr "toutes traces dans le terminal (par exemple: log de compilation)." -msgid "put the command result and paths to log files." +msgid "put the command result and paths to log files" msgstr "redirige resultats de commandes vers log files" msgid " is not a valid command" msgstr " n'est pas une commande valide" -msgid "" -"WARNING: the logs_paths_in_file option will not be taken into account.\n" -"Here is the error:" -msgstr "" +msgid "the 'logs_paths_in_file' option will not be taken into account:" +msgstr "l'option 'logs_paths_in_file' ne sera pas prise en compte:" -msgid "Usage: " -msgstr "Utilisation : " +msgid "Usage:" +msgstr "Utilisation:" -msgid "Available commands are:\n" -msgstr "Les commandes disponibles sont:\n" +msgid "Available commands are:" +msgstr "Les commandes disponibles sont:" -msgid "" -"\n" -"Getting the help for a specific command: " -msgstr "" -"\n" -"Obtenir l'aide d'une commande spécifique : " +msgid "Getting help for a specific command: " +msgstr "Obtenir l'aide d'une commande spécifique: " -msgid "lsb_release not installed\n" -msgstr "lsb_release n'est pas installé\n" +msgid "'lsb_release' is not installed" +msgstr "'lsb_release' n'est pas installé" -msgid "You can define $LSB_PATH to give the path to lsb_release\n" -msgstr "Vous pouvez définir $LSB_PATH pour donner le chemin vers lsb_release\n" +msgid "You can define $LSB_PATH to give the path to lsb_release" +msgstr "Vous pouvez définir $LSB_PATH pour donner le chemin vers lsb_release" #, python-format -msgid "Unknown distribution: '%s'\n" -msgstr "Distribution inconnue : '%s'\n" +msgid "Unknown distribution: '%s'" +msgstr "Distribution inconnue : '%s'" -msgid "Please add your distribution to src/internal_config/distrib.pyconf\n" -msgstr "" -"SVP ajoutez votre distribution au fichier src/internal_config/distrib." -"pyconf\n" +msgid "Add your distribution to src/internal_config/distrib.pyconf" +msgstr "Ajoutez votre distribution au fichier src/internal_config/distrib.pyconf" msgid " is not a valid option" msgstr " n'est pas une option valide" diff --git a/src/loggingSat.py b/src/loggingSat.py index 2ac44a0..30f1a5e 100755 --- a/src/loggingSat.py +++ b/src/loggingSat.py @@ -16,6 +16,7 @@ import os import sys import logging import pprint as PP +import src.coloringSat as COLS _verbose = False _name = "loggingSat" @@ -37,6 +38,7 @@ log("import logging on %s" % logging.__file__) _loggerDefaultName = 'SatDefaultLogger' _loggerUnittestName = 'SatUnittestLogger' + def getDefaultLogger(): log("getDefaultLogger %s" % _loggerDefaultName) return logging.getLogger(_loggerDefaultName) @@ -53,18 +55,34 @@ _loggerUnittest = getUnittestLogger() class DefaultFormatter(logging.Formatter): + + # to set color prefix, problem with indent format + _ColorLevelname = { + "DEBUG": "", + "INFO": "", + "WARNING": "", + "ERROR": "", + "CRITICAL": "", + } + 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 + "" + class UnittestFormatter(logging.Formatter): def format(self, record): # print "", record.levelname #type(record), dir(record) nb = len("2018-03-17 12:15:41 :: INFO :: ") - return indent(super(UnittestFormatter, self).format(record), nb) + res = indent(super(UnittestFormatter, self).format(record), nb) + return COLS.toColor(res) class UnittestStream(object): @@ -75,17 +93,25 @@ class UnittestStream(object): https://stackoverflow.com/questions/31999627/storing-logger-messages-in-a-string """ def __init__(self): - self.logs = '' + self._logs = '' + + def getLogs(self): + return self._logs + + def getLogsAndClear(self): + res = self._logs + self._logs = '' + return res def write(self, astr): # log("UnittestStream.write('%s')" % astr) - self.logs += astr + self._logs += astr def flush(self): pass def __str__(self): - return self.logs + return self._logs def initLoggerAsDefault(logger, fmt=None, level=None): @@ -94,7 +120,7 @@ def initLoggerAsDefault(logger, fmt=None, level=None): exept info() outed 'as it' without any format """ log("initLoggerAsDefault name=%s\nfmt='%s' level='%s'" % (logger.name, fmt, level)) - handler = logging.StreamHandler() # Logging vers console + handler = logging.StreamHandler(sys.stdout) # Logging vers console if fmt is not None: # formatter = logging.Formatter(fmt, "%Y-%m-%d %H:%M:%S") formatter = DefaultFormatter(fmt, "%y-%m-%d %H:%M:%S") @@ -120,7 +146,9 @@ def initLoggerAsUnittest(logger, fmt=None, level=None): formatter = UnittestFormatter(fmt, "%Y-%m-%d %H:%M:%S") handler.setFormatter(formatter) logger.addHandler(handler) - logger.streamUnittest = stream + logger.stream = stream + logger.getLogs = stream.getLogs + logger.getLogsAndClear = stream.getLogsAndClear if level is not None: logger.setLevel(level) else: @@ -135,16 +163,17 @@ def testLogger_1(logger): logger.warning('test logger warning') logger.error('test logger error') logger.critical('test logger critical') - logger.info('test logger info:\n- second line\n- third line') + logger.info('\ntest logger info: no indent\n- second line\n- third line\n') logger.warning('test logger warning:\n- second line\n- third line') if __name__ == "__main__": - print("\n**** DEFAULT") + print("\n**** DEFAULT logger") logdef = getDefaultLogger() + # problem if add +2? if append 2 setColorLevelname , not fixed initLoggerAsDefault(logdef, '%(levelname)-8s :: %(message)s', level=logging.INFO) testLogger_1(logdef) - print("\n**** UNITTEST") + print("\n**** UNITTEST logger") loguni = getUnittestLogger() initLoggerAsUnittest(loguni, '%(asctime)s :: %(levelname)-8s :: %(message)s', level=logging.DEBUG) testLogger_1(loguni) # is silent @@ -153,5 +182,10 @@ if __name__ == "__main__": from colorama import Fore as FG from colorama import Style as ST - print("this is %scolored%s!" % (FG.G)) - \ No newline at end of file + print("this is %scolored in green%s !!!" % (FG.GREEN, ST.RESET_ALL)) + +else: + _loggerDefault = getDefaultLogger() + _loggerUnittest = getUnittestLogger() + initLoggerAsDefault(_loggerDefault, '%(levelname)-8s :: %(message)s', level=logging.INFO) + initLoggerAsUnittest(_loggerUnittest, '%(asctime)s :: %(levelname)-8s :: %(message)s', level=logging.DEBUG) diff --git a/src/options.py b/src/options.py index ac7270e..714fcc4 100644 --- a/src/options.py +++ b/src/options.py @@ -15,26 +15,29 @@ # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -'''The Options class that manages the access to all options passed as - parameters in salomeTools command lines -''' + +"""\ +The Options class that manages the access to all options passed as +parameters in salomeTools command lines +""" + import getopt import sys import pprint as PP import src import src.debug as DBG # Easy print stderr (for DEBUG only) -import src.printcolors class OptResult(object): - '''An instance of this class will be the object manipulated - in code of all salomeTools commands - The aim of this class is to have an elegant syntax - to manipulate the options. - ex: - print(options.level) - 5 - ''' + """ + An instance of this class will be the object manipulated + in code of all salomeTools commands + The aim of this class is to have an elegant syntax to manipulate the options. + + example: + >> print(options.level) + >> 5 + """ def __init__(self): '''Initialization ''' @@ -99,6 +102,13 @@ class Options(object): :return: Nothing. :rtype: N\A ''' + tmp = [o['shortName'] for o in self.options if o['shortName'] != ''] + if shortName in tmp: + raise Exception("option '-%s' existing yet" % shortName) + tmp = [o['longName'] for o in self.options if o['longName'] != ''] + if longName in tmp: + raise Exception("option '--%s' existing yet" % longName) + option = dict() option['shortName'] = shortName option['longName'] = longName @@ -111,6 +121,7 @@ class Options(object): option['destName'] = destName option['helpString'] = helpString option['result'] = default + self.options.append(option) def get_help(self): @@ -127,7 +138,7 @@ class Options(object): # for all options, gets its values. # "shortname" is an optional field of the options - msg += src.printcolors.printcHeader(_("Available options are:")) + "\n" + msg += "
" + _("Available options are:") + "\n" for option in self.options: if 'shortName' in option and len(option['shortName']) > 0: msg += "\n -%(shortName)1s, --%(longName)s" \ @@ -137,9 +148,6 @@ class Options(object): % option return msg - def print_help(self): - print(self.get_help()) - def parse_args(self, argList=None): '''Method that instantiates the class OptResult @@ -177,7 +185,7 @@ class Options(object): try: optlist, args = getopt.getopt(argList, shortNameOption, longNameOption) except Exception as e: - msg = str(e) + ", expected:\n\n%s" % str(self) + msg = str(e) + "\n\n" + self.get_help() raise Exception(msg) # instantiate and completing the optResult that will be returned diff --git a/src/salomeTools.py b/src/salomeTools.py index a009fdb..12e5101 100755 --- a/src/salomeTools.py +++ b/src/salomeTools.py @@ -18,7 +18,7 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA '''This file is the main entry file to salomeTools -NO __main__ entry allowed, use sat +NO __main__ entry allowed, use 'sat' (in parent directory) ''' ######################################################################## @@ -39,9 +39,9 @@ import traceback import subprocess as SP import pprint as PP +import src # for __version__ import src.debug as DBG # Easy print stderr (for DEBUG only) import src.returnCode as RCO # Easy (ok/ko, why) return methods code -from src.exceptionSat import ExceptionSat # get path to src rootdir = os.path.realpath( os.path.join(os.path.dirname(__file__), "..") ) @@ -50,7 +50,7 @@ srcdir = os.path.join(rootdir, "src") cmdsdir = os.path.join(rootdir, "commands") # load resources for internationalization -gettext.install('salomeTools', os.path.join(srcdir, 'i18n')) +gettext.install("salomeTools", os.path.join(srcdir, "i18n")) # The possible hooks : # pre is for hooks to be executed before commands @@ -64,69 +64,91 @@ _LANG = os.environ["LANG"] # original locale # utility methods ######################################################################## def find_command_list(dirPath): - '''Parse files in dirPath that end with .py : it gives commands list + """ + Parse files in dirPath that end with '.py' : it gives commands list :param dirPath str: The directory path where to search the commands :return: cmd_list : the list containing the commands name :rtype: list - ''' + """ cmd_list = [] for item in os.listdir(dirPath): if item in ["__init__.py"]: #avoid theses files continue - if item.endswith('.py'): - cmd_list.append(item[:-len('.py')]) - return cmd_list + if item.endswith(".py"): + cmd_list.append(item[:-len(".py")]) + return sorted(cmd_list) # The list of valid salomeTools commands from cmdsdir #_COMMANDS_NAMES = ['config', 'compile', 'prepare',...] _COMMANDS_NAMES = find_command_list(cmdsdir) def getCommandsList(): - """Gives commands list (as basename of files cmdsdir/*.py) - """ + """Gives commands list (as basename of files cmdsdir/*.py)""" return _COMMANDS_NAMES def launchSat(command): - """launch sat as subprocess popen + """ + launch sat as subprocess popen command as string ('sat --help' for example) used for unittest, or else... returns tuple (stdout, stderr) """ if "sat" not in command.split()[0]: raise Exception(_("Not a valid command for launchSat: '%s'") % command) - env = dict(os.environ) - env["PATH"] = rootdir + ":" + env["PATH"] + env = dict(os.environ) #copy + # theorically useless + # env["PATH"] = rootdir + ":" + env["PATH"] res =SP.Popen(command, shell=True, env=env, stdout=SP.PIPE, stderr=SP.PIPE).communicate() return res def setNotLocale(): """force english at any moment""" os.environ["LANG"] = '' - gettext.install('salomeTools', os.path.join(srcdir, 'i18n')) + gettext.install("salomeTools", os.path.join(srcdir, "i18n")) DBG.write("setNotLocale", os.environ["LANG"]) def setLocale(): """reset initial locale at any moment - 'fr' or else 'TODO' from initial environment var '$LANG' + 'fr' or else (TODO) from initial environment var '$LANG' + 'i18n' as 'internationalization' """ os.environ["LANG"] = _LANG - gettext.install('salomeTools', os.path.join(srcdir, 'i18n')) + gettext.install("salomeTools", os.path.join(srcdir, "i18n")) DBG.write("setLocale", os.environ["LANG"]) +def getVersion(): + """get version number as string""" + return src.__version__ + +def assumeAsList(strOrList): + """return a list as sys.argv if string""" + if type(strOrList) is list: + return list(strOrList) # copy + else: + res = strOrList.split(" ") + return [r for r in res if r != ""] # supposed string to split for convenience ######################################################################## # _BaseCmd class ######################################################################## class _BaseCommand(object): - """_BaseCmd is the base class for all inherited commands of salomeTools + """ + _BaseCmd is the base class for all inherited commands of salomeTools instancied as classes 'Command' in files '.../commands/*.py' """ - def __init__(self, name): - self.name = name - self.runner = None # runner (as caller) usually as Sat instance - # self.config = None # config pyconf usually loaded with _getConfig method - self.logger = None # logger (from caller) usually as Sat instance logger + + # supposed never seen, set "config", "prepare"... in inherited commands + name = "salomeTools" + + def __init__(self, runner): + # runner (as caller) usually as Sat instance + self._runner = runner + # config pyconf usually loaded in runner, but sometimes local value + self._config = None + # logger (from caller) usually as Sat instance logger, but sometimes local value + self._logger = runner.logger + self._options = None def getClassName(self): """ @@ -135,230 +157,117 @@ class _BaseCommand(object): '.../commands/config.py' or '.../commands/prepare.py' """ return "%s.%s" % (self.name, self.__class__.__name__) - + def __repr__(self): tmp = PP.pformat(self.__dict__) res = "%s(\n %s)\n" % (self.getClassName(), tmp[1:-1]) return res def run(self, args): - return RCO.ReturnCode("KO", "_BaseCommand.run() have to be inherited") - - def setRunner(self, runner): - """set who owns me, and use me whith method run()""" - self.runner = runner - + """ + virtual example method for Command instance + have to return RCO.ReturnCode() + """ + return RCO.ReturnCode("KO", "_BaseCommand.run() have not to be instancied and called") + def setLogger(self, logger): """set logger for run command""" - self.logger = logger - + if self._logger is not None: + # supposed logger.debug for future + self._logger.warning("change logger for %s, are you sure" % self.getClassName()) + self._logger = logger + def getLogger(self): - if self.logger is None: # could use runner Sat instance logger - return self.runner.getLogger() - else: # could use local logger - return self.logger - + if self._logger is None: + raise Exception("%s instance needs self._logger not None, fix it." % self.getClassName()) + else: + return self._logger + + def getOptions(self): + if self._options is None: + raise Exception("%s instance needs self._option not None, fix it." % self.getClassName()) + else: + return self._options + def getRunner(self): - if self.runner is None: - raise Exception("have to set runner attribute, fix it.") + if self._runner is None: + raise Exception("%s instance needs self.runner not None, fix it." % self.getClassName()) else: - return self.runner + return self._runner + + def getConfig(self): + """ + supposedly (for now) no multiply local config(s) + only one config in runner.config + may be some for future... + """ + if self._runner.config is None: + self._logger.error("%s instance have runner.config None, fix it." % self.getClassName()) + return self._runner.config + + def assumeAsList(self, strOrList): + return assumeAsList(strOrList) def getParser(self): raise Exception("_BaseCmd class have not to be instancied, only for inheritage") - def parse_args(self, args): - """smart parse command arguments skipping first argument name appli to load if present""" - parser = self.getParser() - if type(args) is list: - argList = args - else: - argList = args.split(' ') - DBG.write("%s args" % self.name, args, True) - # or if args[0][0] == "-": #as argument name appli without "--" - if self.runner.nameAppliLoaded is None: - (options, argsc) = parser.parse_args(args) - else: - (options, argsc) = parser.parse_args(args[1:]) # skip name appli - DBG.write("%s options" % self.name, options) - DBG.write("%s remainders args" % self.name, argsc) - if argsc != []: - self.getLogger().error("\n\ncommand '%s' remainders args %s\n\n" % (self.name, argsc)) - return (options, argsc) + def parseArguments(self, cmd_arguments): + """ + smart parse command arguments skip + first argument name appli to load, if present + """ + argList = self.assumeAsList(cmd_arguments) + DBG.write("%s.Command arguments" % self.name, argList) + commandOptions, remaindersArgs = self.getParser().parse_args(argList) + DBG.write("%s.Command options" % self.name, commandOptions) + DBG.write("%s.Command remainders arguments" % self.name, remaindersArgs) + if remaindersArgs != []: + self.getLogger().error("%s.Command have unknown remainders arguments:\n%s\n" % \ + (self.name, remaindersArgs)) + return commandOptions, remaindersArgs def description(self): - '''method that is called when salomeTools is called with --help option. - - :return: The text to display for the config command description. - :rtype: str - ''' - raise Exception("_BaseCmd class have not to be instancied, only for inheritage") + """ + method called when salomeTools have '--help' argument. + returns The text to display for the command description + which is current Command class docstring 'self.__doc__', + with traduction + """ + return _(self.__doc__) - def run(self, args, runner, logger): - '''method that is called when salomeTools is called with self.name parameter. - ''' - raise Exception("_BaseCmd class have not to be instancied, only for inheritage") - - def getConfig(self): - if self.runner.config is None: - self.runner.config = self._getConfig() - #DBG.write("_baseCommand runner", self.runner) - DBG.write("_baseCommand runner.config", self.runner.config) - return self.runner.config - - def _getConfig(self): - '''The function that will load the configuration (all pyconf) - and returns the config from files .pyconf - ''' - if self.runner.config is not None: - raise Exception("config existing yet in 's' instance" % self.runner.getClassName()) - - # Get the arguments in a list and remove the empty elements - # DBG.write("%s.runner.arguments" % self.name, self.runner.arguments) - - self.parser = self.getParser() - try: - options, args = self.parser.parse_args(self.runner.arguments[1:]) - DBG.write("%s args" % self.name, args) - DBG.write("%s options" % self.name, options) - except Exception as exc: - write_exception(exc) - sys.exit(RCO.KOSYS) - - self.arguments = args # args are postfixes options: args[0] is the 'commands' command - self.options = options # the options passed to salomeTools - - if type(args) == type(''): - # split by spaces without considering spaces in quotes - argv_0 = re.findall(r'(?:"[^"]*"|[^\s"])+', args) - else: - argv_0 = args - - if argv_0 != ['']: - while "" in argv_0: argv_0.remove("") - - # Format the argv list in order to prevent strings - # that contain a blank to be separated - argv = [] - elem_old = "" - for elem in argv_0: - if argv == [] or elem_old.startswith("-") or elem.startswith("-"): - argv.append(elem) - else: - argv[-1] += " " + elem - elem_old = elem - - # if it is provided by the command line, get the application - appliToLoad = None - if argv not in [[''], []] and argv[0][0] != "-": - appliToLoad = argv[0].rstrip('*') - argv = argv[1:] - - # Check if the global options of salomeTools have to be changed - if options: - options_save = self.options - self.options = options - - # read the configuration from all the pyconf files - cfgManager = getConfigManager() # commands.config.ConfigManager() - DBG.write("appli to load", appliToLoad, True) - config = cfgManager.get_config(datadir=self.runner.datadir, - application=appliToLoad, - options=self.runner.options, - command=self.name) # command=__nameCmd__) - self.runner.nameAppliLoaded = appliToLoad - # DBG.write("appli loaded", config, True) - - # Set the verbose mode if called - DBG.tofix("verbose/batch/logger_add_link -1/False/None", True) - verbose = -1 - batch = False - logger_add_link = None - if verbose > -1: - verbose_save = self.options.output_verbose_level - self.options.__setattr__("output_verbose_level", verbose) - - # Set batch mode if called - if batch: - batch_save = self.options.batch - self.options.__setattr__("batch", True) - - # set output level - if self.runner.options.output_verbose_level is not None: - config.USER.output_verbose_level = self.runner.options.output_verbose_level - if config.USER.output_verbose_level < 1: - config.USER.output_verbose_level = 0 - silent = (config.USER.output_verbose_level == 0) - - # create log file - micro_command = False - if logger_add_link: - micro_command = True - logger_command = src.logger.Logger(config, - silent_sysstd=silent, - all_in_terminal=self.runner.options.all_in_terminal, - micro_command=micro_command) - - # Check that the path given by the logs_paths_in_file option - # is a file path that can be written - if self.runner.options.logs_paths_in_file and not micro_command: - try: - self.options.logs_paths_in_file = os.path.abspath( - self.options.logs_paths_in_file) - dir_file = os.path.dirname(self.options.logs_paths_in_file) - if not os.path.exists(dir_file): - os.makedirs(dir_file) - if os.path.exists(self.options.logs_paths_in_file): - os.remove(self.options.logs_paths_in_file) - file_test = open(self.options.logs_paths_in_file, "w") - file_test.close() - except Exception as e: - msg = _("WARNING: the logs_paths_in_file option will " - "not be taken into account.\nHere is the error:") - logger_command.write("%s\n%s\n\n" % ( - src.printcolors.printcWarning(msg), - str(e))) - self.options.logs_paths_in_file = None - - return config + def run(self, cmd_arguments): + """ + method called when salomeTools processes command(s) parameters""" + raise Exception("_BaseCmd class have not to be instancied, useful only for inheritage") - def get_products_list(self, options, cfg, logger): - '''method that gives the product list with their informations from - configuration regarding the passed options. - - :param options Options: The Options instance that stores the commands - arguments - :param config Config: The global configuration - :param logger Logger: The logger instance to use for the display and logging - :return: The list of (product name, product_informations). - :rtype: List - ''' - # Get the products to be prepared, regarding the options - if options.products is None: - # No options, get all products sources - products = cfg.APPLICATION.products - else: - # if option --products, check that all products of the command line - # are present in the application. - products = options.products - for p in products: - if p not in cfg.APPLICATION.products: - raise src.SatException(_("Product %(product)s " - "not defined in application %(application)s") % - { 'product': p, 'application': cfg.VARS.application} ) - - # Construct the list of tuple containing - # the products name and their definition - products_infos = src.product.get_products_infos(products, cfg) + def print_help(self): + """ + Prints help for a command. Function called with + 'sat --help ' or + 'sat --help --help' or + 'sat ' 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 = "
Version: " + version + # description of the command that is done in the command.py file + msg += "
Description:\n" + msg += self.description() + "\n\n" - return products_infos - + # description of the command options + msg += self.getParser().get_help() + "\n" + return msg ######################################################################## # Sat class ######################################################################## class Sat(object): """The main class that stores all the commands of salomeTools + (usually known as 'runner' argument in Command classes) """ def __init__(self, logger): """Initialization @@ -373,8 +282,9 @@ class Sat(object): self.CONFIG_FILENAME = "sat-config.pyconf" + self.configManager = None # the config Manager that will be used to set self.config self.config = None # the config that will be read using pyconf module - self.logger = None # the logger that will be use + self.logger = logger # the logger that will be use self.arguments = None # args are postfixes options: args[0] is the 'commands' command self.options = None # the options passed to salomeTools @@ -404,19 +314,16 @@ class Sat(object): if self.logger is None: # could use owner Sat instance logger import src.loggingSat as LOG self.logger=LOG.getDefaultLogger() - self.logger.error("Sat logger not set, fixed as default") + self.logger.critical("Sat logger not set, unexpected situation, fixed as default") return self.logger else: # could use local logger return self.logger + def getConfig(self): + return self.config + def assumeAsList(self, strOrList): - """return a list as sys.argv if string - """ - if type(strOrList) is list: - return list(strOrList) # copy - else: - return strOrList.split(" ") # supposed string to split for convenience - + return assumeAsList(strOrList) def _getParser(self): """ @@ -442,47 +349,53 @@ class Sat(object): return parser - def parseGenericArguments(self, arguments): + def parseArguments(self, arguments): args = self.assumeAsList(arguments) genericOptions, remaindersArgs = self.parser.parse_args(args) - DBG.write("Sat generic arguments", genericArgs) + DBG.write("Sat generic options", genericOptions) DBG.write("Sat remainders arguments", remaindersArgs) return genericOptions, remaindersArgs - def _getCommand(self, name): + def _getModule(self, name): """ - create and add Command 'name' as instance of class in dict self.commands - create only one instance + load and add module Command 'name' in dict self.commands + have to be called only one time maximum for each module Command """ if name not in _COMMANDS_NAMES: - raise AttributeError(_("command not valid: '%s'") % name) + raise Exception(_("module command not valid: '%s'") % name) if name in self.commands.keys(): - raise AttributeError(_("command existing yet: '%s', use getCommand") % name) + raise Exception(_("module command existing yet: '%s', use getModule") % name) file_, pathname, description = imp.find_module(name, [cmdsdir]) + # could raise Exception in load (catched in sat, logger.critical) module = imp.load_module(name, file_, pathname, description) - try: - cmdInstance = module.Command(name) - except: - DBG.tofix("no Command() class in %s" % pathname, dir(module), True) - raise Exception("no Command() class in %s" % pathname) - - cmdInstance.setRunner(self) # self is runner, owns cmdInstance - DBG.write("Sat load new command", cmdInstance) - return cmdInstance - - def getCommand(self, name): + self.commands[name] = module # store module loaded (only one time) + self.logger.debug("Sat load module command %s" % name) + return module + + def getModule(self, name): + """ + returns only-one-time loaded module Command 'name' + assume load if not done yet """ - returns inherited instance of _BaseCmd for command 'name' - if not existing as self.commands[name], create it. + if name in self.commands.keys(): + return self.commands[name] + else: + return self._getModule(name) - example: - returns Command() from command.config + def getCommandInstance(self, name): """ - if name not in self.commands.keys(): - self.commands[name] = self._getCommand(name) - return self.commands[name] - + returns inherited instance of Command(_BaseCmd) for command 'name' + if module not loaded yet, load it. + """ + module = self.getModule(name) + try: + commandInstance = module.Command(self) # set runner as 'parent' (and logger...) + except Exception as e: + raise Exception("Problem instance %s.Command(): %s" % (name, e)) + self.logger.debug("Sat new instance %s.Command()" % name) + return commandInstance + def execute_cli(self, cli_arguments): """select first argument as a command in directory 'commands', and launch on arguments @@ -492,146 +405,57 @@ class Sat(object): # print general help and returns if len(args) == 0: - print_help() - return RCO.ReturnCode("OK", "No arguments as --help") - + self.print_help() + return RCO.ReturnCode("OK", "No arguments, as 'sat --help'") + + self.options, remaindersArgs = self.parseArguments(args) + # if the help option has been called, print command help and returns if self.options.help: - self.print_help(self.arguments) + self.print_help() return RCO.ReturnCode("OK", "Option --help") # the command called - cmdName = args[0] + cmdName = remaindersArgs[0] # create/get dynamically the command instance to call its 'run' method - cmdInstance = self.getCommand(cmdName) + cmdInstance = self.getCommandInstance(cmdName) # Run the command using the arguments - returnCode = cmdInstance.run(args[1:]) + returnCode = cmdInstance.run(remaindersArgs[1:]) return returnCode - - def print_help(self, opt): - '''Prints help for a command. Function called when "sat -h " - - :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] [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 \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 += "
Usage: sat [generic_options] [product] [command_options]\n\n" + msg += self._getParser().get_help() + "\n" + msg += "
" + _("Available commands are:") + "\n\n" + for command in _COMMANDS_NAMES: + msg += " - %s\n" % (command) + msg += "\n" + # how to get the help for a specific command + msg += "
" + _("Getting the help for a specific command: ") + \ + "sat --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 = "
Version: " + version + return msg + + diff --git a/src/test/APPLI_TEST/APPLI_TEST.pyconf b/src/test/APPLI_TEST/APPLI_TEST.pyconf deleted file mode 100644 index 5fc08b3..0000000 --- a/src/test/APPLI_TEST/APPLI_TEST.pyconf +++ /dev/null @@ -1,45 +0,0 @@ - -APPLICATION : -{ - name : 'APPLI_TEST' - workdir : $LOCAL.workdir + $VARS.sep + $APPLICATION.name + '-' + $VARS.dist - base : 'base' - tag : 'master' - get_method : 'git' - environ : - { - ACCEPT_SALOME_WARNINGS : '1' - LC_NUMERIC : 'C' - TESTS_ROOT_DIR : "/tmp/" + $VARS.user+ "/TESTS/APPLI_TEST" - } - products : - { - # PREREQUISITES : - 'Python' : 'native' - - # SALOME MODULES : - 'CONFIGURATION' - 'MEDCOUPLING' - 'KERNEL' - 'GUI' - 'GEOM' - 'SMESH' - - } - grid_to_test : 'SALOME_V8' - profile : - { - launcher_name : "appli_test" - product : "SALOME" - } - virtual_app: - { - name : "appli_test" - application_name : "APPLI" - } - test_base : - { - name : "SALOME" - tag : "SalomeV8" - } -} diff --git a/src/test/APPLI_TEST_Test.py b/src/test/APPLI_TEST_Test.py deleted file mode 100755 index e29e0a7..0000000 --- a/src/test/APPLI_TEST_Test.py +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env python -#-*- coding:utf-8 -*- - -# Copyright (C) 2010-2018 CEA/DEN -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -import os -import sys -import unittest - -import src.salomeTools as SAT -import src -import src.debug as DBG # Easy print stderr (for DEBUG only) - -class TestCase(unittest.TestCase): - "Test the sat commands on APPLI_TEST configuration pyconf etc. files""" - - def test_000(self): - # one shot setUp() for this TestCase - # DBG.push_debug(True) - SAT.setNotLocale() # test english - return - - def test_010(self): - cmd = "-v 5 config -l" - s = SAT.Sat(cmd) - # DBG.push_debug(True) - DBG.write("s.cfg", s.cfg) #none - DBG.write("s.__dict__", s.__dict__) # have - exitCode = s.execute_command() - # DBG.write("s.cfg", s.cfg) - self.assertEqual(src.okToStr(exitCode), "OK") - DBG.pop_debug() - - def test_999(self): - # one shot tearDown() for this TestCase - SAT.setLocale() # end test english - # DBG.pop_debug() - return - -if __name__ == '__main__': - unittest.main(exit=False) - pass diff --git a/src/test/README_config_0_3_9.txt b/src/test/README_config_0_3_9.txt deleted file mode 100644 index 4605ae9..0000000 --- a/src/test/README_config_0_3_9.txt +++ /dev/null @@ -1,2 +0,0 @@ -#TODO -switch pyconf.py 0.3.7.1 -> 0.3.9, here for test diff --git a/src/test/__init__.py b/src/test/__init__.py deleted file mode 100755 index e69de29..0000000 diff --git a/src/test/config_0_3_9/LICENSE b/src/test/config_0_3_9/LICENSE deleted file mode 100644 index 98773c8..0000000 --- a/src/test/config_0_3_9/LICENSE +++ /dev/null @@ -1,16 +0,0 @@ -Copyright (C) 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. diff --git a/src/test/config_0_3_9/PKG-INFO b/src/test/config_0_3_9/PKG-INFO deleted file mode 100644 index 69ba705..0000000 --- a/src/test/config_0_3_9/PKG-INFO +++ /dev/null @@ -1,16 +0,0 @@ -Metadata-Version: 1.0 -Name: config -Version: 0.3.9 -Summary: A hierarchical, easy-to-use, powerful configuration module for Python -Home-page: http://www.red-dove.com/python_config.html -Author: Vinay Sajip -Author-email: vinay_sajip@red-dove.com -License: Copyright (C) 2004-2010 by Vinay Sajip. All Rights Reserved. See LICENSE for license. -Description: This module allows a hierarchical configuration scheme with support for mappings - and sequences, cross-references between one part of the configuration and - another, the ability to flexibly access real Python objects without full-blown - eval(), an include facility, simple expression evaluation and the ability to - change, save, cascade and merge configurations. Interfaces easily with - environment variables and command-line options. It has been developed on python - 2.3 but should work on version 2.2 or greater. -Platform: UNKNOWN diff --git a/src/test/config_0_3_9/README.txt b/src/test/config_0_3_9/README.txt deleted file mode 100644 index 0c20eab..0000000 --- a/src/test/config_0_3_9/README.txt +++ /dev/null @@ -1,84 +0,0 @@ -This module is intended to provide configuration functionality for Python -programs. - -Change History --------------- - -Version Date Description -============================================================================= -0.3.9 11 May 2010 Fixed parsing bug which caused failure for numbers with - exponents. ------------------------------------------------------------------------------ -0.3.8 03 Mar 2010 Fixed parsing bug which caused failure for negative - numbers in sequences. Improved resolution logic. ------------------------------------------------------------------------------ -0.3.7 05 Oct 2007 Added Mapping.__delitem__ (patch by John Drummond). - Mapping.__getattribute__ no longer returns "" when - asked for "__class__" - doing so causes pickle to - crash (reported by Jamila Gunawardena). - Allow negative numbers (reported by Gary Schoep; had - already been fixed but not yet released). ------------------------------------------------------------------------------ -0.3.6 09 Mar 2006 Made classes derive from object (previously they were - old-style classes). - Changed ConfigMerger to use a more flexible merge - strategy. - Multiline strings (using """ or ''') are now supported. - A typo involving raising a ConfigError was fixed. - Patches received with thanks from David Janes & Tim - Desjardins (BlogMatrix) and Erick Tryzelaar. ------------------------------------------------------------------------------ -0.3.5 27 Dec 2004 Added ConfigOutputStream to provide better Unicode - output support. Altered save code to put platform- - dependent newlines for Unicode. ------------------------------------------------------------------------------ -0.3.4 11 Nov 2004 Added ConfigInputStream to provide better Unicode - support. - Added ConfigReader.setStream(). ------------------------------------------------------------------------------ -0.3.3 09 Nov 2004 Renamed config.get() to getByPath(), and likewise for - ConfigList. - Added Mapping.get() to work like dict.get(). - Added logconfig.py and logconfig.cfg to distribution. ------------------------------------------------------------------------------ -0.3.2 04 Nov 2004 Simplified parseMapping(). - Allowed Config.__init__ to accept a string as well as a - stream. If a string is passed in, streamOpener is used - to obtain the stream to be used. ------------------------------------------------------------------------------ -0.3.1 04 Nov 2004 Changed addNamespace/removeNamespace to make name - specification easier. - Refactored save(), added Container.writeToStream and - Container.writeValue() to help with this. ------------------------------------------------------------------------------ -0.3 03 Nov 2004 Added test harness (test_config.py) - Fixed bugs in bracket parsing. - Refactored internal classes. - Added merging functionality. ------------------------------------------------------------------------------ -0.2 01 Nov 2004 Added support for None. - Stream closed in load() and save(). - Added support for changing configuration. - Fixed bugs in identifier parsing and isword(). ------------------------------------------------------------------------------ -0.1 31 Oct 2004 Initial implementation (for community feedback) ------------------------------------------------------------------------------ - ------------------------------------------------------------------------------ -COPYRIGHT ------------------------------------------------------------------------------ -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. diff --git a/src/test/config_0_3_9/__init__.py b/src/test/config_0_3_9/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/test/config_0_3_9/config.py b/src/test/config_0_3_9/config.py deleted file mode 100644 index 94d04c0..0000000 --- a/src/test/config_0_3_9/config.py +++ /dev/null @@ -1,1678 +0,0 @@ -# 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. - -""" -This is a configuration module for Python. - -This module should work under Python versions >= 2.2, and cannot be used with -earlier versions since it uses new-style classes. - -Development and testing has only been carried out (so far) on Python 2.3.4 and -Python 2.4.2. See the test module (test_config.py) included in the -U{distribution} (follow the -download link). - -A simple example - with the example configuration file:: - - messages: - [ - { - stream : `sys.stderr` - message: 'Welcome' - name: 'Harry' - } - { - stream : `sys.stdout` - message: 'Welkom' - name: 'Ruud' - } - { - stream : $messages[0].stream - message: 'Bienvenue' - name: Yves - } - ] - -a program to read the configuration would be:: - - from config import Config - - f = file('simple.cfg') - cfg = Config(f) - for m in cfg.messages: - s = '%s, %s' % (m.message, m.name) - try: - print >> m.stream, s - except IOError, e: - print e - -which, when run, would yield the console output:: - - Welcome, Harry - Welkom, Ruud - Bienvenue, Yves - -See U{this tutorial} for more -information. - -@version: 0.3.9 - -@author: Vinay Sajip - -@copyright: Copyright (C) 2004-2010 Vinay Sajip. All Rights Reserved. - - -@var streamOpener: The default stream opener. This is a factory function which -takes a string (e.g. filename) and returns a stream suitable for reading. If -unable to open the stream, an IOError exception should be thrown. - -The default value of this variable is L{defaultStreamOpener}. For an example -of how it's used, see test_config.py (search for streamOpener). -""" - -__author__ = "Vinay Sajip " -__status__ = "alpha" -__version__ = "0.3.9" -__date__ = "11 May 2010" - -from types import StringType, UnicodeType - -import codecs -import logging -import os -import sys - -WORD = 'a' -NUMBER = '9' -STRING = '"' -EOF = '' -LCURLY = '{' -RCURLY = '}' -LBRACK = '[' -LBRACK2 = 'a[' -RBRACK = ']' -LPAREN = '(' -LPAREN2 = '((' -RPAREN = ')' -DOT = '.' -COMMA = ',' -COLON = ':' -AT = '@' -PLUS = '+' -MINUS = '-' -STAR = '*' -SLASH = '/' -MOD = '%' -BACKTICK = '`' -DOLLAR = '$' -TRUE = 'True' -FALSE = 'False' -NONE = 'None' - -WORDCHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_" - -if sys.platform == 'win32': - NEWLINE = '\r\n' -elif os.name == 'mac': - NEWLINE = '\r' -else: - NEWLINE = '\n' - -try: - import encodings.utf_32 - has_utf32 = True -except: - has_utf32 = False - -try: - from logging.handlers import NullHandler -except ImportError: - class NullHandler(logging.Handler): - def emit(self, record): - pass - -logger = logging.getLogger(__name__) -if not logger.handlers: - logger.addHandler(NullHandler()) - -class ConfigInputStream(object): - """ - An input stream which can read either ANSI files with default encoding - or Unicode files with BOMs. - - Handles UTF-8, UTF-16LE, UTF-16BE. Could handle UTF-32 if Python had - built-in support. - """ - def __init__(self, stream): - """ - Initialize an instance. - - @param stream: The underlying stream to be read. Should be seekable. - @type stream: A stream (file-like object). - """ - encoding = None - signature = stream.read(4) - used = -1 - if has_utf32: - if signature == codecs.BOM_UTF32_LE: - encoding = 'utf-32le' - elif signature == codecs.BOM_UTF32_BE: - encoding = 'utf-32be' - if encoding is None: - if signature[:3] == codecs.BOM_UTF8: - used = 3 - encoding = 'utf-8' - elif signature[:2] == codecs.BOM_UTF16_LE: - used = 2 - encoding = 'utf-16le' - elif signature[:2] == codecs.BOM_UTF16_BE: - used = 2 - encoding = 'utf-16be' - else: - used = 0 - if used >= 0: - stream.seek(used) - if encoding: - reader = codecs.getreader(encoding) - stream = reader(stream) - self.stream = stream - self.encoding = encoding - - def read(self, size): - if (size == 0) or (self.encoding is None): - rv = self.stream.read(size) - else: - rv = u'' - while size > 0: - rv += self.stream.read(1) - size -= 1 - return rv - - def close(self): - self.stream.close() - - def readline(self): - if self.encoding is None: - line = '' - else: - line = u'' - while True: - c = self.stream.read(1) - if c: - line += c - if c == '\n': - break - return line - -class ConfigOutputStream(object): - """ - An output stream which can write either ANSI files with default encoding - or Unicode files with BOMs. - - Handles UTF-8, UTF-16LE, UTF-16BE. Could handle UTF-32 if Python had - built-in support. - """ - - def __init__(self, stream, encoding=None): - """ - Initialize an instance. - - @param stream: The underlying stream to be written. - @type stream: A stream (file-like object). - @param encoding: The desired encoding. - @type encoding: str - """ - if encoding is not None: - encoding = str(encoding).lower() - self.encoding = encoding - if encoding == "utf-8": - stream.write(codecs.BOM_UTF8) - elif encoding == "utf-16be": - stream.write(codecs.BOM_UTF16_BE) - elif encoding == "utf-16le": - stream.write(codecs.BOM_UTF16_LE) - elif encoding == "utf-32be": - stream.write(codecs.BOM_UTF32_BE) - elif encoding == "utf-32le": - stream.write(codecs.BOM_UTF32_LE) - - if encoding is not None: - writer = codecs.getwriter(encoding) - stream = writer(stream) - self.stream = stream - - def write(self, data): - self.stream.write(data) - - def flush(self): - self.stream.flush() - - def close(self): - self.stream.close() - -def defaultStreamOpener(name): - """ - This function returns a read-only stream, given its name. The name passed - in should correspond to an existing stream, otherwise an exception will be - raised. - - This is the default value of L{streamOpener}; assign your own callable to - streamOpener to return streams based on names. For example, you could use - urllib2.urlopen(). - - @param name: The name of a stream, most commonly a file name. - @type name: str - @return: A stream with the specified name. - @rtype: A read-only stream (file-like object) - """ - return ConfigInputStream(file(name, 'rb')) - -streamOpener = None - -class ConfigError(Exception): - """ - This is the base class of exceptions raised by this module. - """ - pass - -class ConfigFormatError(ConfigError): - """ - This is the base class of exceptions raised due to syntax errors in - configurations. - """ - pass - -class ConfigResolutionError(ConfigError): - """ - This is the base class of exceptions raised due to semantic errors in - configurations. - """ - pass - -def isWord(s): - """ - See if a passed-in value is an identifier. If the value passed in is not a - string, False is returned. An identifier consists of alphanumerics or - underscore characters. - - Examples:: - - isWord('a word') ->False - isWord('award') -> True - isWord(9) -> False - isWord('a_b_c_') ->True - - @note: isWord('9abc') will return True - not exactly correct, but adequate - for the way it's used here. - - @param s: The name to be tested - @type s: any - @return: True if a word, else False - @rtype: bool - """ - if type(s) != type(''): - return False - s = s.replace('_', '') - return s.isalnum() - -def makePath(prefix, suffix): - """ - Make a path from a prefix and suffix. - - Examples:: - - makePath('', 'suffix') -> 'suffix' - makePath('prefix', 'suffix') -> 'prefix.suffix' - makePath('prefix', '[1]') -> 'prefix[1]' - - @param prefix: The prefix to use. If it evaluates as false, the suffix - is returned. - @type prefix: str - @param suffix: The suffix to use. It is either an identifier or an - index in brackets. - @type suffix: str - @return: The path concatenation of prefix and suffix, with a - dot if the suffix is not a bracketed index. - @rtype: str - - """ - if not prefix: - rv = suffix - elif suffix[0] == '[': - rv = prefix + suffix - else: - rv = prefix + '.' + suffix - return rv - - -class Container(object): - """ - This internal class is the base class for mappings and sequences. - - @ivar path: A string which describes how to get - to this instance from the root of the hierarchy. - - Example:: - - a.list.of[1].or['more'].elements - """ - def __init__(self, parent): - """ - Initialize an instance. - - @param parent: The parent of this instance in the hierarchy. - @type parent: A L{Container} instance. - """ - object.__setattr__(self, 'parent', parent) - - def setPath(self, path): - """ - Set the path for this instance. - @param path: The path - a string which describes how to get - to this instance from the root of the hierarchy. - @type path: str - """ - object.__setattr__(self, 'path', path) - - def evaluate(self, item): - """ - Evaluate items which are instances of L{Reference} or L{Expression}. - - L{Reference} instances are evaluated using L{Reference.resolve}, - and L{Expression} instances are evaluated using - L{Expression.evaluate}. - - @param item: The item to be evaluated. - @type item: any - @return: If the item is an instance of L{Reference} or L{Expression}, - the evaluated value is returned, otherwise the item is returned - unchanged. - """ - if isinstance(item, Reference): - item = item.resolve(self) - elif isinstance(item, Expression): - item = item.evaluate(self) - return item - - def writeToStream(self, stream, indent, container): - """ - Write this instance to a stream at the specified indentation level. - - Should be redefined in subclasses. - - @param stream: The stream to write to - @type stream: A writable stream (file-like object) - @param indent: The indentation level - @type indent: int - @param container: The container of this instance - @type container: L{Container} - @raise NotImplementedError: If a subclass does not override this - """ - raise NotImplementedError - - def writeValue(self, value, stream, indent): - if isinstance(self, Mapping): - indstr = ' ' - else: - indstr = indent * ' ' - if isinstance(value, Reference) or isinstance(value, Expression): - stream.write('%s%r%s' % (indstr, value, NEWLINE)) - else: - if (type(value) is StringType): # and not isWord(value): - value = repr(value) - stream.write('%s%s%s' % (indstr, value, NEWLINE)) - -class Mapping(Container): - """ - This internal class implements key-value mappings in configurations. - """ - - def __init__(self, parent=None): - """ - Initialize an instance. - - @param parent: The parent of this instance in the hierarchy. - @type parent: A L{Container} instance. - """ - Container.__init__(self, parent) - object.__setattr__(self, 'path', '') - object.__setattr__(self, 'data', {}) - object.__setattr__(self, 'order', []) # to preserve ordering - object.__setattr__(self, 'comments', {}) - - def __delitem__(self, key): - """ - Remove an item - """ - data = object.__getattribute__(self, 'data') - if key not in data: - raise AttributeError(key) - order = object.__getattribute__(self, 'order') - comments = object.__getattribute__(self, 'comments') - del data[key] - order.remove(key) - del comments[key] - - def __getitem__(self, key): - data = object.__getattribute__(self, 'data') - if key not in data: - raise AttributeError(key) - rv = data[key] - return self.evaluate(rv) - - __getattr__ = __getitem__ - - def __getattribute__(self, name): - if name == "__dict__": - return {} - if name in ["__methods__", "__members__"]: - return [] - #if name == "__class__": - # return '' - data = object.__getattribute__(self, "data") - useData = data.has_key(name) - if useData: - rv = getattr(data, name) - else: - rv = object.__getattribute__(self, name) - if rv is None: - raise AttributeError(name) - return rv - - def iteritems(self): - for key in self.keys(): - yield(key, self[key]) - raise StopIteration - - def __contains__(self, item): - order = object.__getattribute__(self, 'order') - return item in order - - def addMapping(self, key, value, comment, setting=False): - """ - Add a key-value mapping with a comment. - - @param key: The key for the mapping. - @type key: str - @param value: The value for the mapping. - @type value: any - @param comment: The comment for the key (can be None). - @type comment: str - @param setting: If True, ignore clashes. This is set - to true when called from L{__setattr__}. - @raise ConfigFormatError: If an existing key is seen - again and setting is False. - """ - data = object.__getattribute__(self, 'data') - order = object.__getattribute__(self, 'order') - comments = object.__getattribute__(self, 'comments') - - data[key] = value - if key not in order: - order.append(key) - elif not setting: - raise ConfigFormatError("repeated key: %s" % key) - comments[key] = comment - - def __setattr__(self, name, value): - self.addMapping(name, value, None, True) - - __setitem__ = __setattr__ - - def keys(self): - """ - Return the keys in a similar way to a dictionary. - """ - return object.__getattribute__(self, 'order') - - def get(self, key, default=None): - """ - Allows a dictionary-style get operation. - """ - if key in self: - return self[key] - return default - - def __str__(self): - return str(object.__getattribute__(self, 'data')) - - def __repr__(self): - return repr(object.__getattribute__(self, 'data')) - - def __len__(self): - return len(object.__getattribute__(self, 'order')) - - def __iter__(self): - return self.iterkeys() - - def iterkeys(self): - order = object.__getattribute__(self, 'order') - return order.__iter__() - - def writeToStream(self, stream, indent, container): - """ - Write this instance to a stream at the specified indentation level. - - Should be redefined in subclasses. - - @param stream: The stream to write to - @type stream: A writable stream (file-like object) - @param indent: The indentation level - @type indent: int - @param container: The container of this instance - @type container: L{Container} - """ - indstr = indent * ' ' - if len(self) == 0: - stream.write(' { }%s' % NEWLINE) - else: - if isinstance(container, Mapping): - stream.write(NEWLINE) - stream.write('%s{%s' % (indstr, NEWLINE)) - self.save(stream, indent + 1) - stream.write('%s}%s' % (indstr, NEWLINE)) - - def save(self, stream, indent=0): - """ - Save this configuration to the specified stream. - @param stream: A stream to which the configuration is written. - @type stream: A write-only stream (file-like object). - @param indent: The indentation level for the output. - @type indent: int - """ - indstr = indent * ' ' - order = object.__getattribute__(self, 'order') - data = object.__getattribute__(self, 'data') - maxlen = 0 # max(map(lambda x: len(x), order)) - for key in order: - comment = self.comments[key] - if isWord(key): - skey = key - else: - skey = repr(key) - if comment: - stream.write('%s#%s' % (indstr, comment)) - stream.write('%s%-*s :' % (indstr, maxlen, skey)) - value = data[key] - if isinstance(value, Container): - value.writeToStream(stream, indent, self) - else: - self.writeValue(value, stream, indent) - -class Config(Mapping): - """ - This class represents a configuration, and is the only one which clients - need to interface to, under normal circumstances. - """ - - class Namespace(object): - """ - This internal class is used for implementing default namespaces. - - An instance acts as a namespace. - """ - def __init__(self): - self.sys = sys - self.os = os - - def __repr__(self): - return "" % ','.join(self.__dict__.keys()) - - def __init__(self, streamOrFile=None, parent=None): - """ - Initializes an instance. - - @param streamOrFile: If specified, causes this instance to be loaded - from the stream (by calling L{load}). If a string is provided, it is - passed to L{streamOpener} to open a stream. Otherwise, the passed - value is assumed to be a stream and used as is. - @type streamOrFile: A readable stream (file-like object) or a name. - @param parent: If specified, this becomes the parent of this instance - in the configuration hierarchy. - @type parent: a L{Container} instance. - """ - Mapping.__init__(self, parent) - object.__setattr__(self, 'reader', ConfigReader(self)) - object.__setattr__(self, 'namespaces', [Config.Namespace()]) - object.__setattr__(self, 'resolving', set()) - if streamOrFile is not None: - if isinstance(streamOrFile, StringType) or isinstance(streamOrFile, UnicodeType): - global streamOpener - if streamOpener is None: - streamOpener = defaultStreamOpener - streamOrFile = streamOpener(streamOrFile) - load = object.__getattribute__(self, "load") - load(streamOrFile) - - def load(self, stream): - """ - Load the configuration from the specified stream. Multiple streams can - be used to populate the same instance, as long as there are no - clashing keys. The stream is closed. - @param stream: A stream from which the configuration is read. - @type stream: A read-only stream (file-like object). - @raise ConfigError: if keys in the loaded configuration clash with - existing keys. - @raise ConfigFormatError: if there is a syntax error in the stream. - """ - reader = object.__getattribute__(self, 'reader') - #object.__setattr__(self, 'root', reader.load(stream)) - reader.load(stream) - stream.close() - - def addNamespace(self, ns, name=None): - """ - Add a namespace to this configuration which can be used to evaluate - (resolve) dotted-identifier expressions. - @param ns: The namespace to be added. - @type ns: A module or other namespace suitable for passing as an - argument to vars(). - @param name: A name for the namespace, which, if specified, provides - an additional level of indirection. - @type name: str - """ - namespaces = object.__getattribute__(self, 'namespaces') - if name is None: - namespaces.append(ns) - else: - setattr(namespaces[0], name, ns) - - def removeNamespace(self, ns, name=None): - """ - Remove a namespace added with L{addNamespace}. - @param ns: The namespace to be removed. - @param name: The name which was specified when L{addNamespace} was - called. - @type name: str - """ - namespaces = object.__getattribute__(self, 'namespaces') - if name is None: - namespaces.remove(ns) - else: - delattr(namespaces[0], name) - - def save(self, stream, indent=0): - """ - Save this configuration to the specified stream. The stream is - closed if this is the top-level configuration in the hierarchy. - L{Mapping.save} is called to do all the work. - @param stream: A stream to which the configuration is written. - @type stream: A write-only stream (file-like object). - @param indent: The indentation level for the output. - @type indent: int - """ - Mapping.save(self, stream, indent) - if indent == 0: - stream.close() - - def getByPath(self, path): - """ - Obtain a value in the configuration via its path. - @param path: The path of the required value - @type path: str - @return the value at the specified path. - @rtype: any - @raise ConfigError: If the path is invalid - """ - s = 'self.' + path - try: - return eval(s) - except Exception, e: - raise ConfigError(str(e)) - -class Sequence(Container): - """ - This internal class implements a value which is a sequence of other values. - """ - class SeqIter(object): - """ - This internal class implements an iterator for a L{Sequence} instance. - """ - def __init__(self, seq): - self.seq = seq - self.limit = len(object.__getattribute__(seq, 'data')) - self.index = 0 - - def __iter__(self): - return self - - def next(self): - if self.index >= self.limit: - raise StopIteration - rv = self.seq[self.index] - self.index += 1 - return rv - - def __init__(self, parent=None): - """ - Initialize an instance. - - @param parent: The parent of this instance in the hierarchy. - @type parent: A L{Container} instance. - """ - Container.__init__(self, parent) - object.__setattr__(self, 'data', []) - object.__setattr__(self, 'comments', []) - - def append(self, item, comment): - """ - Add an item to the sequence. - - @param item: The item to add. - @type item: any - @param comment: A comment for the item. - @type comment: str - """ - data = object.__getattribute__(self, 'data') - comments = object.__getattribute__(self, 'comments') - data.append(item) - comments.append(comment) - - def __getitem__(self, index): - data = object.__getattribute__(self, 'data') - try: - rv = data[index] - except (IndexError, KeyError, TypeError): - raise ConfigResolutionError('%r is not a valid index for %r' % (index, object.__getattribute__(self, 'path'))) - if not isinstance(rv, list): - rv = self.evaluate(rv) - else: - # deal with a slice - result = [] - for a in rv: - result.append(self.evaluate(a)) - rv = result - return rv - - def __iter__(self): - return Sequence.SeqIter(self) - - def __repr__(self): - return repr(object.__getattribute__(self, 'data')) - - def __str__(self): - return str(self[:]) # using the slice evaluates the contents - - def __len__(self): - return len(object.__getattribute__(self, 'data')) - - def writeToStream(self, stream, indent, container): - """ - Write this instance to a stream at the specified indentation level. - - Should be redefined in subclasses. - - @param stream: The stream to write to - @type stream: A writable stream (file-like object) - @param indent: The indentation level - @type indent: int - @param container: The container of this instance - @type container: L{Container} - """ - indstr = indent * ' ' - if len(self) == 0: - stream.write(' [ ]%s' % NEWLINE) - else: - if isinstance(container, Mapping): - stream.write(NEWLINE) - stream.write('%s[%s' % (indstr, NEWLINE)) - self.save(stream, indent + 1) - stream.write('%s]%s' % (indstr, NEWLINE)) - - def save(self, stream, indent): - """ - Save this instance to the specified stream. - @param stream: A stream to which the configuration is written. - @type stream: A write-only stream (file-like object). - @param indent: The indentation level for the output, > 0 - @type indent: int - """ - if indent == 0: - raise ConfigError("sequence cannot be saved as a top-level item") - data = object.__getattribute__(self, 'data') - comments = object.__getattribute__(self, 'comments') - indstr = indent * ' ' - for i in xrange(0, len(data)): - value = data[i] - comment = comments[i] - if comment: - stream.write('%s#%s' % (indstr, comment)) - if isinstance(value, Container): - value.writeToStream(stream, indent, self) - else: - self.writeValue(value, stream, indent) - -class Reference(object): - """ - This internal class implements a value which is a reference to another value. - """ - def __init__(self, config, type, ident): - """ - Initialize an instance. - - @param config: The configuration which contains this reference. - @type config: A L{Config} instance. - @param type: The type of reference. - @type type: BACKTICK or DOLLAR - @param ident: The identifier which starts the reference. - @type ident: str - """ - self.config = config - self.type = type - self.elements = [ident] - - def addElement(self, type, ident): - """ - Add an element to the reference. - - @param type: The type of reference. - @type type: BACKTICK or DOLLAR - @param ident: The identifier which continues the reference. - @type ident: str - """ - self.elements.append((type, ident)) - - def findConfig(self, container): - """ - Find the closest enclosing configuration to the specified container. - - @param container: The container to start from. - @type container: L{Container} - @return: The closest enclosing configuration, or None. - @rtype: L{Config} - """ - while (container is not None) and not isinstance(container, Config): - container = object.__getattribute__(container, 'parent') - return container - - def resolve(self, container): - """ - Resolve this instance in the context of a container. - - @param container: The container to resolve from. - @type container: L{Container} - @return: The resolved value. - @rtype: any - @raise ConfigResolutionError: If resolution fails. - """ - rv = None - path = object.__getattribute__(container, 'path') - current = self.findConfig(container) - while current is not None: - if self.type == BACKTICK: - namespaces = object.__getattribute__(current, 'namespaces') - found = False - s = str(self)[1:-1] - for ns in namespaces: - try: - try: - rv = eval(s, vars(ns)) - except TypeError: #Python 2.7 - vars is a dictproxy - rv = eval(s, {}, vars(ns)) - found = True - break - except: - logger.debug("unable to resolve %r in %r", s, ns) - pass - if found: - break - else: - firstkey = self.elements[0] - if firstkey in current.resolving: - current.resolving.remove(firstkey) - raise ConfigResolutionError("Circular reference: %r" % firstkey) - current.resolving.add(firstkey) - key = firstkey - try: - rv = current[key] - for item in self.elements[1:]: - key = item[1] - rv = rv[key] - current.resolving.remove(firstkey) - break - except ConfigResolutionError: - raise - except: - logger.debug("Unable to resolve %r: %s", key, sys.exc_info()[1]) - rv = None - pass - current.resolving.discard(firstkey) - current = self.findConfig(object.__getattribute__(current, 'parent')) - if current is None: - raise ConfigResolutionError("unable to evaluate %r in the configuration %s" % (self, path)) - return rv - - def __str__(self): - s = self.elements[0] - for tt, tv in self.elements[1:]: - if tt == DOT: - s += '.%s' % tv - else: - s += '[%r]' % tv - if self.type == BACKTICK: - return BACKTICK + s + BACKTICK - else: - return DOLLAR + s - - def __repr__(self): - return self.__str__() - -class Expression(object): - """ - This internal class implements a value which is obtained by evaluating an expression. - """ - def __init__(self, op, lhs, rhs): - """ - Initialize an instance. - - @param op: the operation expressed in the expression. - @type op: PLUS, MINUS, STAR, SLASH, MOD - @param lhs: the left-hand-side operand of the expression. - @type lhs: any Expression or primary value. - @param rhs: the right-hand-side operand of the expression. - @type rhs: any Expression or primary value. - """ - self.op = op - self.lhs = lhs - self.rhs = rhs - - def __str__(self): - return '%r %s %r' % (self.lhs, self.op, self.rhs) - - def __repr__(self): - return self.__str__() - - def evaluate(self, container): - """ - Evaluate this instance in the context of a container. - - @param container: The container to evaluate in from. - @type container: L{Container} - @return: The evaluated value. - @rtype: any - @raise ConfigResolutionError: If evaluation fails. - @raise ZeroDivideError: If division by zero occurs. - @raise TypeError: If the operation is invalid, e.g. - subtracting one string from another. - """ - lhs = self.lhs - if isinstance(lhs, Reference): - lhs = lhs.resolve(container) - elif isinstance(lhs, Expression): - lhs = lhs.evaluate(container) - rhs = self.rhs - if isinstance(rhs, Reference): - rhs = rhs.resolve(container) - elif isinstance(rhs, Expression): - rhs = rhs.evaluate(container) - op = self.op - if op == PLUS: - rv = lhs + rhs - elif op == MINUS: - rv = lhs - rhs - elif op == STAR: - rv = lhs * rhs - elif op == SLASH: - rv = lhs / rhs - else: - rv = lhs % rhs - return rv - -class ConfigReader(object): - """ - This internal class implements a parser for configurations. - """ - - def __init__(self, config): - self.filename = None - self.config = config - self.lineno = 0 - self.colno = 0 - self.lastc = None - self.last_token = None - self.commentchars = '#' - self.whitespace = ' \t\r\n' - self.quotes = '\'"' - self.punct = ':-+*/%,.{}[]()@`$' - self.digits = '0123456789' - self.wordchars = '%s' % WORDCHARS # make a copy - self.identchars = self.wordchars + self.digits - self.pbchars = [] - self.pbtokens = [] - self.comment = None - - def location(self): - """ - Return the current location (filename, line, column) in the stream - as a string. - - Used when printing error messages, - - @return: A string representing a location in the stream being read. - @rtype: str - """ - return "%s(%d,%d)" % (self.filename, self.lineno, self.colno) - - def getChar(self): - """ - Get the next char from the stream. Update line and column numbers - appropriately. - - @return: The next character from the stream. - @rtype: str - """ - if self.pbchars: - c = self.pbchars.pop() - else: - c = self.stream.read(1) - self.colno += 1 - if c == '\n': - self.lineno += 1 - self.colno = 1 - return c - - def __repr__(self): - return "" % id(self) - - __str__ = __repr__ - - def getToken(self): - """ - Get a token from the stream. String values are returned in a form - where you need to eval() the returned value to get the actual - string. The return value is (token_type, token_value). - - Multiline string tokenizing is thanks to David Janes (BlogMatrix) - - @return: The next token. - @rtype: A token tuple. - """ - if self.pbtokens: - return self.pbtokens.pop() - stream = self.stream - self.comment = None - token = '' - tt = EOF - while True: - c = self.getChar() - if not c: - break - elif c == '#': - self.comment = stream.readline() - self.lineno += 1 - continue - if c in self.quotes: - token = c - quote = c - tt = STRING - escaped = False - multiline = False - c1 = self.getChar() - if c1 == quote: - c2 = self.getChar() - if c2 == quote: - multiline = True - token += quote - token += quote - else: - self.pbchars.append(c2) - self.pbchars.append(c1) - else: - self.pbchars.append(c1) - while True: - c = self.getChar() - if not c: - break - token += c - if (c == quote) and not escaped: - if not multiline or (len(token) >= 6 and token.endswith(token[:3]) and token[-4] != '\\'): - break - if c == '\\': - escaped = not escaped - else: - escaped = False - if not c: - raise ConfigFormatError('%s: Unterminated quoted string: %r, %r' % (self.location(), token, c)) - break - if c in self.whitespace: - self.lastc = c - continue - elif c in self.punct: - token = c - tt = c - if (self.lastc == ']') or (self.lastc in self.identchars): - if c == '[': - tt = LBRACK2 - elif c == '(': - tt = LPAREN2 - break - elif c in self.digits: - token = c - tt = NUMBER - in_exponent=False - while True: - c = self.getChar() - if not c: - break - if c in self.digits: - token += c - elif (c == '.') and token.find('.') < 0 and not in_exponent: - token += c - elif (c == '-') and token.find('-') < 0 and in_exponent: - token += c - elif (c in 'eE') and token.find('e') < 0 and\ - token.find('E') < 0: - token += c - in_exponent = True - else: - if c and (c not in self.whitespace): - self.pbchars.append(c) - break - break - elif c in self.wordchars: - token = c - tt = WORD - c = self.getChar() - while c and (c in self.identchars): - token += c - c = self.getChar() - if c: # and c not in self.whitespace: - self.pbchars.append(c) - if token == "True": - tt = TRUE - elif token == "False": - tt = FALSE - elif token == "None": - tt = NONE - break - else: - raise ConfigFormatError('%s: Unexpected character: %r' % (self.location(), c)) - if token: - self.lastc = token[-1] - else: - self.lastc = None - self.last_token = tt - return (tt, token) - - def load(self, stream, parent=None, suffix=None): - """ - Load the configuration from the specified stream. - - @param stream: A stream from which to load the configuration. - @type stream: A stream (file-like object). - @param parent: The parent of the configuration (to which this reader - belongs) in the hierarchy. Specified when the configuration is - included in another one. - @type parent: A L{Container} instance. - @param suffix: The suffix of this configuration in the parent - configuration. Should be specified whenever the parent is not None. - @raise ConfigError: If parent is specified but suffix is not. - @raise ConfigFormatError: If there are syntax errors in the stream. - """ - if parent is not None: - if suffix is None: - raise ConfigError("internal error: load called with parent but no suffix") - self.config.setPath(makePath(object.__getattribute__(parent, 'path'), suffix)) - self.setStream(stream) - self.token = self.getToken() - self.parseMappingBody(self.config) - if self.token[0] != EOF: - raise ConfigFormatError('%s: expecting EOF, found %r' % (self.location(), self.token[1])) - - def setStream(self, stream): - """ - Set the stream to the specified value, and prepare to read from it. - - @param stream: A stream from which to load the configuration. - @type stream: A stream (file-like object). - """ - self.stream = stream - if hasattr(stream, 'name'): - filename = stream.name - else: - filename = '?' - self.filename = filename - self.lineno = 1 - self.colno = 1 - - def match(self, t): - """ - Ensure that the current token type matches the specified value, and - advance to the next token. - - @param t: The token type to match. - @type t: A valid token type. - @return: The token which was last read from the stream before this - function is called. - @rtype: a token tuple - see L{getToken}. - @raise ConfigFormatError: If the token does not match what's expected. - """ - if self.token[0] != t: - raise ConfigFormatError("%s: expecting %s, found %r" % (self.location(), t, self.token[1])) - rv = self.token - self.token = self.getToken() - return rv - - def parseMappingBody(self, parent): - """ - Parse the internals of a mapping, and add entries to the provided - L{Mapping}. - - @param parent: The mapping to add entries to. - @type parent: A L{Mapping} instance. - """ - while self.token[0] in [WORD, STRING]: - self.parseKeyValuePair(parent) - - def parseKeyValuePair(self, parent): - """ - Parse a key-value pair, and add it to the provided L{Mapping}. - - @param parent: The mapping to add entries to. - @type parent: A L{Mapping} instance. - @raise ConfigFormatError: if a syntax error is found. - """ - comment = self.comment - tt, tv = self.token - if tt == WORD: - key = tv - suffix = tv - elif tt == STRING: - key = eval(tv) - suffix = '[%s]' % tv - else: - msg = "%s: expecting word or string, found %r" - raise ConfigFormatError(msg % (self.location(), tv)) - self.token = self.getToken() - # for now, we allow key on its own as a short form of key : True - if self.token[0] == COLON: - self.token = self.getToken() - value = self.parseValue(parent, suffix) - else: - value = True - try: - parent.addMapping(key, value, comment) - except Exception, e: - raise ConfigFormatError("%s: %s, %r" % (self.location(), e, - self.token[1])) - tt = self.token[0] - if tt not in [EOF, WORD, STRING, RCURLY, COMMA]: - msg = "%s: expecting one of EOF, WORD, STRING,\ -RCURLY, COMMA, found %r" - raise ConfigFormatError(msg % (self.location(), self.token[1])) - if tt == COMMA: - self.token = self.getToken() - - def parseValue(self, parent, suffix): - """ - Parse a value. - - @param parent: The container to which the value will be added. - @type parent: A L{Container} instance. - @param suffix: The suffix for the value. - @type suffix: str - @return: The value - @rtype: any - @raise ConfigFormatError: if a syntax error is found. - """ - tt = self.token[0] - if tt in [STRING, WORD, NUMBER, LPAREN, DOLLAR, - TRUE, FALSE, NONE, BACKTICK, MINUS]: - rv = self.parseScalar() - elif tt == LBRACK: - rv = self.parseSequence(parent, suffix) - elif tt in [LCURLY, AT]: - rv = self.parseMapping(parent, suffix) - else: - raise ConfigFormatError("%s: unexpected input: %r" % - (self.location(), self.token[1])) - return rv - - def parseSequence(self, parent, suffix): - """ - Parse a sequence. - - @param parent: The container to which the sequence will be added. - @type parent: A L{Container} instance. - @param suffix: The suffix for the value. - @type suffix: str - @return: a L{Sequence} instance representing the sequence. - @rtype: L{Sequence} - @raise ConfigFormatError: if a syntax error is found. - """ - rv = Sequence(parent) - rv.setPath(makePath(object.__getattribute__(parent, 'path'), suffix)) - self.match(LBRACK) - comment = self.comment - tt = self.token[0] - while tt in [STRING, WORD, NUMBER, LCURLY, LBRACK, LPAREN, DOLLAR, - TRUE, FALSE, NONE, BACKTICK, MINUS]: - suffix = '[%d]' % len(rv) - value = self.parseValue(parent, suffix) - rv.append(value, comment) - tt = self.token[0] - comment = self.comment - if tt == COMMA: - self.match(COMMA) - tt = self.token[0] - comment = self.comment - continue - self.match(RBRACK) - return rv - - def parseMapping(self, parent, suffix): - """ - Parse a mapping. - - @param parent: The container to which the mapping will be added. - @type parent: A L{Container} instance. - @param suffix: The suffix for the value. - @type suffix: str - @return: a L{Mapping} instance representing the mapping. - @rtype: L{Mapping} - @raise ConfigFormatError: if a syntax error is found. - """ - if self.token[0] == LCURLY: - self.match(LCURLY) - rv = Mapping(parent) - rv.setPath( - makePath(object.__getattribute__(parent, 'path'), suffix)) - self.parseMappingBody(rv) - self.match(RCURLY) - else: - self.match(AT) - tt, fn = self.match(STRING) - rv = Config(eval(fn), parent) - return rv - - def parseScalar(self): - """ - Parse a scalar - a terminal value such as a string or number, or - an L{Expression} or L{Reference}. - - @return: the parsed scalar - @rtype: any scalar - @raise ConfigFormatError: if a syntax error is found. - """ - lhs = self.parseTerm() - tt = self.token[0] - while tt in [PLUS, MINUS]: - self.match(tt) - rhs = self.parseTerm() - lhs = Expression(tt, lhs, rhs) - tt = self.token[0] - return lhs - - def parseTerm(self): - """ - Parse a term in an additive expression (a + b, a - b) - - @return: the parsed term - @rtype: any scalar - @raise ConfigFormatError: if a syntax error is found. - """ - lhs = self.parseFactor() - tt = self.token[0] - while tt in [STAR, SLASH, MOD]: - self.match(tt) - rhs = self.parseFactor() - lhs = Expression(tt, lhs, rhs) - tt = self.token[0] - return lhs - - def parseFactor(self): - """ - Parse a factor in an multiplicative expression (a * b, a / b, a % b) - - @return: the parsed factor - @rtype: any scalar - @raise ConfigFormatError: if a syntax error is found. - """ - tt = self.token[0] - if tt in [NUMBER, WORD, STRING, TRUE, FALSE, NONE]: - rv = self.token[1] - if tt != WORD: - rv = eval(rv) - self.match(tt) - elif tt == LPAREN: - self.match(LPAREN) - rv = self.parseScalar() - self.match(RPAREN) - elif tt == DOLLAR: - self.match(DOLLAR) - rv = self.parseReference(DOLLAR) - elif tt == BACKTICK: - self.match(BACKTICK) - rv = self.parseReference(BACKTICK) - self.match(BACKTICK) - elif tt == MINUS: - self.match(MINUS) - rv = -self.parseScalar() - else: - raise ConfigFormatError("%s: unexpected input: %r" % - (self.location(), self.token[1])) - return rv - - def parseReference(self, type): - """ - Parse a reference. - - @return: the parsed reference - @rtype: L{Reference} - @raise ConfigFormatError: if a syntax error is found. - """ - word = self.match(WORD) - rv = Reference(self.config, type, word[1]) - while self.token[0] in [DOT, LBRACK2]: - self.parseSuffix(rv) - return rv - - def parseSuffix(self, ref): - """ - Parse a reference suffix. - - @param ref: The reference of which this suffix is a part. - @type ref: L{Reference}. - @raise ConfigFormatError: if a syntax error is found. - """ - tt = self.token[0] - if tt == DOT: - self.match(DOT) - word = self.match(WORD) - ref.addElement(DOT, word[1]) - else: - self.match(LBRACK2) - tt, tv = self.token - if tt not in [NUMBER, STRING]: - raise ConfigFormatError("%s: expected number or string, found %r" % (self.location(), tv)) - self.token = self.getToken() - tv = eval(tv) - self.match(RBRACK) - ref.addElement(LBRACK, tv) - -def defaultMergeResolve(map1, map2, key): - """ - A default resolver for merge conflicts. Returns a string - indicating what action to take to resolve the conflict. - - @param map1: The map being merged into. - @type map1: L{Mapping}. - @param map2: The map being used as the merge operand. - @type map2: L{Mapping}. - @param key: The key in map2 (which also exists in map1). - @type key: str - @return: One of "merge", "append", "mismatch" or "overwrite" - indicating what action should be taken. This should - be appropriate to the objects being merged - e.g. - there is no point returning "merge" if the two objects - are instances of L{Sequence}. - @rtype: str - """ - obj1 = map1[key] - obj2 = map2[key] - if isinstance(obj1, Mapping) and isinstance(obj2, Mapping): - rv = "merge" - elif isinstance(obj1, Sequence) and isinstance(obj2, Sequence): - rv = "append" - else: - rv = "mismatch" - return rv - -def overwriteMergeResolve(map1, map2, key): - """ - An overwriting resolver for merge conflicts. Calls L{defaultMergeResolve}, - but where a "mismatch" is detected, returns "overwrite" instead. - - @param map1: The map being merged into. - @type map1: L{Mapping}. - @param map2: The map being used as the merge operand. - @type map2: L{Mapping}. - @param key: The key in map2 (which also exists in map1). - @type key: str - """ - rv = defaultMergeResolve(map1, map2, key) - if rv == "mismatch": - rv = "overwrite" - return rv - -class ConfigMerger(object): - """ - This class is used for merging two configurations. If a key exists in the - merge operand but not the merge target, then the entry is copied from the - merge operand to the merge target. If a key exists in both configurations, - then a resolver (a callable) is called to decide how to handle the - conflict. - """ - - def __init__(self, resolver=defaultMergeResolve): - """ - Initialise an instance. - - @param resolver: - @type resolver: A callable which takes the argument list - (map1, map2, key) where map1 is the mapping being merged into, - map2 is the merge operand and key is the clashing key. The callable - should return a string indicating how the conflict should be resolved. - For possible return values, see L{defaultMergeResolve}. The default - value preserves the old behaviour - """ - self.resolver = resolver - - def merge(self, merged, mergee): - """ - Merge two configurations. The second configuration is unchanged, - and the first is changed to reflect the results of the merge. - - @param merged: The configuration to merge into. - @type merged: L{Config}. - @param mergee: The configuration to merge. - @type mergee: L{Config}. - """ - self.mergeMapping(merged, mergee) - - def mergeMapping(self, map1, map2): - """ - Merge two mappings recursively. The second mapping is unchanged, - and the first is changed to reflect the results of the merge. - - @param map1: The mapping to merge into. - @type map1: L{Mapping}. - @param map2: The mapping to merge. - @type map2: L{Mapping}. - """ - keys = map1.keys() - for key in map2.keys(): - if key not in keys: - map1[key] = map2[key] - else: - obj1 = map1[key] - obj2 = map2[key] - decision = self.resolver(map1, map2, key) - if decision == "merge": - self.mergeMapping(obj1, obj2) - elif decision == "append": - self.mergeSequence(obj1, obj2) - elif decision == "overwrite": - map1[key] = obj2 - elif decision == "mismatch": - self.handleMismatch(obj1, obj2) - else: - msg = "unable to merge: don't know how to implement %r" - raise ValueError(msg % decision) - - def mergeSequence(self, seq1, seq2): - """ - Merge two sequences. The second sequence is unchanged, - and the first is changed to have the elements of the second - appended to it. - - @param seq1: The sequence to merge into. - @type seq1: L{Sequence}. - @param seq2: The sequence to merge. - @type seq2: L{Sequence}. - """ - data1 = object.__getattribute__(seq1, 'data') - data2 = object.__getattribute__(seq2, 'data') - for obj in data2: - data1.append(obj) - comment1 = object.__getattribute__(seq1, 'comments') - comment2 = object.__getattribute__(seq2, 'comments') - for obj in comment2: - comment1.append(obj) - - def handleMismatch(self, obj1, obj2): - """ - Handle a mismatch between two objects. - - @param obj1: The object to merge into. - @type obj1: any - @param obj2: The object to merge. - @type obj2: any - """ - raise ConfigError("unable to merge %r with %r" % (obj1, obj2)) - -class ConfigList(list): - """ - This class implements an ordered list of configurations and allows you - to try getting the configuration from each entry in turn, returning - the first successfully obtained value. - """ - - def getByPath(self, path): - """ - Obtain a value from the first configuration in the list which defines - it. - - @param path: The path of the value to retrieve. - @type path: str - @return: The value from the earliest configuration in the list which - defines it. - @rtype: any - @raise ConfigError: If no configuration in the list has an entry with - the specified path. - """ - found = False - rv = None - for entry in self: - try: - rv = entry.getByPath(path) - found = True - break - except ConfigError: - pass - if not found: - raise ConfigError("unable to resolve %r" % path) - return rv diff --git a/src/test/config_0_3_9/logconfig.cfg b/src/test/config_0_3_9/logconfig.cfg deleted file mode 100644 index 2845e3c..0000000 --- a/src/test/config_0_3_9/logconfig.cfg +++ /dev/null @@ -1,65 +0,0 @@ -# Configuration file for logconfig.py - -# root logger configuration -root: -{ - level : `DEBUG` - handlers : [$handlers.console, $handlers.file] -} -formatters: { - brief: - { - format: '%(levelname)-8s: %(name)s: %(message)s' - } - precise: - { - format: '%(asctime)s %(name)-15s %(levelname)-8s %(message)s' - } -} -handlers: -{ - console: - { - class : `logconfig.StreamHandler` - config: - { - level : `INFO` - stream : `sys.stdout` - formatter: $formatters.brief - } - } - file: - { - class : `logconfig.RotatingFileHandler` - config: - { - name: 'logconfig.log' - maxBytes: 1024 - backupCount: 3 - formatter: $formatters.precise - } - } - debugfile: - { - class : `logconfig.FileHandler` - config: - { - name: 'logconfig-detail.log' - mode: 'a' - formatter: $formatters.precise - } - } -} -loggers: -{ - area1: - { - level : `ERROR` - handlers: [$handlers.debugfile] - } - area2: - { - level : `CRITICAL` - handlers: [$handlers.debugfile] - } -} \ No newline at end of file diff --git a/src/test/config_0_3_9/logconfig.py b/src/test/config_0_3_9/logconfig.py deleted file mode 100644 index 44ae1ed..0000000 --- a/src/test/config_0_3_9/logconfig.py +++ /dev/null @@ -1,138 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2001-2004 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. -# -# This file is part of the Python config distribution. See -# http://www.red-dove.com/python_config.html -# -""" -A test for the config module through seeing how to use it to configure logging. - -Copyright (C) 2004 Vinay Sajip. All Rights Reserved. -""" - -from config import Config -from optparse import OptionParser, get_prog_name -from random import choice -import logging -import logging.handlers -import sys - -class Usage(Exception): - pass - -class BaseHandler: - def __init__(self, config): - if 'level' in config: - self.setLevel(config.level) - if 'formatter' in config: - self.setFormatter(config.formatter) - -class StreamHandler(logging.StreamHandler, BaseHandler): - def __init__(self, config): - stream = config.get('stream') - logging.StreamHandler.__init__(self, stream) - BaseHandler.__init__(self, config) - -class RotatingFileHandler(logging.handlers.RotatingFileHandler, BaseHandler): - def __init__(self, config): - name = config.get('name') - if name is None: - raise ValueError('RotatingFileHandler: name not specified') - mode = config.get('mode', 'a') - maxBytes = config.get('maxBytes', 0) - backupCount = config.get('backupCount', 0) - logging.handlers.RotatingFileHandler.__init__(self, name, mode, maxBytes, backupCount) - BaseHandler.__init__(self, config) - -class FileHandler(logging.FileHandler, BaseHandler): - def __init__(self, config): - name = config.get('name') - if name is None: - raise ValueError('FileHandler: name not specified') - mode = config.get('mode', 'a') - logging.FileHandler.__init__(self, name, mode) - BaseHandler.__init__(self, config) - -def configLogger(logger, config): - for handler in logger.handlers: - logger.removeHandler(handler) - if 'level' in config: - logger.setLevel(config.level) - if 'handlers' in config: - for handler in config.handlers: - logger.addHandler(handler) - -def fileConfig(fname, *args, **kwargs): - cfg = Config(fname) - cfg.addNamespace(logging) - cfg.addNamespace(sys.modules[StreamHandler.__module__], 'logconfig') - - for name in cfg.formatters.keys(): - formatterConfig = cfg.formatters[name] - fmt = formatterConfig.get('format') - datefmt = formatterConfig.get('datefmt') - formatter = logging.Formatter(fmt, datefmt) - cfg.formatters[name] = formatter - - for name in cfg.handlers.keys(): - klass = cfg.handlers[name].get('class') - config = cfg.handlers[name].get('config') - cfg.handlers[name] = klass(config) - - for name in cfg.loggers.keys(): - loggerConfig = cfg.loggers[name] - logger = logging.getLogger(name) - configLogger(logger, loggerConfig) - - if 'root' in cfg: - configLogger(logging.getLogger(''), cfg.root) - -def testConfig(): - levels = [logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL] - loggers = ['', 'area1', 'area2'] - for i in xrange(1000): - logger = logging.getLogger(choice(loggers)) - level = choice(levels) - logger.log(level, "Message number %d", i) - -def main(args=None): - rv = 0 - if args is None: - args = sys.argv[1:] - parser = OptionParser(usage="usage: %prog [options] CONFIG-FILE") - - (options, args) = parser.parse_args(args) - try: - if len(args) == 0: - raise Usage("No configuration file specified") - fileConfig(args[0]) - testConfig() - except Usage, e: - parser.print_help() - print "\n%s: error: %s" % (get_prog_name(), e) - rv = 1 - except Exception, e: - print "\n%s: error: %s" % (get_prog_name(), e) - typ, val, tb = sys.exc_info() - import traceback - traceback.print_tb(tb) - rv = 2 - return rv - -if __name__ == "__main__": - sys.exit(main()) diff --git a/src/test/config_0_3_9/setup.py b/src/test/config_0_3_9/setup.py deleted file mode 100644 index 9c7dfab..0000000 --- a/src/test/config_0_3_9/setup.py +++ /dev/null @@ -1,20 +0,0 @@ -from distutils.core import setup - -setup(name = "config", - description="A hierarchical, easy-to-use, powerful configuration module for Python", - long_description = """This module allows a hierarchical configuration scheme with support for mappings -and sequences, cross-references between one part of the configuration and -another, the ability to flexibly access real Python objects without full-blown -eval(), an include facility, simple expression evaluation and the ability to -change, save, cascade and merge configurations. Interfaces easily with -environment variables and command-line options. It has been developed on python -2.3 but should work on version 2.2 or greater.""", - license="""Copyright (C) 2004-2010 by Vinay Sajip. All Rights Reserved. See LICENSE for license.""", - version = "0.3.9", - author = "Vinay Sajip", - author_email = "vinay_sajip@red-dove.com", - maintainer = "Vinay Sajip", - maintainer_email = "vinay_sajip@red-dove.com", - url = "http://www.red-dove.com/python_config.html", - py_modules = ["config"], - ) diff --git a/src/test/config_0_3_9/styles.json b/src/test/config_0_3_9/styles.json deleted file mode 100644 index 259697e..0000000 --- a/src/test/config_0_3_9/styles.json +++ /dev/null @@ -1,554 +0,0 @@ -{ - "embeddedFonts" : [ ], - "pageSetup" : { - "size": "A4", - "width": null, - "height": null, - "margin-top": "2cm", - "margin-bottom": "2cm", - "margin-left": "2cm", - "margin-right": "2cm", - "margin-gutter": "0cm", - "spacing-header": "5mm", - "spacing-footer": "5mm", - "firstTemplate": "oneColumn" - }, - "pageTemplates" : { - "coverPage": { - "frames": [ - ["0cm", "0cm", "100%", "100%"] - ], - "showHeader" : false, - "showFooter" : false - }, - "oneColumn": { - "frames": [ - ["0cm", "0cm", "100%", "100%"] - ], - "showHeader" : true, - "showFooter" : true - }, - "twoColumn": { - "frames": [ - ["0cm", "0cm", "49%", "100%"], - ["51%", "0cm", "49%", "100%"] - ], - "showHeader" : true, - "showFooter" : true - }, - "threeColumn": { - "frames": [ - ["2%", "0cm", "29.333%", "100%"], - ["35.333%", "0cm", "29.333%", "100%"], - ["68.666%", "0cm", "29.333%", "100%"] - ], - "showHeader" : true, - "showFooter" : true - }, - "cutePage": { - "frames": [ - ["0%", "0%", "100%", "100%"] - ], - "showHeader" : true, - "showFooter" : true, - "defaultFooter" : "###Page###", - "defaultHeader" : "###Section###" - } - }, - "fontsAlias" : { - "stdFont": "Helvetica", - "stdBold": "Helvetica-Bold", - "stdItalic": "Helvetica-Oblique", - "stdBoldItalic": "Helvetica-BoldOblique", - "stdSans": "Helvetica", - "stdSansBold": "Helvetica-Bold", - "stdSansItalic": "Helvetica-Oblique", - "stdSansBoldItalic": "Helvetica-BoldOblique", - "stdMono": "Courier", - "stdMonoItalic": "Courier-Oblique", - "stdMonoBold": "Courier-Bold", - "stdMonoBoldItalic": "Courier-BoldOblique", - "stdSerif": "Times-Roman" - }, - "linkColor" : "navy", - "styles" : [ - [ "base" , { - "parent": null, - "fontName": "stdFont", - "fontSize":10, - "leading":12, - "leftIndent":0, - "rightIndent":0, - "firstLineIndent":0, - "alignment":"TA_LEFT", - "spaceBefore":0, - "spaceAfter":0, - "bulletFontName":"stdFont", - "bulletFontSize":10, - "bulletIndent":0, - "textColor": "black", - "backColor": null, - "wordWrap": null, - "borderWidth": 0, - "borderPadding": 0, - "borderColor": null, - "borderRadius": null, - "allowWidows": false, - "allowOrphans": false, - "hyphenation": false, - "kerning": false - }] , - ["normal" , { - "parent": "base" - }], - ["title_reference" , { - "parent": "normal", - "fontName": "stdItalic" - }], - ["bodytext" , { - "parent": "normal", - "spaceBefore": 6, - "alignment": "TA_JUSTIFY", - "hyphenation": true - }], - ["toc" , { - "parent": "normal" - }], - ["blockquote" , { - "parent": "bodytext", - "leftIndent": 20 - }], - ["lineblock" , { - "parent": "bodytext" - }], - ["line" , { - "parent": "lineblock", - "spaceBefore": 0 - }], - ["toc1" , { - "parent": "toc", - "fontName": "stdBold" - }], - ["toc2" , { - "parent": "toc", - "leftIndent": 20 - }], - ["toc3" , { - "parent": "toc", - "leftIndent": 40 - }], - ["toc4" , { - "parent": "toc", - "leftIndent": 60 - }], - ["toc5" , { - "parent": "toc", - "leftIndent": 80 - }], - ["toc6" , { - "parent": "toc", - "leftIndent": 100 - }], - ["toc7" , { - "parent": "toc", - "leftIndent": 100 - }], - ["toc8" , { - "parent": "toc", - "leftIndent": 100 - }], - ["toc9" , { - "parent": "toc", - "leftIndent": 100 - }], - ["toc10" , { - "parent": "toc", - "leftIndent": 100 - }], - ["toc11" , { - "parent": "toc", - "leftIndent": 100 - }], - ["toc12" , { - "parent": "toc", - "leftIndent": 100 - }], - ["toc13" , { - "parent": "toc", - "leftIndent": 100 - }], - ["toc14" , { - "parent": "toc", - "leftIndent": 100 - }], - ["toc15" , { - "parent": "toc", - "leftIndent": 100 - }], - ["footer" , { - "parent": "normal", - "alignment": "TA_CENTER" - }], - ["header" , { - "parent": "normal", - "alignment": "TA_CENTER" - }], - ["attribution" , { - "parent": "bodytext", - "alignment": "TA_RIGHT" - }], - ["figure" , { - "parent": "bodytext", - "alignment": "TA_CENTER" - }], - ["figure-caption" , { - "parent": "bodytext", - "fontName": "stdItalic", - "alignment": "TA_CENTER" - }], - ["figure-legend" , { - "parent": "bodytext", - "alignment": "TA_CENTER" - }], - ["bullet_list", { - "parent": "bodytext", - "commands": [ - [ "VALIGN", [ 0, 0 ], [ -1, -1 ], "TOP" ], - [ "RIGHTPADDING", [ 0, 0 ], [ 1, -1 ], 0 ] - ], - "colWidths": ["20",null] - }], - ["bullet_list_item" , { - "parent": "bodytext" - }], - ["item_list", { - "parent": "bodytext", - "commands": [ - [ "VALIGN", [ 0, 0 ], [ -1, -1 ], "TOP" ], - [ "RIGHTPADDING", [ 0, 0 ], [ 1, -1 ], 0 ] - ], - "colWidths": ["20pt",null] - }], - ["item_list_item" , { - "parent": "bodytext" - }], - ["definition_list_term" , { - "parent": "normal", - "fontName": "stdBold", - "spaceBefore": 4, - "spaceAfter": 0, - "keepWithNext": true - }], - ["definition_list_classifier" , { - "parent": "normal", - "fontName": "stdItalic" - }], - ["definition" , { - "parent": "bodytext", - "firstLineIndent": 0, - "bulletIndent": 0, - "spaceBefore": 0 - }], - ["fieldname" , { - "parent": "bodytext", - "alignment": "TA_RIGHT", - "fontName": "stdBold" - }], - ["fieldvalue" , { - "parent": "bodytext" - }], - ["rubric" , { - "parent": "bodytext", - "textColor": "darkred", - "alignment": "TA_CENTER" - }], - ["italic" , { - "parent": "bodytext", - "fontName": "stdItalic" - }], - ["heading" , { - "parent": "normal", - "keepWithNext": true, - "spaceBefore": 12, - "spaceAfter": 6 - }], - ["title" , { - "parent": "heading", - "fontName": "stdBold", - "fontSize": "200%", - "alignment": "TA_CENTER", - "keepWithNext": false, - "spaceAfter": 10 - }], - ["subtitle" , { - "parent": "title", - "spaceBefore": 12, - "fontSize": "75%" - }], - ["heading1" , { - "parent": "heading", - "fontName": "stdBold", - "fontSize": "175%" - }], - ["heading2" , { - "parent": "heading", - "fontName": "stdBold", - "fontSize": "150%" - }], - ["heading3" , { - "parent": "heading", - "fontName": "stdBoldItalic", - "fontSize": "125%" - }], - ["heading4" , { - "parent": "heading", - "fontName": "stdBoldItalic" - }], - ["heading5" , { - "parent": "heading", - "fontName": "stdBoldItalic" - }], - ["heading6" , { - "parent": "heading", - "fontName": "stdBoldItalic" - }], - ["topic-title" , { - "parent": "heading3" - }], - ["sidebar-title" , { - "parent": "heading3" - }], - ["sidebar-subtitle" , { - "parent": "heading4" - }], - ["sidebar" , { - "float": "none", - "width": "100%", - "parent": "normal", - "backColor": "beige", - "borderColor": "darkgray", - "borderPadding": 8, - "borderWidth": 0.5 - }], - ["admonition" , { - "parent": "normal", - "spaceBefore": 12, - "spaceAfter": 6, - "borderPadding": [16,16,16,16], - "backColor": "beige", - "borderColor": "darkgray", - "borderWidth": 0.5, - "commands":[ - [ "VALIGN", [ 0, 0 ], [ -1, -1 ], "TOP" ] - ] - }], - ["attention" , { - "parent": "admonition" - }], - ["caution" , { - "parent": "admonition" - }], - ["danger" , { - "parent": "admonition" - }], - ["error" , { - "parent": "admonition" - }], - ["hint" , { - "parent": "admonition" - }], - ["important" , { - "parent": "admonition" - }], - ["note" , { - "parent": "admonition" - }], - ["tip" , { - "parent": "admonition" - }], - ["warning" , { - "parent": "admonition" - }], - ["admonition-title" , { - "parent": "heading3" - }], - ["admonition-heading" , { - "parent": "heading3" - }], - ["attention-heading" , { - "parent": "admonition-heading" - }], - ["caution-heading" , { - "parent": "admonition-heading" - }], - ["danger-heading" , { - "parent": "admonition-heading" - }], - ["error-heading" , { - "parent": "admonition-heading" - }], - ["hint-heading" , { - "parent": "admonition-heading" - }], - ["important-heading" , { - "parent": "admonition-heading" - }], - ["note-heading" , { - "parent": "admonition-heading" - }], - ["tip-heading" , { - "parent": "admonition-heading" - }], - ["warning-heading" , { - "parent": "admonition-heading" - }], - ["literal" , { - "parent": "normal", - "fontName": "stdMono", - "firstLineIndent": 0, - "hyphenation": false - }], - ["aafigure" , { - "parent": "literal" - }], - ["table" , { - "spaceBefore":6, - "spaceAfter":0, - "alignment": "TA_CENTER", - "commands": [ - [ "VALIGN", [ 0, 0 ], [ -1, -1 ], "TOP" ], - [ "INNERGRID", [ 0, 0 ], [ -1, -1 ], 0.25, "black" ], - [ "ROWBACKGROUNDS", [0, 0], [-1, -1], ["white","#E0E0E0"]], - [ "BOX", [ 0, 0 ], [ -1, -1 ], 0.25, "black" ] - ] - }], - ["table-title" , { - "parent" : "heading4", - "keepWithNext": false, - "alignment" : "TA_CENTER" - }], - ["table-heading" , { - "parent" : "heading", - "backColor" : "beige", - "alignment" : "TA_CENTER", - "valign" : "BOTTOM", - "borderPadding" : 0 - }], - ["table-body", { - "parent" : "normal" - }], - ["dedication" , { - "parent" : "normal" - }], - ["abstract" , { - "parent" : "normal" - }], - ["contents" , { - "parent" : "normal" - }], - ["tableofcontents" , { - "parent" : "normal" - }], - ["code" , { - "parent": "literal", - "leftIndent": 0, - "spaceBefore": 8, - "spaceAfter": 8, - "backColor": "beige", - "borderColor": "darkgray", - "borderWidth": 0.5, - "borderPadding": 6 - }], - ["pygments-n" , {"parent": "code"}], - ["pygments-nx" , {"parent": "code"}], - ["pygments-p" , {"parent": "code"}], - ["pygments-hll", {"parent": "code", "backColor": "#ffffcc"}], - ["pygments-c", {"textColor": "#008800", "parent": "code"}], - ["pygments-err", {"parent": "code"}], - ["pygments-k", {"textColor": "#AA22FF", "parent": "code"}], - ["pygments-o", {"textColor": "#666666", "parent": "code"}], - ["pygments-cm", {"textColor": "#008800", "parent": "code"}], - ["pygments-cp", {"textColor": "#008800", "parent": "code"}], - ["pygments-c1", {"textColor": "#008800", "parent": "code"}], - ["pygments-cs", {"textColor": "#008800", "parent": "code"}], - ["pygments-gd", {"textColor": "#A00000", "parent": "code"}], - ["pygments-ge", {"parent": "code"}], - ["pygments-gr", {"textColor": "#FF0000", "parent": "code"}], - ["pygments-gh", {"textColor": "#000080", "parent": "code"}], - ["pygments-gi", {"textColor": "#00A000", "parent": "code"}], - ["pygments-go", {"textColor": "#808080", "parent": "code"}], - ["pygments-gp", {"textColor": "#000080", "parent": "code"}], - ["pygments-gs", {"parent": "code"}], - ["pygments-gu", {"textColor": "#800080", "parent": "code"}], - ["pygments-gt", {"textColor": "#0040D0", "parent": "code"}], - ["pygments-kc", {"textColor": "#AA22FF", "parent": "code"}], - ["pygments-kd", {"textColor": "#AA22FF", "parent": "code"}], - ["pygments-kn", {"textColor": "#AA22FF", "parent": "code"}], - ["pygments-kp", {"textColor": "#AA22FF", "parent": "code"}], - ["pygments-kr", {"textColor": "#AA22FF", "parent": "code"}], - ["pygments-kt", {"textColor": "#00BB00", "parent": "code"}], - ["pygments-m", {"textColor": "#666666", "parent": "code"}], - ["pygments-s", {"textColor": "#BB4444", "parent": "code"}], - ["pygments-na", {"textColor": "#BB4444", "parent": "code"}], - ["pygments-nb", {"textColor": "#AA22FF", "parent": "code"}], - ["pygments-nc", {"textColor": "#0000FF", "parent": "code"}], - ["pygments-no", {"textColor": "#880000", "parent": "code"}], - ["pygments-nd", {"textColor": "#AA22FF", "parent": "code"}], - ["pygments-ni", {"textColor": "#999999", "parent": "code"}], - ["pygments-ne", {"textColor": "#D2413A", "parent": "code"}], - ["pygments-nf", {"textColor": "#00A000", "parent": "code"}], - ["pygments-nl", {"textColor": "#A0A000", "parent": "code"}], - ["pygments-nn", {"textColor": "#0000FF", "parent": "code"}], - ["pygments-nt", {"textColor": "#008000", "parent": "code"}], - ["pygments-nv", {"textColor": "#B8860B", "parent": "code"}], - ["pygments-ow", {"textColor": "#AA22FF", "parent": "code"}], - ["pygments-w", {"textColor": "#bbbbbb", "parent": "code"}], - ["pygments-mf", {"textColor": "#666666", "parent": "code"}], - ["pygments-mh", {"textColor": "#666666", "parent": "code"}], - ["pygments-mi", {"textColor": "#666666", "parent": "code"}], - ["pygments-mo", {"textColor": "#666666", "parent": "code"}], - ["pygments-sb", {"textColor": "#BB4444", "parent": "code"}], - ["pygments-sc", {"textColor": "#BB4444", "parent": "code"}], - ["pygments-sd", {"textColor": "#BB4444", "parent": "code"}], - ["pygments-s2", {"textColor": "#BB4444", "parent": "code"}], - ["pygments-se", {"textColor": "#BB6622", "parent": "code"}], - ["pygments-sh", {"textColor": "#BB4444", "parent": "code"}], - ["pygments-si", {"textColor": "#BB6688", "parent": "code"}], - ["pygments-sx", {"textColor": "#008000", "parent": "code"}], - ["pygments-sr", {"textColor": "#BB6688", "parent": "code"}], - ["pygments-s1", {"textColor": "#BB4444", "parent": "code"}], - ["pygments-ss", {"textColor": "#B8860B", "parent": "code"}], - ["pygments-bp", {"textColor": "#AA22FF", "parent": "code"}], - ["pygments-vc", {"textColor": "#B8860B", "parent": "code"}], - ["pygments-vg", {"textColor": "#B8860B", "parent": "code"}], - ["pygments-vi", {"textColor": "#B8860B", "parent": "code"}], - ["pygments-il", {"textColor": "#666666", "parent": "code"}], - - [ "endnote", { - "parent": "bodytext", - "commands": [ - [ "VALIGN", [ 0, 0 ], [ -1, -1 ], "TOP" ], - [ "TOPPADDING", [ 0, 0 ], [ -1, -1 ], 0 ], - [ "BOTTOMPADDING", [ 0, 0 ], [ -1, -1 ], 0 ], - [ "RIGHTPADDING", [ 0, 0 ], [ 1, -1 ], 0 ] - ], - "colWidths": ["3cm",null] - }], - [ "field_list", { - "parent": "bodytext", - "commands": [ - [ "VALIGN", [ 0, 0 ], [ -1, -1 ], "TOP" ], - [ "TOPPADDING", [ 0, 0 ], [ -1, -1 ], 0 ] - ], - "colWidths": ["3cm",null], - "spaceBefore": 6 - }], - [ "option_list", { - "commands": [ - [ "VALIGN", [ 0, 0 ], [ -1, -1 ], "TOP" ], - [ "TOPPADDING", [ 0, 0 ], [ -1, -1 ], 0 ] - ], - "colWidths": [null,null] - }] - ] -} diff --git a/src/test/config_0_3_9/test_config.py b/src/test/config_0_3_9/test_config.py deleted file mode 100644 index 393be86..0000000 --- a/src/test/config_0_3_9/test_config.py +++ /dev/null @@ -1,439 +0,0 @@ -# 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. -""" - -import unittest -# import test_support -import config -from config import Config, ConfigMerger, ConfigList -from config 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__": - unittest.main(exit=False) - pass - # test_main() diff --git a/src/test/debugTest.py b/src/test/debugTest.py deleted file mode 100755 index bc84f53..0000000 --- a/src/test/debugTest.py +++ /dev/null @@ -1,127 +0,0 @@ -#!/usr/bin/env python -#-*- coding:utf-8 -*- - -# Copyright (C) 2010-2018 CEA/DEN -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -import os -import sys -import unittest - -import src -import src.debug as DBG # Easy print stderr (for DEBUG only) -import src.pyconf as PYF # 0.3.7 -import src.test.config_0_3_9.config as PYF9 # TODO 0.3.9 - -_EXAMPLES = { -1 : """\ - messages: - [ - { - stream : "sys.stderr" # modified - message: 111 # modified - name: 'Harry' - } - { - stream : $messages[0].stream - message: 1.23e4 # modified do not work 0.3.7 - name: 'Ruud' - } - { - stream : "HELLO " + $messages[0].stream - message: 'Bienvenue' - name: "Yves" - } - ] -""", - -2 : """\ - aa: 111 - bb: $aa + 222 -""", - -3 : """\ - aa: Yves - bb: "Herve" # avoid Hervé -> 'utf8' codec can't decode byte -""", - -4 : """\ - aa: Yves - bb: "Hervé" # avoid Hervé -> 'utf8' codec can't decode byte -""", - - -} - - -class TestCase(unittest.TestCase): - "Test the debug.py""" - - def test_000(self): - # one shot setUp() for this TestCase - # DBG.push_debug(True) - # SAT.setNotLocale() # test english - return - - def test_005(self): - res = DBG.getLocalEnv() - self.assertTrue(len(res.split()) > 0) - self.assertTrue("USER :" in res) - self.assertTrue("LANG :" in res) - - def test_010(self): - inStream = DBG.InStream(_EXAMPLES[1]) - self.assertEqual(inStream.getvalue(), _EXAMPLES[1]) - cfg = PYF.Config(inStream) - self.assertEqual(len(cfg.messages), 3) - outStream = DBG.OutStream() - DBG.saveConfigStd(cfg, outStream) - res = outStream.value - DBG.write("test_010 cfg std", res) - self.assertTrue("messages :" in res) - self.assertTrue("'sys.stderr'" in res) - - def test_020(self): - inStream = DBG.InStream(_EXAMPLES[2]) - cfg = PYF.Config(inStream) - res = DBG.getStrConfigDbg(cfg) - DBG.write("test_020 cfg dbg", res) - ress = res.split("\n") - self.assertTrue(".aa : '111'" in ress[0]) - self.assertTrue(".bb : $aa + 222 --> '333'" in ress[1]) - - def test_025(self): - inStream = DBG.InStream(_EXAMPLES[1]) - cfg = PYF.Config(inStream) - outStream = DBG.OutStream() - DBG.saveConfigDbg(cfg, outStream) - res = outStream.value - DBG.write("test_025 cfg dbg", res) - for i in range(len(cfg.messages)): - self.assertTrue("messages[%i].name" % i in res) - self.assertTrue("--> 'HELLO sys.stderr'" in res) - - - def test_999(self): - # one shot tearDown() for this TestCase - # SAT.setLocale() # end test english - # DBG.pop_debug() - return - -if __name__ == '__main__': - unittest.main(exit=False) - pass - diff --git a/src/test/pyconfTest.py b/src/test/pyconfTest.py deleted file mode 100755 index 2adaeb8..0000000 --- a/src/test/pyconfTest.py +++ /dev/null @@ -1,152 +0,0 @@ -#!/usr/bin/env python -#-*- coding:utf-8 -*- - -# Copyright (C) 2010-2018 CEA/DEN -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -import os -import sys -import unittest - -import src -import src.debug as DBG # Easy print stderr (for DEBUG only) -import src.pyconf as PYF # 0.3.7 -import src.test.config_0_3_9.config as PYF9 # TODO 0.3.9 - -_EXAMPLES = { -1 : """\ - messages: - [ - { - stream : "sys.stderr" # modified - message: 'Welcome' - name: 'Harry' - } - { - stream : "sys.stdout" # modified - message: 'Welkom' - name: 'Ruud' - } - { - stream : $messages[0].stream - message: 'Bienvenue' - name: "Yves" - } - ] -""", - -2 : """\ - aa: 111 - bb: $aa + 222 -""", - -3 : """\ - aa: Yves - bb: "Herve" # avoid Hervé -> 'utf8' codec can't decode byte -""", - -4 : """\ - aa: Yves - bb: "Hervé" # avoid Hervé -> 'utf8' codec can't decode byte -""", - - -} - - -class TestCase(unittest.TestCase): - "Test the pyconf.py""" - - def test_000(self): - # one shot setUp() for this TestCase - # DBG.push_debug(True) - # SAT.setNotLocale() # test english - return - - def test_010(self): - # pyconf.py doc example 0.3.7 - # https://www.red-dove.com/config-doc/ is 0.3.9 ! - # which, when run, would yield the console output: - - expected = """\ -Welcome, Harry -Welkom, Ruud -Bienvenue, Yves -""" - inStream = DBG.InStream(_EXAMPLES[1]) - cfg = PYF.Config(inStream) - res = '' - for m in cfg.messages: - res += '%s, %s\n' % (m.message, m.name) - self.assertEqual(res, expected) - outStream = DBG.OutStream() - cfg.__save__(outStream) # sat renamed save() in __save__() - res = outStream.value - DBG.write("test_010 cfg", res) - self.assertTrue("name : 'Harry'" in res) - self.assertTrue("name : 'Ruud'" in res) - self.assertTrue("name : 'Yves'" in res) - - def test_020(self): - cfg = PYF.Config() - self.assertEqual(str(cfg), '{}') - self.assertEqual(cfg.__repr__(), '{}') - cfg.aa = "1111" - self.assertEqual(str(cfg), "{'aa': '1111'}") - cfg.bb = 2222 - self.assertTrue("'bb': 2222" in str(cfg)) - self.assertTrue("'aa': '1111'" in str(cfg)) - cfg.cc = 3333. - self.assertTrue("'cc': 3333." in str(cfg)) - - def test_030(self): - inStream = DBG.InStream(_EXAMPLES[2]) - cfg = PYF.Config(inStream) - self.assertEqual(str(cfg), "{'aa': 111, 'bb': $aa + 222}") - self.assertEqual(cfg.aa, 111) - self.assertEqual(cfg.bb, 333) - - def test_040(self): - inStream = DBG.InStream(_EXAMPLES[3]) - cfg = PYF.Config(inStream) - self.assertEqual(cfg.aa, "Yves") - self.assertEqual(cfg.bb, "Herve") - self.assertEqual(type(cfg.bb), str) - cfg.bb = "Hervé" # try this - self.assertEqual(type(cfg.bb), str) - self.assertEqual(cfg.bb, "Hervé") - - def test_045(self): - """TODO: make Hervé valid with pyconf.py as 0.3.9""" - inStream = DBG.InStream(_EXAMPLES[4]) - cfg = PYF9.Config(inStream) - outStream = DBG.OutStream() - cfg.save(outStream) # sat renamed save() in __save__() - res = outStream.value - DBG.write("test_045 cfg", res) - self.assertTrue("aa : 'Yves'" in res) - self.assertTrue(r"bb : 'Herv\xc3\xa9'" in res) - self.assertEqual(cfg.bb, "Hervé") - - def test_999(self): - # one shot tearDown() for this TestCase - # SAT.setLocale() # end test english - # DBG.pop_debug() - return - -if __name__ == '__main__': - unittest.main(exit=False) - pass diff --git a/src/test/satHelpTest.py b/src/test/satHelpTest.py deleted file mode 100755 index 23d8ba2..0000000 --- a/src/test/satHelpTest.py +++ /dev/null @@ -1,85 +0,0 @@ -#!/usr/bin/env python -#-*- coding:utf-8 -*- - -# Copyright (C) 2010-2018 CEA/DEN -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -import os -import sys -import unittest - -import src.salomeTools as SAT -import src -import src.debug as DBG # Easy print stderr (for DEBUG only) - -class TestCase(unittest.TestCase): - "Test the sat --help commands""" - - def test_000(self): - # one shot setUp() for this TestCase - # DBG.push_debug(True) - SAT.setNotLocale() # test english - return - - def test_010(self): - cmd = "sat --help" - stdout, stderr = SAT.launchSat(cmd) - print stdout, stderr - self.assertEqual(stderr, "") - self.assertTrue(" - config" in stdout) - - def xtest_011(self): - cmd = "--help" - s = SAT.Sat(cmd) - exitCode = s.execute_command() - self.assertEqual(src.okToStr(exitCode), "OK") - - def xtest_030(self): - cmd = "sat --help config" - stdout, stderr = SAT.launchSat(cmd) - self.assertEqual(stderr, "") - self.assertTrue("--value" in stdout) - - def xtest_031(self): - cmd = "--help config" - s = SAT.Sat(cmd) - exitCode = s.execute_command() - self.assertEqual(src.okToStr(exitCode), "OK") - - def xtest_032(self): - cmd = "config -l" - s = SAT.Sat(cmd) - exitCode = s.execute_command() - self.assertEqual(src.okToStr(exitCode), "OK") - - def xtest_040(self): - cmds = SAT.getCommandsList() - for c in cmds: - cmd = "sat --help %s" % c - stdout, stderr = SAT.launchSat(cmd) - self.assertEqual(stderr, "") - # DBG.write("stdout '%s'" % cmd, stdout) - self.assertTrue("vailable options" in stdout) - - def test_999(self): - # one shot tearDown() for this TestCase - SAT.setLocale() # end test english - # DBG.pop_debug() - return - -if __name__ == '__main__': - unittest.main(exit=False) - pass diff --git a/src/test/test_pyconf.py b/src/test/test_pyconf.py deleted file mode 100755 index 7f884de..0000000 --- a/src/test/test_pyconf.py +++ /dev/null @@ -1,450 +0,0 @@ -#!/usr/bin/env python -#-*- coding:utf-8 -*- - -# Copyright 2004-2010 by Vinay Sajip. All Rights Reserved. -# -# Permission to use, copy, modify, and distribute this software and its -# documentation for any purpose and without fee is hereby granted, -# provided that the above copyright notice appear in all copies and that -# both that copyright notice and this permission notice appear in -# supporting documentation, and that the name of Vinay Sajip -# not be used in advertising or publicity pertaining to distribution -# of the software without specific, written prior permission. -# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL -# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -""" -Test harness for the configuration module 'config' for Python. - -from test_config 0.3.9 modified to test 0.3.7.1 -this test obviously have FAILED (errors=6), TODO, fix upgrading 0.3.9, or not. -""" - -import unittest -# import test_support -import src.pyconf as config -from src.pyconf import Config, ConfigMerger, ConfigList -from src.pyconf import ConfigError, ConfigFormatError, ConfigResolutionError -import logging -from StringIO import StringIO - -STREAMS = { - "simple_1" : -""" -message: 'Hello, world!' -""", - "malformed_1" : -""" -123 -""", - "malformed_2" : -""" -[ 123, 'abc' ] -""", - "malformed_3" : -""" -{ a : 7, b : 1.3, c : 'test' } -""", - "malformed_4" : -""" -test: $a [7] # note space before bracket -""", - "malformed_5" : -""" -test: 'abc' -test: 'def' -""", - "wellformed_1" : -""" -test: $a[7] # note no space before bracket -""", - "boolean_1": -""" -test : False -another_test: True -""", - "boolean_2": -""" -test : false -another_test: true -""", - "none_1": -""" -test : None -""", - "none_2": -""" -test : none -""", - "number_1": -""" -root: 1 -stream: 1.7 -neg: -1 -negfloat: -2.0 -posexponent: 2.0999999e-08 -negexponent: -2.0999999e-08 -exponent: 2.0999999e08 -""", - "sequence_1": -""" -mixed: [ "VALIGN", [ 0, 0 ], [ -1, -1 ], "TOP" ] -simple: [1, 2] -nested: [1, [2, 3], [4, [5, 6]]] -""", - "include_1": -""" -included: @'include_2' -""", - "include_2": -""" -test: 123 -another_test: 'abc' -""", - "expr_1": -""" -value1 : 10 -value2 : 5 -value3 : 'abc' -value4 : 'ghi' -value5 : 0 -value6 : { 'a' : $value1, 'b': $value2 } -derived1 : $value1 + $value2 -derived2 : $value1 - $value2 -derived3 : $value1 * $value2 -derived4 : $value1 / $value2 -derived5 : $value1 % $value2 -derived6 : $value3 + $value4 -derived7 : $value3 + 'def' + $value4 -derived8 : $value3 - $value4 # meaningless -derived9 : $value1 / $value5 # div by zero -derived10 : $value1 % $value5 # div by zero -derived11 : $value17 # doesn't exist -derived12 : $value6.a + $value6.b -""", - "eval_1": -""" -stderr : `sys.stderr` -stdout : `sys.stdout` -stdin : `sys.stdin` -debug : `debug` -DEBUG : `DEBUG` -derived: $DEBUG * 10 -""", - "merge_1": -""" -value1: True -value3: [1, 2, 3] -value5: [ 7 ] -value6: { 'a' : 1, 'c' : 3 } -""", - "merge_2": -""" -value2: False -value4: [4, 5, 6] -value5: ['abc'] -value6: { 'b' : 2, 'd' : 4 } -""", - "merge_3": -""" -value1: True -value2: 3 -value3: [1, 3, 5] -value4: [1, 3, 5] -""", - "merge_4": -""" -value1: False -value2: 4 -value3: [2, 4, 6] -value4: [2, 4, 6] -""", - "list_1": -""" -verbosity : 1 -""", - "list_2": -""" -verbosity : 2 -program_value: 4 -""", - "list_3": -""" -verbosity : 3 -suite_value: 5 -""", - "get_1": -""" -value1 : 123 -value2 : 'abcd' -value3 : True -value4 : None -value5: -{ - value1 : 123 - value2 : 'abcd' - value3 : True - value4 : None -} -""", - "multiline_1": -""" -value1: '''Value One -Value Two -''' -value2: \"\"\"Value Three -Value Four\"\"\" -""" -} - -def makeStream(name): - s = StringIO(STREAMS[name]) - s.name = name - return s - -class OutStream(StringIO): - def close(self): - self.value = self.getvalue() - StringIO.close(self) - -class TestConfig(unittest.TestCase): - - def setUp(self): - self.cfg = Config(None) - - def tearDown(self): - del self.cfg - - def testCreation(self): - self.assertEqual(0, len(self.cfg)) # should be empty - - def testSimple(self): - self.cfg.load(makeStream("simple_1")) - self.failUnless('message' in self.cfg) - self.failIf('root' in self.cfg) - self.failIf('stream' in self.cfg) - self.failIf('load' in self.cfg) - self.failIf('save' in self.cfg) - - def testValueOnly(self): - self.assertRaises(ConfigError, self.cfg.load, - makeStream("malformed_1")) - self.assertRaises(ConfigError, self.cfg.load, - makeStream("malformed_2")) - self.assertRaises(ConfigError, self.cfg.load, - makeStream("malformed_3")) - - def testBadBracket(self): - self.assertRaises(ConfigError, self.cfg.load, - makeStream("malformed_4")) - - def testDuplicate(self): - self.assertRaises(ConfigError, self.cfg.load, - makeStream("malformed_5")) - - def testGoodBracket(self): - self.cfg.load(makeStream("wellformed_1")) - - def testBoolean(self): - self.cfg.load(makeStream("boolean_1")) - self.assertEqual(True, self.cfg.another_test) - self.assertEqual(False, self.cfg.test) - - def testNotBoolean(self): - self.cfg.load(makeStream("boolean_2")) - self.assertEqual('true', self.cfg.another_test) - self.assertEqual('false', self.cfg.test) - - def testNone(self): - self.cfg.load(makeStream("none_1")) - self.assertEqual(None, self.cfg.test) - - def testNotNone(self): - self.cfg.load(makeStream("none_2")) - self.assertEqual('none', self.cfg.test) - - def testNumber(self): - self.cfg.load(makeStream("number_1")) - self.assertEqual(1, self.cfg.root) - self.assertEqual(1.7, self.cfg.stream) - self.assertEqual(-1, self.cfg.neg) - self.assertEqual(-2.0, self.cfg.negfloat) - self.assertAlmostEqual(-2.0999999e-08, self.cfg.negexponent) - self.assertAlmostEqual(2.0999999e-08, self.cfg.posexponent) - self.assertAlmostEqual(2.0999999e08, self.cfg.exponent) - - def testChange(self): - self.cfg.load(makeStream("simple_1")) - self.cfg.message = 'Goodbye, cruel world!' - self.assertEqual('Goodbye, cruel world!', self.cfg.message) - - def testSave(self): - self.cfg.load(makeStream("simple_1")) - self.cfg.message = 'Goodbye, cruel world!' - out = OutStream() - self.cfg.save(out) - self.assertEqual("message : 'Goodbye, cruel world!'" + config.NEWLINE, - out.value) - - def testInclude(self): - config.streamOpener = makeStream - self.cfg = Config("include_1") - config.streamOpener = config.defaultStreamOpener - out = OutStream() - self.cfg.save(out) - s = "included :%s{%s test : 123%s another_test : 'abc'%s}%s" % (5 * - (config.NEWLINE,)) - self.assertEqual(s, out.value) - - def testExpression(self): - self.cfg.load(makeStream("expr_1")) - self.assertEqual(15, self.cfg.derived1) - self.assertEqual(5, self.cfg.derived2) - self.assertEqual(50, self.cfg.derived3) - self.assertEqual(2, self.cfg.derived4) - self.assertEqual(0, self.cfg.derived5) - self.assertEqual('abcghi', self.cfg.derived6) - self.assertEqual('abcdefghi', self.cfg.derived7) - self.assertRaises(TypeError, lambda x: x.derived8, self.cfg) - self.assertRaises(ZeroDivisionError, lambda x: x.derived9, self.cfg) - self.assertRaises(ZeroDivisionError, lambda x: x.derived10, self.cfg) - self.assertRaises(ConfigResolutionError, - lambda x: x.derived11, self.cfg) - self.assertEqual(15, self.cfg.derived12) - - def testEval(self): - import sys, logging - self.cfg.load(makeStream("eval_1")) - self.assertEqual(sys.stderr, self.cfg.stderr) - self.assertEqual(sys.stdout, self.cfg.stdout) - self.assertEqual(sys.stdin, self.cfg.stdin) - self.assertRaises(ConfigResolutionError, lambda x: x.debug, self.cfg) - self.cfg.addNamespace(logging.Logger) - self.assertEqual(logging.Logger.debug.im_func, self.cfg.debug) - self.assertRaises(ConfigResolutionError, lambda x: x.DEBUG, self.cfg) - self.cfg.addNamespace(logging) - self.assertEqual(logging.DEBUG, self.cfg.DEBUG) - self.cfg.removeNamespace(logging.Logger) - self.assertEqual(logging.debug, self.cfg.debug) - self.assertEqual(logging.DEBUG * 10, self.cfg.derived) - - def testFunctions(self): - makePath = config.makePath - isWord = config.isWord - self.assertEqual('suffix', makePath('', 'suffix')) - self.assertEqual('suffix', makePath(None, 'suffix')) - self.assertEqual('prefix.suffix', makePath('prefix', 'suffix')) - self.assertEqual('prefix[1]', makePath('prefix', '[1]')) - self.failUnless(isWord('a9')) - self.failUnless(isWord('9a')) #perverse, but there you go - self.failIf(isWord(9)) - self.failIf(isWord(None)) - self.failIf(isWord(self)) - self.failIf(isWord('')) - - def testMerge(self): - cfg1 = Config() - cfg1.load(makeStream("merge_1")) - cfg2 = Config(makeStream("merge_2")) - ConfigMerger().merge(cfg1, cfg2) - merged = cfg1 - cfg1 = Config() - cfg1.load(makeStream("merge_1")) - for i in xrange(0, 5): - key = 'value%d' % (i + 1,) - self.failUnless(key in merged) - self.assertEqual(len(cfg1.value5) + len(cfg2.value5), - len(merged.value5)) - cfg3 = Config() - cfg3.load(makeStream("merge_3")) - cfg4 = Config(makeStream("merge_4")) - merger = ConfigMerger() - self.assertRaises(ConfigError, merger.merge, cfg3, cfg4) - - cfg3 = Config(makeStream("merge_3")) - cfg4 = Config(makeStream("merge_4")) - merger = ConfigMerger(config.overwriteMergeResolve) - merger.merge(cfg3, cfg4) - self.assertEqual(False, cfg3['value1']) - self.assertEqual(4, cfg3['value2']) - - def customMergeResolve(map1, map2, key): - if key == "value3": - rv = "overwrite" - else: - rv = config.overwriteMergeResolve(map1, map2, key) - return rv - - cfg3 = Config(makeStream("merge_3")) - cfg4 = Config(makeStream("merge_4")) - merger = ConfigMerger(customMergeResolve) - merger.merge(cfg3, cfg4) - self.assertEqual("[2, 4, 6]", str(cfg3.value3)) - self.assertEqual("[1, 3, 5, 2, 4, 6]", str(cfg3.value4)) - - def testList(self): - list = ConfigList() - list.append(Config(makeStream("list_1"))) - list.append(Config(makeStream("list_2"))) - list.append(Config(makeStream("list_3"))) - self.assertEqual(1, list.getByPath('verbosity')) - self.assertEqual(4, list.getByPath('program_value')) - self.assertEqual(5, list.getByPath('suite_value')) - self.assertRaises(ConfigError, list.getByPath, 'nonexistent_value') - - def testGet(self): - cfg = self.cfg - cfg.load(makeStream("get_1")) - self.assertEqual(123, cfg.get('value1')) - self.assertEqual(123, cfg.get('value1', -123)) - self.assertEqual(-123, cfg.get('value11', -123)) - self.assertEqual('abcd', cfg.get('value2')) - self.failUnless(cfg.get('value3')) - self.failIf(cfg.get('value4') is not None) - self.assertEqual(123, cfg.value5.get('value1')) - self.assertEqual(123, cfg.value5.get('value1', -123)) - self.assertEqual(-123, cfg.value5.get('value11', -123)) - self.assertEqual('abcd', cfg.value5.get('value2')) - self.failUnless(cfg.value5.get('value3')) - self.failIf(cfg.value5.get('value4') is not None) - - def testMultiline(self): - cfg = self.cfg - cfg.load(makeStream("multiline_1")) - self.assertEqual("Value One\nValue Two\n", cfg.get('value1')) - self.assertEqual("Value Three\nValue Four", cfg.get('value2')) - - def testSequence(self): - cfg = self.cfg - strm = makeStream("sequence_1") - cfg.load(strm) - self.assertEqual(str(cfg.simple), "[1, 2]") - self.assertEqual(str(cfg.nested), "[1, [2, 3], [4, [5, 6]]]") - self.assertEqual(str(cfg.mixed), "['VALIGN', [0, 0], [-1, -1], 'TOP']") - - def testJSON(self): - data = StringIO('dummy: ' + open('styles.json', 'r').read()) - self.cfg.load(data) - -def init_logging(): - logging.basicConfig(level=logging.DEBUG, filename="test_config.log", - filemode="w", format="%(asctime)s %(levelname)-5s %(name)-10s %(message)s") -""" -def test_main(): - init_logging() - test_support.run_unittest(TestConfig) -""" - -if __name__ == "__main__": - # test_main() - unittest.main(exit=False) - import sys - sys.stderr.write(""" -WARNING: this test obviously have FAILED (errors=6), -TODO: fix upgrading 0.3.9, (or not).\n\n""") - pass - diff --git a/test/APPLI_TEST/APPLI_TEST.pyconf b/test/APPLI_TEST/APPLI_TEST.pyconf new file mode 100644 index 0000000..5fc08b3 --- /dev/null +++ b/test/APPLI_TEST/APPLI_TEST.pyconf @@ -0,0 +1,45 @@ + +APPLICATION : +{ + name : 'APPLI_TEST' + workdir : $LOCAL.workdir + $VARS.sep + $APPLICATION.name + '-' + $VARS.dist + base : 'base' + tag : 'master' + get_method : 'git' + environ : + { + ACCEPT_SALOME_WARNINGS : '1' + LC_NUMERIC : 'C' + TESTS_ROOT_DIR : "/tmp/" + $VARS.user+ "/TESTS/APPLI_TEST" + } + products : + { + # PREREQUISITES : + 'Python' : 'native' + + # SALOME MODULES : + 'CONFIGURATION' + 'MEDCOUPLING' + 'KERNEL' + 'GUI' + 'GEOM' + 'SMESH' + + } + grid_to_test : 'SALOME_V8' + profile : + { + launcher_name : "appli_test" + product : "SALOME" + } + virtual_app: + { + name : "appli_test" + application_name : "APPLI" + } + test_base : + { + name : "SALOME" + tag : "SalomeV8" + } +} diff --git a/test/README_config_0_3_9.txt b/test/README_config_0_3_9.txt new file mode 100644 index 0000000..4605ae9 --- /dev/null +++ b/test/README_config_0_3_9.txt @@ -0,0 +1,2 @@ +#TODO +switch pyconf.py 0.3.7.1 -> 0.3.9, here for test diff --git a/test/__init__.py b/test/__init__.py old mode 100644 new mode 100755 diff --git a/test/compilation/test_compilation.py b/test/compilation/test_compilation.py deleted file mode 100755 index 79192ad..0000000 --- a/test/compilation/test_compilation.py +++ /dev/null @@ -1,227 +0,0 @@ -#!/usr/bin/env python -#-*- coding:utf-8 -*- - -# Copyright (C) 2010-2018 CEA/DEN -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -import os -import sys -import unittest - -import src.product -from src.salomeTools import Sat - -class TestCase(unittest.TestCase): - """Test of the compile command""" - - def test_010(self): - # Test the compile command with '--products' option - OK = 'KO' - - appli = 'appli-test' - product_name = 'PRODUCT_GIT' - - sat = Sat() - - sat.prepare(appli + ' --product ' + product_name) - expected_install_dir = src.product.get_product_config(sat.cfg, product_name).install_dir - expected_file_path = os.path.join(expected_install_dir, 'bin/hello') - - sat.clean(appli + ' --build --install --product ' + product_name, batch=True) - sat.compile(appli + ' --product ' + product_name) - - if os.path.exists(expected_file_path): - OK = 'OK' - # pyunit method to compare 2 str - self.assertEqual(OK, 'OK') - - def test_020(self): - # Test the configure command with '--fathers' option - OK = 'KO' - - appli = 'appli-test' - product_name = 'PRODUCT_GIT' - product_name2 = 'PRODUCT_ARCHIVE' - - sat = Sat() - - sat.prepare(appli + ' --product ' + product_name +"," +product_name2) - expected_install_dir = src.product.get_product_config(sat.cfg, product_name).install_dir - expected_file_path = os.path.join(expected_install_dir, 'bin/hello') - expected_install_dir2 = src.product.get_product_config(sat.cfg, product_name2).install_dir - expected_file_path2 = os.path.join(expected_install_dir2, 'bin/hello-archive') - - sat.clean(appli + ' --build --install --product ' + product_name +"," +product_name2, batch=True) - sat.compile(appli + ' --with_fathers --product ' + product_name) - - if os.path.exists(expected_file_path) and os.path.exists(expected_file_path2): - OK = 'OK' - # pyunit method to compare 2 str - self.assertEqual(OK, 'OK') - - def test_030(self): - # Test the configure command with '--children' option - OK = 'KO' - - appli = 'appli-test' - product_name = 'PRODUCT_GIT' - product_name2 = 'PRODUCT_ARCHIVE' - - sat = Sat() - - sat.prepare(appli + ' --product ' + product_name +"," +product_name2) - expected_install_dir = src.product.get_product_config(sat.cfg, product_name).install_dir - expected_file_path = os.path.join(expected_install_dir, 'bin/hello') - expected_install_dir2 = src.product.get_product_config(sat.cfg, product_name2).install_dir - expected_file_path2 = os.path.join(expected_install_dir2, 'bin/hello-archive') - - sat.clean(appli + ' --build --install --product ' + product_name +"," +product_name2, batch=True) - sat.compile(appli + ' --with_children --product ' + product_name2) - - if os.path.exists(expected_file_path) and os.path.exists(expected_file_path2): - OK = 'OK' - # pyunit method to compare 2 str - self.assertEqual(OK, 'OK') - - def test_040(self): - # Test the configure command with '--clean_all' option - OK = 'KO' - - appli = 'appli-test' - product_name = 'PRODUCT_GIT' - product_name2 = 'PRODUCT_ARCHIVE' - - sat = Sat() - - sat.prepare(appli + ' --product ' + product_name +"," +product_name2) - expected_install_dir = src.product.get_product_config(sat.cfg, product_name).install_dir - expected_file_path = os.path.join(expected_install_dir, 'bin/hello') - expected_install_dir2 = src.product.get_product_config(sat.cfg, product_name2).install_dir - expected_file_path2 = os.path.join(expected_install_dir2, 'bin/hello-archive') - - sat.compile(appli + ' --with_children --product ' + product_name2) - - sat.compile(appli + ' --clean_all --with_children --product ' + product_name2, batch=True) - - if os.path.exists(expected_file_path) and os.path.exists(expected_file_path2): - OK = 'OK' - # pyunit method to compare 2 str - self.assertEqual(OK, 'OK') - - def test_050(self): - # Test the configure command with '--clean_install' option - OK = 'KO' - - appli = 'appli-test' - product_name = 'PRODUCT_GIT' - product_name2 = 'PRODUCT_ARCHIVE' - - sat = Sat() - - sat.prepare(appli + ' --product ' + product_name +"," +product_name2) - expected_install_dir = src.product.get_product_config(sat.cfg, product_name).install_dir - expected_file_path = os.path.join(expected_install_dir, 'bin/hello') - expected_install_dir2 = src.product.get_product_config(sat.cfg, product_name2).install_dir - expected_file_path2 = os.path.join(expected_install_dir2, 'bin/hello-archive') - - sat.compile(appli + ' --with_children --product ' + product_name2) - - sat.compile(appli + ' --clean_install --with_children --product ' + product_name2, batch=True) - - if os.path.exists(expected_file_path) and os.path.exists(expected_file_path2): - OK = 'OK' - # pyunit method to compare 2 str - self.assertEqual(OK, 'OK') - - def test_060(self): - # Test the configure command with '--make_flags' option - OK = 'KO' - - appli = 'appli-test' - product_name = 'PRODUCT_GIT' - - sat = Sat() - - sat.prepare(appli + ' --product ' + product_name) - expected_install_dir = src.product.get_product_config(sat.cfg, product_name).install_dir - expected_file_path = os.path.join(expected_install_dir, 'bin/hello') - - sat.clean(appli + ' --build --install --product ' + product_name, batch=True) - sat.compile(appli + ' --make_flags 3 --product ' + product_name) - - if os.path.exists(expected_file_path): - OK = 'OK' - # pyunit method to compare 2 str - self.assertEqual(OK, 'OK') - - def test_070(self): - # Test the configure command with '--show' option - OK = 'KO' - - appli = 'appli-test' - product_name = 'PRODUCT_GIT' - - sat = Sat() - - sat.prepare(appli + ' --product ' + product_name) - expected_install_dir = src.product.get_product_config(sat.cfg, product_name).install_dir - expected_file_path = os.path.join(expected_install_dir, 'bin/hello') - - sat.clean(appli + ' --build --install --product ' + product_name, batch=True) - sat.compile(appli + ' --show --product ' + product_name) - - if not(os.path.exists(expected_file_path)): - OK = 'OK' - # pyunit method to compare 2 str - self.assertEqual(OK, 'OK') - - def test_080(self): - # Test the configure command with '--stop_first_fail' option - OK = 'KO' - - appli = 'appli-test' - - sat = Sat() - - sat.prepare(appli + ' --product PRODUCT_CVS,Python') - expected_install_dir = src.product.get_product_config(sat.cfg, "PRODUCT_CVS").install_dir - - sat.clean(appli + ' --build --install --product PRODUCT_CVS', batch=True) - sat.compile(appli + ' --stop_first_fail --product PRODUCT_CVS,Python') - - if not(os.path.exists(expected_install_dir)): - OK = 'OK' - # pyunit method to compare 2 str - self.assertEqual(OK, 'OK') - - def test_090(self): - # Test the 'sat -h compile' command to get description - - OK = "KO" - - import compile - - if "The compile command constructs the products" in compile.description(): - OK = "OK" - - # pyunit method to compare 2 str - self.assertEqual(OK, "OK") - -# test launch -if __name__ == '__main__': - unittest.main() - pass - diff --git a/test/compilation/test_configure.py b/test/compilation/test_configure.py deleted file mode 100755 index 9d995a2..0000000 --- a/test/compilation/test_configure.py +++ /dev/null @@ -1,110 +0,0 @@ -#!/usr/bin/env python -#-*- coding:utf-8 -*- - -# Copyright (C) 2010-2018 CEA/DEN -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -import os -import sys -import unittest - -import src.product -from src.salomeTools import Sat - -class TestCase(unittest.TestCase): - """Test of the configure command""" - - def setUp(self): - print("setUp") - - def tearDown(self): - print("tearDown") - - def test_010(self): - # Test the configure command with a product in cmake - OK = 'KO' - - appli = 'appli-test' - product_name = 'PRODUCT_GIT' - - sat = Sat() - - sat.prepare(appli + ' --product ' + product_name) - expected_build_dir = src.product.get_product_config(sat.cfg, product_name).build_dir - expected_file_path = os.path.join(expected_build_dir, 'CMakeCache.txt') - - sat.configure(appli + ' --product ' + product_name) - - if os.path.exists(os.path.join(expected_build_dir, expected_file_path)): - OK = 'OK' - # pyunit method to compare 2 str - self.assertEqual(OK, 'OK') - - def test_020(self): - # Test the configure command with a product in autotools - OK = 'KO' - - appli = 'appli-test' - product_name = 'PRODUCT_CVS' - - sat = Sat() - - sat.prepare(appli + ' --product ' + product_name) - expected_build_dir = src.product.get_product_config(sat.cfg, product_name).build_dir - expected_file_path = os.path.join(expected_build_dir, 'config.log') - - sat.configure(appli + ' --product ' + product_name) - - if os.path.exists(os.path.join(expected_build_dir, expected_file_path)): - OK = 'OK' - # pyunit method to compare 2 str - self.assertEqual(OK, 'OK') - - def test_030(self): - # Test the configure command with a product in script mode - OK = 'KO' - - appli = 'appli-test' - product_name = 'Python' - - sat = Sat() - - sat.prepare(appli + ' --product ' + product_name) - expected_build_dir = src.product.get_product_config(sat.cfg, product_name).build_dir - - sat.configure(appli + ' --product ' + product_name) - - if os.path.exists(expected_build_dir): - OK = 'OK' - # pyunit method to compare 2 str - self.assertEqual(OK, 'OK') - - def test_040(self): - # Test the 'sat -h configure' - OK = "KO" - - import configure - - if "The configure command executes in the build directory" in configure.description(): - OK = "OK" - - # pyunit method to compare 2 str - self.assertEqual(OK, "OK") - -# test launch -if __name__ == '__main__': - unittest.main() - pass diff --git a/test/compilation/test_make.py b/test/compilation/test_make.py deleted file mode 100755 index c956965..0000000 --- a/test/compilation/test_make.py +++ /dev/null @@ -1,106 +0,0 @@ -#!/usr/bin/env python -#-*- coding:utf-8 -*- - -# Copyright (C) 2010-2018 CEA/DEN -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -import os -import sys -import unittest - -import src.product -from src.salomeTools import Sat - -class TestCase(unittest.TestCase): - """Test of the make command""" - - def test_010(self): - # Test the configure command without any option - OK = 'KO' - - appli = 'appli-test' - product_name = 'PRODUCT_GIT' - - sat = Sat() - - sat.prepare(appli + ' --product ' + product_name) - expected_build_dir = src.product.get_product_config(sat.cfg, product_name).build_dir - expected_file_path = os.path.join(expected_build_dir, 'hello') - - sat.configure(appli + ' --product ' + product_name) - sat.make(appli + ' --product ' + product_name) - - if os.path.exists(os.path.join(expected_build_dir, expected_file_path)): - OK = 'OK' - # pyunit method to compare 2 str - self.assertEqual(OK, 'OK') - - def test_020(self): - # Test the make command with an option - OK = 'KO' - appli = 'appli-test' - product_name = 'PRODUCT_GIT' - - sat = Sat() - - sat.prepare(appli + ' --product ' + product_name) - expected_build_dir = src.product.get_product_config(sat.cfg, product_name).build_dir - expected_file_path = os.path.join(expected_build_dir, 'hello') - - sat.configure(appli + ' --product ' + product_name) - sat.make(appli + ' --product ' + product_name + ' --option -j3') - - if os.path.exists(os.path.join(expected_build_dir, expected_file_path)): - OK = 'OK' - # pyunit method to compare 2 str - self.assertEqual(OK, 'OK') - - def test_030(self): - # Test the make command with a product in script mode - OK = 'KO' - - appli = 'appli-test' - product_name = 'Python' - - sat = Sat() - - sat.prepare(appli + ' --product ' + product_name) - expected_install_dir = src.product.get_product_config(sat.cfg, product_name).install_dir - expected_file = "bin/python2.7" - - sat.make(appli + ' --product ' + product_name) - - if os.path.exists(os.path.join(expected_install_dir, expected_file)): - OK = 'OK' - # pyunit method to compare 2 str - self.assertEqual(OK, 'OK') - - def test_040(self): - # Test the sat -h make - OK = "KO" - - import make - - if "The make command executes the \"make\" command" in make.description(): - OK = "OK" - - # pyunit method to compare 2 str - self.assertEqual(OK, "OK") - -# test launch -if __name__ == '__main__': - unittest.main() - pass diff --git a/test/compilation/test_makeinstall.py b/test/compilation/test_makeinstall.py deleted file mode 100755 index 62aba79..0000000 --- a/test/compilation/test_makeinstall.py +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/env python -#-*- coding:utf-8 -*- - -# Copyright (C) 2010-2018 CEA/DEN -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -import os -import sys -import unittest - -import src.product -from src.salomeTools import Sat - -class TestMakeinstall(unittest.TestCase): - """Test of the makeinstall command""" - - def test_010(self): - # Test the configure-make-makeinstall command without any option - OK = 'KO' - - appli = 'appli-test' - product_name = 'PRODUCT_GIT' - - sat = Sat() - - sat.prepare(appli + ' --product ' + product_name) - expected_install_dir = src.product.get_product_config(sat.cfg, product_name).install_dir - expected_file_path = os.path.join(expected_install_dir, 'bin/hello') - - sat.configure(appli + ' --product ' + product_name) - - sat.make(appli + ' --product ' + product_name) - - sat.makeinstall(appli + ' --product ' + product_name) - - if os.path.exists(expected_file_path): - OK = 'OK' - # pyunit method to compare 2 str - self.assertEqual(OK, 'OK') - - def test_020(self): - # Test the sat -h make - OK = "KO" - - import makeinstall - - if "The makeinstall command executes the 'make install' command" in makeinstall.description(): - OK = "OK" - - # pyunit method to compare 2 str - self.assertEqual(OK, "OK") - -# test launch -if __name__ == '__main__': - unittest.main() - pass diff --git a/test/config/test_create_user_pyconf.py b/test/config/test_create_user_pyconf.py deleted file mode 100755 index df1c0b0..0000000 --- a/test/config/test_create_user_pyconf.py +++ /dev/null @@ -1,119 +0,0 @@ -#!/usr/bin/env python -#-*- coding:utf-8 -*- - -# Copyright (C) 2010-2018 CEA/DEN -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -import os -import sys -import shutil -import unittest - -from src.salomeTools import Sat - -class TestCase(unittest.TestCase): - """Test create file .pyconf""" - - def test_010(self): - # Test creation of ~/.salomeTools/salomeTools.pyconf - res = "KO" - user_dir = os.path.expanduser(os.path.join('~','.salomeTools')) - user_dir_save = os.path.expanduser(os.path.join('~','.salomeTools_save')) - if os.path.exists(user_dir_save): - shutil.rmtree(user_dir_save) - if os.path.exists(user_dir): - shutil.move(user_dir, user_dir_save) - - # The command to test - sat = Sat('') - sat.config('-v .') - - expected_file = os.path.expanduser(os.path.join('~','.salomeTools', 'salomeTools.pyconf')) - - if os.path.exists(expected_file): - res = "OK" - - shutil.rmtree(user_dir) - shutil.move(user_dir_save, user_dir) - self.assertEqual(res, "OK") - - def test_020(self): - # Test override VARS - OK = "KO" - - # The command to test - sat = Sat("-oVARS.user='user_test'") - sat.config() - - if sat.cfg.VARS.user == 'user_test': - OK = "OK" - self.assertEqual(OK, "OK") - - def test_030(self): - # Test override INTERNAL - OK = "KO" - - # The command to test - sat = Sat("-oINTERNAL.sat_version='V0'") - sat.config() - - if sat.cfg.INTERNAL.sat_version == 'V0': - OK = "OK" - self.assertEqual(OK, "OK") - - """ - def test_040(self): - # Test override SITE - OK = "KO" - - # The command to test - sat = Sat("-oSITE.jobs.config_path='/tmp'") - sat.config() - - if sat.cfg.SITE.jobs.config_path == '/tmp': - OK = "OK" - - self.assertEqual(OK, "OK") - """ - - def test_050(self): - # Test override APPLICATION - OK = "KO" - - # The command to test - sat = Sat("-oAPPLICATION.out_dir='/tmp'") - sat.config('appli-test') - - if sat.cfg.APPLICATION.out_dir == '/tmp': - OK = "OK" - self.assertEqual(OK, "OK") - - def test_060(self): - # Test override PRODUCTS - OK = "KO" - - # The command to test - sat = Sat("-oPRODUCTS.PRODUCT_GIT.default.name='test'") - sat.config('') - - if sat.cfg.PRODUCTS.PRODUCT_GIT.default.name == 'test': - OK = "OK" - self.assertEqual(OK, "OK") - -# test launch -if __name__ == '__main__': - unittest.main() - pass diff --git a/test/config/test_option_copy.py b/test/config/test_option_copy.py deleted file mode 100755 index bb7fe0b..0000000 --- a/test/config/test_option_copy.py +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env python -#-*- coding:utf-8 -*- - -# Copyright (C) 2010-2018 CEA/DEN -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -import os -import sys -import unittest - -from src.salomeTools import Sat - -class TestCase(unittest.TestCase): - """sat config --copy""" - - def test_010(self): - # Test the copy of a pyconf - res = "KO" - appli_to_copy = "appli-test" - - expected_file = os.path.expanduser(os.path.join('~','.salomeTools', 'Applications', 'LOCAL_' + appli_to_copy + '.pyconf')) - if os.path.exists(expected_file): - os.remove(expected_file) - - # The command to test - sat = Sat('') - sat.config('appli-test -c') - - if os.path.exists(expected_file): - res = "OK" - os.remove(expected_file) - self.assertEqual(res, "OK") - -# test launch -if __name__ == '__main__': - unittest.main() - pass diff --git a/test/config/test_option_edit.py b/test/config/test_option_edit.py deleted file mode 100755 index c6674e9..0000000 --- a/test/config/test_option_edit.py +++ /dev/null @@ -1,73 +0,0 @@ -#!/usr/bin/env python -#-*- coding:utf-8 -*- - -# Copyright (C) 2010-2018 CEA/DEN -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -import os -import sys -import threading -import time -import unittest - -from src.salomeTools import Sat -from unittestpy.tools import check_proc_existence_and_kill_multi - -sleep_time = 2 - -class TestCase(unittest.TestCase): - """sat config --edit""" - - def test_010(self): - # Test the launch of the editor when invoking the config -e - OK = "KO" - - sat = Sat("-oUSER.editor='cooledit'") - sat.config() - cmd_config = threading.Thread(target=sat.config, args=('-e',)) - cmd_config.start() - - time.sleep(sleep_time) - - editor = sat.cfg.USER.editor - pid = check_proc_existence_and_kill_multi(editor + ".*" + "salomeTools\.pyconf", 10) - - if pid: - OK = "OK" - self.assertEqual(OK, "OK") - - def test_020(self): - # Test the launch of the editor when invoking the config -e appli-test - OK = "KO" - - sat = Sat("-oUSER.editor='cooledit'") - sat.config() - cmd_config = threading.Thread(target=sat.config, args=('appli-test -e',)) - cmd_config.start() - - time.sleep(sleep_time) - - editor = sat.cfg.USER.editor - pid = check_proc_existence_and_kill_multi(editor + ".*" + "appli-test\.pyconf", 10) - - if pid: - OK = "OK" - self.assertEqual(OK, "OK") - -# test launch -if __name__ == '__main__': - unittest.main() - pass diff --git a/test/config/test_option_value.py b/test/config/test_option_value.py deleted file mode 100755 index 50a7d84..0000000 --- a/test/config/test_option_value.py +++ /dev/null @@ -1,109 +0,0 @@ -#!/usr/bin/env python -#-*- coding:utf-8 -*- - -# Copyright (C) 2010-2018 CEA/DEN -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -import os -import sys -import platform -import unittest - -from src.salomeTools import Sat -from unittestpy.tools import outRedirection - -class TestCase(unittest.TestCase): - """sat config --value""" - - def test_010(self): - # Test the display of the right value of "sat config -v VARS.hostname" - OK = "KO" - - # output redirection - my_out = outRedirection() - - # The command to test - sat = Sat() - sat.config('-v VARS.hostname') - - # stop output redirection - my_out.end_redirection() - - # get results - res = my_out.read_results() - - if platform.node() in res: - OK = "OK" - self.assertEqual(OK, "OK") - - def test_020(self): - # Test the display of the right value of "sat config -l" - OK = "KO" - - # output redirection - my_out = outRedirection() - - # The command to test - sat = Sat() - sat.config('-l') - - # stop output redirection - my_out.end_redirection() - - # get results - res = my_out.read_results() - - # get results - if "ERROR" not in res: - OK = "OK" - self.assertEqual(OK, "OK") - - """ - def test_030(self): - # Test the exception when salomeTools.pyconf has errors - OK = "KO" - - # The command to test - sat = Sat() - sat.config() - - salomeToolspyconfPath = os.path.join(sat.cfg.VARS.srcDir, "internal_config", "salomeTools.pyconf") - salomeToolspyconfPath_save = os.path.join(sat.cfg.VARS.srcDir, "internal_config", "salomeTools.pyconf_save") - if os.path.exists(salomeToolspyconfPath_save): - os.remove(salomeToolspyconfPath_save) - shutil.copyfile(salomeToolspyconfPath, salomeToolspyconfPath_save) - f_read = open(salomeToolspyconfPath, 'r') - text = f_read.read() - f_read.close() - os.remove(salomeToolspyconfPath) - f_write = open(salomeToolspyconfPath, 'w') - f_write.write(text.replace(':', '')) - f_write.close() - - try: - sat.config() - except TypeError: - OK = "OK" - finally: - shutil.copyfile(salomeToolspyconfPath_save, salomeToolspyconfPath) - os.remove(salomeToolspyconfPath_save) - self.assertEqual(OK, "OK") - """ - -# test launch -if __name__ == '__main__': - unittest.main() - pass diff --git a/test/config/test_option_value_2.py b/test/config/test_option_value_2.py deleted file mode 100755 index c11fee1..0000000 --- a/test/config/test_option_value_2.py +++ /dev/null @@ -1,103 +0,0 @@ -#!/usr/bin/env python -#-*- coding:utf-8 -*- - -# Copyright (C) 2010-2018 CEA/DEN -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -import os -import sys -import platform -import unittest - -from src.salomeTools import Sat -from unittestpy.tools import outRedirection - -class TestCase(unittest.TestCase): - """sat config -v VARS.python""" - - def test_010(self): - # Test the display of the right value of 'sat config -v VARS.python' - OK = 'KO' - - # output redirection - my_out = outRedirection() - - # The command to test - sat = Sat('') - sat.config('-v VARS.python') - - # stop output redirection - my_out.end_redirection() - - # get results - res = my_out.read_results() - - - if platform.python_version() in res: - OK = 'OK' - self.assertEqual(OK, 'OK') - - def test_020(self): - # Test the display of the right value of 'sat config -s' - OK = 'KO' - - # output redirection - my_out = outRedirection() - - # The command to test - sat = Sat('') - sat.config('-s') - - # stop output redirection - my_out.end_redirection() - - # get results - res = my_out.read_results() - - - if 'INTERNAL' in res: - OK = 'OK' - self.assertEqual(OK, 'OK') - - def test_030(self): - # Test the display of the right value of 'sat config --info' - application = 'appli-test' - product = 'PRODUCT_DEV' - - OK = 'KO' - - # output redirection - my_out = outRedirection() - - # The command to test - sat = Sat('') - sat.config(application + ' --info ' + product) - - # stop output redirection - my_out.end_redirection() - - # get results - res = my_out.read_results() - - - if 'compilation method = cmake' in res: - OK = 'OK' - self.assertEqual(OK, 'OK') - -# test launch -if __name__ == '__main__': - unittest.main() - pass diff --git a/test/config_0_3_9/LICENSE b/test/config_0_3_9/LICENSE new file mode 100644 index 0000000..98773c8 --- /dev/null +++ b/test/config_0_3_9/LICENSE @@ -0,0 +1,16 @@ +Copyright (C) 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. diff --git a/test/config_0_3_9/PKG-INFO b/test/config_0_3_9/PKG-INFO new file mode 100644 index 0000000..69ba705 --- /dev/null +++ b/test/config_0_3_9/PKG-INFO @@ -0,0 +1,16 @@ +Metadata-Version: 1.0 +Name: config +Version: 0.3.9 +Summary: A hierarchical, easy-to-use, powerful configuration module for Python +Home-page: http://www.red-dove.com/python_config.html +Author: Vinay Sajip +Author-email: vinay_sajip@red-dove.com +License: Copyright (C) 2004-2010 by Vinay Sajip. All Rights Reserved. See LICENSE for license. +Description: This module allows a hierarchical configuration scheme with support for mappings + and sequences, cross-references between one part of the configuration and + another, the ability to flexibly access real Python objects without full-blown + eval(), an include facility, simple expression evaluation and the ability to + change, save, cascade and merge configurations. Interfaces easily with + environment variables and command-line options. It has been developed on python + 2.3 but should work on version 2.2 or greater. +Platform: UNKNOWN diff --git a/test/config_0_3_9/README.txt b/test/config_0_3_9/README.txt new file mode 100644 index 0000000..0c20eab --- /dev/null +++ b/test/config_0_3_9/README.txt @@ -0,0 +1,84 @@ +This module is intended to provide configuration functionality for Python +programs. + +Change History +-------------- + +Version Date Description +============================================================================= +0.3.9 11 May 2010 Fixed parsing bug which caused failure for numbers with + exponents. +----------------------------------------------------------------------------- +0.3.8 03 Mar 2010 Fixed parsing bug which caused failure for negative + numbers in sequences. Improved resolution logic. +----------------------------------------------------------------------------- +0.3.7 05 Oct 2007 Added Mapping.__delitem__ (patch by John Drummond). + Mapping.__getattribute__ no longer returns "" when + asked for "__class__" - doing so causes pickle to + crash (reported by Jamila Gunawardena). + Allow negative numbers (reported by Gary Schoep; had + already been fixed but not yet released). +----------------------------------------------------------------------------- +0.3.6 09 Mar 2006 Made classes derive from object (previously they were + old-style classes). + Changed ConfigMerger to use a more flexible merge + strategy. + Multiline strings (using """ or ''') are now supported. + A typo involving raising a ConfigError was fixed. + Patches received with thanks from David Janes & Tim + Desjardins (BlogMatrix) and Erick Tryzelaar. +----------------------------------------------------------------------------- +0.3.5 27 Dec 2004 Added ConfigOutputStream to provide better Unicode + output support. Altered save code to put platform- + dependent newlines for Unicode. +----------------------------------------------------------------------------- +0.3.4 11 Nov 2004 Added ConfigInputStream to provide better Unicode + support. + Added ConfigReader.setStream(). +----------------------------------------------------------------------------- +0.3.3 09 Nov 2004 Renamed config.get() to getByPath(), and likewise for + ConfigList. + Added Mapping.get() to work like dict.get(). + Added logconfig.py and logconfig.cfg to distribution. +----------------------------------------------------------------------------- +0.3.2 04 Nov 2004 Simplified parseMapping(). + Allowed Config.__init__ to accept a string as well as a + stream. If a string is passed in, streamOpener is used + to obtain the stream to be used. +----------------------------------------------------------------------------- +0.3.1 04 Nov 2004 Changed addNamespace/removeNamespace to make name + specification easier. + Refactored save(), added Container.writeToStream and + Container.writeValue() to help with this. +----------------------------------------------------------------------------- +0.3 03 Nov 2004 Added test harness (test_config.py) + Fixed bugs in bracket parsing. + Refactored internal classes. + Added merging functionality. +----------------------------------------------------------------------------- +0.2 01 Nov 2004 Added support for None. + Stream closed in load() and save(). + Added support for changing configuration. + Fixed bugs in identifier parsing and isword(). +----------------------------------------------------------------------------- +0.1 31 Oct 2004 Initial implementation (for community feedback) +----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- +COPYRIGHT +----------------------------------------------------------------------------- +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. diff --git a/test/config_0_3_9/__init__.py b/test/config_0_3_9/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/config_0_3_9/config.py b/test/config_0_3_9/config.py new file mode 100644 index 0000000..94d04c0 --- /dev/null +++ b/test/config_0_3_9/config.py @@ -0,0 +1,1678 @@ +# 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. + +""" +This is a configuration module for Python. + +This module should work under Python versions >= 2.2, and cannot be used with +earlier versions since it uses new-style classes. + +Development and testing has only been carried out (so far) on Python 2.3.4 and +Python 2.4.2. See the test module (test_config.py) included in the +U{distribution} (follow the +download link). + +A simple example - with the example configuration file:: + + messages: + [ + { + stream : `sys.stderr` + message: 'Welcome' + name: 'Harry' + } + { + stream : `sys.stdout` + message: 'Welkom' + name: 'Ruud' + } + { + stream : $messages[0].stream + message: 'Bienvenue' + name: Yves + } + ] + +a program to read the configuration would be:: + + from config import Config + + f = file('simple.cfg') + cfg = Config(f) + for m in cfg.messages: + s = '%s, %s' % (m.message, m.name) + try: + print >> m.stream, s + except IOError, e: + print e + +which, when run, would yield the console output:: + + Welcome, Harry + Welkom, Ruud + Bienvenue, Yves + +See U{this tutorial} for more +information. + +@version: 0.3.9 + +@author: Vinay Sajip + +@copyright: Copyright (C) 2004-2010 Vinay Sajip. All Rights Reserved. + + +@var streamOpener: The default stream opener. This is a factory function which +takes a string (e.g. filename) and returns a stream suitable for reading. If +unable to open the stream, an IOError exception should be thrown. + +The default value of this variable is L{defaultStreamOpener}. For an example +of how it's used, see test_config.py (search for streamOpener). +""" + +__author__ = "Vinay Sajip " +__status__ = "alpha" +__version__ = "0.3.9" +__date__ = "11 May 2010" + +from types import StringType, UnicodeType + +import codecs +import logging +import os +import sys + +WORD = 'a' +NUMBER = '9' +STRING = '"' +EOF = '' +LCURLY = '{' +RCURLY = '}' +LBRACK = '[' +LBRACK2 = 'a[' +RBRACK = ']' +LPAREN = '(' +LPAREN2 = '((' +RPAREN = ')' +DOT = '.' +COMMA = ',' +COLON = ':' +AT = '@' +PLUS = '+' +MINUS = '-' +STAR = '*' +SLASH = '/' +MOD = '%' +BACKTICK = '`' +DOLLAR = '$' +TRUE = 'True' +FALSE = 'False' +NONE = 'None' + +WORDCHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_" + +if sys.platform == 'win32': + NEWLINE = '\r\n' +elif os.name == 'mac': + NEWLINE = '\r' +else: + NEWLINE = '\n' + +try: + import encodings.utf_32 + has_utf32 = True +except: + has_utf32 = False + +try: + from logging.handlers import NullHandler +except ImportError: + class NullHandler(logging.Handler): + def emit(self, record): + pass + +logger = logging.getLogger(__name__) +if not logger.handlers: + logger.addHandler(NullHandler()) + +class ConfigInputStream(object): + """ + An input stream which can read either ANSI files with default encoding + or Unicode files with BOMs. + + Handles UTF-8, UTF-16LE, UTF-16BE. Could handle UTF-32 if Python had + built-in support. + """ + def __init__(self, stream): + """ + Initialize an instance. + + @param stream: The underlying stream to be read. Should be seekable. + @type stream: A stream (file-like object). + """ + encoding = None + signature = stream.read(4) + used = -1 + if has_utf32: + if signature == codecs.BOM_UTF32_LE: + encoding = 'utf-32le' + elif signature == codecs.BOM_UTF32_BE: + encoding = 'utf-32be' + if encoding is None: + if signature[:3] == codecs.BOM_UTF8: + used = 3 + encoding = 'utf-8' + elif signature[:2] == codecs.BOM_UTF16_LE: + used = 2 + encoding = 'utf-16le' + elif signature[:2] == codecs.BOM_UTF16_BE: + used = 2 + encoding = 'utf-16be' + else: + used = 0 + if used >= 0: + stream.seek(used) + if encoding: + reader = codecs.getreader(encoding) + stream = reader(stream) + self.stream = stream + self.encoding = encoding + + def read(self, size): + if (size == 0) or (self.encoding is None): + rv = self.stream.read(size) + else: + rv = u'' + while size > 0: + rv += self.stream.read(1) + size -= 1 + return rv + + def close(self): + self.stream.close() + + def readline(self): + if self.encoding is None: + line = '' + else: + line = u'' + while True: + c = self.stream.read(1) + if c: + line += c + if c == '\n': + break + return line + +class ConfigOutputStream(object): + """ + An output stream which can write either ANSI files with default encoding + or Unicode files with BOMs. + + Handles UTF-8, UTF-16LE, UTF-16BE. Could handle UTF-32 if Python had + built-in support. + """ + + def __init__(self, stream, encoding=None): + """ + Initialize an instance. + + @param stream: The underlying stream to be written. + @type stream: A stream (file-like object). + @param encoding: The desired encoding. + @type encoding: str + """ + if encoding is not None: + encoding = str(encoding).lower() + self.encoding = encoding + if encoding == "utf-8": + stream.write(codecs.BOM_UTF8) + elif encoding == "utf-16be": + stream.write(codecs.BOM_UTF16_BE) + elif encoding == "utf-16le": + stream.write(codecs.BOM_UTF16_LE) + elif encoding == "utf-32be": + stream.write(codecs.BOM_UTF32_BE) + elif encoding == "utf-32le": + stream.write(codecs.BOM_UTF32_LE) + + if encoding is not None: + writer = codecs.getwriter(encoding) + stream = writer(stream) + self.stream = stream + + def write(self, data): + self.stream.write(data) + + def flush(self): + self.stream.flush() + + def close(self): + self.stream.close() + +def defaultStreamOpener(name): + """ + This function returns a read-only stream, given its name. The name passed + in should correspond to an existing stream, otherwise an exception will be + raised. + + This is the default value of L{streamOpener}; assign your own callable to + streamOpener to return streams based on names. For example, you could use + urllib2.urlopen(). + + @param name: The name of a stream, most commonly a file name. + @type name: str + @return: A stream with the specified name. + @rtype: A read-only stream (file-like object) + """ + return ConfigInputStream(file(name, 'rb')) + +streamOpener = None + +class ConfigError(Exception): + """ + This is the base class of exceptions raised by this module. + """ + pass + +class ConfigFormatError(ConfigError): + """ + This is the base class of exceptions raised due to syntax errors in + configurations. + """ + pass + +class ConfigResolutionError(ConfigError): + """ + This is the base class of exceptions raised due to semantic errors in + configurations. + """ + pass + +def isWord(s): + """ + See if a passed-in value is an identifier. If the value passed in is not a + string, False is returned. An identifier consists of alphanumerics or + underscore characters. + + Examples:: + + isWord('a word') ->False + isWord('award') -> True + isWord(9) -> False + isWord('a_b_c_') ->True + + @note: isWord('9abc') will return True - not exactly correct, but adequate + for the way it's used here. + + @param s: The name to be tested + @type s: any + @return: True if a word, else False + @rtype: bool + """ + if type(s) != type(''): + return False + s = s.replace('_', '') + return s.isalnum() + +def makePath(prefix, suffix): + """ + Make a path from a prefix and suffix. + + Examples:: + + makePath('', 'suffix') -> 'suffix' + makePath('prefix', 'suffix') -> 'prefix.suffix' + makePath('prefix', '[1]') -> 'prefix[1]' + + @param prefix: The prefix to use. If it evaluates as false, the suffix + is returned. + @type prefix: str + @param suffix: The suffix to use. It is either an identifier or an + index in brackets. + @type suffix: str + @return: The path concatenation of prefix and suffix, with a + dot if the suffix is not a bracketed index. + @rtype: str + + """ + if not prefix: + rv = suffix + elif suffix[0] == '[': + rv = prefix + suffix + else: + rv = prefix + '.' + suffix + return rv + + +class Container(object): + """ + This internal class is the base class for mappings and sequences. + + @ivar path: A string which describes how to get + to this instance from the root of the hierarchy. + + Example:: + + a.list.of[1].or['more'].elements + """ + def __init__(self, parent): + """ + Initialize an instance. + + @param parent: The parent of this instance in the hierarchy. + @type parent: A L{Container} instance. + """ + object.__setattr__(self, 'parent', parent) + + def setPath(self, path): + """ + Set the path for this instance. + @param path: The path - a string which describes how to get + to this instance from the root of the hierarchy. + @type path: str + """ + object.__setattr__(self, 'path', path) + + def evaluate(self, item): + """ + Evaluate items which are instances of L{Reference} or L{Expression}. + + L{Reference} instances are evaluated using L{Reference.resolve}, + and L{Expression} instances are evaluated using + L{Expression.evaluate}. + + @param item: The item to be evaluated. + @type item: any + @return: If the item is an instance of L{Reference} or L{Expression}, + the evaluated value is returned, otherwise the item is returned + unchanged. + """ + if isinstance(item, Reference): + item = item.resolve(self) + elif isinstance(item, Expression): + item = item.evaluate(self) + return item + + def writeToStream(self, stream, indent, container): + """ + Write this instance to a stream at the specified indentation level. + + Should be redefined in subclasses. + + @param stream: The stream to write to + @type stream: A writable stream (file-like object) + @param indent: The indentation level + @type indent: int + @param container: The container of this instance + @type container: L{Container} + @raise NotImplementedError: If a subclass does not override this + """ + raise NotImplementedError + + def writeValue(self, value, stream, indent): + if isinstance(self, Mapping): + indstr = ' ' + else: + indstr = indent * ' ' + if isinstance(value, Reference) or isinstance(value, Expression): + stream.write('%s%r%s' % (indstr, value, NEWLINE)) + else: + if (type(value) is StringType): # and not isWord(value): + value = repr(value) + stream.write('%s%s%s' % (indstr, value, NEWLINE)) + +class Mapping(Container): + """ + This internal class implements key-value mappings in configurations. + """ + + def __init__(self, parent=None): + """ + Initialize an instance. + + @param parent: The parent of this instance in the hierarchy. + @type parent: A L{Container} instance. + """ + Container.__init__(self, parent) + object.__setattr__(self, 'path', '') + object.__setattr__(self, 'data', {}) + object.__setattr__(self, 'order', []) # to preserve ordering + object.__setattr__(self, 'comments', {}) + + def __delitem__(self, key): + """ + Remove an item + """ + data = object.__getattribute__(self, 'data') + if key not in data: + raise AttributeError(key) + order = object.__getattribute__(self, 'order') + comments = object.__getattribute__(self, 'comments') + del data[key] + order.remove(key) + del comments[key] + + def __getitem__(self, key): + data = object.__getattribute__(self, 'data') + if key not in data: + raise AttributeError(key) + rv = data[key] + return self.evaluate(rv) + + __getattr__ = __getitem__ + + def __getattribute__(self, name): + if name == "__dict__": + return {} + if name in ["__methods__", "__members__"]: + return [] + #if name == "__class__": + # return '' + data = object.__getattribute__(self, "data") + useData = data.has_key(name) + if useData: + rv = getattr(data, name) + else: + rv = object.__getattribute__(self, name) + if rv is None: + raise AttributeError(name) + return rv + + def iteritems(self): + for key in self.keys(): + yield(key, self[key]) + raise StopIteration + + def __contains__(self, item): + order = object.__getattribute__(self, 'order') + return item in order + + def addMapping(self, key, value, comment, setting=False): + """ + Add a key-value mapping with a comment. + + @param key: The key for the mapping. + @type key: str + @param value: The value for the mapping. + @type value: any + @param comment: The comment for the key (can be None). + @type comment: str + @param setting: If True, ignore clashes. This is set + to true when called from L{__setattr__}. + @raise ConfigFormatError: If an existing key is seen + again and setting is False. + """ + data = object.__getattribute__(self, 'data') + order = object.__getattribute__(self, 'order') + comments = object.__getattribute__(self, 'comments') + + data[key] = value + if key not in order: + order.append(key) + elif not setting: + raise ConfigFormatError("repeated key: %s" % key) + comments[key] = comment + + def __setattr__(self, name, value): + self.addMapping(name, value, None, True) + + __setitem__ = __setattr__ + + def keys(self): + """ + Return the keys in a similar way to a dictionary. + """ + return object.__getattribute__(self, 'order') + + def get(self, key, default=None): + """ + Allows a dictionary-style get operation. + """ + if key in self: + return self[key] + return default + + def __str__(self): + return str(object.__getattribute__(self, 'data')) + + def __repr__(self): + return repr(object.__getattribute__(self, 'data')) + + def __len__(self): + return len(object.__getattribute__(self, 'order')) + + def __iter__(self): + return self.iterkeys() + + def iterkeys(self): + order = object.__getattribute__(self, 'order') + return order.__iter__() + + def writeToStream(self, stream, indent, container): + """ + Write this instance to a stream at the specified indentation level. + + Should be redefined in subclasses. + + @param stream: The stream to write to + @type stream: A writable stream (file-like object) + @param indent: The indentation level + @type indent: int + @param container: The container of this instance + @type container: L{Container} + """ + indstr = indent * ' ' + if len(self) == 0: + stream.write(' { }%s' % NEWLINE) + else: + if isinstance(container, Mapping): + stream.write(NEWLINE) + stream.write('%s{%s' % (indstr, NEWLINE)) + self.save(stream, indent + 1) + stream.write('%s}%s' % (indstr, NEWLINE)) + + def save(self, stream, indent=0): + """ + Save this configuration to the specified stream. + @param stream: A stream to which the configuration is written. + @type stream: A write-only stream (file-like object). + @param indent: The indentation level for the output. + @type indent: int + """ + indstr = indent * ' ' + order = object.__getattribute__(self, 'order') + data = object.__getattribute__(self, 'data') + maxlen = 0 # max(map(lambda x: len(x), order)) + for key in order: + comment = self.comments[key] + if isWord(key): + skey = key + else: + skey = repr(key) + if comment: + stream.write('%s#%s' % (indstr, comment)) + stream.write('%s%-*s :' % (indstr, maxlen, skey)) + value = data[key] + if isinstance(value, Container): + value.writeToStream(stream, indent, self) + else: + self.writeValue(value, stream, indent) + +class Config(Mapping): + """ + This class represents a configuration, and is the only one which clients + need to interface to, under normal circumstances. + """ + + class Namespace(object): + """ + This internal class is used for implementing default namespaces. + + An instance acts as a namespace. + """ + def __init__(self): + self.sys = sys + self.os = os + + def __repr__(self): + return "" % ','.join(self.__dict__.keys()) + + def __init__(self, streamOrFile=None, parent=None): + """ + Initializes an instance. + + @param streamOrFile: If specified, causes this instance to be loaded + from the stream (by calling L{load}). If a string is provided, it is + passed to L{streamOpener} to open a stream. Otherwise, the passed + value is assumed to be a stream and used as is. + @type streamOrFile: A readable stream (file-like object) or a name. + @param parent: If specified, this becomes the parent of this instance + in the configuration hierarchy. + @type parent: a L{Container} instance. + """ + Mapping.__init__(self, parent) + object.__setattr__(self, 'reader', ConfigReader(self)) + object.__setattr__(self, 'namespaces', [Config.Namespace()]) + object.__setattr__(self, 'resolving', set()) + if streamOrFile is not None: + if isinstance(streamOrFile, StringType) or isinstance(streamOrFile, UnicodeType): + global streamOpener + if streamOpener is None: + streamOpener = defaultStreamOpener + streamOrFile = streamOpener(streamOrFile) + load = object.__getattribute__(self, "load") + load(streamOrFile) + + def load(self, stream): + """ + Load the configuration from the specified stream. Multiple streams can + be used to populate the same instance, as long as there are no + clashing keys. The stream is closed. + @param stream: A stream from which the configuration is read. + @type stream: A read-only stream (file-like object). + @raise ConfigError: if keys in the loaded configuration clash with + existing keys. + @raise ConfigFormatError: if there is a syntax error in the stream. + """ + reader = object.__getattribute__(self, 'reader') + #object.__setattr__(self, 'root', reader.load(stream)) + reader.load(stream) + stream.close() + + def addNamespace(self, ns, name=None): + """ + Add a namespace to this configuration which can be used to evaluate + (resolve) dotted-identifier expressions. + @param ns: The namespace to be added. + @type ns: A module or other namespace suitable for passing as an + argument to vars(). + @param name: A name for the namespace, which, if specified, provides + an additional level of indirection. + @type name: str + """ + namespaces = object.__getattribute__(self, 'namespaces') + if name is None: + namespaces.append(ns) + else: + setattr(namespaces[0], name, ns) + + def removeNamespace(self, ns, name=None): + """ + Remove a namespace added with L{addNamespace}. + @param ns: The namespace to be removed. + @param name: The name which was specified when L{addNamespace} was + called. + @type name: str + """ + namespaces = object.__getattribute__(self, 'namespaces') + if name is None: + namespaces.remove(ns) + else: + delattr(namespaces[0], name) + + def save(self, stream, indent=0): + """ + Save this configuration to the specified stream. The stream is + closed if this is the top-level configuration in the hierarchy. + L{Mapping.save} is called to do all the work. + @param stream: A stream to which the configuration is written. + @type stream: A write-only stream (file-like object). + @param indent: The indentation level for the output. + @type indent: int + """ + Mapping.save(self, stream, indent) + if indent == 0: + stream.close() + + def getByPath(self, path): + """ + Obtain a value in the configuration via its path. + @param path: The path of the required value + @type path: str + @return the value at the specified path. + @rtype: any + @raise ConfigError: If the path is invalid + """ + s = 'self.' + path + try: + return eval(s) + except Exception, e: + raise ConfigError(str(e)) + +class Sequence(Container): + """ + This internal class implements a value which is a sequence of other values. + """ + class SeqIter(object): + """ + This internal class implements an iterator for a L{Sequence} instance. + """ + def __init__(self, seq): + self.seq = seq + self.limit = len(object.__getattribute__(seq, 'data')) + self.index = 0 + + def __iter__(self): + return self + + def next(self): + if self.index >= self.limit: + raise StopIteration + rv = self.seq[self.index] + self.index += 1 + return rv + + def __init__(self, parent=None): + """ + Initialize an instance. + + @param parent: The parent of this instance in the hierarchy. + @type parent: A L{Container} instance. + """ + Container.__init__(self, parent) + object.__setattr__(self, 'data', []) + object.__setattr__(self, 'comments', []) + + def append(self, item, comment): + """ + Add an item to the sequence. + + @param item: The item to add. + @type item: any + @param comment: A comment for the item. + @type comment: str + """ + data = object.__getattribute__(self, 'data') + comments = object.__getattribute__(self, 'comments') + data.append(item) + comments.append(comment) + + def __getitem__(self, index): + data = object.__getattribute__(self, 'data') + try: + rv = data[index] + except (IndexError, KeyError, TypeError): + raise ConfigResolutionError('%r is not a valid index for %r' % (index, object.__getattribute__(self, 'path'))) + if not isinstance(rv, list): + rv = self.evaluate(rv) + else: + # deal with a slice + result = [] + for a in rv: + result.append(self.evaluate(a)) + rv = result + return rv + + def __iter__(self): + return Sequence.SeqIter(self) + + def __repr__(self): + return repr(object.__getattribute__(self, 'data')) + + def __str__(self): + return str(self[:]) # using the slice evaluates the contents + + def __len__(self): + return len(object.__getattribute__(self, 'data')) + + def writeToStream(self, stream, indent, container): + """ + Write this instance to a stream at the specified indentation level. + + Should be redefined in subclasses. + + @param stream: The stream to write to + @type stream: A writable stream (file-like object) + @param indent: The indentation level + @type indent: int + @param container: The container of this instance + @type container: L{Container} + """ + indstr = indent * ' ' + if len(self) == 0: + stream.write(' [ ]%s' % NEWLINE) + else: + if isinstance(container, Mapping): + stream.write(NEWLINE) + stream.write('%s[%s' % (indstr, NEWLINE)) + self.save(stream, indent + 1) + stream.write('%s]%s' % (indstr, NEWLINE)) + + def save(self, stream, indent): + """ + Save this instance to the specified stream. + @param stream: A stream to which the configuration is written. + @type stream: A write-only stream (file-like object). + @param indent: The indentation level for the output, > 0 + @type indent: int + """ + if indent == 0: + raise ConfigError("sequence cannot be saved as a top-level item") + data = object.__getattribute__(self, 'data') + comments = object.__getattribute__(self, 'comments') + indstr = indent * ' ' + for i in xrange(0, len(data)): + value = data[i] + comment = comments[i] + if comment: + stream.write('%s#%s' % (indstr, comment)) + if isinstance(value, Container): + value.writeToStream(stream, indent, self) + else: + self.writeValue(value, stream, indent) + +class Reference(object): + """ + This internal class implements a value which is a reference to another value. + """ + def __init__(self, config, type, ident): + """ + Initialize an instance. + + @param config: The configuration which contains this reference. + @type config: A L{Config} instance. + @param type: The type of reference. + @type type: BACKTICK or DOLLAR + @param ident: The identifier which starts the reference. + @type ident: str + """ + self.config = config + self.type = type + self.elements = [ident] + + def addElement(self, type, ident): + """ + Add an element to the reference. + + @param type: The type of reference. + @type type: BACKTICK or DOLLAR + @param ident: The identifier which continues the reference. + @type ident: str + """ + self.elements.append((type, ident)) + + def findConfig(self, container): + """ + Find the closest enclosing configuration to the specified container. + + @param container: The container to start from. + @type container: L{Container} + @return: The closest enclosing configuration, or None. + @rtype: L{Config} + """ + while (container is not None) and not isinstance(container, Config): + container = object.__getattribute__(container, 'parent') + return container + + def resolve(self, container): + """ + Resolve this instance in the context of a container. + + @param container: The container to resolve from. + @type container: L{Container} + @return: The resolved value. + @rtype: any + @raise ConfigResolutionError: If resolution fails. + """ + rv = None + path = object.__getattribute__(container, 'path') + current = self.findConfig(container) + while current is not None: + if self.type == BACKTICK: + namespaces = object.__getattribute__(current, 'namespaces') + found = False + s = str(self)[1:-1] + for ns in namespaces: + try: + try: + rv = eval(s, vars(ns)) + except TypeError: #Python 2.7 - vars is a dictproxy + rv = eval(s, {}, vars(ns)) + found = True + break + except: + logger.debug("unable to resolve %r in %r", s, ns) + pass + if found: + break + else: + firstkey = self.elements[0] + if firstkey in current.resolving: + current.resolving.remove(firstkey) + raise ConfigResolutionError("Circular reference: %r" % firstkey) + current.resolving.add(firstkey) + key = firstkey + try: + rv = current[key] + for item in self.elements[1:]: + key = item[1] + rv = rv[key] + current.resolving.remove(firstkey) + break + except ConfigResolutionError: + raise + except: + logger.debug("Unable to resolve %r: %s", key, sys.exc_info()[1]) + rv = None + pass + current.resolving.discard(firstkey) + current = self.findConfig(object.__getattribute__(current, 'parent')) + if current is None: + raise ConfigResolutionError("unable to evaluate %r in the configuration %s" % (self, path)) + return rv + + def __str__(self): + s = self.elements[0] + for tt, tv in self.elements[1:]: + if tt == DOT: + s += '.%s' % tv + else: + s += '[%r]' % tv + if self.type == BACKTICK: + return BACKTICK + s + BACKTICK + else: + return DOLLAR + s + + def __repr__(self): + return self.__str__() + +class Expression(object): + """ + This internal class implements a value which is obtained by evaluating an expression. + """ + def __init__(self, op, lhs, rhs): + """ + Initialize an instance. + + @param op: the operation expressed in the expression. + @type op: PLUS, MINUS, STAR, SLASH, MOD + @param lhs: the left-hand-side operand of the expression. + @type lhs: any Expression or primary value. + @param rhs: the right-hand-side operand of the expression. + @type rhs: any Expression or primary value. + """ + self.op = op + self.lhs = lhs + self.rhs = rhs + + def __str__(self): + return '%r %s %r' % (self.lhs, self.op, self.rhs) + + def __repr__(self): + return self.__str__() + + def evaluate(self, container): + """ + Evaluate this instance in the context of a container. + + @param container: The container to evaluate in from. + @type container: L{Container} + @return: The evaluated value. + @rtype: any + @raise ConfigResolutionError: If evaluation fails. + @raise ZeroDivideError: If division by zero occurs. + @raise TypeError: If the operation is invalid, e.g. + subtracting one string from another. + """ + lhs = self.lhs + if isinstance(lhs, Reference): + lhs = lhs.resolve(container) + elif isinstance(lhs, Expression): + lhs = lhs.evaluate(container) + rhs = self.rhs + if isinstance(rhs, Reference): + rhs = rhs.resolve(container) + elif isinstance(rhs, Expression): + rhs = rhs.evaluate(container) + op = self.op + if op == PLUS: + rv = lhs + rhs + elif op == MINUS: + rv = lhs - rhs + elif op == STAR: + rv = lhs * rhs + elif op == SLASH: + rv = lhs / rhs + else: + rv = lhs % rhs + return rv + +class ConfigReader(object): + """ + This internal class implements a parser for configurations. + """ + + def __init__(self, config): + self.filename = None + self.config = config + self.lineno = 0 + self.colno = 0 + self.lastc = None + self.last_token = None + self.commentchars = '#' + self.whitespace = ' \t\r\n' + self.quotes = '\'"' + self.punct = ':-+*/%,.{}[]()@`$' + self.digits = '0123456789' + self.wordchars = '%s' % WORDCHARS # make a copy + self.identchars = self.wordchars + self.digits + self.pbchars = [] + self.pbtokens = [] + self.comment = None + + def location(self): + """ + Return the current location (filename, line, column) in the stream + as a string. + + Used when printing error messages, + + @return: A string representing a location in the stream being read. + @rtype: str + """ + return "%s(%d,%d)" % (self.filename, self.lineno, self.colno) + + def getChar(self): + """ + Get the next char from the stream. Update line and column numbers + appropriately. + + @return: The next character from the stream. + @rtype: str + """ + if self.pbchars: + c = self.pbchars.pop() + else: + c = self.stream.read(1) + self.colno += 1 + if c == '\n': + self.lineno += 1 + self.colno = 1 + return c + + def __repr__(self): + return "" % id(self) + + __str__ = __repr__ + + def getToken(self): + """ + Get a token from the stream. String values are returned in a form + where you need to eval() the returned value to get the actual + string. The return value is (token_type, token_value). + + Multiline string tokenizing is thanks to David Janes (BlogMatrix) + + @return: The next token. + @rtype: A token tuple. + """ + if self.pbtokens: + return self.pbtokens.pop() + stream = self.stream + self.comment = None + token = '' + tt = EOF + while True: + c = self.getChar() + if not c: + break + elif c == '#': + self.comment = stream.readline() + self.lineno += 1 + continue + if c in self.quotes: + token = c + quote = c + tt = STRING + escaped = False + multiline = False + c1 = self.getChar() + if c1 == quote: + c2 = self.getChar() + if c2 == quote: + multiline = True + token += quote + token += quote + else: + self.pbchars.append(c2) + self.pbchars.append(c1) + else: + self.pbchars.append(c1) + while True: + c = self.getChar() + if not c: + break + token += c + if (c == quote) and not escaped: + if not multiline or (len(token) >= 6 and token.endswith(token[:3]) and token[-4] != '\\'): + break + if c == '\\': + escaped = not escaped + else: + escaped = False + if not c: + raise ConfigFormatError('%s: Unterminated quoted string: %r, %r' % (self.location(), token, c)) + break + if c in self.whitespace: + self.lastc = c + continue + elif c in self.punct: + token = c + tt = c + if (self.lastc == ']') or (self.lastc in self.identchars): + if c == '[': + tt = LBRACK2 + elif c == '(': + tt = LPAREN2 + break + elif c in self.digits: + token = c + tt = NUMBER + in_exponent=False + while True: + c = self.getChar() + if not c: + break + if c in self.digits: + token += c + elif (c == '.') and token.find('.') < 0 and not in_exponent: + token += c + elif (c == '-') and token.find('-') < 0 and in_exponent: + token += c + elif (c in 'eE') and token.find('e') < 0 and\ + token.find('E') < 0: + token += c + in_exponent = True + else: + if c and (c not in self.whitespace): + self.pbchars.append(c) + break + break + elif c in self.wordchars: + token = c + tt = WORD + c = self.getChar() + while c and (c in self.identchars): + token += c + c = self.getChar() + if c: # and c not in self.whitespace: + self.pbchars.append(c) + if token == "True": + tt = TRUE + elif token == "False": + tt = FALSE + elif token == "None": + tt = NONE + break + else: + raise ConfigFormatError('%s: Unexpected character: %r' % (self.location(), c)) + if token: + self.lastc = token[-1] + else: + self.lastc = None + self.last_token = tt + return (tt, token) + + def load(self, stream, parent=None, suffix=None): + """ + Load the configuration from the specified stream. + + @param stream: A stream from which to load the configuration. + @type stream: A stream (file-like object). + @param parent: The parent of the configuration (to which this reader + belongs) in the hierarchy. Specified when the configuration is + included in another one. + @type parent: A L{Container} instance. + @param suffix: The suffix of this configuration in the parent + configuration. Should be specified whenever the parent is not None. + @raise ConfigError: If parent is specified but suffix is not. + @raise ConfigFormatError: If there are syntax errors in the stream. + """ + if parent is not None: + if suffix is None: + raise ConfigError("internal error: load called with parent but no suffix") + self.config.setPath(makePath(object.__getattribute__(parent, 'path'), suffix)) + self.setStream(stream) + self.token = self.getToken() + self.parseMappingBody(self.config) + if self.token[0] != EOF: + raise ConfigFormatError('%s: expecting EOF, found %r' % (self.location(), self.token[1])) + + def setStream(self, stream): + """ + Set the stream to the specified value, and prepare to read from it. + + @param stream: A stream from which to load the configuration. + @type stream: A stream (file-like object). + """ + self.stream = stream + if hasattr(stream, 'name'): + filename = stream.name + else: + filename = '?' + self.filename = filename + self.lineno = 1 + self.colno = 1 + + def match(self, t): + """ + Ensure that the current token type matches the specified value, and + advance to the next token. + + @param t: The token type to match. + @type t: A valid token type. + @return: The token which was last read from the stream before this + function is called. + @rtype: a token tuple - see L{getToken}. + @raise ConfigFormatError: If the token does not match what's expected. + """ + if self.token[0] != t: + raise ConfigFormatError("%s: expecting %s, found %r" % (self.location(), t, self.token[1])) + rv = self.token + self.token = self.getToken() + return rv + + def parseMappingBody(self, parent): + """ + Parse the internals of a mapping, and add entries to the provided + L{Mapping}. + + @param parent: The mapping to add entries to. + @type parent: A L{Mapping} instance. + """ + while self.token[0] in [WORD, STRING]: + self.parseKeyValuePair(parent) + + def parseKeyValuePair(self, parent): + """ + Parse a key-value pair, and add it to the provided L{Mapping}. + + @param parent: The mapping to add entries to. + @type parent: A L{Mapping} instance. + @raise ConfigFormatError: if a syntax error is found. + """ + comment = self.comment + tt, tv = self.token + if tt == WORD: + key = tv + suffix = tv + elif tt == STRING: + key = eval(tv) + suffix = '[%s]' % tv + else: + msg = "%s: expecting word or string, found %r" + raise ConfigFormatError(msg % (self.location(), tv)) + self.token = self.getToken() + # for now, we allow key on its own as a short form of key : True + if self.token[0] == COLON: + self.token = self.getToken() + value = self.parseValue(parent, suffix) + else: + value = True + try: + parent.addMapping(key, value, comment) + except Exception, e: + raise ConfigFormatError("%s: %s, %r" % (self.location(), e, + self.token[1])) + tt = self.token[0] + if tt not in [EOF, WORD, STRING, RCURLY, COMMA]: + msg = "%s: expecting one of EOF, WORD, STRING,\ +RCURLY, COMMA, found %r" + raise ConfigFormatError(msg % (self.location(), self.token[1])) + if tt == COMMA: + self.token = self.getToken() + + def parseValue(self, parent, suffix): + """ + Parse a value. + + @param parent: The container to which the value will be added. + @type parent: A L{Container} instance. + @param suffix: The suffix for the value. + @type suffix: str + @return: The value + @rtype: any + @raise ConfigFormatError: if a syntax error is found. + """ + tt = self.token[0] + if tt in [STRING, WORD, NUMBER, LPAREN, DOLLAR, + TRUE, FALSE, NONE, BACKTICK, MINUS]: + rv = self.parseScalar() + elif tt == LBRACK: + rv = self.parseSequence(parent, suffix) + elif tt in [LCURLY, AT]: + rv = self.parseMapping(parent, suffix) + else: + raise ConfigFormatError("%s: unexpected input: %r" % + (self.location(), self.token[1])) + return rv + + def parseSequence(self, parent, suffix): + """ + Parse a sequence. + + @param parent: The container to which the sequence will be added. + @type parent: A L{Container} instance. + @param suffix: The suffix for the value. + @type suffix: str + @return: a L{Sequence} instance representing the sequence. + @rtype: L{Sequence} + @raise ConfigFormatError: if a syntax error is found. + """ + rv = Sequence(parent) + rv.setPath(makePath(object.__getattribute__(parent, 'path'), suffix)) + self.match(LBRACK) + comment = self.comment + tt = self.token[0] + while tt in [STRING, WORD, NUMBER, LCURLY, LBRACK, LPAREN, DOLLAR, + TRUE, FALSE, NONE, BACKTICK, MINUS]: + suffix = '[%d]' % len(rv) + value = self.parseValue(parent, suffix) + rv.append(value, comment) + tt = self.token[0] + comment = self.comment + if tt == COMMA: + self.match(COMMA) + tt = self.token[0] + comment = self.comment + continue + self.match(RBRACK) + return rv + + def parseMapping(self, parent, suffix): + """ + Parse a mapping. + + @param parent: The container to which the mapping will be added. + @type parent: A L{Container} instance. + @param suffix: The suffix for the value. + @type suffix: str + @return: a L{Mapping} instance representing the mapping. + @rtype: L{Mapping} + @raise ConfigFormatError: if a syntax error is found. + """ + if self.token[0] == LCURLY: + self.match(LCURLY) + rv = Mapping(parent) + rv.setPath( + makePath(object.__getattribute__(parent, 'path'), suffix)) + self.parseMappingBody(rv) + self.match(RCURLY) + else: + self.match(AT) + tt, fn = self.match(STRING) + rv = Config(eval(fn), parent) + return rv + + def parseScalar(self): + """ + Parse a scalar - a terminal value such as a string or number, or + an L{Expression} or L{Reference}. + + @return: the parsed scalar + @rtype: any scalar + @raise ConfigFormatError: if a syntax error is found. + """ + lhs = self.parseTerm() + tt = self.token[0] + while tt in [PLUS, MINUS]: + self.match(tt) + rhs = self.parseTerm() + lhs = Expression(tt, lhs, rhs) + tt = self.token[0] + return lhs + + def parseTerm(self): + """ + Parse a term in an additive expression (a + b, a - b) + + @return: the parsed term + @rtype: any scalar + @raise ConfigFormatError: if a syntax error is found. + """ + lhs = self.parseFactor() + tt = self.token[0] + while tt in [STAR, SLASH, MOD]: + self.match(tt) + rhs = self.parseFactor() + lhs = Expression(tt, lhs, rhs) + tt = self.token[0] + return lhs + + def parseFactor(self): + """ + Parse a factor in an multiplicative expression (a * b, a / b, a % b) + + @return: the parsed factor + @rtype: any scalar + @raise ConfigFormatError: if a syntax error is found. + """ + tt = self.token[0] + if tt in [NUMBER, WORD, STRING, TRUE, FALSE, NONE]: + rv = self.token[1] + if tt != WORD: + rv = eval(rv) + self.match(tt) + elif tt == LPAREN: + self.match(LPAREN) + rv = self.parseScalar() + self.match(RPAREN) + elif tt == DOLLAR: + self.match(DOLLAR) + rv = self.parseReference(DOLLAR) + elif tt == BACKTICK: + self.match(BACKTICK) + rv = self.parseReference(BACKTICK) + self.match(BACKTICK) + elif tt == MINUS: + self.match(MINUS) + rv = -self.parseScalar() + else: + raise ConfigFormatError("%s: unexpected input: %r" % + (self.location(), self.token[1])) + return rv + + def parseReference(self, type): + """ + Parse a reference. + + @return: the parsed reference + @rtype: L{Reference} + @raise ConfigFormatError: if a syntax error is found. + """ + word = self.match(WORD) + rv = Reference(self.config, type, word[1]) + while self.token[0] in [DOT, LBRACK2]: + self.parseSuffix(rv) + return rv + + def parseSuffix(self, ref): + """ + Parse a reference suffix. + + @param ref: The reference of which this suffix is a part. + @type ref: L{Reference}. + @raise ConfigFormatError: if a syntax error is found. + """ + tt = self.token[0] + if tt == DOT: + self.match(DOT) + word = self.match(WORD) + ref.addElement(DOT, word[1]) + else: + self.match(LBRACK2) + tt, tv = self.token + if tt not in [NUMBER, STRING]: + raise ConfigFormatError("%s: expected number or string, found %r" % (self.location(), tv)) + self.token = self.getToken() + tv = eval(tv) + self.match(RBRACK) + ref.addElement(LBRACK, tv) + +def defaultMergeResolve(map1, map2, key): + """ + A default resolver for merge conflicts. Returns a string + indicating what action to take to resolve the conflict. + + @param map1: The map being merged into. + @type map1: L{Mapping}. + @param map2: The map being used as the merge operand. + @type map2: L{Mapping}. + @param key: The key in map2 (which also exists in map1). + @type key: str + @return: One of "merge", "append", "mismatch" or "overwrite" + indicating what action should be taken. This should + be appropriate to the objects being merged - e.g. + there is no point returning "merge" if the two objects + are instances of L{Sequence}. + @rtype: str + """ + obj1 = map1[key] + obj2 = map2[key] + if isinstance(obj1, Mapping) and isinstance(obj2, Mapping): + rv = "merge" + elif isinstance(obj1, Sequence) and isinstance(obj2, Sequence): + rv = "append" + else: + rv = "mismatch" + return rv + +def overwriteMergeResolve(map1, map2, key): + """ + An overwriting resolver for merge conflicts. Calls L{defaultMergeResolve}, + but where a "mismatch" is detected, returns "overwrite" instead. + + @param map1: The map being merged into. + @type map1: L{Mapping}. + @param map2: The map being used as the merge operand. + @type map2: L{Mapping}. + @param key: The key in map2 (which also exists in map1). + @type key: str + """ + rv = defaultMergeResolve(map1, map2, key) + if rv == "mismatch": + rv = "overwrite" + return rv + +class ConfigMerger(object): + """ + This class is used for merging two configurations. If a key exists in the + merge operand but not the merge target, then the entry is copied from the + merge operand to the merge target. If a key exists in both configurations, + then a resolver (a callable) is called to decide how to handle the + conflict. + """ + + def __init__(self, resolver=defaultMergeResolve): + """ + Initialise an instance. + + @param resolver: + @type resolver: A callable which takes the argument list + (map1, map2, key) where map1 is the mapping being merged into, + map2 is the merge operand and key is the clashing key. The callable + should return a string indicating how the conflict should be resolved. + For possible return values, see L{defaultMergeResolve}. The default + value preserves the old behaviour + """ + self.resolver = resolver + + def merge(self, merged, mergee): + """ + Merge two configurations. The second configuration is unchanged, + and the first is changed to reflect the results of the merge. + + @param merged: The configuration to merge into. + @type merged: L{Config}. + @param mergee: The configuration to merge. + @type mergee: L{Config}. + """ + self.mergeMapping(merged, mergee) + + def mergeMapping(self, map1, map2): + """ + Merge two mappings recursively. The second mapping is unchanged, + and the first is changed to reflect the results of the merge. + + @param map1: The mapping to merge into. + @type map1: L{Mapping}. + @param map2: The mapping to merge. + @type map2: L{Mapping}. + """ + keys = map1.keys() + for key in map2.keys(): + if key not in keys: + map1[key] = map2[key] + else: + obj1 = map1[key] + obj2 = map2[key] + decision = self.resolver(map1, map2, key) + if decision == "merge": + self.mergeMapping(obj1, obj2) + elif decision == "append": + self.mergeSequence(obj1, obj2) + elif decision == "overwrite": + map1[key] = obj2 + elif decision == "mismatch": + self.handleMismatch(obj1, obj2) + else: + msg = "unable to merge: don't know how to implement %r" + raise ValueError(msg % decision) + + def mergeSequence(self, seq1, seq2): + """ + Merge two sequences. The second sequence is unchanged, + and the first is changed to have the elements of the second + appended to it. + + @param seq1: The sequence to merge into. + @type seq1: L{Sequence}. + @param seq2: The sequence to merge. + @type seq2: L{Sequence}. + """ + data1 = object.__getattribute__(seq1, 'data') + data2 = object.__getattribute__(seq2, 'data') + for obj in data2: + data1.append(obj) + comment1 = object.__getattribute__(seq1, 'comments') + comment2 = object.__getattribute__(seq2, 'comments') + for obj in comment2: + comment1.append(obj) + + def handleMismatch(self, obj1, obj2): + """ + Handle a mismatch between two objects. + + @param obj1: The object to merge into. + @type obj1: any + @param obj2: The object to merge. + @type obj2: any + """ + raise ConfigError("unable to merge %r with %r" % (obj1, obj2)) + +class ConfigList(list): + """ + This class implements an ordered list of configurations and allows you + to try getting the configuration from each entry in turn, returning + the first successfully obtained value. + """ + + def getByPath(self, path): + """ + Obtain a value from the first configuration in the list which defines + it. + + @param path: The path of the value to retrieve. + @type path: str + @return: The value from the earliest configuration in the list which + defines it. + @rtype: any + @raise ConfigError: If no configuration in the list has an entry with + the specified path. + """ + found = False + rv = None + for entry in self: + try: + rv = entry.getByPath(path) + found = True + break + except ConfigError: + pass + if not found: + raise ConfigError("unable to resolve %r" % path) + return rv diff --git a/test/config_0_3_9/logconfig.cfg b/test/config_0_3_9/logconfig.cfg new file mode 100644 index 0000000..2845e3c --- /dev/null +++ b/test/config_0_3_9/logconfig.cfg @@ -0,0 +1,65 @@ +# Configuration file for logconfig.py + +# root logger configuration +root: +{ + level : `DEBUG` + handlers : [$handlers.console, $handlers.file] +} +formatters: { + brief: + { + format: '%(levelname)-8s: %(name)s: %(message)s' + } + precise: + { + format: '%(asctime)s %(name)-15s %(levelname)-8s %(message)s' + } +} +handlers: +{ + console: + { + class : `logconfig.StreamHandler` + config: + { + level : `INFO` + stream : `sys.stdout` + formatter: $formatters.brief + } + } + file: + { + class : `logconfig.RotatingFileHandler` + config: + { + name: 'logconfig.log' + maxBytes: 1024 + backupCount: 3 + formatter: $formatters.precise + } + } + debugfile: + { + class : `logconfig.FileHandler` + config: + { + name: 'logconfig-detail.log' + mode: 'a' + formatter: $formatters.precise + } + } +} +loggers: +{ + area1: + { + level : `ERROR` + handlers: [$handlers.debugfile] + } + area2: + { + level : `CRITICAL` + handlers: [$handlers.debugfile] + } +} \ No newline at end of file diff --git a/test/config_0_3_9/logconfig.py b/test/config_0_3_9/logconfig.py new file mode 100644 index 0000000..44ae1ed --- /dev/null +++ b/test/config_0_3_9/logconfig.py @@ -0,0 +1,138 @@ +#!/usr/bin/env python +# +# Copyright 2001-2004 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. +# +# This file is part of the Python config distribution. See +# http://www.red-dove.com/python_config.html +# +""" +A test for the config module through seeing how to use it to configure logging. + +Copyright (C) 2004 Vinay Sajip. All Rights Reserved. +""" + +from config import Config +from optparse import OptionParser, get_prog_name +from random import choice +import logging +import logging.handlers +import sys + +class Usage(Exception): + pass + +class BaseHandler: + def __init__(self, config): + if 'level' in config: + self.setLevel(config.level) + if 'formatter' in config: + self.setFormatter(config.formatter) + +class StreamHandler(logging.StreamHandler, BaseHandler): + def __init__(self, config): + stream = config.get('stream') + logging.StreamHandler.__init__(self, stream) + BaseHandler.__init__(self, config) + +class RotatingFileHandler(logging.handlers.RotatingFileHandler, BaseHandler): + def __init__(self, config): + name = config.get('name') + if name is None: + raise ValueError('RotatingFileHandler: name not specified') + mode = config.get('mode', 'a') + maxBytes = config.get('maxBytes', 0) + backupCount = config.get('backupCount', 0) + logging.handlers.RotatingFileHandler.__init__(self, name, mode, maxBytes, backupCount) + BaseHandler.__init__(self, config) + +class FileHandler(logging.FileHandler, BaseHandler): + def __init__(self, config): + name = config.get('name') + if name is None: + raise ValueError('FileHandler: name not specified') + mode = config.get('mode', 'a') + logging.FileHandler.__init__(self, name, mode) + BaseHandler.__init__(self, config) + +def configLogger(logger, config): + for handler in logger.handlers: + logger.removeHandler(handler) + if 'level' in config: + logger.setLevel(config.level) + if 'handlers' in config: + for handler in config.handlers: + logger.addHandler(handler) + +def fileConfig(fname, *args, **kwargs): + cfg = Config(fname) + cfg.addNamespace(logging) + cfg.addNamespace(sys.modules[StreamHandler.__module__], 'logconfig') + + for name in cfg.formatters.keys(): + formatterConfig = cfg.formatters[name] + fmt = formatterConfig.get('format') + datefmt = formatterConfig.get('datefmt') + formatter = logging.Formatter(fmt, datefmt) + cfg.formatters[name] = formatter + + for name in cfg.handlers.keys(): + klass = cfg.handlers[name].get('class') + config = cfg.handlers[name].get('config') + cfg.handlers[name] = klass(config) + + for name in cfg.loggers.keys(): + loggerConfig = cfg.loggers[name] + logger = logging.getLogger(name) + configLogger(logger, loggerConfig) + + if 'root' in cfg: + configLogger(logging.getLogger(''), cfg.root) + +def testConfig(): + levels = [logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL] + loggers = ['', 'area1', 'area2'] + for i in xrange(1000): + logger = logging.getLogger(choice(loggers)) + level = choice(levels) + logger.log(level, "Message number %d", i) + +def main(args=None): + rv = 0 + if args is None: + args = sys.argv[1:] + parser = OptionParser(usage="usage: %prog [options] CONFIG-FILE") + + (options, args) = parser.parse_args(args) + try: + if len(args) == 0: + raise Usage("No configuration file specified") + fileConfig(args[0]) + testConfig() + except Usage, e: + parser.print_help() + print "\n%s: error: %s" % (get_prog_name(), e) + rv = 1 + except Exception, e: + print "\n%s: error: %s" % (get_prog_name(), e) + typ, val, tb = sys.exc_info() + import traceback + traceback.print_tb(tb) + rv = 2 + return rv + +if __name__ == "__main__": + sys.exit(main()) diff --git a/test/config_0_3_9/setup.py b/test/config_0_3_9/setup.py new file mode 100644 index 0000000..9c7dfab --- /dev/null +++ b/test/config_0_3_9/setup.py @@ -0,0 +1,20 @@ +from distutils.core import setup + +setup(name = "config", + description="A hierarchical, easy-to-use, powerful configuration module for Python", + long_description = """This module allows a hierarchical configuration scheme with support for mappings +and sequences, cross-references between one part of the configuration and +another, the ability to flexibly access real Python objects without full-blown +eval(), an include facility, simple expression evaluation and the ability to +change, save, cascade and merge configurations. Interfaces easily with +environment variables and command-line options. It has been developed on python +2.3 but should work on version 2.2 or greater.""", + license="""Copyright (C) 2004-2010 by Vinay Sajip. All Rights Reserved. See LICENSE for license.""", + version = "0.3.9", + author = "Vinay Sajip", + author_email = "vinay_sajip@red-dove.com", + maintainer = "Vinay Sajip", + maintainer_email = "vinay_sajip@red-dove.com", + url = "http://www.red-dove.com/python_config.html", + py_modules = ["config"], + ) diff --git a/test/config_0_3_9/styles.json b/test/config_0_3_9/styles.json new file mode 100644 index 0000000..259697e --- /dev/null +++ b/test/config_0_3_9/styles.json @@ -0,0 +1,554 @@ +{ + "embeddedFonts" : [ ], + "pageSetup" : { + "size": "A4", + "width": null, + "height": null, + "margin-top": "2cm", + "margin-bottom": "2cm", + "margin-left": "2cm", + "margin-right": "2cm", + "margin-gutter": "0cm", + "spacing-header": "5mm", + "spacing-footer": "5mm", + "firstTemplate": "oneColumn" + }, + "pageTemplates" : { + "coverPage": { + "frames": [ + ["0cm", "0cm", "100%", "100%"] + ], + "showHeader" : false, + "showFooter" : false + }, + "oneColumn": { + "frames": [ + ["0cm", "0cm", "100%", "100%"] + ], + "showHeader" : true, + "showFooter" : true + }, + "twoColumn": { + "frames": [ + ["0cm", "0cm", "49%", "100%"], + ["51%", "0cm", "49%", "100%"] + ], + "showHeader" : true, + "showFooter" : true + }, + "threeColumn": { + "frames": [ + ["2%", "0cm", "29.333%", "100%"], + ["35.333%", "0cm", "29.333%", "100%"], + ["68.666%", "0cm", "29.333%", "100%"] + ], + "showHeader" : true, + "showFooter" : true + }, + "cutePage": { + "frames": [ + ["0%", "0%", "100%", "100%"] + ], + "showHeader" : true, + "showFooter" : true, + "defaultFooter" : "###Page###", + "defaultHeader" : "###Section###" + } + }, + "fontsAlias" : { + "stdFont": "Helvetica", + "stdBold": "Helvetica-Bold", + "stdItalic": "Helvetica-Oblique", + "stdBoldItalic": "Helvetica-BoldOblique", + "stdSans": "Helvetica", + "stdSansBold": "Helvetica-Bold", + "stdSansItalic": "Helvetica-Oblique", + "stdSansBoldItalic": "Helvetica-BoldOblique", + "stdMono": "Courier", + "stdMonoItalic": "Courier-Oblique", + "stdMonoBold": "Courier-Bold", + "stdMonoBoldItalic": "Courier-BoldOblique", + "stdSerif": "Times-Roman" + }, + "linkColor" : "navy", + "styles" : [ + [ "base" , { + "parent": null, + "fontName": "stdFont", + "fontSize":10, + "leading":12, + "leftIndent":0, + "rightIndent":0, + "firstLineIndent":0, + "alignment":"TA_LEFT", + "spaceBefore":0, + "spaceAfter":0, + "bulletFontName":"stdFont", + "bulletFontSize":10, + "bulletIndent":0, + "textColor": "black", + "backColor": null, + "wordWrap": null, + "borderWidth": 0, + "borderPadding": 0, + "borderColor": null, + "borderRadius": null, + "allowWidows": false, + "allowOrphans": false, + "hyphenation": false, + "kerning": false + }] , + ["normal" , { + "parent": "base" + }], + ["title_reference" , { + "parent": "normal", + "fontName": "stdItalic" + }], + ["bodytext" , { + "parent": "normal", + "spaceBefore": 6, + "alignment": "TA_JUSTIFY", + "hyphenation": true + }], + ["toc" , { + "parent": "normal" + }], + ["blockquote" , { + "parent": "bodytext", + "leftIndent": 20 + }], + ["lineblock" , { + "parent": "bodytext" + }], + ["line" , { + "parent": "lineblock", + "spaceBefore": 0 + }], + ["toc1" , { + "parent": "toc", + "fontName": "stdBold" + }], + ["toc2" , { + "parent": "toc", + "leftIndent": 20 + }], + ["toc3" , { + "parent": "toc", + "leftIndent": 40 + }], + ["toc4" , { + "parent": "toc", + "leftIndent": 60 + }], + ["toc5" , { + "parent": "toc", + "leftIndent": 80 + }], + ["toc6" , { + "parent": "toc", + "leftIndent": 100 + }], + ["toc7" , { + "parent": "toc", + "leftIndent": 100 + }], + ["toc8" , { + "parent": "toc", + "leftIndent": 100 + }], + ["toc9" , { + "parent": "toc", + "leftIndent": 100 + }], + ["toc10" , { + "parent": "toc", + "leftIndent": 100 + }], + ["toc11" , { + "parent": "toc", + "leftIndent": 100 + }], + ["toc12" , { + "parent": "toc", + "leftIndent": 100 + }], + ["toc13" , { + "parent": "toc", + "leftIndent": 100 + }], + ["toc14" , { + "parent": "toc", + "leftIndent": 100 + }], + ["toc15" , { + "parent": "toc", + "leftIndent": 100 + }], + ["footer" , { + "parent": "normal", + "alignment": "TA_CENTER" + }], + ["header" , { + "parent": "normal", + "alignment": "TA_CENTER" + }], + ["attribution" , { + "parent": "bodytext", + "alignment": "TA_RIGHT" + }], + ["figure" , { + "parent": "bodytext", + "alignment": "TA_CENTER" + }], + ["figure-caption" , { + "parent": "bodytext", + "fontName": "stdItalic", + "alignment": "TA_CENTER" + }], + ["figure-legend" , { + "parent": "bodytext", + "alignment": "TA_CENTER" + }], + ["bullet_list", { + "parent": "bodytext", + "commands": [ + [ "VALIGN", [ 0, 0 ], [ -1, -1 ], "TOP" ], + [ "RIGHTPADDING", [ 0, 0 ], [ 1, -1 ], 0 ] + ], + "colWidths": ["20",null] + }], + ["bullet_list_item" , { + "parent": "bodytext" + }], + ["item_list", { + "parent": "bodytext", + "commands": [ + [ "VALIGN", [ 0, 0 ], [ -1, -1 ], "TOP" ], + [ "RIGHTPADDING", [ 0, 0 ], [ 1, -1 ], 0 ] + ], + "colWidths": ["20pt",null] + }], + ["item_list_item" , { + "parent": "bodytext" + }], + ["definition_list_term" , { + "parent": "normal", + "fontName": "stdBold", + "spaceBefore": 4, + "spaceAfter": 0, + "keepWithNext": true + }], + ["definition_list_classifier" , { + "parent": "normal", + "fontName": "stdItalic" + }], + ["definition" , { + "parent": "bodytext", + "firstLineIndent": 0, + "bulletIndent": 0, + "spaceBefore": 0 + }], + ["fieldname" , { + "parent": "bodytext", + "alignment": "TA_RIGHT", + "fontName": "stdBold" + }], + ["fieldvalue" , { + "parent": "bodytext" + }], + ["rubric" , { + "parent": "bodytext", + "textColor": "darkred", + "alignment": "TA_CENTER" + }], + ["italic" , { + "parent": "bodytext", + "fontName": "stdItalic" + }], + ["heading" , { + "parent": "normal", + "keepWithNext": true, + "spaceBefore": 12, + "spaceAfter": 6 + }], + ["title" , { + "parent": "heading", + "fontName": "stdBold", + "fontSize": "200%", + "alignment": "TA_CENTER", + "keepWithNext": false, + "spaceAfter": 10 + }], + ["subtitle" , { + "parent": "title", + "spaceBefore": 12, + "fontSize": "75%" + }], + ["heading1" , { + "parent": "heading", + "fontName": "stdBold", + "fontSize": "175%" + }], + ["heading2" , { + "parent": "heading", + "fontName": "stdBold", + "fontSize": "150%" + }], + ["heading3" , { + "parent": "heading", + "fontName": "stdBoldItalic", + "fontSize": "125%" + }], + ["heading4" , { + "parent": "heading", + "fontName": "stdBoldItalic" + }], + ["heading5" , { + "parent": "heading", + "fontName": "stdBoldItalic" + }], + ["heading6" , { + "parent": "heading", + "fontName": "stdBoldItalic" + }], + ["topic-title" , { + "parent": "heading3" + }], + ["sidebar-title" , { + "parent": "heading3" + }], + ["sidebar-subtitle" , { + "parent": "heading4" + }], + ["sidebar" , { + "float": "none", + "width": "100%", + "parent": "normal", + "backColor": "beige", + "borderColor": "darkgray", + "borderPadding": 8, + "borderWidth": 0.5 + }], + ["admonition" , { + "parent": "normal", + "spaceBefore": 12, + "spaceAfter": 6, + "borderPadding": [16,16,16,16], + "backColor": "beige", + "borderColor": "darkgray", + "borderWidth": 0.5, + "commands":[ + [ "VALIGN", [ 0, 0 ], [ -1, -1 ], "TOP" ] + ] + }], + ["attention" , { + "parent": "admonition" + }], + ["caution" , { + "parent": "admonition" + }], + ["danger" , { + "parent": "admonition" + }], + ["error" , { + "parent": "admonition" + }], + ["hint" , { + "parent": "admonition" + }], + ["important" , { + "parent": "admonition" + }], + ["note" , { + "parent": "admonition" + }], + ["tip" , { + "parent": "admonition" + }], + ["warning" , { + "parent": "admonition" + }], + ["admonition-title" , { + "parent": "heading3" + }], + ["admonition-heading" , { + "parent": "heading3" + }], + ["attention-heading" , { + "parent": "admonition-heading" + }], + ["caution-heading" , { + "parent": "admonition-heading" + }], + ["danger-heading" , { + "parent": "admonition-heading" + }], + ["error-heading" , { + "parent": "admonition-heading" + }], + ["hint-heading" , { + "parent": "admonition-heading" + }], + ["important-heading" , { + "parent": "admonition-heading" + }], + ["note-heading" , { + "parent": "admonition-heading" + }], + ["tip-heading" , { + "parent": "admonition-heading" + }], + ["warning-heading" , { + "parent": "admonition-heading" + }], + ["literal" , { + "parent": "normal", + "fontName": "stdMono", + "firstLineIndent": 0, + "hyphenation": false + }], + ["aafigure" , { + "parent": "literal" + }], + ["table" , { + "spaceBefore":6, + "spaceAfter":0, + "alignment": "TA_CENTER", + "commands": [ + [ "VALIGN", [ 0, 0 ], [ -1, -1 ], "TOP" ], + [ "INNERGRID", [ 0, 0 ], [ -1, -1 ], 0.25, "black" ], + [ "ROWBACKGROUNDS", [0, 0], [-1, -1], ["white","#E0E0E0"]], + [ "BOX", [ 0, 0 ], [ -1, -1 ], 0.25, "black" ] + ] + }], + ["table-title" , { + "parent" : "heading4", + "keepWithNext": false, + "alignment" : "TA_CENTER" + }], + ["table-heading" , { + "parent" : "heading", + "backColor" : "beige", + "alignment" : "TA_CENTER", + "valign" : "BOTTOM", + "borderPadding" : 0 + }], + ["table-body", { + "parent" : "normal" + }], + ["dedication" , { + "parent" : "normal" + }], + ["abstract" , { + "parent" : "normal" + }], + ["contents" , { + "parent" : "normal" + }], + ["tableofcontents" , { + "parent" : "normal" + }], + ["code" , { + "parent": "literal", + "leftIndent": 0, + "spaceBefore": 8, + "spaceAfter": 8, + "backColor": "beige", + "borderColor": "darkgray", + "borderWidth": 0.5, + "borderPadding": 6 + }], + ["pygments-n" , {"parent": "code"}], + ["pygments-nx" , {"parent": "code"}], + ["pygments-p" , {"parent": "code"}], + ["pygments-hll", {"parent": "code", "backColor": "#ffffcc"}], + ["pygments-c", {"textColor": "#008800", "parent": "code"}], + ["pygments-err", {"parent": "code"}], + ["pygments-k", {"textColor": "#AA22FF", "parent": "code"}], + ["pygments-o", {"textColor": "#666666", "parent": "code"}], + ["pygments-cm", {"textColor": "#008800", "parent": "code"}], + ["pygments-cp", {"textColor": "#008800", "parent": "code"}], + ["pygments-c1", {"textColor": "#008800", "parent": "code"}], + ["pygments-cs", {"textColor": "#008800", "parent": "code"}], + ["pygments-gd", {"textColor": "#A00000", "parent": "code"}], + ["pygments-ge", {"parent": "code"}], + ["pygments-gr", {"textColor": "#FF0000", "parent": "code"}], + ["pygments-gh", {"textColor": "#000080", "parent": "code"}], + ["pygments-gi", {"textColor": "#00A000", "parent": "code"}], + ["pygments-go", {"textColor": "#808080", "parent": "code"}], + ["pygments-gp", {"textColor": "#000080", "parent": "code"}], + ["pygments-gs", {"parent": "code"}], + ["pygments-gu", {"textColor": "#800080", "parent": "code"}], + ["pygments-gt", {"textColor": "#0040D0", "parent": "code"}], + ["pygments-kc", {"textColor": "#AA22FF", "parent": "code"}], + ["pygments-kd", {"textColor": "#AA22FF", "parent": "code"}], + ["pygments-kn", {"textColor": "#AA22FF", "parent": "code"}], + ["pygments-kp", {"textColor": "#AA22FF", "parent": "code"}], + ["pygments-kr", {"textColor": "#AA22FF", "parent": "code"}], + ["pygments-kt", {"textColor": "#00BB00", "parent": "code"}], + ["pygments-m", {"textColor": "#666666", "parent": "code"}], + ["pygments-s", {"textColor": "#BB4444", "parent": "code"}], + ["pygments-na", {"textColor": "#BB4444", "parent": "code"}], + ["pygments-nb", {"textColor": "#AA22FF", "parent": "code"}], + ["pygments-nc", {"textColor": "#0000FF", "parent": "code"}], + ["pygments-no", {"textColor": "#880000", "parent": "code"}], + ["pygments-nd", {"textColor": "#AA22FF", "parent": "code"}], + ["pygments-ni", {"textColor": "#999999", "parent": "code"}], + ["pygments-ne", {"textColor": "#D2413A", "parent": "code"}], + ["pygments-nf", {"textColor": "#00A000", "parent": "code"}], + ["pygments-nl", {"textColor": "#A0A000", "parent": "code"}], + ["pygments-nn", {"textColor": "#0000FF", "parent": "code"}], + ["pygments-nt", {"textColor": "#008000", "parent": "code"}], + ["pygments-nv", {"textColor": "#B8860B", "parent": "code"}], + ["pygments-ow", {"textColor": "#AA22FF", "parent": "code"}], + ["pygments-w", {"textColor": "#bbbbbb", "parent": "code"}], + ["pygments-mf", {"textColor": "#666666", "parent": "code"}], + ["pygments-mh", {"textColor": "#666666", "parent": "code"}], + ["pygments-mi", {"textColor": "#666666", "parent": "code"}], + ["pygments-mo", {"textColor": "#666666", "parent": "code"}], + ["pygments-sb", {"textColor": "#BB4444", "parent": "code"}], + ["pygments-sc", {"textColor": "#BB4444", "parent": "code"}], + ["pygments-sd", {"textColor": "#BB4444", "parent": "code"}], + ["pygments-s2", {"textColor": "#BB4444", "parent": "code"}], + ["pygments-se", {"textColor": "#BB6622", "parent": "code"}], + ["pygments-sh", {"textColor": "#BB4444", "parent": "code"}], + ["pygments-si", {"textColor": "#BB6688", "parent": "code"}], + ["pygments-sx", {"textColor": "#008000", "parent": "code"}], + ["pygments-sr", {"textColor": "#BB6688", "parent": "code"}], + ["pygments-s1", {"textColor": "#BB4444", "parent": "code"}], + ["pygments-ss", {"textColor": "#B8860B", "parent": "code"}], + ["pygments-bp", {"textColor": "#AA22FF", "parent": "code"}], + ["pygments-vc", {"textColor": "#B8860B", "parent": "code"}], + ["pygments-vg", {"textColor": "#B8860B", "parent": "code"}], + ["pygments-vi", {"textColor": "#B8860B", "parent": "code"}], + ["pygments-il", {"textColor": "#666666", "parent": "code"}], + + [ "endnote", { + "parent": "bodytext", + "commands": [ + [ "VALIGN", [ 0, 0 ], [ -1, -1 ], "TOP" ], + [ "TOPPADDING", [ 0, 0 ], [ -1, -1 ], 0 ], + [ "BOTTOMPADDING", [ 0, 0 ], [ -1, -1 ], 0 ], + [ "RIGHTPADDING", [ 0, 0 ], [ 1, -1 ], 0 ] + ], + "colWidths": ["3cm",null] + }], + [ "field_list", { + "parent": "bodytext", + "commands": [ + [ "VALIGN", [ 0, 0 ], [ -1, -1 ], "TOP" ], + [ "TOPPADDING", [ 0, 0 ], [ -1, -1 ], 0 ] + ], + "colWidths": ["3cm",null], + "spaceBefore": 6 + }], + [ "option_list", { + "commands": [ + [ "VALIGN", [ 0, 0 ], [ -1, -1 ], "TOP" ], + [ "TOPPADDING", [ 0, 0 ], [ -1, -1 ], 0 ] + ], + "colWidths": [null,null] + }] + ] +} diff --git a/test/config_0_3_9/test_config.py b/test/config_0_3_9/test_config.py new file mode 100644 index 0000000..393be86 --- /dev/null +++ b/test/config_0_3_9/test_config.py @@ -0,0 +1,439 @@ +# 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. +""" + +import unittest +# import test_support +import config +from config import Config, ConfigMerger, ConfigList +from config 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__": + unittest.main(exit=False) + pass + # test_main() diff --git a/test/environ/test_environ.py b/test/environ/test_environ.py deleted file mode 100755 index 3a63fd5..0000000 --- a/test/environ/test_environ.py +++ /dev/null @@ -1,150 +0,0 @@ -#!/usr/bin/env python -#-*- coding:utf-8 -*- - -# Copyright (C) 2010-2018 CEA/DEN -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -import os -import sys -import unittest - -from src.salomeTools import Sat - -class TestSource(unittest.TestCase): - """Test of the environ command""" - - def test_010(self): - # Test the environ command without any option - OK = 'KO' - - appli = 'appli-test' - - file_env_name = 'env_launch.sh' - - sat = Sat() - sat.config(appli) - - expected_file_path = os.path.join(sat.cfg.APPLICATION.workdir, file_env_name) - - if os.path.exists(expected_file_path): - os.remove(expected_file_path) - - sat.environ(appli) - - if os.path.exists(expected_file_path): - OK = 'OK' - self.assertEqual(OK, 'OK') - - def test_020(self): - # Test the environ command with option '--products' - OK = 'KO' - - appli = 'appli-test' - product_name = 'PRODUCT_GIT' - - file_env_name = 'env_launch.sh' - - sat = Sat() - sat.config(appli) - - expected_file_path = os.path.join(sat.cfg.APPLICATION.workdir, file_env_name) - - if os.path.exists(expected_file_path): - os.remove(expected_file_path) - - sat.environ(appli + ' --products ' + product_name) - - if os.path.exists(expected_file_path): - OK = 'OK' - self.assertEqual(OK, 'OK') - - def test_030(self): - # Test the environ command with option --target - OK = 'KO' - - appli = 'appli-test' - - file_env_name = 'env_launch.sh' - - sat = Sat() - sat.config(appli) - - expected_file_path = os.path.join('.', file_env_name) - expected_file_path2 = os.path.join('.', 'env_build.sh') - - if os.path.exists(expected_file_path): - os.remove(expected_file_path) - - sat.environ(appli + ' --target .') - - if os.path.exists(expected_file_path): - OK = 'OK' - - if os.path.exists(expected_file_path): - os.remove(expected_file_path) - os.remove(expected_file_path2) - - # pyunit method to compare 2 str - self.assertEqual(OK, 'OK') - - def test_040(self): - # Test the environ command with option --prefix - OK = 'KO' - - appli = 'appli-test' - prefix = 'TEST' - file_env_name = prefix + '_launch.sh' - - sat = Sat() - sat.config(appli) - - expected_file_path = os.path.join(sat.cfg.APPLICATION.workdir, file_env_name) - - if os.path.exists(expected_file_path): - os.remove(expected_file_path) - - sat.environ(appli + ' --prefix ' + prefix) - - if os.path.exists(expected_file_path): - OK = 'OK' - self.assertEqual(OK, 'OK') - - def test_050(self): - # Test the environ command with option --shell - OK = 'KO' - - appli = 'appli-test' - shell = 'bat' - file_env_name = 'env_launch.bat' - - sat = Sat() - sat.config(appli) - - expected_file_path = os.path.join(sat.cfg.APPLICATION.workdir, file_env_name) - - if os.path.exists(expected_file_path): - os.remove(expected_file_path) - - sat.environ(appli + ' --shell ' + shell) - - if os.path.exists(expected_file_path): - OK = 'OK' - self.assertEqual(OK, 'OK') - -# test launch -if __name__ == '__main__': - unittest.main() - pass diff --git a/test/job/test_job.py b/test/job/test_job.py deleted file mode 100755 index fc23191..0000000 --- a/test/job/test_job.py +++ /dev/null @@ -1,122 +0,0 @@ -#!/usr/bin/env python -#-*- coding:utf-8 -*- - -# Copyright (C) 2010-2018 CEA/DEN -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -import os -import sys -import unittest - -from src.salomeTools import Sat - -class TestCase(unittest.TestCase): - """Test the job command""" - - def test_010(self): - # Test the job command - OK = 'KO' - tmp_file = "/tmp/test.txt" - - sat = Sat("-l " + tmp_file) - - # Execute the job command - sat.job("--jobs_config .test --name Job 1" ) - - ff = open(tmp_file, "r") - log_files = ff.readlines() - ff.close() - os.remove(tmp_file) - log_config = [line.replace("\n", "") for line in log_files if 'config.xml' in line] - - text = open(log_config[0], "r").read() - - if "nb_proc" in text: - OK = 'OK' - self.assertEqual(OK, 'OK') - - - def test_020(self): - # Test the job command with a failing command - OK = 'KO' - tmp_file = "/tmp/test.txt" - - sat = Sat("-l " + tmp_file) - - # Execute the job command - res = sat.job("--jobs_config .test --name Job 4" ) - - if res == 1: - OK = 'OK' - # pyunit method to compare 2 str - self.assertEqual(OK, 'OK') - - def test_030(self): - # Test the job command with a wrong file configuration - OK = 'KO' - tmp_file = "/tmp/test.txt" - - sat = Sat("-l " + tmp_file) - - # Execute the job command - res = sat.job("--jobs_config NOTEXIST --name Job 4" ) - - if res == 1: - OK = 'OK' - self.assertEqual(OK, 'OK') - - def test_040(self): - # Test the job command without --jobs_config option - OK = 'KO' - tmp_file = "/tmp/test.txt" - - sat = Sat("-l " + tmp_file) - - # Execute the job command - res = sat.job("--name Job 4" ) - - if res == 1: - OK = 'OK' - self.assertEqual(OK, 'OK') - - def test_050(self): - # Test the job command without --jobs_config option - OK = 'KO' - tmp_file = "/tmp/test.txt" - - sat = Sat("-l " + tmp_file) - - # Execute the job command - res = sat.job("--jobs_config .test --name NOTEXIST" ) - - if res == 1: - OK = 'OK' - self.assertEqual(OK, 'OK') - - def test_060(self): - # Test the sat -h job - OK = "KO" - - import job - - if "Executes the commands of the job defined in the jobs configuration file" in job.description(): - OK = "OK" - self.assertEqual(OK, "OK") - -# test launch -if __name__ == '__main__': - unittest.main() - pass diff --git a/test/jobs/test_jobs.py b/test/jobs/test_jobs.py deleted file mode 100755 index 1b22378..0000000 --- a/test/jobs/test_jobs.py +++ /dev/null @@ -1,159 +0,0 @@ -#!/usr/bin/env python -#-*- coding:utf-8 -*- - -# Copyright (C) 2010-2018 CEA/DEN -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -import os -import sys -import unittest - -from src.salomeTools import Sat -from unittestpy.tools import outRedirection - -class TestCase(unittest.TestCase): - "Test the jobs command""" - - def test_010(self): - # Test the jobs command - OK = 'KO' - tmp_file = "/tmp/test.txt" - - sat = Sat("-l " + tmp_file) - - # Execute the jobs command - sat.jobs("--name .test --publish" ) - - ff = open(tmp_file, "r") - log_files = ff.readlines() - ff.close() - os.remove(tmp_file) - log_jobs = [line.replace("\n", "") for line in log_files if 'jobs.xml' in line] - - text = open(log_jobs[0], "r").read() - - expected_res = [ - "Establishing connection with all the machines", - "Executing the jobs", - "Results for job" - ] - - res = 0 - for exp_res in expected_res: - if exp_res not in text: - res += 1 - - if res == 0: - OK = 'OK' - self.assertEqual(OK, 'OK') - - def test_020(self): - # Test the jobs command with option --only_jobs - OK = 'KO' - tmp_file = "/tmp/test.txt" - - sat = Sat("-l " + tmp_file) - - # Execute the jobs command - sat.jobs("--name .test --publish --only_jobs Job 1" ) - - ff = open(tmp_file, "r") - log_files = ff.readlines() - ff.close() - os.remove(tmp_file) - log_jobs = [line.replace("\n", "") for line in log_files if 'jobs.xml' in line] - - text = open(log_jobs[0], "r").read() - - expected_res = [ - "Establishing connection with all the machines", - "Executing the jobs", - "Results for job" - ] - - res = 0 - for exp_res in expected_res: - if exp_res not in text: - res += 1 - - if res == 0: - OK = 'OK' - self.assertEqual(OK, 'OK') - - def test_030(self): - # Test the jobs command without --name option - OK = 'KO' - tmp_file = "/tmp/test.txt" - - sat = Sat("-l " + tmp_file) - - # Execute the job command - res = sat.jobs() - - if res == 1: - OK = 'OK' - self.assertEqual(OK, 'OK') - - def test_040(self): - # Test the jobs command with a wrong file configuration - OK = 'KO' - tmp_file = "/tmp/test.txt" - - sat = Sat("-l " + tmp_file) - - # Execute the job command - res = sat.jobs("--name NOTEXIST" ) - - if res == 1: - OK = 'OK' - self.assertEqual(OK, 'OK') - - def test_050(self): - # Test the display of the right value of 'sat jobs --list' - OK = "KO" - - # output redirection - my_out = outRedirection() - - # The command to test - sat = Sat() - sat.jobs('--list') - - # stop output redirection - my_out.end_redirection() - - # get results - res = my_out.read_results() - - # get results - if "ERROR" not in res: - OK = "OK" - self.assertEqual(OK, "OK") - - def test_060(self): - # Test the sat -h jobs - OK = "KO" - - import jobs - - if "The jobs command launches maintenances that are described in the dedicated jobs configuration file." in jobs.description(): - OK = "OK" - self.assertEqual(OK, "OK") - -# test launch -if __name__ == '__main__': - unittest.main() - pass diff --git a/test/log/test_launch_browser.py b/test/log/test_launch_browser.py deleted file mode 100755 index a9c8be4..0000000 --- a/test/log/test_launch_browser.py +++ /dev/null @@ -1,294 +0,0 @@ -#!/usr/bin/env python -#-*- coding:utf-8 -*- - -# Copyright (C) 2010-2018 CEA/DEN -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -import os -import sys -import threading -import time -import shutil -import io -import unittest - -from src.salomeTools import Sat -from unittestpy.tools import check_proc_existence_and_kill_multi - -sleep_time = 2 - -class TestCase(unittest.TestCase): - """Test of log command: launch of browser""" - - def test_010(self): - # Test the write of xml log when invoking a command - OK = "KO" - - # launch the command that will write a log - sat = Sat() - sat.config('appli-test -v USER.browser') - - # get log file path - logDir = sat.cfg.USER.log_dir - logPath = os.path.join(logDir, sat.cfg.VARS.datehour + "_" + sat.cfg.VARS.command + ".xml") - - if os.path.exists(logPath): - OK = "OK" - self.assertEqual(OK, "OK") - - def test_020(self): - # Test the terminal option without application - OK = "KO" - - # launch the command that will write a log - sat = Sat() - - one = u"1" - sys.stdin = io.StringIO(one) - - - try: - sat.log('-t') - OK = "OK" - sys.stdin = sys.__stdin__ - except: - sys.stdin = sys.__stdin__ - self.assertEqual(OK, "OK") - - def test_030(self): - # Test the terminal option with application - OK = "KO" - - # launch the command that will write a log - sat = Sat() - - sat.config('appli-test -v VARS.python') - - one = u"1" - sys.stdin = io.StringIO(one) - - try: - sat.log('appli-test -t --last') - OK = "OK" - sys.stdin = sys.__stdin__ - except: - pass - self.assertEqual(OK, "OK") - - def test_040(self): - # Test the terminal option with 0 as input - OK = "KO" - - # launch the command that will write a log - sat = Sat() - - sat.config('appli-test -v VARS.python') - - zero = u"0\n1" - sys.stdin = io.StringIO(zero) - - try: - sat.log('--terminal') - OK = "OK" - finally: - sys.stdin = sys.__stdin__ - self.assertEqual(OK, "OK") - - def test_050(self): - # Test the terminal option with input bigger than the number of logs - OK = "KO" - - # launch the command that will write a log - sat = Sat() - - sat.config('appli-test -v VARS.python') - - nb_logs = len(os.listdir(sat.cfg.USER.log_dir)) - - nb_logs_u = unicode(str(nb_logs) + "\n1") - sys.stdin = io.StringIO(nb_logs_u) - - try: - sat.log('--terminal') - OK = "OK" - finally: - sys.stdin = sys.__stdin__ - self.assertEqual(OK, "OK") - - def test_060(self): - # Test the terminal option with input return - OK = "KO" - - # launch the command that will write a log - sat = Sat() - - sat.config('appli-test -v VARS.python') - - ret = unicode("\n0") - sys.stdin = io.StringIO(ret) - - try: - sat.log('--terminal') - OK = "OK" - finally: - sys.stdin = sys.__stdin__ - self.assertEqual(OK, "OK") - - def test_070(self): - # Test the terminal option with input not int - OK = "KO" - - # launch the command that will write a log - sat = Sat() - - sat.config('appli-test -v VARS.python') - - ret = unicode("blabla\n0") - sys.stdin = io.StringIO(ret) - - try: - sat.log('--terminal') - OK = "OK" - finally: - sys.stdin = sys.__stdin__ - self.assertEqual(OK, "OK") - - def test_080(self): - # Test the terminal option and option last - OK = "KO" - - # launch the command that will write a log - sat = Sat() - - try: - sat.log('--terminal --last') - OK = "OK" - finally: - sys.stdin = sys.__stdin__ - - # pyunit method to compare 2 str - self.assertEqual(OK, "OK") - - def test_090(self): - # Test the option --last - OK = "KO" - - # launch the command that will write a log - sat = Sat("-oUSER.browser='konqueror'") - - sat.config('appli-test -v VARS.python') - - - time.sleep(sleep_time) - cmd_log = threading.Thread(target=sat.log, args=('appli-test --last',)) - cmd_log.start() - - time.sleep(sleep_time) - - browser = sat.cfg.USER.browser - pid = check_proc_existence_and_kill_multi(browser + ".*" + "xml", 10) - - if pid: - OK = "OK" - self.assertEqual(OK, "OK") - - def test_100(self): - # Test the option --clean - OK = "KO" - - # launch the command that will write a log - sat = Sat() - - sat.config('-v VARS.user') - - nb_logs_t0 = len(os.listdir(sat.cfg.USER.log_dir)) - - sat.log('--clean 1') - - nb_logs_t1 = len(os.listdir(sat.cfg.USER.log_dir)) - - if nb_logs_t1-nb_logs_t0 == 0: - OK = "OK" - self.assertEqual(OK, "OK") - - def test_120(self): - # Test the option --clean with big number of files to clean - OK = "KO" - - # launch the command that will write a log - sat = Sat() - - sat.config('-v VARS.user') - - nb_logs_t0 = len(os.listdir(sat.cfg.USER.log_dir)) - - if os.path.exists(sat.cfg.USER.log_dir + "_save"): - shutil.rmtree(sat.cfg.USER.log_dir + "_save") - print("TODO: risky !!!copytree!!!", sat.cfg.USER.log_dir, sat.cfg.USER.log_dir + "_save") - """ - shutil.copytree(sat.cfg.USER.log_dir,sat.cfg.USER.log_dir + "_save") - - sat.log('--clean ' + str(nb_logs_t0)) - - nb_logs_t1 = len(os.listdir(sat.cfg.USER.log_dir)) - - shutil.rmtree(sat.cfg.USER.log_dir) - shutil.move(sat.cfg.USER.log_dir + "_save", sat.cfg.USER.log_dir) - - if nb_logs_t0-nb_logs_t1 > 10: - OK = "OK" - """ - self.assertEqual(OK, "OK") - - """ - def test_130(self): - # Test the option --full - OK = "KO" - - sat = Sat("-oUSER.browser='konqueror'") - time.sleep(sleep_time) - cmd_log = threading.Thread(target=sat.log, args=('--full',)) - cmd_log.start() - - time.sleep(sleep_time) - - browser = sat.cfg.USER.browser - check_proc_existence_and_kill_multi(browser + ".*" + "hat\.xml", 10) - - # Read and check the hat.xml file contains at least one log file corresponding to log - hatFilePath = os.path.join(sat.cfg.USER.log_dir, "hat.xml") - xmlHatFile = src.xmlManager.ReadXmlFile(hatFilePath) - for field in xmlHatFile.xmlroot: - if field.attrib[b'cmd'] == b'log': - OK = "OK" - break - self.assertEqual(OK, "OK") - """ - - def test_140(self): - # Test the sat -h log - OK = "KO" - - import log - - if "Gives access to the logs produced" in log.description(): - OK = "OK" - self.assertEqual(OK, "OK") - -# test launch -if __name__ == '__main__': - unittest.main() - pass diff --git a/test/log/test_launch_browser2.py b/test/log/test_launch_browser2.py deleted file mode 100755 index 38a6184..0000000 --- a/test/log/test_launch_browser2.py +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env python -#-*- coding:utf-8 -*- - -# Copyright (C) 2010-2018 CEA/DEN -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -import os -import sys -import threading -import time -import unittest - -from src.salomeTools import Sat -from unittestpy.tools import check_proc_existence_and_kill_multi - -sleep_time = 2 - -class TestCase(unittest.TestCase): - """Test of log command: launch of browser""" - - def test_010(self): - # Test the launch of browser when invoking the log command - OK = "KO" - - sat = Sat("-oUSER.browser='konqueror'") - time.sleep(sleep_time) - cmd_log = threading.Thread(target=sat.log, args=('',)) - cmd_log.start() - - time.sleep(sleep_time) - - sat.config("") - browser = sat.cfg.USER.browser - pid = check_proc_existence_and_kill_multi(browser + ".*" + "hat\.xml", 10) - - if pid: - OK = "OK" - self.assertEqual(OK, "OK") - -# test launch -if __name__ == '__main__': - unittest.main() - pass diff --git a/test/prepare/test_clean.py b/test/prepare/test_clean.py deleted file mode 100755 index 08bb54f..0000000 --- a/test/prepare/test_clean.py +++ /dev/null @@ -1,180 +0,0 @@ -#!/usr/bin/env python -#-*- coding:utf-8 -*- - -# Copyright (C) 2010-2018 CEA/DEN -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -import os -import sys -import unittest - -from src.salomeTools import Sat -import src.product -from unittestpy.tools import outRedirection - -class TestCase(unittest.TestCase): - """Test of the clean command""" - - def test_010(self): - # Test the clean command with no arguments (nothing to clean) - OK = 'KO' - - appli = 'appli-test' - - sat = Sat() - - # output redirection - my_out = outRedirection() - - sat.clean(appli) - - # stop output redirection - my_out.end_redirection() - - # get results - res = my_out.read_results() - - if "Nothing to suppress" in res: - OK = 'OK' - self.assertEqual(OK, 'OK') - - def test_020(self): - # Test the clean of sources - OK = "KO" - - appli = 'appli-test' - product_name = "PRODUCT_GIT" - - sat = Sat() - - # Make sure the sources exist - sat.prepare(appli + " -p " + product_name) - - # Call the command - sat.clean(appli + " -p " + product_name + " --sources", batch=True) - - expected_src_dir = src.product.get_product_config(sat.cfg, product_name).source_dir - - if not os.path.exists(expected_src_dir): - OK = "OK" - self.assertEqual(OK, "OK") - - def test_030(self): - # Test the clean of build - OK = "KO" - - appli = 'appli-test' - product_name = "PRODUCT_GIT" - - sat = Sat() - - # Make sure the build exists - sat.prepare(appli + " -p " + product_name) - sat.configure(appli + " -p " + product_name) - - # Call the command - sat.clean(appli + " -p " + product_name + " --build", batch=True) - - expected_build_dir = src.product.get_product_config(sat.cfg, product_name).build_dir - - if not os.path.exists(expected_build_dir): - OK = "OK" - self.assertEqual(OK, "OK") - - def test_040(self): - # Test the clean of install - OK = "KO" - - appli = 'appli-test' - product_name = "PRODUCT_GIT" - - sat = Sat() - - # Make sure the build exists - sat.prepare(appli + " -p " + product_name) - sat.configure(appli + " -p " + product_name) - - # Call the command - sat.clean(appli + " -p " + product_name + " --install", batch=True) - - expected_install_dir = src.product.get_product_config(sat.cfg, product_name).install_dir - - if not os.path.exists(expected_install_dir): - OK = "OK" - self.assertEqual(OK, "OK") - - def test_050(self): - # Test the clean of all (build, src, install) - OK = "KO" - - appli = 'appli-test' - product_name = "PRODUCT_GIT" - - sat = Sat() - - # Make sure the build exists - sat.prepare(appli + " -p " + product_name) - sat.compile(appli + " -p " + product_name) - - # Call the command - sat.clean(appli + " -p " + product_name + " --all", batch=True) - - expected_install_dir = src.product.get_product_config(sat.cfg, product_name).install_dir - expected_build_dir = src.product.get_product_config(sat.cfg, product_name).build_dir - expected_src_dir = src.product.get_product_config(sat.cfg, product_name).source_dir - - if not os.path.exists(expected_install_dir) and not os.path.exists(expected_build_dir) and not os.path.exists(expected_src_dir): - OK = "OK" - self.assertEqual(OK, "OK") - - def test_060(self): - # Test the clean with sources_without_dev option - OK = "KO" - - appli = 'appli-test' - product_name = "PRODUCT_GIT" - product_name2 = "PRODUCT_DEV" - - sat = Sat() - - # Make sure the build exists - sat.prepare(appli + " -p " + product_name + "," + product_name2) - - # Call the command - sat.clean(appli + " -p " + product_name + " --sources_without_dev", batch=True) - - expected_src_dir = src.product.get_product_config(sat.cfg, product_name).source_dir - expected_src_dir2 = src.product.get_product_config(sat.cfg, product_name2).source_dir - - if not os.path.exists(expected_src_dir) and os.path.exists(expected_src_dir2): - OK = "OK" - self.assertEqual(OK, "OK") - - - def test_070(self): - # Test the sat -h clean - OK = "KO" - - import clean - - if "The clean command suppress the source, build, or install" in clean.description(): - OK = "OK" - self.assertEqual(OK, "OK") - -# test launch -if __name__ == '__main__': - unittest.main() - pass diff --git a/test/prepare/test_patch.py b/test/prepare/test_patch.py deleted file mode 100755 index 1dc24d4..0000000 --- a/test/prepare/test_patch.py +++ /dev/null @@ -1,167 +0,0 @@ -#!/usr/bin/env python -#-*- coding:utf-8 -*- - -# Copyright (C) 2010-2018 CEA/DEN -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -import os -import sys -import shutil -import unittest - -from src.salomeTools import Sat -import src.product -from unittestpy.tools import outRedirection - -class TestCase(unittest.TestCase): - """Test of the patch command""" - - def test_010(self): - # Test the patch command with a product in dev mode - OK = 'KO' - - appli = 'appli-test' - product_name = 'PRODUCT_DEV' - - sat = Sat("-oUSER.output_level=2") - - sat.config(appli) - - expected_src_dir = src.product.get_product_config(sat.cfg, product_name).source_dir - expected_file_path = os.path.join(expected_src_dir, 'my_test_file.txt') - expected_text = 'HELLO WORLD\n' - - if os.path.exists(expected_src_dir): - shutil.rmtree(expected_src_dir) - - sat.source(appli + ' --product ' + product_name) - - f = open(expected_file_path, 'r') - text = f.readlines()[0] - OK1 = 'KO' - if text == expected_text: - OK1 = 'OK' - - sat.patch(appli + ' --product ' + product_name) - - new_expected_text = 'HELLO WORLD MODIFIED\n' - f = open(expected_file_path, 'r') - text = f.readlines()[0] - - OK2 = 'KO' - if text == new_expected_text: - OK2 = 'OK' - - if (OK1, OK2)==('OK', 'OK'): - OK = 'OK' - self.assertEqual(OK, 'OK') - - def test_020(self): - # Test the patch command with a product with no sources found - OK = 'KO' - - appli = 'appli-test' - product_name = 'PRODUCT_DEV' - - sat = Sat('') - sat.config(appli) - - expected_src_dir = src.product.get_product_config(sat.cfg, product_name).source_dir - - if os.path.exists(expected_src_dir): - shutil.rmtree(expected_src_dir) - - # output redirection - my_out = outRedirection() - - sat.patch(appli + ' --product ' + product_name) - - # stop output redirection - my_out.end_redirection() - - # get results - res = my_out.read_results() - - if "No sources found for the " + product_name +" product" in res: - OK = 'OK' - self.assertEqual(OK, 'OK') - - def test_030(self): - # Test the patch command with a product without patch - OK = 'KO' - - appli = 'appli-test' - product_name = 'PRODUCT_ARCHIVE' - - sat = Sat('-v4') - - sat.source(appli + ' --product ' + product_name) - - # output redirection - my_out = outRedirection() - - sat.patch(appli + ' --product ' + product_name) - - # stop output redirection - my_out.end_redirection() - - # get results - res = my_out.read_results() - - if "No patch for the " + product_name +" product" in res: - OK = 'OK' - self.assertEqual(OK, 'OK') - - def test_040(self): - # Test the patch command with a product with a not valid patch - OK = 'KO' - - appli = 'appli-test' - product_name = 'PRODUCT_DEV' - - sat = Sat("-oPRODUCTS.PRODUCT_DEV.default.patches=['/']") - - sat.source(appli + ' --product ' + product_name) - - # output redirection - my_out = outRedirection() - - sat.patch(appli + ' --product ' + product_name) - - # stop output redirection - my_out.end_redirection() - - # get results - res = my_out.read_results() - - if "Not a valid patch" in res: - OK = 'OK' - self.assertEqual(OK, 'OK') - - def test_050(self): - # Test the sat -h patch - OK = "KO" - - import patch - - if "The patch command apply the patches on the sources of" in patch.description(): - OK = "OK" - self.assertEqual(OK, "OK") - -# test launch -if __name__ == '__main__': - unittest.main() - pass diff --git a/test/prepare/test_prepare.py b/test/prepare/test_prepare.py deleted file mode 100755 index 3340547..0000000 --- a/test/prepare/test_prepare.py +++ /dev/null @@ -1,111 +0,0 @@ -#!/usr/bin/env python -#-*- coding:utf-8 -*- - -# Copyright (C) 2010-2018 CEA/DEN -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -import os -import sys -import shutil -import unittest - -import src -from src.salomeTools import Sat - -class TestCase(unittest.TestCase): - """Test of the prepare command""" - - def test_010(self): - # Test the prepare command with a product in dev mode - OK = 'KO' - - appli = 'appli-test' - product_name = 'PRODUCT_DEV' - - sat = Sat() - - sat.config(appli) - - expected_src_dir = src.product.get_product_config(sat.cfg, product_name).source_dir - expected_file_path = os.path.join(expected_src_dir, 'my_test_file.txt') - expected_text = 'HELLO WORLD\n' - - if os.path.exists(expected_src_dir): - shutil.rmtree(expected_src_dir) - - sat.prepare(appli + ' --product ' + product_name) - - f = open(expected_file_path, 'r') - text = f.readlines()[0] - if text == expected_text: - OK = 'OK' - self.assertEqual(OK, 'OK') - - def test_020(self): - # Test the prepare command with all products - OK = 'KO' - - appli = 'appli-test' - product_name = 'PRODUCT_DEV' - - sat = Sat() - sat.config(appli) - - expected_src_dir = src.product.get_product_config(sat.cfg, product_name).source_dir - expected_file_path = os.path.join(expected_src_dir, 'my_test_file.txt') - expected_text = 'HELLO WORLD\n' - - if os.path.exists(expected_src_dir): - shutil.rmtree(expected_src_dir) - - sat.prepare(appli) - - f = open(expected_file_path, 'r') - text = f.readlines()[0] - if text == expected_text: - OK = 'OK' - self.assertEqual(OK, 'OK') - - def test_030(self): - # Test the prepare command with all products - OK = 'KO' - - appli = 'appli-test' - - sat = Sat() - sat.config(appli) - - try: - sat.prepare(appli + " --force --force_patch") - OK = 'OK' - except: - pass - self.assertEqual(OK, 'OK') - - def test_040(self): - # Test the sat -h prepare - OK = "KO" - - import prepare - - if "The prepare command gets the sources" in prepare.description(): - OK = "OK" - self.assertEqual(OK, "OK") - -# test launch -if __name__ == '__main__': - unittest.main() - pass diff --git a/test/prepare/test_source.py b/test/prepare/test_source.py deleted file mode 100755 index f7a053d..0000000 --- a/test/prepare/test_source.py +++ /dev/null @@ -1,175 +0,0 @@ -#!/usr/bin/env python -#-*- coding:utf-8 -*- - -# Copyright (C) 2010-2018 CEA/DEN -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -import os -import sys -import unittest - -from src.salomeTools import Sat -import src.product -from unittestpy.tools import outRedirection - -class TestCase(unittest.TestCase): - """Test of the source command""" - - def test_010(self): - # Test the source command with archive product - appli = 'appli-test' - product_name = 'PRODUCT_ARCHIVE' - - sat = Sat() - sat.source(appli + ' --product ' + product_name) - - expected_src_dir = src.product.get_product_config(sat.cfg, product_name).source_dir - expected_file_path = os.path.join(expected_src_dir, 'my_test_file.txt') - expected_text = 'HELLO WORLD\n' - - f = open(expected_file_path, 'r') - text = f.read() - self.assertEqual(text, expected_text) - - def test_020(self): - # Test the source command with git product - appli = 'appli-test' - product_name = 'PRODUCT_GIT' - - sat = Sat() - sat.source(appli + ' --product ' + product_name) - - expected_src_dir = src.product.get_product_config(sat.cfg, product_name).source_dir - expected_file_path = os.path.join(expected_src_dir, 'my_test_file.txt') - expected_text = 'HELLO WORLD\n' - - f = open(expected_file_path, 'r') - text = f.read() - self.assertEqual(text, expected_text) - - def test_030(self): - # Test the source command with cvs product - appli = 'appli-test' - product_name = 'PRODUCT_CVS' - - sat = Sat() - sat.source(appli + ' --product ' + product_name) - - expected_src_dir = src.product.get_product_config(sat.cfg, product_name).source_dir - expected_file_path = os.path.join(expected_src_dir, 'README.FIRST.txt') - expected_text = 'Copyright (C) 2007-2012 CEA/DEN, EDF R&D, OPEN CASCADE\n' - - f = open(expected_file_path, 'r') - text = f.readlines()[0] - - # pyunit method to compare 2 str - self.assertEqual(text, expected_text) - - """ - def test_040(self): - # Test the source command with svn product - OK = 'KO' - - appli = 'appli-test' - product_name = 'PRODUCT_SVN' - - sat = Sat() - sat.source(appli + ' --product ' + product_name) - - expected_src_dir = src.product.get_product_config(sat.cfg, product_name).source_dir - expected_file_path = os.path.join(expected_src_dir, 'scripts', 'README') - expected_text = 'this directory contains scripts used by salomeTool' - - f = open(expected_file_path, 'r') - text = f.readlines()[0] - - if expected_text in text: - OK = 'OK' - - # pyunit method to compare 2 str - self.assertEqual(OK, 'OK') - """ - - def test_050(self): - # Test the source command with native product - OK = 'KO' - - appli = 'appli-test' - product_name = 'PRODUCT_NATIVE' - - sat = Sat() - sat.source(appli + ' --product ' + product_name) - - expected_src_dir = os.path.join(sat.cfg.APPLICATION.workdir, 'SOURCES', product_name) - if not os.path.exists(expected_src_dir): - OK = 'OK' - self.assertEqual(OK, 'OK') - - def test_060(self): - # Test the source command with fixed product - OK = 'KO' - - appli = 'appli-test' - product_name = 'PRODUCT_FIXED' - - sat = Sat() - sat.source(appli + ' --product ' + product_name) - - expected_src_dir = src.product.get_product_config(sat.cfg, product_name).install_dir - - if os.path.exists(expected_src_dir): - OK = 'OK' - self.assertEqual(OK, 'OK') - - """ - def test_070(self): - # Test the source command with unknown product - OK = 'KO' - - # output redirection - my_out = outRedirection() - - appli = 'appli-test' - product_name = 'PRODUCT_UNKNOWN' - - sat = Sat() - sat.source(appli + ' --product ' + product_name) - - # stop output redirection - my_out.end_redirection() - - # get results - res = my_out.read_results() - - if "Unknown get source method" in res: - OK = 'OK' - self.assertEqual(OK, 'OK') - """ - - def test_080(self): - # Test the sat -h source - OK = "KO" - - import source - - if "gets the sources of the application" in source.description(): - OK = "OK" - self.assertEqual(OK, "OK") - -# test launch -if __name__ == '__main__': - unittest.main() - pass diff --git a/test/run_all.sh b/test/run_all.sh deleted file mode 100755 index 5905725..0000000 --- a/test/run_all.sh +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/env bash -#-*- coding:utf-8 -*- - -# Copyright (C) 2010-2018 CEA/DEN -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -echo "TODO: OBSOLETE: to set as python script, may be" -echo "Begin date:" -date -echo -echo "Remove old results ... " -rm -rf .coverage htmlcov -echo "Done" -echo -echo "****************************" -coverage run --source=../commands/config.py config/option_value.py > test_res.html -coverage run --source=../commands/config.py -a config/option_value_2.py >> test_res.html -coverage run --source=../commands/config.py -a config/create_user_pyconf.py >> test_res.html -coverage run --source=../commands/config.py -a config/option_copy.py >> test_res.html -coverage run --source=../commands/config.py -a config/option_edit.py >> test_res.html -coverage run --source=../commands/config.py,../commands/log.py,../src/xmlManager.py,../src/logger.py -a log/launch_browser.py >> test_res.html -coverage run --source=../commands/config.py,../commands/log.py,../src/xmlManager.py,../src/logger.py -a log/launch_browser2.py >> test_res.html -coverage run --source=../commands/config.py,../commands/source.py,../commands/patch.py,../commands/prepare.py -a prepare/test_source.py >> test_res.html -coverage run --source=../commands/config.py,../commands/source.py,../commands/patch.py,../commands/prepare.py -a prepare/test_patch.py >> test_res.html -coverage run --source=../commands/config.py,../commands/source.py,../commands/patch.py,../commands/prepare.py -a prepare/test_prepare.py >> test_res.html -coverage run --source=../commands/config.py,../commands/source.py,../commands/patch.py,../commands/prepare.py,../commands/clean.py -a prepare/test_clean.py >> test_res.html -coverage run --source=../commands/config.py,../commands/environ.py -a environ/test_environ.py >> test_res.html -coverage run --source=../commands/config.py,../commands/configure.py,../commands/environ.py -a compilation/test_configure.py >> test_res.html -coverage run --source=../commands/config.py,../commands/make.py,../commands/environ.py -a compilation/test_make.py >> test_res.html -coverage run --source=../commands/config.py,../commands/makeinstall.py,../commands/environ.py -a compilation/test_makeinstall.py >> test_res.html -coverage run --source=../commands/config.py,../commands/compile.py,../commands/configure.py,../commands/make.py,../commands/makeinstall.py,../commands/environ.py -a compilation/test_compilation.py >> test_res.html -coverage run --source=../commands/shell.py -a shell/test_shell.py >> test_res.html -coverage run --source=../commands/job.py -a job/test_job.py >> test_res.html -coverage run --source=../commands/jobs.py -a jobs/test_jobs.py >> test_res.html -coverage run --source=../commands/test.py,../src/test_module.py,../src/fork.py -a test/test_command.py >> test_res.html -echo "****************************" -echo -echo "building html coverage" -coverage html -echo "Done" -echo -echo "End date:" -date -echo - -#firefox test_res.html htmlcov/index.html diff --git a/test/shell/test_shell.py b/test/shell/test_shell.py deleted file mode 100755 index 80f579e..0000000 --- a/test/shell/test_shell.py +++ /dev/null @@ -1,91 +0,0 @@ -#!/usr/bin/env python -#-*- coding:utf-8 -*- - -# Copyright (C) 2010-2018 CEA/DEN -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -import os -import sys -import unittest - -from src.salomeTools import Sat - -class TestCase(unittest.TestCase): - """Test of the shell command""" - - def test_010(self): - # Test the shell command with the --command option - OK = 'KO' - tmp_file = "/tmp/test.txt" - - sat = Sat("-l " + tmp_file) - - sat.config() - sat_way = sat.cfg.VARS.salometoolsway - - # Execute the shell command - sat.shell("--command ls " + sat_way) - - ff = open(tmp_file, "r") - log_files = ff.readlines() - ff.close() - os.remove(tmp_file) - log_files = [line.replace("\n", "") for line in log_files] - - text = open(log_files[2], "r").read() - - if "salomeTools.py" in text: - OK = 'OK' - self.assertEqual(OK, 'OK') - - def test_020(self): - # Test the shell command with the --command option with a failing command - OK = 'KO' - tmp_file = "/tmp/test.txt" - - sat = Sat("-l " + tmp_file) - - sat.config() - - # Execute the shell command - res = sat.shell("--command i_fail") - - ff = open(tmp_file, "r") - log_files = ff.readlines() - ff.close() - os.remove(tmp_file) - log_files = [line.replace("\n", "") for line in log_files] - - text = open(log_files[2], "r").read() - - if "i_fail" in text and res == 1: - OK = 'OK' - self.assertEqual(OK, 'OK') - - def test_030(self): - # Test the sat -h shell - OK = "KO" - - import shell - - if "Executes the shell command passed as argument" in shell.description(): - OK = "OK" - self.assertEqual(OK, "OK") - -# test launch -if __name__ == '__main__': - unittest.main() - pass diff --git a/test/test/test_command.py b/test/test/test_command.py deleted file mode 100755 index 136df62..0000000 --- a/test/test/test_command.py +++ /dev/null @@ -1,88 +0,0 @@ -#!/usr/bin/env python -#-*- coding:utf-8 -*- - -# Copyright (C) 2010-2018 CEA/DEN -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -import os -import sys -import unittest - -from src.salomeTools import Sat - -class TestTest(unittest.TestCase): - """Test of the test command""" - - def test_010(self): - # Test the test command - OK = 'KO' - tmp_file = "/tmp/test.txt" - application = "SALOME-7.8.0" - - sat = Sat("-l " + tmp_file) - - # Execute the job command - sat.test(application + " --grid GEOM --session light" ) - - ff = open(tmp_file, "r") - log_files = ff.readlines() - ff.close() - os.remove(tmp_file) - log_testboard = [line.replace("\n", "") for line in log_files if 'testboard.xml' in line] - - text = open(log_testboard[0], "r").read() - - if '' 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 '' in text: - OK = 'OK' - self.assertEqual(OK, 'OK') - - def test_030(self): - # Test the sat -h test - OK = "KO" - - import test - - if "The test command runs a test base on a SALOME installation" in test.description(): - OK = "OK" - self.assertEqual(OK, "OK") - -# test launch -if __name__ == '__main__': - unittest.main() - pass diff --git a/test/test_020_debug.py b/test/test_020_debug.py new file mode 100755 index 0000000..27e46ef --- /dev/null +++ b/test/test_020_debug.py @@ -0,0 +1,126 @@ +#!/usr/bin/env python +#-*- coding:utf-8 -*- + +# Copyright (C) 2010-2018 CEA/DEN +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import os +import sys +import unittest + +import src.debug as DBG # Easy print stderr (for DEBUG only) +import src.pyconf as PYF # 0.3.7 +import config_0_3_9.config as PYF9 # TODO 0.3.9 + +_EXAMPLES = { +1 : """\ + messages: + [ + { + stream : "sys.stderr" # modified + message: 111 # modified + name: 'Harry' + } + { + stream : $messages[0].stream + message: 1.23e4 # modified do not work 0.3.7 + name: 'Ruud' + } + { + stream : "HELLO " + $messages[0].stream + message: 'Bienvenue' + name: "Yves" + } + ] +""", + +2 : """\ + aa: 111 + bb: $aa + 222 +""", + +3 : """\ + aa: Yves + bb: "Herve" # avoid Hervé -> 'utf8' codec can't decode byte +""", + +4 : """\ + aa: Yves + bb: "Hervé" # avoid Hervé -> 'utf8' codec can't decode byte +""", + + +} + + +class TestCase(unittest.TestCase): + "Test the debug.py""" + + def test_000(self): + # one shot setUp() for this TestCase + # DBG.push_debug(True) + # SAT.setNotLocale() # test english + return + + def test_005(self): + res = DBG.getLocalEnv() + self.assertTrue(len(res.split()) > 0) + self.assertTrue("USER :" in res) + self.assertTrue("LANG :" in res) + + def test_010(self): + inStream = DBG.InStream(_EXAMPLES[1]) + self.assertEqual(inStream.getvalue(), _EXAMPLES[1]) + cfg = PYF.Config(inStream) + self.assertEqual(len(cfg.messages), 3) + outStream = DBG.OutStream() + DBG.saveConfigStd(cfg, outStream) + res = outStream.value + DBG.write("test_010 cfg std", res) + self.assertTrue("messages :" in res) + self.assertTrue("'sys.stderr'" in res) + + def test_020(self): + inStream = DBG.InStream(_EXAMPLES[2]) + cfg = PYF.Config(inStream) + res = DBG.getStrConfigDbg(cfg) + DBG.write("test_020 cfg dbg", res) + ress = res.split("\n") + self.assertTrue(".aa : '111'" in ress[0]) + self.assertTrue(".bb : $aa + 222 --> '333'" in ress[1]) + + def test_025(self): + inStream = DBG.InStream(_EXAMPLES[1]) + cfg = PYF.Config(inStream) + outStream = DBG.OutStream() + DBG.saveConfigDbg(cfg, outStream) + res = outStream.value + DBG.write("test_025 cfg dbg", res) + for i in range(len(cfg.messages)): + self.assertTrue("messages[%i].name" % i in res) + self.assertTrue("--> 'HELLO sys.stderr'" in res) + + + def test_999(self): + # one shot tearDown() for this TestCase + # SAT.setLocale() # end test english + # DBG.pop_debug() + return + +if __name__ == '__main__': + unittest.main(exit=False) + pass + diff --git a/test/test_025_pyconf.py b/test/test_025_pyconf.py new file mode 100755 index 0000000..8d1107f --- /dev/null +++ b/test/test_025_pyconf.py @@ -0,0 +1,151 @@ +#!/usr/bin/env python +#-*- coding:utf-8 -*- + +# Copyright (C) 2010-2018 CEA/DEN +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import os +import sys +import unittest + +import src.debug as DBG # Easy print stderr (for DEBUG only) +import src.pyconf as PYF # 0.3.7 +import config_0_3_9.config as PYF9 # TODO 0.3.9 + +_EXAMPLES = { +1 : """\ + messages: + [ + { + stream : "sys.stderr" # modified + message: 'Welcome' + name: 'Harry' + } + { + stream : "sys.stdout" # modified + message: 'Welkom' + name: 'Ruud' + } + { + stream : $messages[0].stream + message: 'Bienvenue' + name: "Yves" + } + ] +""", + +2 : """\ + aa: 111 + bb: $aa + 222 +""", + +3 : """\ + aa: Yves + bb: "Herve" # avoid Hervé -> 'utf8' codec can't decode byte +""", + +4 : """\ + aa: Yves + bb: "Hervé" # avoid Hervé -> 'utf8' codec can't decode byte +""", + + +} + + +class TestCase(unittest.TestCase): + "Test the pyconf.py""" + + def test_000(self): + # one shot setUp() for this TestCase + # DBG.push_debug(True) + # SAT.setNotLocale() # test english + return + + def test_010(self): + # pyconf.py doc example 0.3.7 + # https://www.red-dove.com/config-doc/ is 0.3.9 ! + # which, when run, would yield the console output: + + expected = """\ +Welcome, Harry +Welkom, Ruud +Bienvenue, Yves +""" + inStream = DBG.InStream(_EXAMPLES[1]) + cfg = PYF.Config(inStream) + res = '' + for m in cfg.messages: + res += '%s, %s\n' % (m.message, m.name) + self.assertEqual(res, expected) + outStream = DBG.OutStream() + cfg.__save__(outStream) # sat renamed save() in __save__() + res = outStream.value + DBG.write("test_010 cfg", res) + self.assertTrue("name : 'Harry'" in res) + self.assertTrue("name : 'Ruud'" in res) + self.assertTrue("name : 'Yves'" in res) + + def test_020(self): + cfg = PYF.Config() + self.assertEqual(str(cfg), '{}') + self.assertEqual(cfg.__repr__(), '{}') + cfg.aa = "1111" + self.assertEqual(str(cfg), "{'aa': '1111'}") + cfg.bb = 2222 + self.assertTrue("'bb': 2222" in str(cfg)) + self.assertTrue("'aa': '1111'" in str(cfg)) + cfg.cc = 3333. + self.assertTrue("'cc': 3333." in str(cfg)) + + def test_030(self): + inStream = DBG.InStream(_EXAMPLES[2]) + cfg = PYF.Config(inStream) + self.assertEqual(str(cfg), "{'aa': 111, 'bb': $aa + 222}") + self.assertEqual(cfg.aa, 111) + self.assertEqual(cfg.bb, 333) + + def test_040(self): + inStream = DBG.InStream(_EXAMPLES[3]) + cfg = PYF.Config(inStream) + self.assertEqual(cfg.aa, "Yves") + self.assertEqual(cfg.bb, "Herve") + self.assertEqual(type(cfg.bb), str) + cfg.bb = "Hervé" # try this + self.assertEqual(type(cfg.bb), str) + self.assertEqual(cfg.bb, "Hervé") + + def test_045(self): + """TODO: make Hervé valid with pyconf.py as 0.3.9""" + inStream = DBG.InStream(_EXAMPLES[4]) + cfg = PYF9.Config(inStream) + outStream = DBG.OutStream() + cfg.save(outStream) # sat renamed save() in __save__() + res = outStream.value + DBG.write("test_045 cfg", res) + self.assertTrue("aa : 'Yves'" in res) + self.assertTrue(r"bb : 'Herv\xc3\xa9'" in res) + self.assertEqual(cfg.bb, "Hervé") + + def test_999(self): + # one shot tearDown() for this TestCase + # SAT.setLocale() # end test english + # DBG.pop_debug() + return + +if __name__ == '__main__': + unittest.main(exit=False) + pass diff --git a/test/test_030_pyconf_0_3_9.py b/test/test_030_pyconf_0_3_9.py new file mode 100755 index 0000000..209d622 --- /dev/null +++ b/test/test_030_pyconf_0_3_9.py @@ -0,0 +1,455 @@ +#!/usr/bin/env python +#-*- coding:utf-8 -*- + +# Copyright 2004-2010 by Vinay Sajip. All Rights Reserved. +# +# Permission to use, copy, modify, and distribute this software and its +# documentation for any purpose and without fee is hereby granted, +# provided that the above copyright notice appear in all copies and that +# both that copyright notice and this permission notice appear in +# supporting documentation, and that the name of Vinay Sajip +# not be used in advertising or publicity pertaining to distribution +# of the software without specific, written prior permission. +# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL +# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER +# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +""" +Test harness for the configuration module 'config' for Python. + +from test_config 0.3.9 modified to test 0.3.7.1 +this test obviously have FAILED (errors=6), +TODO, fix upgrading 0.3.9, or not. +""" + +import unittest +# import test_support +import src.pyconf as config +from src.pyconf import Config, ConfigMerger, ConfigList +from src.pyconf import ConfigError, ConfigFormatError, ConfigResolutionError +import logging +from StringIO import StringIO + +STREAMS = { + "simple_1" : +""" +message: 'Hello, world!' +""", + "malformed_1" : +""" +123 +""", + "malformed_2" : +""" +[ 123, 'abc' ] +""", + "malformed_3" : +""" +{ a : 7, b : 1.3, c : 'test' } +""", + "malformed_4" : +""" +test: $a [7] # note space before bracket +""", + "malformed_5" : +""" +test: 'abc' +test: 'def' +""", + "wellformed_1" : +""" +test: $a[7] # note no space before bracket +""", + "boolean_1": +""" +test : False +another_test: True +""", + "boolean_2": +""" +test : false +another_test: true +""", + "none_1": +""" +test : None +""", + "none_2": +""" +test : none +""", + "number_1": +""" +root: 1 +stream: 1.7 +neg: -1 +negfloat: -2.0 +posexponent: 2.0999999e-08 +negexponent: -2.0999999e-08 +exponent: 2.0999999e08 +""", + "sequence_1": +""" +mixed: [ "VALIGN", [ 0, 0 ], [ -1, -1 ], "TOP" ] +simple: [1, 2] +nested: [1, [2, 3], [4, [5, 6]]] +""", + "include_1": +""" +included: @'include_2' +""", + "include_2": +""" +test: 123 +another_test: 'abc' +""", + "expr_1": +""" +value1 : 10 +value2 : 5 +value3 : 'abc' +value4 : 'ghi' +value5 : 0 +value6 : { 'a' : $value1, 'b': $value2 } +derived1 : $value1 + $value2 +derived2 : $value1 - $value2 +derived3 : $value1 * $value2 +derived4 : $value1 / $value2 +derived5 : $value1 % $value2 +derived6 : $value3 + $value4 +derived7 : $value3 + 'def' + $value4 +derived8 : $value3 - $value4 # meaningless +derived9 : $value1 / $value5 # div by zero +derived10 : $value1 % $value5 # div by zero +derived11 : $value17 # doesn't exist +derived12 : $value6.a + $value6.b +""", + "eval_1": +""" +stderr : `sys.stderr` +stdout : `sys.stdout` +stdin : `sys.stdin` +debug : `debug` +DEBUG : `DEBUG` +derived: $DEBUG * 10 +""", + "merge_1": +""" +value1: True +value3: [1, 2, 3] +value5: [ 7 ] +value6: { 'a' : 1, 'c' : 3 } +""", + "merge_2": +""" +value2: False +value4: [4, 5, 6] +value5: ['abc'] +value6: { 'b' : 2, 'd' : 4 } +""", + "merge_3": +""" +value1: True +value2: 3 +value3: [1, 3, 5] +value4: [1, 3, 5] +""", + "merge_4": +""" +value1: False +value2: 4 +value3: [2, 4, 6] +value4: [2, 4, 6] +""", + "list_1": +""" +verbosity : 1 +""", + "list_2": +""" +verbosity : 2 +program_value: 4 +""", + "list_3": +""" +verbosity : 3 +suite_value: 5 +""", + "get_1": +""" +value1 : 123 +value2 : 'abcd' +value3 : True +value4 : None +value5: +{ + value1 : 123 + value2 : 'abcd' + value3 : True + value4 : None +} +""", + "multiline_1": +""" +value1: '''Value One +Value Two +''' +value2: \"\"\"Value Three +Value Four\"\"\" +""" +} + +def makeStream(name): + s = StringIO(STREAMS[name]) + s.name = name + return s + +class OutStream(StringIO): + def close(self): + self.value = self.getvalue() + StringIO.close(self) + +class TestConfig(unittest.TestCase): + + def setUp(self): + self.cfg = Config(None) + + def tearDown(self): + del self.cfg + + def testCreation(self): + self.assertEqual(0, len(self.cfg)) # should be empty + + def testSimple(self): + self.cfg.load(makeStream("simple_1")) + self.failUnless('message' in self.cfg) + self.failIf('root' in self.cfg) + self.failIf('stream' in self.cfg) + self.failIf('load' in self.cfg) + self.failIf('save' in self.cfg) + + def testValueOnly(self): + self.assertRaises(ConfigError, self.cfg.load, + makeStream("malformed_1")) + self.assertRaises(ConfigError, self.cfg.load, + makeStream("malformed_2")) + self.assertRaises(ConfigError, self.cfg.load, + makeStream("malformed_3")) + + def testBadBracket(self): + self.assertRaises(ConfigError, self.cfg.load, + makeStream("malformed_4")) + + def testDuplicate(self): + self.assertRaises(ConfigError, self.cfg.load, + makeStream("malformed_5")) + + def testGoodBracket(self): + self.cfg.load(makeStream("wellformed_1")) + + def testBoolean(self): + self.cfg.load(makeStream("boolean_1")) + self.assertEqual(True, self.cfg.another_test) + self.assertEqual(False, self.cfg.test) + + def testNotBoolean(self): + self.cfg.load(makeStream("boolean_2")) + self.assertEqual('true', self.cfg.another_test) + self.assertEqual('false', self.cfg.test) + + def testNone(self): + self.cfg.load(makeStream("none_1")) + self.assertEqual(None, self.cfg.test) + + def testNotNone(self): + self.cfg.load(makeStream("none_2")) + self.assertEqual('none', self.cfg.test) + + def testNumber(self): + self.cfg.load(makeStream("number_1")) + self.assertEqual(1, self.cfg.root) + self.assertEqual(1.7, self.cfg.stream) + self.assertEqual(-1, self.cfg.neg) + self.assertEqual(-2.0, self.cfg.negfloat) + self.assertAlmostEqual(-2.0999999e-08, self.cfg.negexponent) + self.assertAlmostEqual(2.0999999e-08, self.cfg.posexponent) + self.assertAlmostEqual(2.0999999e08, self.cfg.exponent) + + def testChange(self): + self.cfg.load(makeStream("simple_1")) + self.cfg.message = 'Goodbye, cruel world!' + self.assertEqual('Goodbye, cruel world!', self.cfg.message) + + def testSave(self): + self.cfg.load(makeStream("simple_1")) + self.cfg.message = 'Goodbye, cruel world!' + out = OutStream() + self.cfg.save(out) + self.assertEqual("message : 'Goodbye, cruel world!'" + config.NEWLINE, + out.value) + + def testInclude(self): + config.streamOpener = makeStream + self.cfg = Config("include_1") + config.streamOpener = config.defaultStreamOpener + out = OutStream() + self.cfg.save(out) + s = "included :%s{%s test : 123%s another_test : 'abc'%s}%s" % (5 * + (config.NEWLINE,)) + self.assertEqual(s, out.value) + + def testExpression(self): + self.cfg.load(makeStream("expr_1")) + self.assertEqual(15, self.cfg.derived1) + self.assertEqual(5, self.cfg.derived2) + self.assertEqual(50, self.cfg.derived3) + self.assertEqual(2, self.cfg.derived4) + self.assertEqual(0, self.cfg.derived5) + self.assertEqual('abcghi', self.cfg.derived6) + self.assertEqual('abcdefghi', self.cfg.derived7) + self.assertRaises(TypeError, lambda x: x.derived8, self.cfg) + self.assertRaises(ZeroDivisionError, lambda x: x.derived9, self.cfg) + self.assertRaises(ZeroDivisionError, lambda x: x.derived10, self.cfg) + self.assertRaises(ConfigResolutionError, + lambda x: x.derived11, self.cfg) + self.assertEqual(15, self.cfg.derived12) + + def testEval(self): + import sys, logging + self.cfg.load(makeStream("eval_1")) + self.assertEqual(sys.stderr, self.cfg.stderr) + self.assertEqual(sys.stdout, self.cfg.stdout) + self.assertEqual(sys.stdin, self.cfg.stdin) + self.assertRaises(ConfigResolutionError, lambda x: x.debug, self.cfg) + self.cfg.addNamespace(logging.Logger) + self.assertEqual(logging.Logger.debug.im_func, self.cfg.debug) + self.assertRaises(ConfigResolutionError, lambda x: x.DEBUG, self.cfg) + self.cfg.addNamespace(logging) + self.assertEqual(logging.DEBUG, self.cfg.DEBUG) + self.cfg.removeNamespace(logging.Logger) + self.assertEqual(logging.debug, self.cfg.debug) + self.assertEqual(logging.DEBUG * 10, self.cfg.derived) + + def testFunctions(self): + makePath = config.makePath + isWord = config.isWord + self.assertEqual('suffix', makePath('', 'suffix')) + self.assertEqual('suffix', makePath(None, 'suffix')) + self.assertEqual('prefix.suffix', makePath('prefix', 'suffix')) + self.assertEqual('prefix[1]', makePath('prefix', '[1]')) + self.failUnless(isWord('a9')) + self.failUnless(isWord('9a')) #perverse, but there you go + self.failIf(isWord(9)) + self.failIf(isWord(None)) + self.failIf(isWord(self)) + self.failIf(isWord('')) + + def testMerge(self): + cfg1 = Config() + cfg1.load(makeStream("merge_1")) + cfg2 = Config(makeStream("merge_2")) + ConfigMerger().merge(cfg1, cfg2) + merged = cfg1 + cfg1 = Config() + cfg1.load(makeStream("merge_1")) + for i in xrange(0, 5): + key = 'value%d' % (i + 1,) + self.failUnless(key in merged) + self.assertEqual(len(cfg1.value5) + len(cfg2.value5), + len(merged.value5)) + cfg3 = Config() + cfg3.load(makeStream("merge_3")) + cfg4 = Config(makeStream("merge_4")) + merger = ConfigMerger() + self.assertRaises(ConfigError, merger.merge, cfg3, cfg4) + + cfg3 = Config(makeStream("merge_3")) + cfg4 = Config(makeStream("merge_4")) + merger = ConfigMerger(config.overwriteMergeResolve) + merger.merge(cfg3, cfg4) + self.assertEqual(False, cfg3['value1']) + self.assertEqual(4, cfg3['value2']) + + def customMergeResolve(map1, map2, key): + if key == "value3": + rv = "overwrite" + else: + rv = config.overwriteMergeResolve(map1, map2, key) + return rv + + cfg3 = Config(makeStream("merge_3")) + cfg4 = Config(makeStream("merge_4")) + merger = ConfigMerger(customMergeResolve) + merger.merge(cfg3, cfg4) + self.assertEqual("[2, 4, 6]", str(cfg3.value3)) + self.assertEqual("[1, 3, 5, 2, 4, 6]", str(cfg3.value4)) + + def testList(self): + list = ConfigList() + list.append(Config(makeStream("list_1"))) + list.append(Config(makeStream("list_2"))) + list.append(Config(makeStream("list_3"))) + self.assertEqual(1, list.getByPath('verbosity')) + self.assertEqual(4, list.getByPath('program_value')) + self.assertEqual(5, list.getByPath('suite_value')) + self.assertRaises(ConfigError, list.getByPath, 'nonexistent_value') + + def testGet(self): + cfg = self.cfg + cfg.load(makeStream("get_1")) + self.assertEqual(123, cfg.get('value1')) + self.assertEqual(123, cfg.get('value1', -123)) + self.assertEqual(-123, cfg.get('value11', -123)) + self.assertEqual('abcd', cfg.get('value2')) + self.failUnless(cfg.get('value3')) + self.failIf(cfg.get('value4') is not None) + self.assertEqual(123, cfg.value5.get('value1')) + self.assertEqual(123, cfg.value5.get('value1', -123)) + self.assertEqual(-123, cfg.value5.get('value11', -123)) + self.assertEqual('abcd', cfg.value5.get('value2')) + self.failUnless(cfg.value5.get('value3')) + self.failIf(cfg.value5.get('value4') is not None) + + def testMultiline(self): + cfg = self.cfg + cfg.load(makeStream("multiline_1")) + self.assertEqual("Value One\nValue Two\n", cfg.get('value1')) + self.assertEqual("Value Three\nValue Four", cfg.get('value2')) + + def testSequence(self): + cfg = self.cfg + strm = makeStream("sequence_1") + cfg.load(strm) + self.assertEqual(str(cfg.simple), "[1, 2]") + self.assertEqual(str(cfg.nested), "[1, [2, 3], [4, [5, 6]]]") + self.assertEqual(str(cfg.mixed), "['VALIGN', [0, 0], [-1, -1], 'TOP']") + + def testJSON(self): + data = StringIO('dummy: ' + open('styles.json', 'r').read()) + self.cfg.load(data) + +def init_logging(): + logging.basicConfig(level=logging.DEBUG, filename="test_config.log", + filemode="w", format="%(asctime)s %(levelname)-5s %(name)-10s %(message)s") +""" +def test_main(): + init_logging() + test_support.run_unittest(TestConfig) +""" + +if __name__ == "__main__": + # test_main() + unittest.main(exit=False) + import sys + sys.stderr.write(""" + +########################################################### +WARNING: this test obviously have 'FAILED (errors=6)', +TODO: fix upgrading 0.3.9, (or not). +########################################################### +""") + pass + diff --git a/test/test_100_satHelp.py b/test/test_100_satHelp.py new file mode 100755 index 0000000..0ffef0e --- /dev/null +++ b/test/test_100_satHelp.py @@ -0,0 +1,120 @@ +#!/usr/bin/env python +#-*- coding:utf-8 -*- + +# Copyright (C) 2010-2018 CEA/DEN +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import os +import sys +import unittest + +import src.salomeTools as SAT +import src.debug as DBG # Easy print stderr (for DEBUG only) +import src.loggingSat as LOG + +class TestCase(unittest.TestCase): + "Test the sat --help commands""" + + logger = LOG.getUnittestLogger() + debug = False + + def tearDown(self): + # print "tearDown", __file__ + # assure self.logger clear for next test + logs = self.logger.getLogsAndClear() + # using assertNotIn() is too much verbose + self.assertFalse("ERROR" in logs) + self.assertFalse("CRITICAL" in logs) + + def test_000(self): + # one shot setUp() for this TestCase + if self.debug: DBG.push_debug(True) + SAT.setNotLocale() # test english + + def test_999(self): + # one shot tearDown() for this TestCase + SAT.setLocale() # end test english + if self.debug: DBG.pop_debug() + + def test_010(self): + cmd = "sat --help" + stdout, stderr = SAT.launchSat(cmd) + DBG.write("test_010 stdout", stdout) + DBG.write("test_010 stderr", stderr) + self.assertEqual(stderr, "") + self.assertTrue(" - config" in stdout) + self.assertTrue(" - prepare" in stdout) + self.assertTrue(" - compile" in stdout) + + def test_011(self): + cmd = "--help" + s = SAT.Sat(self.logger) + returnCode = s.execute_cli(cmd) + self.assertTrue(returnCode.isOk()) + logs = self.logger.getLogs() + DBG.write("test_011 logger", logs) + self.assertTrue(" - config" in logs) + self.assertTrue(" - prepare" in logs) + self.assertTrue(" - compile" in logs) + + def test_030(self): + cmd = "sat config --help" + stdout, stderr = SAT.launchSat(cmd) + DBG.write("test_030 stdout", stdout) + self.assertEqual(stderr, "") + self.assertTrue("--value" in stdout) + + def test_031(self): + cmd = "config --help" + s = SAT.Sat(self.logger) + returnCode = s.execute_cli(cmd) + self.assertTrue(returnCode.isOk()) + logs = self.logger.getLogs() + DBG.write("test_031 logger", logs) + self.assertTrue("--value" in logs) + + def xxtest_040(self): + cmd = "config --list" + s = SAT.Sat(self.logger) + returnCode = s.execute_cli(cmd) + self.assertTrue(returnCode.isOk()) + logs = self.logger.getLogs() + self.assertTrue("--value" in logs) + + def test_050(self): + cmds = SAT.getCommandsList() + DBG.write("test_050 getCommandsList", cmds) + for c in cmds: + cmd = "sat %s --help" % c + stdout, stderr = SAT.launchSat(cmd) + self.assertEqual(stderr, "") + self.assertTrue(c in stdout) + self.assertTrue("Available options" in stdout) + + def test_051(self): + cmds = SAT.getCommandsList() + for c in cmds: + cmd = "%s --help" % c + s = SAT.Sat(self.logger) + returnCode = s.execute_cli(cmd) + self.assertTrue(returnCode.isOk()) + logs = self.logger.getLogsAndClear() + DBG.write(cmd, logs, True) + self.assertTrue("Available options" in logs) + +if __name__ == '__main__': + unittest.main(exit=False) + pass diff --git a/test/test_500_APPLI_TEST.py b/test/test_500_APPLI_TEST.py new file mode 100755 index 0000000..dcb58c7 --- /dev/null +++ b/test/test_500_APPLI_TEST.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python +#-*- coding:utf-8 -*- + +# Copyright (C) 2010-2018 CEA/DEN +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import os +import sys +import unittest + +import src.salomeTools as SAT +import src.debug as DBG # Easy print stderr (for DEBUG only) +import src.loggingSat as LOG + +class TestCase(unittest.TestCase): + "Test the sat commands on APPLI_TEST configuration pyconf etc. files""" + + logger = LOG.getUnittestLogger() + debug = False + + def tearDown(self): + # print "tearDown", __file__ + # assure self.logger clear for next test + logs = self.logger.getLogsAndClear() + # using assertNotIn() is too much verbose + self.assertFalse("ERROR" in logs) + self.assertFalse("CRITICAL" in logs) + + def test_000(self): + # one shot setUp() for this TestCase + if self.debug: DBG.push_debug(True) + SAT.setNotLocale() # test english + return + + def test_999(self): + # one shot tearDown() for this TestCase + SAT.setLocale() # end test english + if self.debug: DBG.pop_debug() + + def test_010(self): + cmd = "-v 5 config -l" + s = SAT.Sat(self.logger) + DBG.write("s.getConfig()", s.getConfig()) #none + DBG.write("s.__dict__", s.__dict__) # have + returnCode = s.execute_cli(cmd) + self.assertTrue(returnCode.isOk()) + +if __name__ == '__main__': + unittest.main(exit=False) + pass diff --git a/test/test_sat5_0/__init__.py b/test/test_sat5_0/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/test_sat5_0/compilation/test_compilation.py b/test/test_sat5_0/compilation/test_compilation.py new file mode 100755 index 0000000..79192ad --- /dev/null +++ b/test/test_sat5_0/compilation/test_compilation.py @@ -0,0 +1,227 @@ +#!/usr/bin/env python +#-*- coding:utf-8 -*- + +# Copyright (C) 2010-2018 CEA/DEN +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import os +import sys +import unittest + +import src.product +from src.salomeTools import Sat + +class TestCase(unittest.TestCase): + """Test of the compile command""" + + def test_010(self): + # Test the compile command with '--products' option + OK = 'KO' + + appli = 'appli-test' + product_name = 'PRODUCT_GIT' + + sat = Sat() + + sat.prepare(appli + ' --product ' + product_name) + expected_install_dir = src.product.get_product_config(sat.cfg, product_name).install_dir + expected_file_path = os.path.join(expected_install_dir, 'bin/hello') + + sat.clean(appli + ' --build --install --product ' + product_name, batch=True) + sat.compile(appli + ' --product ' + product_name) + + if os.path.exists(expected_file_path): + OK = 'OK' + # pyunit method to compare 2 str + self.assertEqual(OK, 'OK') + + def test_020(self): + # Test the configure command with '--fathers' option + OK = 'KO' + + appli = 'appli-test' + product_name = 'PRODUCT_GIT' + product_name2 = 'PRODUCT_ARCHIVE' + + sat = Sat() + + sat.prepare(appli + ' --product ' + product_name +"," +product_name2) + expected_install_dir = src.product.get_product_config(sat.cfg, product_name).install_dir + expected_file_path = os.path.join(expected_install_dir, 'bin/hello') + expected_install_dir2 = src.product.get_product_config(sat.cfg, product_name2).install_dir + expected_file_path2 = os.path.join(expected_install_dir2, 'bin/hello-archive') + + sat.clean(appli + ' --build --install --product ' + product_name +"," +product_name2, batch=True) + sat.compile(appli + ' --with_fathers --product ' + product_name) + + if os.path.exists(expected_file_path) and os.path.exists(expected_file_path2): + OK = 'OK' + # pyunit method to compare 2 str + self.assertEqual(OK, 'OK') + + def test_030(self): + # Test the configure command with '--children' option + OK = 'KO' + + appli = 'appli-test' + product_name = 'PRODUCT_GIT' + product_name2 = 'PRODUCT_ARCHIVE' + + sat = Sat() + + sat.prepare(appli + ' --product ' + product_name +"," +product_name2) + expected_install_dir = src.product.get_product_config(sat.cfg, product_name).install_dir + expected_file_path = os.path.join(expected_install_dir, 'bin/hello') + expected_install_dir2 = src.product.get_product_config(sat.cfg, product_name2).install_dir + expected_file_path2 = os.path.join(expected_install_dir2, 'bin/hello-archive') + + sat.clean(appli + ' --build --install --product ' + product_name +"," +product_name2, batch=True) + sat.compile(appli + ' --with_children --product ' + product_name2) + + if os.path.exists(expected_file_path) and os.path.exists(expected_file_path2): + OK = 'OK' + # pyunit method to compare 2 str + self.assertEqual(OK, 'OK') + + def test_040(self): + # Test the configure command with '--clean_all' option + OK = 'KO' + + appli = 'appli-test' + product_name = 'PRODUCT_GIT' + product_name2 = 'PRODUCT_ARCHIVE' + + sat = Sat() + + sat.prepare(appli + ' --product ' + product_name +"," +product_name2) + expected_install_dir = src.product.get_product_config(sat.cfg, product_name).install_dir + expected_file_path = os.path.join(expected_install_dir, 'bin/hello') + expected_install_dir2 = src.product.get_product_config(sat.cfg, product_name2).install_dir + expected_file_path2 = os.path.join(expected_install_dir2, 'bin/hello-archive') + + sat.compile(appli + ' --with_children --product ' + product_name2) + + sat.compile(appli + ' --clean_all --with_children --product ' + product_name2, batch=True) + + if os.path.exists(expected_file_path) and os.path.exists(expected_file_path2): + OK = 'OK' + # pyunit method to compare 2 str + self.assertEqual(OK, 'OK') + + def test_050(self): + # Test the configure command with '--clean_install' option + OK = 'KO' + + appli = 'appli-test' + product_name = 'PRODUCT_GIT' + product_name2 = 'PRODUCT_ARCHIVE' + + sat = Sat() + + sat.prepare(appli + ' --product ' + product_name +"," +product_name2) + expected_install_dir = src.product.get_product_config(sat.cfg, product_name).install_dir + expected_file_path = os.path.join(expected_install_dir, 'bin/hello') + expected_install_dir2 = src.product.get_product_config(sat.cfg, product_name2).install_dir + expected_file_path2 = os.path.join(expected_install_dir2, 'bin/hello-archive') + + sat.compile(appli + ' --with_children --product ' + product_name2) + + sat.compile(appli + ' --clean_install --with_children --product ' + product_name2, batch=True) + + if os.path.exists(expected_file_path) and os.path.exists(expected_file_path2): + OK = 'OK' + # pyunit method to compare 2 str + self.assertEqual(OK, 'OK') + + def test_060(self): + # Test the configure command with '--make_flags' option + OK = 'KO' + + appli = 'appli-test' + product_name = 'PRODUCT_GIT' + + sat = Sat() + + sat.prepare(appli + ' --product ' + product_name) + expected_install_dir = src.product.get_product_config(sat.cfg, product_name).install_dir + expected_file_path = os.path.join(expected_install_dir, 'bin/hello') + + sat.clean(appli + ' --build --install --product ' + product_name, batch=True) + sat.compile(appli + ' --make_flags 3 --product ' + product_name) + + if os.path.exists(expected_file_path): + OK = 'OK' + # pyunit method to compare 2 str + self.assertEqual(OK, 'OK') + + def test_070(self): + # Test the configure command with '--show' option + OK = 'KO' + + appli = 'appli-test' + product_name = 'PRODUCT_GIT' + + sat = Sat() + + sat.prepare(appli + ' --product ' + product_name) + expected_install_dir = src.product.get_product_config(sat.cfg, product_name).install_dir + expected_file_path = os.path.join(expected_install_dir, 'bin/hello') + + sat.clean(appli + ' --build --install --product ' + product_name, batch=True) + sat.compile(appli + ' --show --product ' + product_name) + + if not(os.path.exists(expected_file_path)): + OK = 'OK' + # pyunit method to compare 2 str + self.assertEqual(OK, 'OK') + + def test_080(self): + # Test the configure command with '--stop_first_fail' option + OK = 'KO' + + appli = 'appli-test' + + sat = Sat() + + sat.prepare(appli + ' --product PRODUCT_CVS,Python') + expected_install_dir = src.product.get_product_config(sat.cfg, "PRODUCT_CVS").install_dir + + sat.clean(appli + ' --build --install --product PRODUCT_CVS', batch=True) + sat.compile(appli + ' --stop_first_fail --product PRODUCT_CVS,Python') + + if not(os.path.exists(expected_install_dir)): + OK = 'OK' + # pyunit method to compare 2 str + self.assertEqual(OK, 'OK') + + def test_090(self): + # Test the 'sat -h compile' command to get description + + OK = "KO" + + import compile + + if "The compile command constructs the products" in compile.description(): + OK = "OK" + + # pyunit method to compare 2 str + self.assertEqual(OK, "OK") + +# test launch +if __name__ == '__main__': + unittest.main() + pass + diff --git a/test/test_sat5_0/compilation/test_configure.py b/test/test_sat5_0/compilation/test_configure.py new file mode 100755 index 0000000..9d995a2 --- /dev/null +++ b/test/test_sat5_0/compilation/test_configure.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python +#-*- coding:utf-8 -*- + +# Copyright (C) 2010-2018 CEA/DEN +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import os +import sys +import unittest + +import src.product +from src.salomeTools import Sat + +class TestCase(unittest.TestCase): + """Test of the configure command""" + + def setUp(self): + print("setUp") + + def tearDown(self): + print("tearDown") + + def test_010(self): + # Test the configure command with a product in cmake + OK = 'KO' + + appli = 'appli-test' + product_name = 'PRODUCT_GIT' + + sat = Sat() + + sat.prepare(appli + ' --product ' + product_name) + expected_build_dir = src.product.get_product_config(sat.cfg, product_name).build_dir + expected_file_path = os.path.join(expected_build_dir, 'CMakeCache.txt') + + sat.configure(appli + ' --product ' + product_name) + + if os.path.exists(os.path.join(expected_build_dir, expected_file_path)): + OK = 'OK' + # pyunit method to compare 2 str + self.assertEqual(OK, 'OK') + + def test_020(self): + # Test the configure command with a product in autotools + OK = 'KO' + + appli = 'appli-test' + product_name = 'PRODUCT_CVS' + + sat = Sat() + + sat.prepare(appli + ' --product ' + product_name) + expected_build_dir = src.product.get_product_config(sat.cfg, product_name).build_dir + expected_file_path = os.path.join(expected_build_dir, 'config.log') + + sat.configure(appli + ' --product ' + product_name) + + if os.path.exists(os.path.join(expected_build_dir, expected_file_path)): + OK = 'OK' + # pyunit method to compare 2 str + self.assertEqual(OK, 'OK') + + def test_030(self): + # Test the configure command with a product in script mode + OK = 'KO' + + appli = 'appli-test' + product_name = 'Python' + + sat = Sat() + + sat.prepare(appli + ' --product ' + product_name) + expected_build_dir = src.product.get_product_config(sat.cfg, product_name).build_dir + + sat.configure(appli + ' --product ' + product_name) + + if os.path.exists(expected_build_dir): + OK = 'OK' + # pyunit method to compare 2 str + self.assertEqual(OK, 'OK') + + def test_040(self): + # Test the 'sat -h configure' + OK = "KO" + + import configure + + if "The configure command executes in the build directory" in configure.description(): + OK = "OK" + + # pyunit method to compare 2 str + self.assertEqual(OK, "OK") + +# test launch +if __name__ == '__main__': + unittest.main() + pass diff --git a/test/test_sat5_0/compilation/test_make.py b/test/test_sat5_0/compilation/test_make.py new file mode 100755 index 0000000..c956965 --- /dev/null +++ b/test/test_sat5_0/compilation/test_make.py @@ -0,0 +1,106 @@ +#!/usr/bin/env python +#-*- coding:utf-8 -*- + +# Copyright (C) 2010-2018 CEA/DEN +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import os +import sys +import unittest + +import src.product +from src.salomeTools import Sat + +class TestCase(unittest.TestCase): + """Test of the make command""" + + def test_010(self): + # Test the configure command without any option + OK = 'KO' + + appli = 'appli-test' + product_name = 'PRODUCT_GIT' + + sat = Sat() + + sat.prepare(appli + ' --product ' + product_name) + expected_build_dir = src.product.get_product_config(sat.cfg, product_name).build_dir + expected_file_path = os.path.join(expected_build_dir, 'hello') + + sat.configure(appli + ' --product ' + product_name) + sat.make(appli + ' --product ' + product_name) + + if os.path.exists(os.path.join(expected_build_dir, expected_file_path)): + OK = 'OK' + # pyunit method to compare 2 str + self.assertEqual(OK, 'OK') + + def test_020(self): + # Test the make command with an option + OK = 'KO' + appli = 'appli-test' + product_name = 'PRODUCT_GIT' + + sat = Sat() + + sat.prepare(appli + ' --product ' + product_name) + expected_build_dir = src.product.get_product_config(sat.cfg, product_name).build_dir + expected_file_path = os.path.join(expected_build_dir, 'hello') + + sat.configure(appli + ' --product ' + product_name) + sat.make(appli + ' --product ' + product_name + ' --option -j3') + + if os.path.exists(os.path.join(expected_build_dir, expected_file_path)): + OK = 'OK' + # pyunit method to compare 2 str + self.assertEqual(OK, 'OK') + + def test_030(self): + # Test the make command with a product in script mode + OK = 'KO' + + appli = 'appli-test' + product_name = 'Python' + + sat = Sat() + + sat.prepare(appli + ' --product ' + product_name) + expected_install_dir = src.product.get_product_config(sat.cfg, product_name).install_dir + expected_file = "bin/python2.7" + + sat.make(appli + ' --product ' + product_name) + + if os.path.exists(os.path.join(expected_install_dir, expected_file)): + OK = 'OK' + # pyunit method to compare 2 str + self.assertEqual(OK, 'OK') + + def test_040(self): + # Test the sat -h make + OK = "KO" + + import make + + if "The make command executes the \"make\" command" in make.description(): + OK = "OK" + + # pyunit method to compare 2 str + self.assertEqual(OK, "OK") + +# test launch +if __name__ == '__main__': + unittest.main() + pass diff --git a/test/test_sat5_0/compilation/test_makeinstall.py b/test/test_sat5_0/compilation/test_makeinstall.py new file mode 100755 index 0000000..62aba79 --- /dev/null +++ b/test/test_sat5_0/compilation/test_makeinstall.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python +#-*- coding:utf-8 -*- + +# Copyright (C) 2010-2018 CEA/DEN +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import os +import sys +import unittest + +import src.product +from src.salomeTools import Sat + +class TestMakeinstall(unittest.TestCase): + """Test of the makeinstall command""" + + def test_010(self): + # Test the configure-make-makeinstall command without any option + OK = 'KO' + + appli = 'appli-test' + product_name = 'PRODUCT_GIT' + + sat = Sat() + + sat.prepare(appli + ' --product ' + product_name) + expected_install_dir = src.product.get_product_config(sat.cfg, product_name).install_dir + expected_file_path = os.path.join(expected_install_dir, 'bin/hello') + + sat.configure(appli + ' --product ' + product_name) + + sat.make(appli + ' --product ' + product_name) + + sat.makeinstall(appli + ' --product ' + product_name) + + if os.path.exists(expected_file_path): + OK = 'OK' + # pyunit method to compare 2 str + self.assertEqual(OK, 'OK') + + def test_020(self): + # Test the sat -h make + OK = "KO" + + import makeinstall + + if "The makeinstall command executes the 'make install' command" in makeinstall.description(): + OK = "OK" + + # pyunit method to compare 2 str + self.assertEqual(OK, "OK") + +# test launch +if __name__ == '__main__': + unittest.main() + pass diff --git a/test/test_sat5_0/config/test_create_user_pyconf.py b/test/test_sat5_0/config/test_create_user_pyconf.py new file mode 100755 index 0000000..df1c0b0 --- /dev/null +++ b/test/test_sat5_0/config/test_create_user_pyconf.py @@ -0,0 +1,119 @@ +#!/usr/bin/env python +#-*- coding:utf-8 -*- + +# Copyright (C) 2010-2018 CEA/DEN +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import os +import sys +import shutil +import unittest + +from src.salomeTools import Sat + +class TestCase(unittest.TestCase): + """Test create file .pyconf""" + + def test_010(self): + # Test creation of ~/.salomeTools/salomeTools.pyconf + res = "KO" + user_dir = os.path.expanduser(os.path.join('~','.salomeTools')) + user_dir_save = os.path.expanduser(os.path.join('~','.salomeTools_save')) + if os.path.exists(user_dir_save): + shutil.rmtree(user_dir_save) + if os.path.exists(user_dir): + shutil.move(user_dir, user_dir_save) + + # The command to test + sat = Sat('') + sat.config('-v .') + + expected_file = os.path.expanduser(os.path.join('~','.salomeTools', 'salomeTools.pyconf')) + + if os.path.exists(expected_file): + res = "OK" + + shutil.rmtree(user_dir) + shutil.move(user_dir_save, user_dir) + self.assertEqual(res, "OK") + + def test_020(self): + # Test override VARS + OK = "KO" + + # The command to test + sat = Sat("-oVARS.user='user_test'") + sat.config() + + if sat.cfg.VARS.user == 'user_test': + OK = "OK" + self.assertEqual(OK, "OK") + + def test_030(self): + # Test override INTERNAL + OK = "KO" + + # The command to test + sat = Sat("-oINTERNAL.sat_version='V0'") + sat.config() + + if sat.cfg.INTERNAL.sat_version == 'V0': + OK = "OK" + self.assertEqual(OK, "OK") + + """ + def test_040(self): + # Test override SITE + OK = "KO" + + # The command to test + sat = Sat("-oSITE.jobs.config_path='/tmp'") + sat.config() + + if sat.cfg.SITE.jobs.config_path == '/tmp': + OK = "OK" + + self.assertEqual(OK, "OK") + """ + + def test_050(self): + # Test override APPLICATION + OK = "KO" + + # The command to test + sat = Sat("-oAPPLICATION.out_dir='/tmp'") + sat.config('appli-test') + + if sat.cfg.APPLICATION.out_dir == '/tmp': + OK = "OK" + self.assertEqual(OK, "OK") + + def test_060(self): + # Test override PRODUCTS + OK = "KO" + + # The command to test + sat = Sat("-oPRODUCTS.PRODUCT_GIT.default.name='test'") + sat.config('') + + if sat.cfg.PRODUCTS.PRODUCT_GIT.default.name == 'test': + OK = "OK" + self.assertEqual(OK, "OK") + +# test launch +if __name__ == '__main__': + unittest.main() + pass diff --git a/test/test_sat5_0/config/test_option_copy.py b/test/test_sat5_0/config/test_option_copy.py new file mode 100755 index 0000000..bb7fe0b --- /dev/null +++ b/test/test_sat5_0/config/test_option_copy.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python +#-*- coding:utf-8 -*- + +# Copyright (C) 2010-2018 CEA/DEN +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import os +import sys +import unittest + +from src.salomeTools import Sat + +class TestCase(unittest.TestCase): + """sat config --copy""" + + def test_010(self): + # Test the copy of a pyconf + res = "KO" + appli_to_copy = "appli-test" + + expected_file = os.path.expanduser(os.path.join('~','.salomeTools', 'Applications', 'LOCAL_' + appli_to_copy + '.pyconf')) + if os.path.exists(expected_file): + os.remove(expected_file) + + # The command to test + sat = Sat('') + sat.config('appli-test -c') + + if os.path.exists(expected_file): + res = "OK" + os.remove(expected_file) + self.assertEqual(res, "OK") + +# test launch +if __name__ == '__main__': + unittest.main() + pass diff --git a/test/test_sat5_0/config/test_option_edit.py b/test/test_sat5_0/config/test_option_edit.py new file mode 100755 index 0000000..c6674e9 --- /dev/null +++ b/test/test_sat5_0/config/test_option_edit.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python +#-*- coding:utf-8 -*- + +# Copyright (C) 2010-2018 CEA/DEN +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import os +import sys +import threading +import time +import unittest + +from src.salomeTools import Sat +from unittestpy.tools import check_proc_existence_and_kill_multi + +sleep_time = 2 + +class TestCase(unittest.TestCase): + """sat config --edit""" + + def test_010(self): + # Test the launch of the editor when invoking the config -e + OK = "KO" + + sat = Sat("-oUSER.editor='cooledit'") + sat.config() + cmd_config = threading.Thread(target=sat.config, args=('-e',)) + cmd_config.start() + + time.sleep(sleep_time) + + editor = sat.cfg.USER.editor + pid = check_proc_existence_and_kill_multi(editor + ".*" + "salomeTools\.pyconf", 10) + + if pid: + OK = "OK" + self.assertEqual(OK, "OK") + + def test_020(self): + # Test the launch of the editor when invoking the config -e appli-test + OK = "KO" + + sat = Sat("-oUSER.editor='cooledit'") + sat.config() + cmd_config = threading.Thread(target=sat.config, args=('appli-test -e',)) + cmd_config.start() + + time.sleep(sleep_time) + + editor = sat.cfg.USER.editor + pid = check_proc_existence_and_kill_multi(editor + ".*" + "appli-test\.pyconf", 10) + + if pid: + OK = "OK" + self.assertEqual(OK, "OK") + +# test launch +if __name__ == '__main__': + unittest.main() + pass diff --git a/test/test_sat5_0/config/test_option_value.py b/test/test_sat5_0/config/test_option_value.py new file mode 100755 index 0000000..50a7d84 --- /dev/null +++ b/test/test_sat5_0/config/test_option_value.py @@ -0,0 +1,109 @@ +#!/usr/bin/env python +#-*- coding:utf-8 -*- + +# Copyright (C) 2010-2018 CEA/DEN +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import os +import sys +import platform +import unittest + +from src.salomeTools import Sat +from unittestpy.tools import outRedirection + +class TestCase(unittest.TestCase): + """sat config --value""" + + def test_010(self): + # Test the display of the right value of "sat config -v VARS.hostname" + OK = "KO" + + # output redirection + my_out = outRedirection() + + # The command to test + sat = Sat() + sat.config('-v VARS.hostname') + + # stop output redirection + my_out.end_redirection() + + # get results + res = my_out.read_results() + + if platform.node() in res: + OK = "OK" + self.assertEqual(OK, "OK") + + def test_020(self): + # Test the display of the right value of "sat config -l" + OK = "KO" + + # output redirection + my_out = outRedirection() + + # The command to test + sat = Sat() + sat.config('-l') + + # stop output redirection + my_out.end_redirection() + + # get results + res = my_out.read_results() + + # get results + if "ERROR" not in res: + OK = "OK" + self.assertEqual(OK, "OK") + + """ + def test_030(self): + # Test the exception when salomeTools.pyconf has errors + OK = "KO" + + # The command to test + sat = Sat() + sat.config() + + salomeToolspyconfPath = os.path.join(sat.cfg.VARS.srcDir, "internal_config", "salomeTools.pyconf") + salomeToolspyconfPath_save = os.path.join(sat.cfg.VARS.srcDir, "internal_config", "salomeTools.pyconf_save") + if os.path.exists(salomeToolspyconfPath_save): + os.remove(salomeToolspyconfPath_save) + shutil.copyfile(salomeToolspyconfPath, salomeToolspyconfPath_save) + f_read = open(salomeToolspyconfPath, 'r') + text = f_read.read() + f_read.close() + os.remove(salomeToolspyconfPath) + f_write = open(salomeToolspyconfPath, 'w') + f_write.write(text.replace(':', '')) + f_write.close() + + try: + sat.config() + except TypeError: + OK = "OK" + finally: + shutil.copyfile(salomeToolspyconfPath_save, salomeToolspyconfPath) + os.remove(salomeToolspyconfPath_save) + self.assertEqual(OK, "OK") + """ + +# test launch +if __name__ == '__main__': + unittest.main() + pass diff --git a/test/test_sat5_0/config/test_option_value_2.py b/test/test_sat5_0/config/test_option_value_2.py new file mode 100755 index 0000000..c11fee1 --- /dev/null +++ b/test/test_sat5_0/config/test_option_value_2.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python +#-*- coding:utf-8 -*- + +# Copyright (C) 2010-2018 CEA/DEN +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import os +import sys +import platform +import unittest + +from src.salomeTools import Sat +from unittestpy.tools import outRedirection + +class TestCase(unittest.TestCase): + """sat config -v VARS.python""" + + def test_010(self): + # Test the display of the right value of 'sat config -v VARS.python' + OK = 'KO' + + # output redirection + my_out = outRedirection() + + # The command to test + sat = Sat('') + sat.config('-v VARS.python') + + # stop output redirection + my_out.end_redirection() + + # get results + res = my_out.read_results() + + + if platform.python_version() in res: + OK = 'OK' + self.assertEqual(OK, 'OK') + + def test_020(self): + # Test the display of the right value of 'sat config -s' + OK = 'KO' + + # output redirection + my_out = outRedirection() + + # The command to test + sat = Sat('') + sat.config('-s') + + # stop output redirection + my_out.end_redirection() + + # get results + res = my_out.read_results() + + + if 'INTERNAL' in res: + OK = 'OK' + self.assertEqual(OK, 'OK') + + def test_030(self): + # Test the display of the right value of 'sat config --info' + application = 'appli-test' + product = 'PRODUCT_DEV' + + OK = 'KO' + + # output redirection + my_out = outRedirection() + + # The command to test + sat = Sat('') + sat.config(application + ' --info ' + product) + + # stop output redirection + my_out.end_redirection() + + # get results + res = my_out.read_results() + + + if 'compilation method = cmake' in res: + OK = 'OK' + self.assertEqual(OK, 'OK') + +# test launch +if __name__ == '__main__': + unittest.main() + pass diff --git a/test/test_sat5_0/environ/test_environ.py b/test/test_sat5_0/environ/test_environ.py new file mode 100755 index 0000000..3a63fd5 --- /dev/null +++ b/test/test_sat5_0/environ/test_environ.py @@ -0,0 +1,150 @@ +#!/usr/bin/env python +#-*- coding:utf-8 -*- + +# Copyright (C) 2010-2018 CEA/DEN +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import os +import sys +import unittest + +from src.salomeTools import Sat + +class TestSource(unittest.TestCase): + """Test of the environ command""" + + def test_010(self): + # Test the environ command without any option + OK = 'KO' + + appli = 'appli-test' + + file_env_name = 'env_launch.sh' + + sat = Sat() + sat.config(appli) + + expected_file_path = os.path.join(sat.cfg.APPLICATION.workdir, file_env_name) + + if os.path.exists(expected_file_path): + os.remove(expected_file_path) + + sat.environ(appli) + + if os.path.exists(expected_file_path): + OK = 'OK' + self.assertEqual(OK, 'OK') + + def test_020(self): + # Test the environ command with option '--products' + OK = 'KO' + + appli = 'appli-test' + product_name = 'PRODUCT_GIT' + + file_env_name = 'env_launch.sh' + + sat = Sat() + sat.config(appli) + + expected_file_path = os.path.join(sat.cfg.APPLICATION.workdir, file_env_name) + + if os.path.exists(expected_file_path): + os.remove(expected_file_path) + + sat.environ(appli + ' --products ' + product_name) + + if os.path.exists(expected_file_path): + OK = 'OK' + self.assertEqual(OK, 'OK') + + def test_030(self): + # Test the environ command with option --target + OK = 'KO' + + appli = 'appli-test' + + file_env_name = 'env_launch.sh' + + sat = Sat() + sat.config(appli) + + expected_file_path = os.path.join('.', file_env_name) + expected_file_path2 = os.path.join('.', 'env_build.sh') + + if os.path.exists(expected_file_path): + os.remove(expected_file_path) + + sat.environ(appli + ' --target .') + + if os.path.exists(expected_file_path): + OK = 'OK' + + if os.path.exists(expected_file_path): + os.remove(expected_file_path) + os.remove(expected_file_path2) + + # pyunit method to compare 2 str + self.assertEqual(OK, 'OK') + + def test_040(self): + # Test the environ command with option --prefix + OK = 'KO' + + appli = 'appli-test' + prefix = 'TEST' + file_env_name = prefix + '_launch.sh' + + sat = Sat() + sat.config(appli) + + expected_file_path = os.path.join(sat.cfg.APPLICATION.workdir, file_env_name) + + if os.path.exists(expected_file_path): + os.remove(expected_file_path) + + sat.environ(appli + ' --prefix ' + prefix) + + if os.path.exists(expected_file_path): + OK = 'OK' + self.assertEqual(OK, 'OK') + + def test_050(self): + # Test the environ command with option --shell + OK = 'KO' + + appli = 'appli-test' + shell = 'bat' + file_env_name = 'env_launch.bat' + + sat = Sat() + sat.config(appli) + + expected_file_path = os.path.join(sat.cfg.APPLICATION.workdir, file_env_name) + + if os.path.exists(expected_file_path): + os.remove(expected_file_path) + + sat.environ(appli + ' --shell ' + shell) + + if os.path.exists(expected_file_path): + OK = 'OK' + self.assertEqual(OK, 'OK') + +# test launch +if __name__ == '__main__': + unittest.main() + pass diff --git a/test/test_sat5_0/job/test_job.py b/test/test_sat5_0/job/test_job.py new file mode 100755 index 0000000..fc23191 --- /dev/null +++ b/test/test_sat5_0/job/test_job.py @@ -0,0 +1,122 @@ +#!/usr/bin/env python +#-*- coding:utf-8 -*- + +# Copyright (C) 2010-2018 CEA/DEN +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import os +import sys +import unittest + +from src.salomeTools import Sat + +class TestCase(unittest.TestCase): + """Test the job command""" + + def test_010(self): + # Test the job command + OK = 'KO' + tmp_file = "/tmp/test.txt" + + sat = Sat("-l " + tmp_file) + + # Execute the job command + sat.job("--jobs_config .test --name Job 1" ) + + ff = open(tmp_file, "r") + log_files = ff.readlines() + ff.close() + os.remove(tmp_file) + log_config = [line.replace("\n", "") for line in log_files if 'config.xml' in line] + + text = open(log_config[0], "r").read() + + if "nb_proc" in text: + OK = 'OK' + self.assertEqual(OK, 'OK') + + + def test_020(self): + # Test the job command with a failing command + OK = 'KO' + tmp_file = "/tmp/test.txt" + + sat = Sat("-l " + tmp_file) + + # Execute the job command + res = sat.job("--jobs_config .test --name Job 4" ) + + if res == 1: + OK = 'OK' + # pyunit method to compare 2 str + self.assertEqual(OK, 'OK') + + def test_030(self): + # Test the job command with a wrong file configuration + OK = 'KO' + tmp_file = "/tmp/test.txt" + + sat = Sat("-l " + tmp_file) + + # Execute the job command + res = sat.job("--jobs_config NOTEXIST --name Job 4" ) + + if res == 1: + OK = 'OK' + self.assertEqual(OK, 'OK') + + def test_040(self): + # Test the job command without --jobs_config option + OK = 'KO' + tmp_file = "/tmp/test.txt" + + sat = Sat("-l " + tmp_file) + + # Execute the job command + res = sat.job("--name Job 4" ) + + if res == 1: + OK = 'OK' + self.assertEqual(OK, 'OK') + + def test_050(self): + # Test the job command without --jobs_config option + OK = 'KO' + tmp_file = "/tmp/test.txt" + + sat = Sat("-l " + tmp_file) + + # Execute the job command + res = sat.job("--jobs_config .test --name NOTEXIST" ) + + if res == 1: + OK = 'OK' + self.assertEqual(OK, 'OK') + + def test_060(self): + # Test the sat -h job + OK = "KO" + + import job + + if "Executes the commands of the job defined in the jobs configuration file" in job.description(): + OK = "OK" + self.assertEqual(OK, "OK") + +# test launch +if __name__ == '__main__': + unittest.main() + pass diff --git a/test/test_sat5_0/jobs/test_jobs.py b/test/test_sat5_0/jobs/test_jobs.py new file mode 100755 index 0000000..1b22378 --- /dev/null +++ b/test/test_sat5_0/jobs/test_jobs.py @@ -0,0 +1,159 @@ +#!/usr/bin/env python +#-*- coding:utf-8 -*- + +# Copyright (C) 2010-2018 CEA/DEN +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import os +import sys +import unittest + +from src.salomeTools import Sat +from unittestpy.tools import outRedirection + +class TestCase(unittest.TestCase): + "Test the jobs command""" + + def test_010(self): + # Test the jobs command + OK = 'KO' + tmp_file = "/tmp/test.txt" + + sat = Sat("-l " + tmp_file) + + # Execute the jobs command + sat.jobs("--name .test --publish" ) + + ff = open(tmp_file, "r") + log_files = ff.readlines() + ff.close() + os.remove(tmp_file) + log_jobs = [line.replace("\n", "") for line in log_files if 'jobs.xml' in line] + + text = open(log_jobs[0], "r").read() + + expected_res = [ + "Establishing connection with all the machines", + "Executing the jobs", + "Results for job" + ] + + res = 0 + for exp_res in expected_res: + if exp_res not in text: + res += 1 + + if res == 0: + OK = 'OK' + self.assertEqual(OK, 'OK') + + def test_020(self): + # Test the jobs command with option --only_jobs + OK = 'KO' + tmp_file = "/tmp/test.txt" + + sat = Sat("-l " + tmp_file) + + # Execute the jobs command + sat.jobs("--name .test --publish --only_jobs Job 1" ) + + ff = open(tmp_file, "r") + log_files = ff.readlines() + ff.close() + os.remove(tmp_file) + log_jobs = [line.replace("\n", "") for line in log_files if 'jobs.xml' in line] + + text = open(log_jobs[0], "r").read() + + expected_res = [ + "Establishing connection with all the machines", + "Executing the jobs", + "Results for job" + ] + + res = 0 + for exp_res in expected_res: + if exp_res not in text: + res += 1 + + if res == 0: + OK = 'OK' + self.assertEqual(OK, 'OK') + + def test_030(self): + # Test the jobs command without --name option + OK = 'KO' + tmp_file = "/tmp/test.txt" + + sat = Sat("-l " + tmp_file) + + # Execute the job command + res = sat.jobs() + + if res == 1: + OK = 'OK' + self.assertEqual(OK, 'OK') + + def test_040(self): + # Test the jobs command with a wrong file configuration + OK = 'KO' + tmp_file = "/tmp/test.txt" + + sat = Sat("-l " + tmp_file) + + # Execute the job command + res = sat.jobs("--name NOTEXIST" ) + + if res == 1: + OK = 'OK' + self.assertEqual(OK, 'OK') + + def test_050(self): + # Test the display of the right value of 'sat jobs --list' + OK = "KO" + + # output redirection + my_out = outRedirection() + + # The command to test + sat = Sat() + sat.jobs('--list') + + # stop output redirection + my_out.end_redirection() + + # get results + res = my_out.read_results() + + # get results + if "ERROR" not in res: + OK = "OK" + self.assertEqual(OK, "OK") + + def test_060(self): + # Test the sat -h jobs + OK = "KO" + + import jobs + + if "The jobs command launches maintenances that are described in the dedicated jobs configuration file." in jobs.description(): + OK = "OK" + self.assertEqual(OK, "OK") + +# test launch +if __name__ == '__main__': + unittest.main() + pass diff --git a/test/test_sat5_0/log/test_launch_browser.py b/test/test_sat5_0/log/test_launch_browser.py new file mode 100755 index 0000000..a9c8be4 --- /dev/null +++ b/test/test_sat5_0/log/test_launch_browser.py @@ -0,0 +1,294 @@ +#!/usr/bin/env python +#-*- coding:utf-8 -*- + +# Copyright (C) 2010-2018 CEA/DEN +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import os +import sys +import threading +import time +import shutil +import io +import unittest + +from src.salomeTools import Sat +from unittestpy.tools import check_proc_existence_and_kill_multi + +sleep_time = 2 + +class TestCase(unittest.TestCase): + """Test of log command: launch of browser""" + + def test_010(self): + # Test the write of xml log when invoking a command + OK = "KO" + + # launch the command that will write a log + sat = Sat() + sat.config('appli-test -v USER.browser') + + # get log file path + logDir = sat.cfg.USER.log_dir + logPath = os.path.join(logDir, sat.cfg.VARS.datehour + "_" + sat.cfg.VARS.command + ".xml") + + if os.path.exists(logPath): + OK = "OK" + self.assertEqual(OK, "OK") + + def test_020(self): + # Test the terminal option without application + OK = "KO" + + # launch the command that will write a log + sat = Sat() + + one = u"1" + sys.stdin = io.StringIO(one) + + + try: + sat.log('-t') + OK = "OK" + sys.stdin = sys.__stdin__ + except: + sys.stdin = sys.__stdin__ + self.assertEqual(OK, "OK") + + def test_030(self): + # Test the terminal option with application + OK = "KO" + + # launch the command that will write a log + sat = Sat() + + sat.config('appli-test -v VARS.python') + + one = u"1" + sys.stdin = io.StringIO(one) + + try: + sat.log('appli-test -t --last') + OK = "OK" + sys.stdin = sys.__stdin__ + except: + pass + self.assertEqual(OK, "OK") + + def test_040(self): + # Test the terminal option with 0 as input + OK = "KO" + + # launch the command that will write a log + sat = Sat() + + sat.config('appli-test -v VARS.python') + + zero = u"0\n1" + sys.stdin = io.StringIO(zero) + + try: + sat.log('--terminal') + OK = "OK" + finally: + sys.stdin = sys.__stdin__ + self.assertEqual(OK, "OK") + + def test_050(self): + # Test the terminal option with input bigger than the number of logs + OK = "KO" + + # launch the command that will write a log + sat = Sat() + + sat.config('appli-test -v VARS.python') + + nb_logs = len(os.listdir(sat.cfg.USER.log_dir)) + + nb_logs_u = unicode(str(nb_logs) + "\n1") + sys.stdin = io.StringIO(nb_logs_u) + + try: + sat.log('--terminal') + OK = "OK" + finally: + sys.stdin = sys.__stdin__ + self.assertEqual(OK, "OK") + + def test_060(self): + # Test the terminal option with input return + OK = "KO" + + # launch the command that will write a log + sat = Sat() + + sat.config('appli-test -v VARS.python') + + ret = unicode("\n0") + sys.stdin = io.StringIO(ret) + + try: + sat.log('--terminal') + OK = "OK" + finally: + sys.stdin = sys.__stdin__ + self.assertEqual(OK, "OK") + + def test_070(self): + # Test the terminal option with input not int + OK = "KO" + + # launch the command that will write a log + sat = Sat() + + sat.config('appli-test -v VARS.python') + + ret = unicode("blabla\n0") + sys.stdin = io.StringIO(ret) + + try: + sat.log('--terminal') + OK = "OK" + finally: + sys.stdin = sys.__stdin__ + self.assertEqual(OK, "OK") + + def test_080(self): + # Test the terminal option and option last + OK = "KO" + + # launch the command that will write a log + sat = Sat() + + try: + sat.log('--terminal --last') + OK = "OK" + finally: + sys.stdin = sys.__stdin__ + + # pyunit method to compare 2 str + self.assertEqual(OK, "OK") + + def test_090(self): + # Test the option --last + OK = "KO" + + # launch the command that will write a log + sat = Sat("-oUSER.browser='konqueror'") + + sat.config('appli-test -v VARS.python') + + + time.sleep(sleep_time) + cmd_log = threading.Thread(target=sat.log, args=('appli-test --last',)) + cmd_log.start() + + time.sleep(sleep_time) + + browser = sat.cfg.USER.browser + pid = check_proc_existence_and_kill_multi(browser + ".*" + "xml", 10) + + if pid: + OK = "OK" + self.assertEqual(OK, "OK") + + def test_100(self): + # Test the option --clean + OK = "KO" + + # launch the command that will write a log + sat = Sat() + + sat.config('-v VARS.user') + + nb_logs_t0 = len(os.listdir(sat.cfg.USER.log_dir)) + + sat.log('--clean 1') + + nb_logs_t1 = len(os.listdir(sat.cfg.USER.log_dir)) + + if nb_logs_t1-nb_logs_t0 == 0: + OK = "OK" + self.assertEqual(OK, "OK") + + def test_120(self): + # Test the option --clean with big number of files to clean + OK = "KO" + + # launch the command that will write a log + sat = Sat() + + sat.config('-v VARS.user') + + nb_logs_t0 = len(os.listdir(sat.cfg.USER.log_dir)) + + if os.path.exists(sat.cfg.USER.log_dir + "_save"): + shutil.rmtree(sat.cfg.USER.log_dir + "_save") + print("TODO: risky !!!copytree!!!", sat.cfg.USER.log_dir, sat.cfg.USER.log_dir + "_save") + """ + shutil.copytree(sat.cfg.USER.log_dir,sat.cfg.USER.log_dir + "_save") + + sat.log('--clean ' + str(nb_logs_t0)) + + nb_logs_t1 = len(os.listdir(sat.cfg.USER.log_dir)) + + shutil.rmtree(sat.cfg.USER.log_dir) + shutil.move(sat.cfg.USER.log_dir + "_save", sat.cfg.USER.log_dir) + + if nb_logs_t0-nb_logs_t1 > 10: + OK = "OK" + """ + self.assertEqual(OK, "OK") + + """ + def test_130(self): + # Test the option --full + OK = "KO" + + sat = Sat("-oUSER.browser='konqueror'") + time.sleep(sleep_time) + cmd_log = threading.Thread(target=sat.log, args=('--full',)) + cmd_log.start() + + time.sleep(sleep_time) + + browser = sat.cfg.USER.browser + check_proc_existence_and_kill_multi(browser + ".*" + "hat\.xml", 10) + + # Read and check the hat.xml file contains at least one log file corresponding to log + hatFilePath = os.path.join(sat.cfg.USER.log_dir, "hat.xml") + xmlHatFile = src.xmlManager.ReadXmlFile(hatFilePath) + for field in xmlHatFile.xmlroot: + if field.attrib[b'cmd'] == b'log': + OK = "OK" + break + self.assertEqual(OK, "OK") + """ + + def test_140(self): + # Test the sat -h log + OK = "KO" + + import log + + if "Gives access to the logs produced" in log.description(): + OK = "OK" + self.assertEqual(OK, "OK") + +# test launch +if __name__ == '__main__': + unittest.main() + pass diff --git a/test/test_sat5_0/log/test_launch_browser2.py b/test/test_sat5_0/log/test_launch_browser2.py new file mode 100755 index 0000000..38a6184 --- /dev/null +++ b/test/test_sat5_0/log/test_launch_browser2.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python +#-*- coding:utf-8 -*- + +# Copyright (C) 2010-2018 CEA/DEN +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import os +import sys +import threading +import time +import unittest + +from src.salomeTools import Sat +from unittestpy.tools import check_proc_existence_and_kill_multi + +sleep_time = 2 + +class TestCase(unittest.TestCase): + """Test of log command: launch of browser""" + + def test_010(self): + # Test the launch of browser when invoking the log command + OK = "KO" + + sat = Sat("-oUSER.browser='konqueror'") + time.sleep(sleep_time) + cmd_log = threading.Thread(target=sat.log, args=('',)) + cmd_log.start() + + time.sleep(sleep_time) + + sat.config("") + browser = sat.cfg.USER.browser + pid = check_proc_existence_and_kill_multi(browser + ".*" + "hat\.xml", 10) + + if pid: + OK = "OK" + self.assertEqual(OK, "OK") + +# test launch +if __name__ == '__main__': + unittest.main() + pass diff --git a/test/test_sat5_0/prepare/test_clean.py b/test/test_sat5_0/prepare/test_clean.py new file mode 100755 index 0000000..08bb54f --- /dev/null +++ b/test/test_sat5_0/prepare/test_clean.py @@ -0,0 +1,180 @@ +#!/usr/bin/env python +#-*- coding:utf-8 -*- + +# Copyright (C) 2010-2018 CEA/DEN +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import os +import sys +import unittest + +from src.salomeTools import Sat +import src.product +from unittestpy.tools import outRedirection + +class TestCase(unittest.TestCase): + """Test of the clean command""" + + def test_010(self): + # Test the clean command with no arguments (nothing to clean) + OK = 'KO' + + appli = 'appli-test' + + sat = Sat() + + # output redirection + my_out = outRedirection() + + sat.clean(appli) + + # stop output redirection + my_out.end_redirection() + + # get results + res = my_out.read_results() + + if "Nothing to suppress" in res: + OK = 'OK' + self.assertEqual(OK, 'OK') + + def test_020(self): + # Test the clean of sources + OK = "KO" + + appli = 'appli-test' + product_name = "PRODUCT_GIT" + + sat = Sat() + + # Make sure the sources exist + sat.prepare(appli + " -p " + product_name) + + # Call the command + sat.clean(appli + " -p " + product_name + " --sources", batch=True) + + expected_src_dir = src.product.get_product_config(sat.cfg, product_name).source_dir + + if not os.path.exists(expected_src_dir): + OK = "OK" + self.assertEqual(OK, "OK") + + def test_030(self): + # Test the clean of build + OK = "KO" + + appli = 'appli-test' + product_name = "PRODUCT_GIT" + + sat = Sat() + + # Make sure the build exists + sat.prepare(appli + " -p " + product_name) + sat.configure(appli + " -p " + product_name) + + # Call the command + sat.clean(appli + " -p " + product_name + " --build", batch=True) + + expected_build_dir = src.product.get_product_config(sat.cfg, product_name).build_dir + + if not os.path.exists(expected_build_dir): + OK = "OK" + self.assertEqual(OK, "OK") + + def test_040(self): + # Test the clean of install + OK = "KO" + + appli = 'appli-test' + product_name = "PRODUCT_GIT" + + sat = Sat() + + # Make sure the build exists + sat.prepare(appli + " -p " + product_name) + sat.configure(appli + " -p " + product_name) + + # Call the command + sat.clean(appli + " -p " + product_name + " --install", batch=True) + + expected_install_dir = src.product.get_product_config(sat.cfg, product_name).install_dir + + if not os.path.exists(expected_install_dir): + OK = "OK" + self.assertEqual(OK, "OK") + + def test_050(self): + # Test the clean of all (build, src, install) + OK = "KO" + + appli = 'appli-test' + product_name = "PRODUCT_GIT" + + sat = Sat() + + # Make sure the build exists + sat.prepare(appli + " -p " + product_name) + sat.compile(appli + " -p " + product_name) + + # Call the command + sat.clean(appli + " -p " + product_name + " --all", batch=True) + + expected_install_dir = src.product.get_product_config(sat.cfg, product_name).install_dir + expected_build_dir = src.product.get_product_config(sat.cfg, product_name).build_dir + expected_src_dir = src.product.get_product_config(sat.cfg, product_name).source_dir + + if not os.path.exists(expected_install_dir) and not os.path.exists(expected_build_dir) and not os.path.exists(expected_src_dir): + OK = "OK" + self.assertEqual(OK, "OK") + + def test_060(self): + # Test the clean with sources_without_dev option + OK = "KO" + + appli = 'appli-test' + product_name = "PRODUCT_GIT" + product_name2 = "PRODUCT_DEV" + + sat = Sat() + + # Make sure the build exists + sat.prepare(appli + " -p " + product_name + "," + product_name2) + + # Call the command + sat.clean(appli + " -p " + product_name + " --sources_without_dev", batch=True) + + expected_src_dir = src.product.get_product_config(sat.cfg, product_name).source_dir + expected_src_dir2 = src.product.get_product_config(sat.cfg, product_name2).source_dir + + if not os.path.exists(expected_src_dir) and os.path.exists(expected_src_dir2): + OK = "OK" + self.assertEqual(OK, "OK") + + + def test_070(self): + # Test the sat -h clean + OK = "KO" + + import clean + + if "The clean command suppress the source, build, or install" in clean.description(): + OK = "OK" + self.assertEqual(OK, "OK") + +# test launch +if __name__ == '__main__': + unittest.main() + pass diff --git a/test/test_sat5_0/prepare/test_patch.py b/test/test_sat5_0/prepare/test_patch.py new file mode 100755 index 0000000..1dc24d4 --- /dev/null +++ b/test/test_sat5_0/prepare/test_patch.py @@ -0,0 +1,167 @@ +#!/usr/bin/env python +#-*- coding:utf-8 -*- + +# Copyright (C) 2010-2018 CEA/DEN +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import os +import sys +import shutil +import unittest + +from src.salomeTools import Sat +import src.product +from unittestpy.tools import outRedirection + +class TestCase(unittest.TestCase): + """Test of the patch command""" + + def test_010(self): + # Test the patch command with a product in dev mode + OK = 'KO' + + appli = 'appli-test' + product_name = 'PRODUCT_DEV' + + sat = Sat("-oUSER.output_level=2") + + sat.config(appli) + + expected_src_dir = src.product.get_product_config(sat.cfg, product_name).source_dir + expected_file_path = os.path.join(expected_src_dir, 'my_test_file.txt') + expected_text = 'HELLO WORLD\n' + + if os.path.exists(expected_src_dir): + shutil.rmtree(expected_src_dir) + + sat.source(appli + ' --product ' + product_name) + + f = open(expected_file_path, 'r') + text = f.readlines()[0] + OK1 = 'KO' + if text == expected_text: + OK1 = 'OK' + + sat.patch(appli + ' --product ' + product_name) + + new_expected_text = 'HELLO WORLD MODIFIED\n' + f = open(expected_file_path, 'r') + text = f.readlines()[0] + + OK2 = 'KO' + if text == new_expected_text: + OK2 = 'OK' + + if (OK1, OK2)==('OK', 'OK'): + OK = 'OK' + self.assertEqual(OK, 'OK') + + def test_020(self): + # Test the patch command with a product with no sources found + OK = 'KO' + + appli = 'appli-test' + product_name = 'PRODUCT_DEV' + + sat = Sat('') + sat.config(appli) + + expected_src_dir = src.product.get_product_config(sat.cfg, product_name).source_dir + + if os.path.exists(expected_src_dir): + shutil.rmtree(expected_src_dir) + + # output redirection + my_out = outRedirection() + + sat.patch(appli + ' --product ' + product_name) + + # stop output redirection + my_out.end_redirection() + + # get results + res = my_out.read_results() + + if "No sources found for the " + product_name +" product" in res: + OK = 'OK' + self.assertEqual(OK, 'OK') + + def test_030(self): + # Test the patch command with a product without patch + OK = 'KO' + + appli = 'appli-test' + product_name = 'PRODUCT_ARCHIVE' + + sat = Sat('-v4') + + sat.source(appli + ' --product ' + product_name) + + # output redirection + my_out = outRedirection() + + sat.patch(appli + ' --product ' + product_name) + + # stop output redirection + my_out.end_redirection() + + # get results + res = my_out.read_results() + + if "No patch for the " + product_name +" product" in res: + OK = 'OK' + self.assertEqual(OK, 'OK') + + def test_040(self): + # Test the patch command with a product with a not valid patch + OK = 'KO' + + appli = 'appli-test' + product_name = 'PRODUCT_DEV' + + sat = Sat("-oPRODUCTS.PRODUCT_DEV.default.patches=['/']") + + sat.source(appli + ' --product ' + product_name) + + # output redirection + my_out = outRedirection() + + sat.patch(appli + ' --product ' + product_name) + + # stop output redirection + my_out.end_redirection() + + # get results + res = my_out.read_results() + + if "Not a valid patch" in res: + OK = 'OK' + self.assertEqual(OK, 'OK') + + def test_050(self): + # Test the sat -h patch + OK = "KO" + + import patch + + if "The patch command apply the patches on the sources of" in patch.description(): + OK = "OK" + self.assertEqual(OK, "OK") + +# test launch +if __name__ == '__main__': + unittest.main() + pass diff --git a/test/test_sat5_0/prepare/test_prepare.py b/test/test_sat5_0/prepare/test_prepare.py new file mode 100755 index 0000000..3340547 --- /dev/null +++ b/test/test_sat5_0/prepare/test_prepare.py @@ -0,0 +1,111 @@ +#!/usr/bin/env python +#-*- coding:utf-8 -*- + +# Copyright (C) 2010-2018 CEA/DEN +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import os +import sys +import shutil +import unittest + +import src +from src.salomeTools import Sat + +class TestCase(unittest.TestCase): + """Test of the prepare command""" + + def test_010(self): + # Test the prepare command with a product in dev mode + OK = 'KO' + + appli = 'appli-test' + product_name = 'PRODUCT_DEV' + + sat = Sat() + + sat.config(appli) + + expected_src_dir = src.product.get_product_config(sat.cfg, product_name).source_dir + expected_file_path = os.path.join(expected_src_dir, 'my_test_file.txt') + expected_text = 'HELLO WORLD\n' + + if os.path.exists(expected_src_dir): + shutil.rmtree(expected_src_dir) + + sat.prepare(appli + ' --product ' + product_name) + + f = open(expected_file_path, 'r') + text = f.readlines()[0] + if text == expected_text: + OK = 'OK' + self.assertEqual(OK, 'OK') + + def test_020(self): + # Test the prepare command with all products + OK = 'KO' + + appli = 'appli-test' + product_name = 'PRODUCT_DEV' + + sat = Sat() + sat.config(appli) + + expected_src_dir = src.product.get_product_config(sat.cfg, product_name).source_dir + expected_file_path = os.path.join(expected_src_dir, 'my_test_file.txt') + expected_text = 'HELLO WORLD\n' + + if os.path.exists(expected_src_dir): + shutil.rmtree(expected_src_dir) + + sat.prepare(appli) + + f = open(expected_file_path, 'r') + text = f.readlines()[0] + if text == expected_text: + OK = 'OK' + self.assertEqual(OK, 'OK') + + def test_030(self): + # Test the prepare command with all products + OK = 'KO' + + appli = 'appli-test' + + sat = Sat() + sat.config(appli) + + try: + sat.prepare(appli + " --force --force_patch") + OK = 'OK' + except: + pass + self.assertEqual(OK, 'OK') + + def test_040(self): + # Test the sat -h prepare + OK = "KO" + + import prepare + + if "The prepare command gets the sources" in prepare.description(): + OK = "OK" + self.assertEqual(OK, "OK") + +# test launch +if __name__ == '__main__': + unittest.main() + pass diff --git a/test/test_sat5_0/prepare/test_source.py b/test/test_sat5_0/prepare/test_source.py new file mode 100755 index 0000000..f7a053d --- /dev/null +++ b/test/test_sat5_0/prepare/test_source.py @@ -0,0 +1,175 @@ +#!/usr/bin/env python +#-*- coding:utf-8 -*- + +# Copyright (C) 2010-2018 CEA/DEN +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import os +import sys +import unittest + +from src.salomeTools import Sat +import src.product +from unittestpy.tools import outRedirection + +class TestCase(unittest.TestCase): + """Test of the source command""" + + def test_010(self): + # Test the source command with archive product + appli = 'appli-test' + product_name = 'PRODUCT_ARCHIVE' + + sat = Sat() + sat.source(appli + ' --product ' + product_name) + + expected_src_dir = src.product.get_product_config(sat.cfg, product_name).source_dir + expected_file_path = os.path.join(expected_src_dir, 'my_test_file.txt') + expected_text = 'HELLO WORLD\n' + + f = open(expected_file_path, 'r') + text = f.read() + self.assertEqual(text, expected_text) + + def test_020(self): + # Test the source command with git product + appli = 'appli-test' + product_name = 'PRODUCT_GIT' + + sat = Sat() + sat.source(appli + ' --product ' + product_name) + + expected_src_dir = src.product.get_product_config(sat.cfg, product_name).source_dir + expected_file_path = os.path.join(expected_src_dir, 'my_test_file.txt') + expected_text = 'HELLO WORLD\n' + + f = open(expected_file_path, 'r') + text = f.read() + self.assertEqual(text, expected_text) + + def test_030(self): + # Test the source command with cvs product + appli = 'appli-test' + product_name = 'PRODUCT_CVS' + + sat = Sat() + sat.source(appli + ' --product ' + product_name) + + expected_src_dir = src.product.get_product_config(sat.cfg, product_name).source_dir + expected_file_path = os.path.join(expected_src_dir, 'README.FIRST.txt') + expected_text = 'Copyright (C) 2007-2012 CEA/DEN, EDF R&D, OPEN CASCADE\n' + + f = open(expected_file_path, 'r') + text = f.readlines()[0] + + # pyunit method to compare 2 str + self.assertEqual(text, expected_text) + + """ + def test_040(self): + # Test the source command with svn product + OK = 'KO' + + appli = 'appli-test' + product_name = 'PRODUCT_SVN' + + sat = Sat() + sat.source(appli + ' --product ' + product_name) + + expected_src_dir = src.product.get_product_config(sat.cfg, product_name).source_dir + expected_file_path = os.path.join(expected_src_dir, 'scripts', 'README') + expected_text = 'this directory contains scripts used by salomeTool' + + f = open(expected_file_path, 'r') + text = f.readlines()[0] + + if expected_text in text: + OK = 'OK' + + # pyunit method to compare 2 str + self.assertEqual(OK, 'OK') + """ + + def test_050(self): + # Test the source command with native product + OK = 'KO' + + appli = 'appli-test' + product_name = 'PRODUCT_NATIVE' + + sat = Sat() + sat.source(appli + ' --product ' + product_name) + + expected_src_dir = os.path.join(sat.cfg.APPLICATION.workdir, 'SOURCES', product_name) + if not os.path.exists(expected_src_dir): + OK = 'OK' + self.assertEqual(OK, 'OK') + + def test_060(self): + # Test the source command with fixed product + OK = 'KO' + + appli = 'appli-test' + product_name = 'PRODUCT_FIXED' + + sat = Sat() + sat.source(appli + ' --product ' + product_name) + + expected_src_dir = src.product.get_product_config(sat.cfg, product_name).install_dir + + if os.path.exists(expected_src_dir): + OK = 'OK' + self.assertEqual(OK, 'OK') + + """ + def test_070(self): + # Test the source command with unknown product + OK = 'KO' + + # output redirection + my_out = outRedirection() + + appli = 'appli-test' + product_name = 'PRODUCT_UNKNOWN' + + sat = Sat() + sat.source(appli + ' --product ' + product_name) + + # stop output redirection + my_out.end_redirection() + + # get results + res = my_out.read_results() + + if "Unknown get source method" in res: + OK = 'OK' + self.assertEqual(OK, 'OK') + """ + + def test_080(self): + # Test the sat -h source + OK = "KO" + + import source + + if "gets the sources of the application" in source.description(): + OK = "OK" + self.assertEqual(OK, "OK") + +# test launch +if __name__ == '__main__': + unittest.main() + pass diff --git a/test/test_sat5_0/run_all.sh b/test/test_sat5_0/run_all.sh new file mode 100755 index 0000000..5905725 --- /dev/null +++ b/test/test_sat5_0/run_all.sh @@ -0,0 +1,59 @@ +#!/usr/bin/env bash +#-*- coding:utf-8 -*- + +# Copyright (C) 2010-2018 CEA/DEN +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +echo "TODO: OBSOLETE: to set as python script, may be" +echo "Begin date:" +date +echo +echo "Remove old results ... " +rm -rf .coverage htmlcov +echo "Done" +echo +echo "****************************" +coverage run --source=../commands/config.py config/option_value.py > test_res.html +coverage run --source=../commands/config.py -a config/option_value_2.py >> test_res.html +coverage run --source=../commands/config.py -a config/create_user_pyconf.py >> test_res.html +coverage run --source=../commands/config.py -a config/option_copy.py >> test_res.html +coverage run --source=../commands/config.py -a config/option_edit.py >> test_res.html +coverage run --source=../commands/config.py,../commands/log.py,../src/xmlManager.py,../src/logger.py -a log/launch_browser.py >> test_res.html +coverage run --source=../commands/config.py,../commands/log.py,../src/xmlManager.py,../src/logger.py -a log/launch_browser2.py >> test_res.html +coverage run --source=../commands/config.py,../commands/source.py,../commands/patch.py,../commands/prepare.py -a prepare/test_source.py >> test_res.html +coverage run --source=../commands/config.py,../commands/source.py,../commands/patch.py,../commands/prepare.py -a prepare/test_patch.py >> test_res.html +coverage run --source=../commands/config.py,../commands/source.py,../commands/patch.py,../commands/prepare.py -a prepare/test_prepare.py >> test_res.html +coverage run --source=../commands/config.py,../commands/source.py,../commands/patch.py,../commands/prepare.py,../commands/clean.py -a prepare/test_clean.py >> test_res.html +coverage run --source=../commands/config.py,../commands/environ.py -a environ/test_environ.py >> test_res.html +coverage run --source=../commands/config.py,../commands/configure.py,../commands/environ.py -a compilation/test_configure.py >> test_res.html +coverage run --source=../commands/config.py,../commands/make.py,../commands/environ.py -a compilation/test_make.py >> test_res.html +coverage run --source=../commands/config.py,../commands/makeinstall.py,../commands/environ.py -a compilation/test_makeinstall.py >> test_res.html +coverage run --source=../commands/config.py,../commands/compile.py,../commands/configure.py,../commands/make.py,../commands/makeinstall.py,../commands/environ.py -a compilation/test_compilation.py >> test_res.html +coverage run --source=../commands/shell.py -a shell/test_shell.py >> test_res.html +coverage run --source=../commands/job.py -a job/test_job.py >> test_res.html +coverage run --source=../commands/jobs.py -a jobs/test_jobs.py >> test_res.html +coverage run --source=../commands/test.py,../src/test_module.py,../src/fork.py -a test/test_command.py >> test_res.html +echo "****************************" +echo +echo "building html coverage" +coverage html +echo "Done" +echo +echo "End date:" +date +echo + +#firefox test_res.html htmlcov/index.html diff --git a/test/test_sat5_0/shell/test_shell.py b/test/test_sat5_0/shell/test_shell.py new file mode 100755 index 0000000..80f579e --- /dev/null +++ b/test/test_sat5_0/shell/test_shell.py @@ -0,0 +1,91 @@ +#!/usr/bin/env python +#-*- coding:utf-8 -*- + +# Copyright (C) 2010-2018 CEA/DEN +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import os +import sys +import unittest + +from src.salomeTools import Sat + +class TestCase(unittest.TestCase): + """Test of the shell command""" + + def test_010(self): + # Test the shell command with the --command option + OK = 'KO' + tmp_file = "/tmp/test.txt" + + sat = Sat("-l " + tmp_file) + + sat.config() + sat_way = sat.cfg.VARS.salometoolsway + + # Execute the shell command + sat.shell("--command ls " + sat_way) + + ff = open(tmp_file, "r") + log_files = ff.readlines() + ff.close() + os.remove(tmp_file) + log_files = [line.replace("\n", "") for line in log_files] + + text = open(log_files[2], "r").read() + + if "salomeTools.py" in text: + OK = 'OK' + self.assertEqual(OK, 'OK') + + def test_020(self): + # Test the shell command with the --command option with a failing command + OK = 'KO' + tmp_file = "/tmp/test.txt" + + sat = Sat("-l " + tmp_file) + + sat.config() + + # Execute the shell command + res = sat.shell("--command i_fail") + + ff = open(tmp_file, "r") + log_files = ff.readlines() + ff.close() + os.remove(tmp_file) + log_files = [line.replace("\n", "") for line in log_files] + + text = open(log_files[2], "r").read() + + if "i_fail" in text and res == 1: + OK = 'OK' + self.assertEqual(OK, 'OK') + + def test_030(self): + # Test the sat -h shell + OK = "KO" + + import shell + + if "Executes the shell command passed as argument" in shell.description(): + OK = "OK" + self.assertEqual(OK, "OK") + +# test launch +if __name__ == '__main__': + unittest.main() + pass diff --git a/test/test_sat5_0/test/test_command.py b/test/test_sat5_0/test/test_command.py new file mode 100755 index 0000000..136df62 --- /dev/null +++ b/test/test_sat5_0/test/test_command.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python +#-*- coding:utf-8 -*- + +# Copyright (C) 2010-2018 CEA/DEN +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import os +import sys +import unittest + +from src.salomeTools import Sat + +class TestTest(unittest.TestCase): + """Test of the test command""" + + def test_010(self): + # Test the test command + OK = 'KO' + tmp_file = "/tmp/test.txt" + application = "SALOME-7.8.0" + + sat = Sat("-l " + tmp_file) + + # Execute the job command + sat.test(application + " --grid GEOM --session light" ) + + ff = open(tmp_file, "r") + log_files = ff.readlines() + ff.close() + os.remove(tmp_file) + log_testboard = [line.replace("\n", "") for line in log_files if 'testboard.xml' in line] + + text = open(log_testboard[0], "r").read() + + if '' 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 '' 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