def run(self, args): """run the command with its specific arguments""" appid = args[0] configs = [ cwcfg.config_for(appid, configname) for configname in cwcfg.possible_configurations(appid) ] if not configs: raise ExecutionError('unable to guess configuration for %s' % appid) for config in configs: helper = self.config_helper(config, required=False) if helper: helper.cleanup() # remove home rm(config.apphome) # remove instance data directory try: rm(config.appdatahome) except OSError as ex: import errno if ex.errno != errno.ENOENT: raise confignames = ', '.join([config.name for config in configs]) print('-> instance %s (%s) deleted.' % (appid, confignames))
def setUp(self): self.CWCTL = CommandLine('cubicweb-ctl', 'The CubicWeb swiss-knife.', version=cw_version, check_duplicated_command=False) cwcfg.load_cwctl_plugins() self.CWCTL.register(_TestCommand) self.CWCTL.register(_TestFailCommand) # pretend that this instance exists patcher = patch.object(cwcfg, 'config_for', return_value=object()) patcher.start() self.addCleanup(patcher.stop)
def run(args=sys.argv[1:]): """command line tool""" filterwarnings('default', category=DeprecationWarning) cwcfg.load_cwctl_plugins() try: CWCTL.run(args) except ConfigurationError as err: print('ERROR: ', err) sys.exit(1) except ExecutionError as err: print(err) sys.exit(2)
def run(self, args): appid = args.pop(0) config = cwcfg.config_for(appid) dest = None if args: dest = args[0] self.generate_static_dir(config, dest)
def get_cw_option(instance_name, cw_option): """ Get a cw option. Parameters ---------- instance_name: str (mandatory) the name of the cw instance we want to connect. cw_option: str (mandatory) the cw option name. Returns ------- basedir: str part of the image path to hide in the virtual fs. """ # Get the configuration file config = cwcfg.config_for(instance_name) config_file = os.path.join(os.path.dirname(config.sources_file()), "all-in-one.conf") # Parse the configuration file and retrive the basedir with open(config_file) as open_file: for line in open_file.readlines(): match = re.match(r"^([a-zA-Z0-9_-]+)=(\S*)$", line) if match: name, value = match.groups() if name == cw_option: return value # If the basedir parameter is nor found raise an exception raise Exception("No '{0}' option has been declared in the '{1}' " "configuration file.".format(cw_option, config_file))
def get_cw_option(instance_name, cw_option): """ Get a cw option. Parameters ---------- instance_name: str (mandatory) the name of the cw instance we want to connect. cw_option: str (mandatory) the cw option name. Returns ------- basedir: str part of the image path to hide in the virtual fs. """ # Get the configuration file config = cwcfg.config_for(instance_name) config_file = os.path.join( os.path.dirname(config.sources_file()), "all-in-one.conf") # Parse the configuration file and retrive the basedir with open(config_file) as open_file: for line in open_file.readlines(): match = re.match(r"^(\w+)=(\S*)$", line) if match: name, value = match.groups() if name == cw_option: return value # If the basedir parameter is nor found raise an exception raise Exception("No '{0}' option has been declared in the '{1}' " "configuration file.".format(cw_option, config_file))
def upgrade_instance(self, appid): print('\n' + underline_title('Upgrading the instance %s' % appid)) from logilab.common.changelog import Version config = cwcfg.config_for(appid) config.repairing = True # notice we're not starting the server config.verbosity = self.config.verbosity set_sources_mode = getattr(config, 'set_sources_mode', None) if set_sources_mode is not None: set_sources_mode(self.config.ext_sources or ('migration', )) # get instance and installed versions for the server and the componants mih = config.migration_handler() repo = mih.repo vcconf = repo.get_versions() helper = self.config_helper(config, required=False) if self.config.force_cube_version: for cube, version in self.config.force_cube_version.items(): vcconf[cube] = Version(version) toupgrade = [] for cube in config.cubes(): installedversion = config.cube_version(cube) try: applversion = vcconf[cube] except KeyError: config.error('no version information for %s' % cube) continue if installedversion > applversion: toupgrade.append((cube, applversion, installedversion)) cubicwebversion = config.cubicweb_version() if self.config.force_cubicweb_version: applcubicwebversion = Version(self.config.force_cubicweb_version) vcconf['cubicweb'] = applcubicwebversion else: applcubicwebversion = vcconf.get('cubicweb') if cubicwebversion > applcubicwebversion: toupgrade.append( ('cubicweb', applcubicwebversion, cubicwebversion)) # run cubicweb/componants migration scripts if self.config.fs_only or toupgrade: for cube, fromversion, toversion in toupgrade: print('-> migration needed from %s to %s for %s' % (fromversion, toversion, cube)) with mih.cnx: with mih.cnx.security_enabled(False, False): mih.migrate(vcconf, reversed(toupgrade), self.config) clear_cache(config, 'instance_md5_version') else: print('-> no data migration needed for instance %s.' % appid) # rewrite main configuration file if not self.config.no_config_update: mih.rewrite_configuration() mih.shutdown() # handle i18n upgrade if not self.i18nupgrade(config): return print() if helper: helper.postupgrade(repo) print('-> instance migrated.') print()
def test_filter_scripts_for_mode(self): config = CubicWebConfiguration('data', __file__) config.verbosity = 0 config = self.config config.__class__.name = 'repository' self.assertListEqual( filter_scripts(config, TMIGRDIR, (0, 0, 4), (0, 1, 0)), [((0, 1, 0), TMIGRDIR + '0.1.0_Any.py'), ((0, 1, 0), TMIGRDIR + '0.1.0_common.py'), ((0, 1, 0), TMIGRDIR + '0.1.0_repository.py')]) config.__class__.name = 'all-in-one' self.assertListEqual( filter_scripts(config, TMIGRDIR, (0, 0, 4), (0, 1, 0)), [((0, 1, 0), TMIGRDIR + '0.1.0_Any.py'), ((0, 1, 0), TMIGRDIR + '0.1.0_common.py'), ((0, 1, 0), TMIGRDIR + '0.1.0_repository.py')]) config.__class__.name = 'repository'
def get_cw_cnx(endpoint): """ Get a cnx on a CubicWeb database """ from cubicweb import dbapi from cubicweb.__pkginfo__ import numversion from cubicweb.cwconfig import CubicWebConfiguration from cubicweb.entities import AnyEntity CubicWebConfiguration.load_cwctl_plugins() config = CubicWebConfiguration.config_for(endpoint) if numversion < (3, 19): sourceinfo = config.sources()['admin'] else: sourceinfo = config.default_admin_config login = sourceinfo['login'] password = sourceinfo['password'] _, cnx = dbapi.in_memory_repo_cnx(config, login, password=password) req = cnx.request() return req
def available_cube_names(cwcfg): """Return a list of available cube names, with 'cubicweb_' prefix dropped. """ def drop_prefix(cube): prefix = 'cubicweb_' if cube.startswith(prefix): cube = cube[len(prefix):] return cube return [drop_prefix(cube) for cube in cwcfg.available_cubes()]
def _datadirs(self, config, repo=None): if repo is None: repo = config.repository() if config._cubes is None: # web only config config.init_cubes(repo.get_cubes()) for cube in repo.get_cubes(): cube_datadir = osp.join(cwcfg.cube_dir(cube), 'data') if osp.isdir(cube_datadir): yield cube_datadir yield _DATA_DIR
def configure_instance(self, appid): if self.config.param is not None: appcfg = cwcfg.config_for(appid) for key, value in self.config.param.items(): try: appcfg.global_set_option(key, value) except KeyError: raise ConfigurationError( 'unknown configuration key "%s" for mode %s' % (key, appcfg.name)) appcfg.save()
def i18ninstance_instance(appid): """recompile instance's messages catalogs""" config = cwcfg.config_for(appid) config.quick_start = True # notify this is not a regular start repo = config.repository() if config._cubes is None: # web only config config.init_cubes(repo.get_cubes()) errors = config.i18ncompile() if errors: print('\n'.join(errors))
def versions_instance(self, appid): config = cwcfg.config_for(appid) # should not raise error if db versions don't match fs versions config.repairing = True # no need to load all appobjects and schema config.quick_start = True if hasattr(config, 'set_sources_mode'): config.set_sources_mode(('migration', )) vcconf = config.repository().get_versions() for key in sorted(vcconf): print(key + ': %s.%s.%s' % vcconf[key])
def admincnx(appid): from cubicweb import repoapi from cubicweb.cwconfig import CubicWebConfiguration from cubicweb.server.repository import Repository config = CubicWebConfiguration.config_for(appid) login = config.default_admin_config['login'] password = config.default_admin_config['password'] repo = Repository(config) repo.bootstrap() return repoapi.connect(repo, login, password=password)
def _get_mih(self, appid): """ returns migration context handler & shutdown function """ config = cwcfg.config_for(appid) if self.config.ext_sources: assert not self.config.system_only sources = self.config.ext_sources elif self.config.system_only: sources = ('system',) else: sources = ('all',) config.set_sources_mode(sources) config.repairing = self.config.force mih = config.migration_handler() return mih, lambda: mih.shutdown()
def get_cw_repo(instance_name): """ Connect to a local instance using an in memory connection. Parameters ---------- instance_name: str (mandatory) the name of the cw instance we want to connect. Returns ------- repo: cubicweb Repository a cubicweb Repository object. """ config = cwcfg.config_for(instance_name) return Repository(config, TasksManager())
def i18nupgrade(self, config): # handle i18n upgrade: # * install new languages # * recompile catalogs # XXX search available language in the first cube given from cubicweb import i18n templdir = cwcfg.cube_dir(config.cubes()[0]) langs = [lang for lang, _ in i18n.available_catalogs(join(templdir, 'i18n'))] errors = config.i18ncompile(langs) if errors: print('\n'.join(errors)) if not ASK.confirm('Error while compiling message catalogs, ' 'continue anyway?'): print('-> migration not completed.') return False return True
def wsgi_application(instance_name=None, debug=None): """ Build a WSGI application from a cubicweb instance name :param instance_name: Name of the cubicweb instance (optional). If not provided, :envvar:`CW_INSTANCE` must exists. :param debug: Enable/disable the debug mode. If defined to True or False, overrides :envvar:`CW_DEBUG`. The following environment variables are used if they exist: .. envvar:: CW_INSTANCE A CubicWeb instance name. .. envvar:: CW_DEBUG If defined, the debugmode is enabled. The function can be used as an entry-point for third-party wsgi containers. Below is a sample uswgi configuration file: .. code-block:: ini [uwsgi] http = 127.0.1.1:8080 env = CW_INSTANCE=myinstance env = CW_DEBUG=1 module = cubicweb.pyramid:wsgi_application() virtualenv = /home/user/.virtualenvs/myvirtualenv processes = 1 threads = 8 stats = 127.0.0.1:9191 plugins = http,python """ if instance_name is None: instance_name = os.environ['CW_INSTANCE'] if debug is None: debug = 'CW_DEBUG' in os.environ cwconfig = cwcfg.config_for(instance_name, debugmode=debug) return wsgi_application_from_cwconfig(cwconfig)
def get_cw_connection(instance_name): """ Connect to a local instance using an in memory connection. Parameters ---------- instance_name: str (mandatory) the name of the cw instance we want to connect. Returns ------- mih: cubicweb.server.migractions.ServerMigrationHelper the server migration object that contains a 'session' and 'shutdown' attributes. """ # Parse/configure the all in one configuration config = cwcfg.config_for(instance_name) sources = ("all",) config.set_sources_mode(sources) config.repairing = False # Create server migration helper mih = config.migration_handler() return mih
def schema_image(): options = [ ('output-file', { 'type': 'file', 'default': None, 'metavar': '<file>', 'short': 'o', 'help': 'output image file' }), ('viewer', { 'type': 'string', 'default': "rsvg-view", 'short': "w", 'metavar': '<cmd>', 'help': 'command use to view the generated file (empty for none)' }), ('lib-dir', { 'type': 'string', 'short': "L", 'metavar': '<dir>', 'help': 'directory to look for schema dependancies' }), ] config = Configuration( options=options, usage="yams-view [-L <lib_dir> | [[[...] deps] deps]] apps", version=version) dirnames = config.load_command_line_configuration() lib_dir = config['lib-dir'] assert lib_dir is not None if lib_dir is not None: app_dir = dirnames[-1] from cubicweb.cwconfig import CubicWebConfiguration as cwcfg packages = cwcfg.expand_cubes(dirnames) packages = cwcfg.reorder_cubes(packages) packages = [pkg for pkg in packages if pkg != app_dir] elif False: glob = globals().copy() execfile(join(app_dir, "__pkginfo__.py"), glob) #dirnames = [ join(lib_dir,dep) for dep in glob['__use__']]+dirnames packages = [dep for dep in glob['__use__']] for dir in dirnames: assert exists(dir), dir import cubicweb cubicweb_dir = dirname(cubicweb.__file__) schm_ldr = SchemaLoader() class MockConfig(object): def packages(self): return packages def packages_path(self): return packages def schemas_lib_dir(self): return join(cubicweb_dir, "schemas") #def apphome(self): # return lib_dir apphome = dirnames[0] def appid(self): "bob" print(MockConfig().packages()) schema = schm_ldr.load(MockConfig()) out, viewer = config['output-file'], config['viewer'] if out is None: tmp_file = NamedTemporaryFile(suffix=".svg") out = tmp_file.name schema2dot.schema2dot( schema, out, #size=size, skiprels=("identity", ), skipentities=("Person", "AbstractPerson", "Card", "AbstractCompany", "Company", "Division")) if viewer: p = Popen((viewer, out)) p.wait() return 0
from os import unlink from os.path import isfile, join from cubicweb.cwconfig import CubicWebConfiguration as cwcfg regdir = cwcfg.instances_dir() if isfile(join(regdir, 'startorder')): if confirm('The startorder file is not used anymore in Cubicweb 3.22. ' 'Should I delete it?', shell=False, pdb=False): unlink(join(regdir, 'startorder'))
def __init__(self, config): self.config = config self.cubes = {'cubicweb': cwcfg.cubicweb_version()}
def includeme(config): """Set-up a CubicWeb instance. The CubicWeb instance can be set in several ways: - Provide an already loaded CubicWeb repository in the registry: .. code-block:: python config.registry['cubicweb.repository'] = your_repo_instance - Provide an already loaded CubicWeb config instance in the registry: .. code-block:: python config.registry['cubicweb.config'] = your_config_instance - Provide an instance name in the pyramid settings with :confval:`cubicweb.instance`. A CubicWeb repository is instantiated and attached in 'cubicweb.repository' registry key if not already present. The CubicWeb instance registry is attached in 'cubicweb.registry' registry key. """ cwconfig = config.registry.get('cubicweb.config') repo = config.registry.get('cubicweb.repository') if repo is not None: if cwconfig is None: config.registry['cubicweb.config'] = cwconfig = repo.config elif cwconfig is not repo.config: raise ConfigurationError( 'CubicWeb config instance (found in "cubicweb.config" ' 'registry key) mismatches with that of the repository ' '(registry["cubicweb.repository"])') if cwconfig is None: debugmode = asbool( config.registry.settings.get('cubicweb.debug', False)) cwconfig = cwcfg.config_for( config.registry.settings['cubicweb.instance'], debugmode=debugmode) config.registry['cubicweb.config'] = cwconfig if repo is None: repo = config.registry['cubicweb.repository'] = cwconfig.repository() config.registry['cubicweb.registry'] = repo.vreg if cwconfig.mode != 'test': @atexit.register def shutdown_repo(): if repo.shutting_down: return repo.shutdown if asbool(config.registry.settings.get('cubicweb.defaults', True)): config.include('cubicweb.pyramid.defaults') for name in aslist(config.registry.settings.get('cubicweb.includes', [])): config.include(name) config.include('cubicweb.pyramid.core') if asbool( config.registry.settings.get('cubicweb.bwcompat', cwconfig.name == 'all-in-one')): if cwconfig.name != 'all-in-one': warnings.warn( '"cubicweb.bwcompat" setting only applies to ' '"all-in-one" instance configuration', UserWarning) else: config.include('cubicweb.pyramid.bwcompat')
def run(self, args): """run the command with its specific arguments""" for cube in cwcfg.available_cubes(): print(cube)
def run(self, args): """run the command with its specific arguments""" regdir = cwcfg.instances_dir() for appid in sorted(listdir(regdir)): print(appid)
def pyramid_instance(self, appid): self._needreload = False debugmode = self['debug-mode'] or self['debug'] autoreload = self['reload'] or self['debug'] daemonize = not (self['no-daemon'] or debugmode or autoreload) cwconfig = cwcfg.config_for(appid, debugmode=debugmode) filelist_path = os.path.join(cwconfig.apphome, '.pyramid-reload-files.list') pyramid_ini_path = os.path.join(cwconfig.apphome, "pyramid.ini") if not os.path.exists(pyramid_ini_path): _generate_pyramid_ini_file(pyramid_ini_path) if autoreload and not os.environ.get(self._reloader_environ_key): return self.restart_with_reloader(filelist_path) if autoreload: _turn_sigterm_into_systemexit() self.debug('Running reloading file monitor') extra_files = [sys.argv[0]] extra_files.extend(self.configfiles(cwconfig)) extra_files.extend(self.i18nfiles(cwconfig)) self.install_reloader(self['reload-interval'], extra_files, filelist_path=filelist_path) if daemonize: self.daemonize(cwconfig['pid-file']) self.record_pid(cwconfig['pid-file']) if self['dbglevel']: self['loglevel'] = 'debug' set_debug('|'.join('DBG_' + x.upper() for x in self['dbglevel'])) init_cmdline_log_threshold(cwconfig, self['loglevel']) app = wsgi_application_from_cwconfig( cwconfig, profile=self['profile'], profile_output=self['profile-output'], profile_dump_every=self['profile-dump-every']) host = cwconfig['interface'] port = cwconfig['port'] or 8080 url_scheme = ('https' if cwconfig['base-url'].startswith('https') else 'http') repo = app.application.registry['cubicweb.repository'] warnings.warn( 'the "pyramid" command does not start repository "looping tasks" ' 'anymore; use the standalone "scheduler" command if needed') try: waitress.serve(app, host=host, port=port, url_scheme=url_scheme, clear_untrusted_proxy_headers=True) finally: repo.shutdown() if self._needreload: return 3 return 0
def run(self, args): """run the command with its specific arguments""" from logilab.common.textutils import splitstrip check_options_consistency(self.config) configname = self.config.config cubes, appid = args cubes = splitstrip(cubes) # get the configuration and helper config = cwcfg.config_for(appid, configname, creating=True) cubes = config.expand_cubes(cubes) config.init_cubes(cubes) helper = self.config_helper(config) # check the cube exists try: templdirs = [cwcfg.cube_dir(cube) for cube in cubes] except ConfigurationError as ex: print(ex) print('\navailable cubes:', end=' ') print(', '.join(available_cube_names(cwcfg))) return # create the registry directory for this instance print('\n' + underline_title('Creating the instance %s' % appid)) create_dir(config.apphome) # cubicweb-ctl configuration if not self.config.automatic: print('\n' + underline_title('Configuring the instance (%s.conf)' % configname)) config.input_config('main', self.config.config_level) # configuration'specific stuff print() helper.bootstrap(cubes, self.config.automatic, self.config.config_level) # input for cubes specific options if not self.config.automatic: sections = set(sect.lower() for sect, opt, odict in config.all_options() if 'type' in odict and odict.get('level', 0) <= self.config.config_level) for section in sections: if section not in ('main', 'email', 'web'): print('\n' + underline_title('%s options' % section)) config.input_config(section, self.config.config_level) # write down configuration config.save() print('-> generated config %s' % config.main_config_file()) # handle i18n files structure # in the first cube given from cubicweb import i18n langs = [lang for lang, _ in i18n.available_catalogs(join(templdirs[0], 'i18n'))] errors = config.i18ncompile(langs) if errors: print('\n'.join(errors)) if self.config.automatic \ or not ASK.confirm('error while compiling message catalogs, ' 'continue anyway ?'): print('creation not completed') return # create the additional data directory for this instance if config.appdatahome != config.apphome: # true in dev mode create_dir(config.appdatahome) create_dir(join(config.appdatahome, 'backup')) if config['uid']: from logilab.common.shellutils import chown # this directory should be owned by the uid of the server process print('set %s as owner of the data directory' % config['uid']) chown(config.appdatahome, config['uid']) print('\n-> creation done for %s\n' % repr(config.apphome)[1:-1]) if not self.config.no_db_create: helper.postcreate(self.config.automatic, self.config.config_level)
def run(self, args): """run the command with its specific arguments""" if not args: mode = 'all' elif len(args) == 1: mode = args[0] else: raise BadCommandUsage('Too many arguments') from cubicweb.migration import ConfigurationProblem if mode == 'all': print('CubicWeb %s (%s mode)' % (cwcfg.cubicweb_version(), cwcfg.mode)) print() if mode in ('all', 'config', 'configurations'): cwcfg.load_available_configs() print('Available configurations:') for config in CONFIGURATIONS: print('*', config.name) for line in config.__doc__.splitlines(): line = line.strip() if not line: continue print(' ', line) print() if mode in ('all', 'cubes'): cfgpb = ConfigurationProblem(cwcfg) try: cube_names = available_cube_names(cwcfg) namesize = max(len(x) for x in cube_names) except ConfigurationError as ex: print('No cubes available:', ex) except ValueError: print('No cubes available') else: print('Available cubes:') for cube in cube_names: try: tinfo = cwcfg.cube_pkginfo(cube) tversion = tinfo.version cfgpb.add_cube(cube, tversion) except (ConfigurationError, AttributeError) as ex: tinfo = None tversion = '[missing cube information: %s]' % ex print('* %s %s' % (cube.ljust(namesize), tversion)) if self.config.verbose: if tinfo: descr = getattr(tinfo, 'description', '') if not descr: descr = tinfo.__doc__ if descr: print(' ' + ' \n'.join(descr.splitlines())) modes = detect_available_modes(cwcfg.cube_dir(cube)) print(' available modes: %s' % ', '.join(modes)) print() if mode in ('all', 'instances'): try: regdir = cwcfg.instances_dir() except ConfigurationError as ex: print('No instance available:', ex) print() return instances = list_instances(regdir) if instances: print('Available instances (%s):' % regdir) for appid in instances: modes = cwcfg.possible_configurations(appid) if not modes: print('* %s (BROKEN instance, no configuration found)' % appid) continue print('* %s (%s)' % (appid, ', '.join(modes))) try: config = cwcfg.config_for(appid, modes[0]) except Exception as exc: print(' (BROKEN instance, %s)' % exc) continue else: print('No instance available in %s' % regdir) print() if mode == 'all': # configuration management problem solving cfgpb.solve() if cfgpb.warnings: print('Warnings:\n', '\n'.join('* ' + txt for txt in cfgpb.warnings)) if cfgpb.errors: print('Errors:') for op, cube, version, src in cfgpb.errors: if op == 'add': print('* cube', cube, end=' ') if version: print(' version', version, end=' ') print('is not installed, but required by %s' % src) else: print( '* cube %s version %s is installed, but version %s is required by %s' % (cube, cfgpb.cubes[cube], version, src) )
def run(self, args): """run the <command>_method on each argument (a list of instance identifiers) """ if not args: if "CW_INSTANCE" in os.environ: appid = os.environ["CW_INSTANCE"] else: raise BadCommandUsage("Error: instance id is missing") else: appid = args[0] cmdmeth = getattr(self, '%s_instance' % self.name) traceback_ = None # debugmode=True is to force to have a StreamHandler used instead of # writting the logs into a file in /tmp self.cwconfig = cwcfg.config_for(appid, debugmode=True) # by default loglevel is 'error' but we keep the default value to None # because some subcommands (e.g: pyramid) can override the loglevel in # certain situations if it's not explicitly set by the user and we want # to detect that (the "None" case) if self['loglevel'] is None: # if no loglevel is set but dbglevel is here we want to set level to debug if self['dbglevel']: init_cmdline_log_threshold(self.cwconfig, 'debug') else: init_cmdline_log_threshold(self.cwconfig, 'error') else: init_cmdline_log_threshold(self.cwconfig, self['loglevel']) if self['dbglevel']: set_debug('|'.join('DBG_' + x.upper() for x in self['dbglevel'])) try: status = cmdmeth(appid) or 0 except (ExecutionError, ConfigurationError) as ex: # we need to do extract this information here for pdb since it is # now lost in python 3 once we exit the try/catch statement exception_type, exception, traceback_ = sys.exc_info() sys.stderr.write('instance %s not %s: %s\n' % ( appid, self.actionverb, ex)) status = 4 except Exception as ex: # idem exception_type, exception, traceback_ = sys.exc_info() traceback.print_exc() sys.stderr.write('instance %s not %s: %s\n' % ( appid, self.actionverb, ex)) status = 8 except (KeyboardInterrupt, SystemExit) as ex: # idem exception_type, exception, traceback_ = sys.exc_info() sys.stderr.write('%s aborted\n' % self.name) if isinstance(ex, KeyboardInterrupt): status = 2 # specific error code else: status = ex.code if status != 0 and self.config.pdb: pdb = utils.get_pdb() if traceback_ is not None: pdb.post_mortem(traceback_) else: print("WARNING: Could not access to the traceback because the command return " "code is different than 0 but the command didn't raised an exception.") # we can't use "header=" of set_trace because ipdb doesn't supports it pdb.set_trace() sys.exit(status)