def get_reusable_executor(max_workers=None, context=None, timeout=10,
                          kill_workers=False, reuse="auto",
                          job_reducers=None, result_reducers=None,
                          initializer=None, initargs=()):
    """Return the current ReusableExectutor instance.

    Start a new instance if it has not been started already or if the previous
    instance was left in a broken state.

    If the previous instance does not have the requested number of workers, the
    executor is dynamically resized to adjust the number of workers prior to
    returning.

    Reusing a singleton instance spares the overhead of starting new worker
    processes and importing common python packages each time.

    ``max_workers`` controls the maximum number of tasks that can be running in
    parallel in worker processes. By default this is set to the number of
    CPUs on the host.

    Setting ``timeout`` (in seconds) makes idle workers automatically shutdown
    so as to release system resources. New workers are respawn upon submission
    of new tasks so that ``max_workers`` are available to accept the newly
    submitted tasks. Setting ``timeout`` to around 100 times the time required
    to spawn new processes and import packages in them (on the order of 100ms)
    ensures that the overhead of spawning workers is negligible.

    Setting ``kill_workers=True`` makes it possible to forcibly interrupt
    previously spawned jobs to get a new instance of the reusable executor
    with new constructor argument values.

    The ``job_reducers`` and ``result_reducers`` are used to customize the
    pickling of tasks and results send to the executor.

    When provided, the ``initializer`` is run first in newly spawned
    processes with argument ``initargs``.
    """
    with _executor_lock:
        global _executor, _executor_kwargs
        executor = _executor

        if max_workers is None:
            if reuse is True and executor is not None:
                max_workers = executor._max_workers
            else:
                max_workers = cpu_count()
        elif max_workers <= 0:
            raise ValueError(
                "max_workers must be greater than 0, got {}."
                .format(max_workers))

        if isinstance(context, STRING_TYPE):
            context = get_context(context)
        if context is not None and context.get_start_method() == "fork":
            raise ValueError("Cannot use reusable executor with the 'fork' "
                             "context")

        kwargs = dict(context=context, timeout=timeout,
                      job_reducers=job_reducers,
                      result_reducers=result_reducers,
                      initializer=initializer, initargs=initargs)
        if executor is None:
            mp.util.debug("Create a executor with max_workers={}."
                          .format(max_workers))
            executor_id = _get_next_executor_id()
            _executor_kwargs = kwargs
            _executor = executor = _ReusablePoolExecutor(
                _executor_lock, max_workers=max_workers,
                executor_id=executor_id, **kwargs)
        else:
            if reuse == 'auto':
                reuse = kwargs == _executor_kwargs
            if (executor._flags.broken or executor._flags.shutdown
                    or not reuse):
                if executor._flags.broken:
                    reason = "broken"
                elif executor._flags.shutdown:
                    reason = "shutdown"
                else:
                    reason = "arguments have changed"
                mp.util.debug(
                    "Creating a new executor with max_workers={} as the "
                    "previous instance cannot be reused ({})."
                    .format(max_workers, reason))
                executor.shutdown(wait=True, kill_workers=kill_workers)
                _executor = executor = _executor_kwargs = None
                # Recursive call to build a new instance
                return get_reusable_executor(max_workers=max_workers,
                                             **kwargs)
            else:
                mp.util.debug("Reusing existing executor with max_workers={}."
                              .format(executor._max_workers))
                executor._resize(max_workers)

    return executor

Return the current ReusableExectutor instance .


def _wait_job_completion(self):
        """Wait for the cache to be empty before resizing the pool."""
        # Issue a warning to the user about the bad effect of this usage.
        if len(self._pending_work_items) > 0:
            warnings.warn("Trying to resize an executor with running jobs: "
                          "waiting for jobs completion before resizing.",
                          UserWarning)
            mp.util.debug("Executor {} waiting for jobs completion before"
                          " resizing".format(self.executor_id))
        # Wait for the completion of the jobs
        while len(self._pending_work_items) > 0:
            time.sleep(1e-3)

Wait for the cache to be empty before resizing the pool .


def get_preparation_data(name, init_main_module=True):
    '''
    Return info about parent needed by child to unpickle process object
    '''
    _check_not_importing_main()
    d = dict(
        log_to_stderr=util._log_to_stderr,
        authkey=bytes(process.current_process().authkey),
    )

    if util._logger is not None:
        d['log_level'] = util._logger.getEffectiveLevel()
        if len(util._logger.handlers) > 0:
            h = util._logger.handlers[0]
            d['log_fmt'] = h.formatter._fmt

    sys_path = [p for p in sys.path]
    try:
        i = sys_path.index('')
    except ValueError:
        pass
    else:
        sys_path[i] = process.ORIGINAL_DIR

    d.update(
        name=name,
        sys_path=sys_path,
        sys_argv=sys.argv,
        orig_dir=process.ORIGINAL_DIR,
        dir=os.getcwd()
    )

    if sys.platform != "win32":
        # Pass the semaphore_tracker pid to avoid re-spawning it in every child
        from . import semaphore_tracker
        semaphore_tracker.ensure_running()
        d['tracker_pid'] = semaphore_tracker._semaphore_tracker._pid

    # Figure out whether to initialise main in the subprocess as a module
    # or through direct execution (or to leave it alone entirely)
    if init_main_module:
        main_module = sys.modules['__main__']
        try:
            main_mod_name = getattr(main_module.__spec__, "name", None)
        except BaseException:
            main_mod_name = None
        if main_mod_name is not None:
            d['init_main_from_name'] = main_mod_name
        elif sys.platform != 'win32' or (not WINEXE and not WINSERVICE):
            main_path = getattr(main_module, '__file__', None)
            if main_path is not None:
                if (not os.path.isabs(main_path) and
                        process.ORIGINAL_DIR is not None):
                    main_path = os.path.join(process.ORIGINAL_DIR, main_path)
                d['init_main_from_path'] = os.path.normpath(main_path)
                # Compat for python2.7
                d['main_path'] = d['init_main_from_path']

    return d

def get_preparation_data ( name , init_main_module = True ) : _check_not_importing_main ( ) d = dict ( log_to_stderr = util . _log_to_stderr , authkey = bytes ( process . current_process ( ) . authkey ) , ) if util . _logger is not None : d [ 'log_level' ] = util . _logger . getEffectiveLevel ( ) if len ( util . _logger . handlers ) > 0 : h = util . _logger . handlers [ 0 ] d [ 'log_fmt' ] = h . formatter . _fmt sys_path = [ p for p in sys . path ] try : i = sys_path . index ( '' ) except ValueError : pass else : sys_path [ i ] = process . ORIGINAL_DIR d . update ( name = name , sys_path = sys_path , sys_argv = sys . argv , orig_dir = process . ORIGINAL_DIR , dir = os . getcwd ( ) ) if sys . platform != "win32" : from . import semaphore_tracker semaphore_tracker . ensure_running ( ) d [ 'tracker_pid' ] = semaphore_tracker . _semaphore_tracker . _pid if init_main_module : main_module = sys . modules [ '__main__' ] try : main_mod_name = getattr ( main_module . __spec__ , "name" , None ) except BaseException : main_mod_name = None if main_mod_name is not None : d [ 'init_main_from_name' ] = main_mod_name elif sys . platform != 'win32' or ( not WINEXE and not WINSERVICE ) : main_path = getattr ( main_module , '__file__' , None ) if main_path is not None : if ( not os . path . isabs ( main_path ) and process . ORIGINAL_DIR is not None ) : main_path = os . path . join ( process . ORIGINAL_DIR , main_path ) d [ 'init_main_from_path' ] = os . path . normpath ( main_path ) d [ 'main_path' ] = d [ 'init_main_from_path' ] return d


def prepare(data):
    '''
    Try to get current process ready to unpickle process object
    '''
    if 'name' in data:
        process.current_process().name = data['name']

    if 'authkey' in data:
        process.current_process().authkey = data['authkey']

    if 'log_to_stderr' in data and data['log_to_stderr']:
        util.log_to_stderr()

    if 'log_level' in data:
        util.get_logger().setLevel(data['log_level'])

    if 'log_fmt' in data:
        import logging
        util.get_logger().handlers[0].setFormatter(
            logging.Formatter(data['log_fmt'])
        )

    if 'sys_path' in data:
        sys.path = data['sys_path']

    if 'sys_argv' in data:
        sys.argv = data['sys_argv']

    if 'dir' in data:
        os.chdir(data['dir'])

    if 'orig_dir' in data:
        process.ORIGINAL_DIR = data['orig_dir']

    if 'tracker_pid' in data:
        from . import semaphore_tracker
        semaphore_tracker._semaphore_tracker._pid = data["tracker_pid"]

    if 'init_main_from_name' in data:
        _fixup_main_from_name(data['init_main_from_name'])
    elif 'init_main_from_path' in data:
        _fixup_main_from_path(data['init_main_from_path'])

def prepare ( data ) : if 'name' in data : process . current_process ( ) . name = data [ 'name' ] if 'authkey' in data : process . current_process ( ) . authkey = data [ 'authkey' ] if 'log_to_stderr' in data and data [ 'log_to_stderr' ] : util . log_to_stderr ( ) if 'log_level' in data : util . get_logger ( ) . setLevel ( data [ 'log_level' ] ) if 'log_fmt' in data : import logging util . get_logger ( ) . handlers [ 0 ] . setFormatter ( logging . Formatter ( data [ 'log_fmt' ] ) ) if 'sys_path' in data : sys . path = data [ 'sys_path' ] if 'sys_argv' in data : sys . argv = data [ 'sys_argv' ] if 'dir' in data : os . chdir ( data [ 'dir' ] ) if 'orig_dir' in data : process . ORIGINAL_DIR = data [ 'orig_dir' ] if 'tracker_pid' in data : from . import semaphore_tracker semaphore_tracker . _semaphore_tracker . _pid = data [ "tracker_pid" ] if 'init_main_from_name' in data : _fixup_main_from_name ( data [ 'init_main_from_name' ] ) elif 'init_main_from_path' in data : _fixup_main_from_path ( data [ 'init_main_from_path' ] )


def close_fds(keep_fds):  # pragma: no cover
    """Close all the file descriptors except those in keep_fds."""

    # Make sure to keep stdout and stderr open for logging purpose
    keep_fds = set(keep_fds).union([1, 2])

    # We try to retrieve all the open fds
    try:
        open_fds = set(int(fd) for fd in os.listdir('/proc/self/fd'))
    except FileNotFoundError:
        import resource
        max_nfds = resource.getrlimit(resource.RLIMIT_NOFILE)[0]
        open_fds = set(fd for fd in range(3, max_nfds))
        open_fds.add(0)

    for i in open_fds - keep_fds:
        try:
            os.close(i)
        except OSError:
            pass

def close_fds ( keep_fds ) : keep_fds = set ( keep_fds ) . union ( [ 1 , 2 ] ) try : open_fds = set ( int ( fd ) for fd in os . listdir ( '/proc/self/fd' ) ) except FileNotFoundError : import resource max_nfds = resource . getrlimit ( resource . RLIMIT_NOFILE ) [ 0 ] open_fds = set ( fd for fd in range ( 3 , max_nfds ) ) open_fds . add ( 0 ) for i in open_fds - keep_fds : try : os . close ( i ) except OSError : pass

Close all the file descriptors except those in keep_fds .


def _recursive_terminate_without_psutil(process):
    """Terminate a process and its descendants.
    """
    try:
        _recursive_terminate(process.pid)
    except OSError as e:
        warnings.warn("Failed to kill subprocesses on this platform. Please"
                      "install psutil: https://github.com/giampaolo/psutil")
        # In case we cannot introspect the children, we fall back to the
        # classic Process.terminate.
        process.terminate()
    process.join()

Terminate a process and its descendants .


def _recursive_terminate(pid):
    """Recursively kill the descendants of a process before killing it.
    """

    if sys.platform == "win32":
        # On windows, the taskkill function with option `/T` terminate a given
        # process pid and its children.
        try:
            subprocess.check_output(
                ["taskkill", "/F", "/T", "/PID", str(pid)],
                stderr=None)
        except subprocess.CalledProcessError as e:
            # In windows, taskkill return 1 for permission denied and 128, 255
            # for no process found.
            if e.returncode not in [1, 128, 255]:
                raise
            elif e.returncode == 1:
                # Try to kill the process without its descendants if taskkill
                # was denied permission. If this fails too, with an error
                # different from process not found, let the top level function
                # raise a warning and retry to kill the process.
                try:
                    os.kill(pid, signal.SIGTERM)
                except OSError as e:
                    if e.errno != errno.ESRCH:
                        raise

    else:
        try:
            children_pids = subprocess.check_output(
                ["pgrep", "-P", str(pid)],
                stderr=None
            )
        except subprocess.CalledProcessError as e:
            # `ps` returns 1 when no child process has been found
            if e.returncode == 1:
                children_pids = b''
            else:
                raise

        # Decode the result, split the cpid and remove the trailing line
        children_pids = children_pids.decode().split('\n')[:-1]
        for cpid in children_pids:
            cpid = int(cpid)
            _recursive_terminate(cpid)

        try:
            os.kill(pid, signal.SIGTERM)
        except OSError as e:
            # if OSError is raised with [Errno 3] no such process, the process
            # is already terminated, else, raise the error and let the top
            # level function raise a warning and retry to kill the process.
            if e.errno != errno.ESRCH:
                raise

def _recursive_terminate ( pid ) : if sys . platform == "win32" : try : subprocess . check_output ( [ "taskkill" , "/F" , "/T" , "/PID" , str ( pid ) ] , stderr = None ) except subprocess . CalledProcessError as e : if e . returncode not in [ 1 , 128 , 255 ] : raise elif e . returncode == 1 : try : os . kill ( pid , signal . SIGTERM ) except OSError as e : if e . errno != errno . ESRCH : raise else : try : children_pids = subprocess . check_output ( [ "pgrep" , "-P" , str ( pid ) ] , stderr = None ) except subprocess . CalledProcessError as e : if e . returncode == 1 : children_pids = b'' else : raise children_pids = children_pids . decode ( ) . split ( '\n' ) [ : - 1 ] for cpid in children_pids : cpid = int ( cpid ) _recursive_terminate ( cpid ) try : os . kill ( pid , signal . SIGTERM ) except OSError as e : if e . errno != errno . ESRCH : raise

Recursively kill the descendants of a process before killing it .


def get_exitcodes_terminated_worker(processes):
    """Return a formated string with the exitcodes of terminated workers.

    If necessary, wait (up to .25s) for the system to correctly set the
    exitcode of one terminated worker.
    """
    patience = 5

    # Catch the exitcode of the terminated workers. There should at least be
    # one. If not, wait a bit for the system to correctly set the exitcode of
    # the terminated worker.
    exitcodes = [p.exitcode for p in list(processes.values())
                 if p.exitcode is not None]
    while len(exitcodes) == 0 and patience > 0:
        patience -= 1
        exitcodes = [p.exitcode for p in list(processes.values())
                     if p.exitcode is not None]
        time.sleep(.05)

    return _format_exitcodes(exitcodes)

def get_exitcodes_terminated_worker ( processes ) : patience = 5 exitcodes = [ p . exitcode for p in list ( processes . values ( ) ) if p . exitcode is not None ] while len ( exitcodes ) == 0 and patience > 0 : patience -= 1 exitcodes = [ p . exitcode for p in list ( processes . values ( ) ) if p . exitcode is not None ] time . sleep ( .05 ) return _format_exitcodes ( exitcodes )

Return a formated string with the exitcodes of terminated workers .


def _format_exitcodes(exitcodes):
    """Format a list of exit code with names of the signals if possible"""
    str_exitcodes = ["{}({})".format(_get_exitcode_name(e), e)
                     for e in exitcodes if e is not None]
    return "{" + ", ".join(str_exitcodes) + "}"

def
_format_exitcodes
(
exitcodes
)
:
str_exitcodes
=
[
"{}({})"
.
format
(
_get_exitcode_name
(
e
)
,
e
)
for
e
in
exitcodes
if
e
is
not
]
return
"{"
+
", "
.
join
(
str_exitcodes
)
+
"}"


def main(fd, verbose=0):
    '''Run semaphore tracker.'''
    # protect the process from ^C and "killall python" etc
    signal.signal(signal.SIGINT, signal.SIG_IGN)
    signal.signal(signal.SIGTERM, signal.SIG_IGN)

    if _HAVE_SIGMASK:
        signal.pthread_sigmask(signal.SIG_UNBLOCK, _IGNORED_SIGNALS)

    for f in (sys.stdin, sys.stdout):
        try:
            f.close()
        except Exception:
            pass

    if verbose:  # pragma: no cover
        sys.stderr.write("Main semaphore tracker is running\n")
        sys.stderr.flush()

    cache = set()
    try:
        # keep track of registered/unregistered semaphores
        with os.fdopen(fd, 'rb') as f:
            for line in f:
                try:
                    cmd, name = line.strip().split(b':')
                    if cmd == b'REGISTER':
                        name = name.decode('ascii')
                        cache.add(name)
                        if verbose:  # pragma: no cover
                            sys.stderr.write("[SemaphoreTracker] register {}\n"
                                             .format(name))
                            sys.stderr.flush()
                    elif cmd == b'UNREGISTER':
                        name = name.decode('ascii')
                        cache.remove(name)
                        if verbose:  # pragma: no cover
                            sys.stderr.write("[SemaphoreTracker] unregister {}"
                                             ": cache({})\n"
                                             .format(name, len(cache)))
                            sys.stderr.flush()
                    elif cmd == b'PROBE':
                        pass
                    else:
                        raise RuntimeError('unrecognized command %r' % cmd)
                except BaseException:
                    try:
                        sys.excepthook(*sys.exc_info())
                    except BaseException:
                        pass
    finally:
        # all processes have terminated; cleanup any remaining semaphores
        if cache:
            try:
                warnings.warn('semaphore_tracker: There appear to be %d '
                              'leaked semaphores to clean up at shutdown' %
                              len(cache))
            except Exception:
                pass
        for name in cache:
            # For some reason the process which created and registered this
            # semaphore has failed to unregister it. Presumably it has died.
            # We therefore unlink it.
            try:
                try:
                    sem_unlink(name)
                    if verbose:  # pragma: no cover
                        sys.stderr.write("[SemaphoreTracker] unlink {}\n"
                                         .format(name))
                        sys.stderr.flush()
                except Exception as e:
                    warnings.warn('semaphore_tracker: %s: %r' % (name, e))
            finally:
                pass

    if verbose:  # pragma: no cover
        sys.stderr.write("semaphore tracker shut down\n")
        sys.stderr.flush()


def ensure_running(self):
        '''Make sure that semaphore tracker process is running.

        This can be run from any process.  Usually a child process will use
        the semaphore created by its parent.'''
        with self._lock:
            if self._fd is not None:
                # semaphore tracker was launched before, is it still running?
                if self._check_alive():
                    # => still alive
                    return
                # => dead, launch it again
                os.close(self._fd)
                try:
                    # Clean-up to avoid dangling processes.
                    os.waitpid(self._pid, 0)
                except OSError:
                    # The process was terminated or is a child from an ancestor
                    # of the current process.
                    pass
                self._fd = None
                self._pid = None

                warnings.warn('semaphore_tracker: process died unexpectedly, '
                              'relaunching.  Some semaphores might leak.')

            fds_to_pass = []
            try:
                fds_to_pass.append(sys.stderr.fileno())
            except Exception:
                pass

            r, w = os.pipe()
            cmd = 'from {} import main; main({}, {})'.format(
                main.__module__, r, VERBOSE)
            try:
                fds_to_pass.append(r)
                # process will out live us, so no need to wait on pid
                exe = spawn.get_executable()
                args = [exe] + util._args_from_interpreter_flags()
                # In python 3.3, there is a bug which put `-RRRRR..` instead of
                # `-R` in args. Replace it to get the correct flags.
                # See https://github.com/python/cpython/blob/3.3/Lib/subprocess.py#L488
                if sys.version_info[:2] <= (3, 3):
                    import re
                    for i in range(1, len(args)):
                        args[i] = re.sub("-R+", "-R", args[i])
                args += ['-c', cmd]
                util.debug("launching Semaphore tracker: {}".format(args))
                # bpo-33613: Register a signal mask that will block the
                # signals.  This signal mask will be inherited by the child
                # that is going to be spawned and will protect the child from a
                # race condition that can make the child die before it
                # registers signal handlers for SIGINT and SIGTERM. The mask is
                # unregistered after spawning the child.
                try:
                    if _HAVE_SIGMASK:
                        signal.pthread_sigmask(signal.SIG_BLOCK,
                                               _IGNORED_SIGNALS)
                    pid = spawnv_passfds(exe, args, fds_to_pass)
                finally:
                    if _HAVE_SIGMASK:
                        signal.pthread_sigmask(signal.SIG_UNBLOCK,
                                               _IGNORED_SIGNALS)
            except BaseException:
                os.close(w)
                raise
            else:
                self._fd = w
                self._pid = pid
            finally:
                os.close(r)

Make sure that semaphore tracker process is running .


def event_processor(self, frame, event, arg):
        'A simple event processor that prints out events.'
        out = self.debugger.intf[-1].output
        lineno = frame.f_lineno
        filename = self.core.canonic_filename(frame)
        filename = self.core.filename(filename)
        if not out:
            print("%s - %s:%d" % (event, filename, lineno))
        else:
            out.write("%s - %s:%d" % (event, filename, lineno))
            if arg is not None:
                out.writeline(', %s ' % repr(arg))
            else:
                out.writeline('')
                pass
            pass
        return self.event_processor

A simple event processor that prints out events .


def run(self, args):
        """Program counter."""
        mainfile = self.core.filename(None)
        if self.core.is_running():
            curframe = self.proc.curframe
            if curframe:
                line_no = inspect.getlineno(curframe)
                offset  = curframe.f_lasti
                self.msg("PC offset is %d." % offset)
                offset = max(offset, 0)
                code = curframe.f_code
                co_code = code.co_code
                disassemble_bytes(self.msg, self.msg_nocr,
                                  co_code, offset, line_no, line_no-1, line_no+1,
                                  constants=code.co_consts, cells=code.co_cellvars,
                                  varnames=code.co_varnames, freevars=code.co_freevars,
                                  linestarts=dict(findlinestarts(code)),
                                  end_offset=offset+10)
                pass
            pass
        else:
            if mainfile:
                part1 = "Python program '%s'" % mainfile
                msg   = "is not currently running. "
                self.msg(Mmisc.wrapped_lines(part1, msg,
                                             self.settings['width']))
            else:
                self.msg('No Python program is currently running.')
                pass
            self.msg(self.core.execution_status)
            pass
        return False


def interact(banner=None, readfunc=None, my_locals=None, my_globals=None):
    """Almost a copy of code.interact
    Closely emulate the interactive Python interpreter.

    This is a backwards compatible interface to the InteractiveConsole
    class.  When readfunc is not specified, it attempts to import the
    readline module to enable GNU readline if it is available.

    Arguments (all optional, all default to None):

    banner -- passed to InteractiveConsole.interact()
    readfunc -- if not None, replaces InteractiveConsole.raw_input()
    local -- passed to InteractiveInterpreter.__init__()

    """
    console = code.InteractiveConsole(my_locals, filename='<trepan>')
    console.runcode = lambda code_obj: runcode(console, code_obj)
    setattr(console, 'globals', my_globals)
    if readfunc is not None:
        console.raw_input = readfunc
    else:
        try:
            import readline
        except ImportError:
            pass
    console.interact(banner)
    pass

def interact ( banner = None , readfunc = None , my_locals = None , my_globals = None ) : console = code . InteractiveConsole ( my_locals , filename = '<trepan>' ) console . runcode = lambda code_obj : runcode ( console , code_obj ) setattr ( console , 'globals' , my_globals ) if readfunc is not None : console . raw_input = readfunc else : try : import readline except ImportError : pass console . interact ( banner ) pass

Almost a copy of code . interact Closely emulate the interactive Python interpreter .


def arg_split(s, posix=False):
    """Split a command line's arguments in a shell-like manner returned
    as a list of lists. Use ';;' with white space to indicate separate
    commands.

    This is a modified version of the standard library's shlex.split()
    function, but with a default of posix=False for splitting, so that quotes
    in inputs are respected.
    """

    args_list = [[]]
    if isinstance(s, bytes):
        s = s.decode("utf-8")
    lex = shlex.shlex(s, posix=posix)

    lex.whitespace_split = True
    args = list(lex)
    for arg in args:
        if ';;' == arg:
            args_list.append([])
        else:
            args_list[-1].append(arg)
            pass
        pass
    return args_list

def arg_split ( s , posix = False ) : args_list = [ [ ] ] if isinstance ( s , bytes ) : s = s . decode ( "utf-8" ) lex = shlex . shlex ( s , posix = posix ) lex . whitespace_split = True args = list ( lex ) for arg in args : if ';;' == arg : args_list . append ( [ ] ) else : args_list [ - 1 ] . append ( arg ) pass pass return args_list

Split a command line s arguments in a shell - like manner returned as a list of lists . Use ;; with white space to indicate separate commands .


def get_stack(f, t, botframe, proc_obj=None):
    """Return a stack of frames which the debugger will use for in
    showing backtraces and in frame switching. As such various frame
    that are really around may be excluded unless we are debugging the
    sebugger. Also we will add traceback frame on top if that
    exists."""
    exclude_frame = lambda f: False
    if proc_obj:
        settings = proc_obj.debugger.settings
        if not settings['dbg_trepan']:
            exclude_frame = lambda f: \
                proc_obj.core.ignore_filter.is_included(f)
            pass
        pass
    stack = []
    if t and t.tb_frame is f:
        t = t.tb_next
    while f is not None:
        if exclude_frame(f): break  # See commented alternative below
        stack.append((f, f.f_lineno))
        # bdb has:
        # if f is botframe: break
        f = f.f_back
        pass
    stack.reverse()
    i = max(0, len(stack) - 1)
    while t is not None:
        stack.append((t.tb_frame, t.tb_lineno))
        t = t.tb_next
        pass
    return stack, i

def get_stack ( f , t , botframe , proc_obj = None ) : exclude_frame = lambda f : False if proc_obj : settings = proc_obj . debugger . settings if not settings [ 'dbg_trepan' ] : exclude_frame = lambda f : proc_obj . core . ignore_filter . is_included ( f ) pass pass stack = [ ] if t and t . tb_frame is f : t = t . tb_next while f is not None : if exclude_frame ( f ) : break stack . append ( ( f , f . f_lineno ) ) f = f . f_back pass stack . reverse ( ) i = max ( 0 , len ( stack ) - 1 ) while t is not None : stack . append ( ( t . tb_frame , t . tb_lineno ) ) t = t . tb_next pass return stack , i

Return a stack of frames which the debugger will use for in showing backtraces and in frame switching . As such various frame that are really around may be excluded unless we are debugging the sebugger . Also we will add traceback frame on top if that exists .


def run_hooks(obj, hooks, *args):
    """Run each function in `hooks' with args"""
    for hook in hooks:
        if hook(obj, *args): return True
        pass
    return False

def run_hooks ( obj , hooks , * args ) : for hook in hooks : if hook ( obj , * args ) : return True pass return False


def forget(self):
        """ Remove memory of state variables set in the command processor """
        self.stack       = []
        self.curindex    = 0
        self.curframe    = None
        self.thread_name = None
        self.frame_thread_name = None
        return

def forget ( self ) : self . stack = [ ] self . curindex = 0 self . curframe = None self . thread_name = None self . frame_thread_name = None return


def get_int_noerr(self, arg):
        """Eval arg and it is an integer return the value. Otherwise
        return None"""
        if self.curframe:
            g = self.curframe.f_globals
            l = self.curframe.f_locals
        else:
            g = globals()
            l = locals()
            pass
        try:
            val = int(eval(arg, g, l))
        except (SyntaxError, NameError, ValueError, TypeError):
            return None
        return val

def get_int_noerr ( self , arg ) : if self . curframe : g = self . curframe . f_globals l = self . curframe . f_locals else : g = globals ( ) l = locals ( ) pass try : val = int ( eval ( arg , g , l ) ) except ( SyntaxError , NameError , ValueError , TypeError ) : return None return val

Eval arg and it is an integer return the value . Otherwise return None


def get_int(self, arg, min_value=0, default=1, cmdname=None,
                at_most=None):
        """If no argument use the default. If arg is a an integer between
        least min_value and at_most, use that. Otherwise report an error.
        If there's a stack frame use that in evaluation."""

        if arg is None: return default
        default = self.get_int_noerr(arg)
        if default is None:
            if cmdname:
                self.errmsg(("Command '%s' expects an integer; "
                             + "got: %s.") % (cmdname, str(arg)))
            else:
                self.errmsg('Expecting a positive integer, got: %s'
                            % str(arg))
                pass
            return None
            pass
        if default < min_value:
            if cmdname:
                self.errmsg(("Command '%s' expects an integer at least" +
                             ' %d; got: %d.')
                            % (cmdname, min_value, default))
            else:
                self.errmsg(("Expecting a positive integer at least" +
                             ' %d; got: %d')
                            % (min_value, default))
                pass
            return None
        elif at_most and default > at_most:
            if cmdname:
                self.errmsg(("Command '%s' expects an integer at most" +
                             ' %d; got: %d.')
                            % (cmdname, at_most, default))
            else:
                self.errmsg(("Expecting an integer at most %d; got: %d")
                            % (at_most, default))
                pass
            pass
        return default

If no argument use the default . If arg is a an integer between least min_value and at_most use that . Otherwise report an error . If there s a stack frame use that in evaluation .


def process_commands(self):
        """Handle debugger commands."""
        if self.core.execution_status != 'No program':
            self.setup()
            self.location()
            pass
        leave_loop = run_hooks(self, self.preloop_hooks)
        self.continue_running = False

        while not leave_loop:
            try:
                run_hooks(self, self.precmd_hooks)
                # bdb had a True return to leave loop.
                # A more straight-forward way is to set
                # instance variable self.continue_running.
                leave_loop = self.process_command()
                if leave_loop or self.continue_running: break
            except EOFError:
                # If we have stacked interfaces, pop to the next
                # one.  If this is the last one however, we'll
                # just stick with that.  FIXME: Possibly we should
                # check to see if we are interactive.  and not
                # leave if that's the case. Is this the right
                # thing?  investigate and fix.
                if len(self.debugger.intf) > 1:
                    del self.debugger.intf[-1]
                    self.last_command = ''
                else:
                    if self.debugger.intf[-1].output:
                        self.debugger.intf[-1].output.writeline('Leaving')
                        raise Mexcept.DebuggerQuit
                        pass
                    break
                pass
            pass
        return run_hooks(self, self.postcmd_hooks)

def
process_commands
(
self
)
:
if
self
.
core
.
execution_status
!=
'No program'
:
self
.
setup
(
)
self
.
location
(
)
pass
leave_loop
=
run_hooks
(
self
,
self
.
preloop_hooks
)
self
.
continue_running
=
False
while
not
leave_loop
:
try
:
run_hooks
(
self
,
self
.
precmd_hooks
)
leave_loop
=
self
.
process_command
(
)
if
leave_loop
or
self
.
continue_running
:
break
except
EOFError
:
if
len
(
self
.
debugger
.
intf
)
>
1
:
del
self
.
debugger
.
intf
[
1
]
self
.
last_command
=
''
else
:
if
self
.
debugger
.
intf
[
1
]
.
output
:
self
.
debugger
.
intf
[
1
]
.
output
.
writeline
(
'Leaving'
)
raise
Mexcept
.
DebuggerQuit
pass
break
pass
pass
return
run_hooks
(
self
,
self
.
postcmd_hooks
)


def queue_startfile(self, cmdfile):
        """Arrange for file of debugger commands to get read in the
        process-command loop."""
        expanded_cmdfile = os.path.expanduser(cmdfile)
        is_readable = Mfile.readable(expanded_cmdfile)
        if is_readable:
            self.cmd_queue.append('source ' + expanded_cmdfile)
        elif is_readable is None:
            self.errmsg("source file '%s' doesn't exist" % expanded_cmdfile)
        else:
            self.errmsg("source file '%s' is not readable" %
                        expanded_cmdfile)
            pass
        return

def
queue_startfile
(
self
,
cmdfile
)
:
expanded_cmdfile
=
os
.
path
.
expanduser
(
cmdfile
)
is_readable
=
Mfile
.
readable
(
expanded_cmdfile
)
if
is_readable
:
self
.
cmd_queue
.
append
(
'source '
+
expanded_cmdfile
)
elif
is_readable
is
:
self
.
errmsg
(
"source file '%s' doesn't exist"
%
expanded_cmdfile
)
else
:
self
.
errmsg
(
"source file '%s' is not readable"
%
expanded_cmdfile
)
pass
return

Arrange for file of debugger commands to get read in the process - command loop .


def next_token(str, start_pos):
    """Find the next token in str string from start_pos, we return
    the token and the next blank position after the token or
    str.size if this is the last token. Tokens are delimited by
    white space."""
    look_at = str[start_pos:]
    match = re.search('\S', look_at)
    if match:
        pos = match.start()
    else:
        pos = 0
        pass
    next_nonblank_pos = start_pos + pos
    next_match = re.search('\s', str[next_nonblank_pos:])
    if next_match:
        next_blank_pos = next_nonblank_pos + next_match.start()
    else:
        next_blank_pos = len(str)
        pass
    return [next_blank_pos, str[next_nonblank_pos:next_blank_pos+1].rstrip()]

def next_token ( str , start_pos ) : look_at = str [ start_pos : ] match = re . search ( '\S' , look_at ) if match : pos = match . start ( ) else : pos = 0 pass next_nonblank_pos = start_pos + pos next_match = re . search ( '\s' , str [ next_nonblank_pos : ] ) if next_match : next_blank_pos = next_nonblank_pos + next_match . start ( ) else : next_blank_pos = len ( str ) pass return [ next_blank_pos , str [ next_nonblank_pos : next_blank_pos + 1 ] . rstrip ( ) ]

Find the next token in str string from start_pos we return the token and the next blank position after the token or str . size if this is the last token . Tokens are delimited by white space .


def errmsg(self, msg, prefix="** "):
        """Common routine for reporting debugger error messages.
           """
        #  self.verbose shows lines so we don't have to duplicate info
        #  here. Perhaps there should be a 'terse' mode to never show
        #  position info.
        if not self.verbose:
            location = ("%s:%s: Error in source command file"
                        % (self.script_name, self.input_lineno))
            msg = "%s%s:\n%s%s" %(prefix, location, prefix, msg)
        else:
            msg = "%s%s" %(prefix, msg)
            pass
        self.msg(msg)
        if self.abort_on_error:
            raise EOFError
        return

def
errmsg
(
self
,
msg
,
prefix
=
"** "
)
:
if
not
self
.
verbose
:
location
=
(
"%s:%s: Error in source command file"
%
(
self
.
script_name
,
self
.
input_lineno
)
)
msg
=
"%s%s:\n%s%s"
%
(
prefix
,
location
,
prefix
,
msg
)
else
:
msg
=
"%s%s"
%
(
prefix
,
msg
)
pass
self
.
msg
(
msg
)
if
self
.
abort_on_error
:
raise
EOFError
return

Common routine for reporting debugger error messages .


def read_command(self, prompt=''):
        '''Script interface to read a command. `prompt' is a parameter for
        compatibilty and is ignored.'''
        self.input_lineno += 1
        line = self.readline()
        if self.verbose:
            location = "%s line %s" % (self.script_name, self.input_lineno)
            self.msg('+ %s: %s' % (location, line))
            pass
        # Do something with history?
        return line

def
read_command
(
self
,
prompt
=
''
)
:
self
.
input_lineno
+=
1
line
=
self
.
readline
(
)
if
self
.
verbose
:
location
=
"%s line %s"
%
(
self
.
script_name
,
self
.
input_lineno
)
self
.
msg
(
'+ %s: %s'
%
(
location
,
line
)
)
pass
return
line

Script interface to read a command . prompt is a parameter for compatibilty and is ignored .


def close(self):
        """ Closes both input and output """
        self.state = 'closing'
        if self.input:
            self.input.close()
            pass
        if self.output:
            self.output.close()
            pass
        self.state = 'disconnnected'
        return

def close ( self ) : self . state = 'closing' if self . input : self . input . close ( ) pass if self . output : self . output . close ( ) pass self . state = 'disconnnected' return


def disassemble(msg, msg_nocr, section, co, lasti=-1, start_line=-1,
                end_line=None, relative_pos=False, highlight='light',
                start_offset=0, end_offset=None):
    """Disassemble a code object."""
    return disassemble_bytes(msg, msg_nocr, co.co_code, lasti, co.co_firstlineno,
                             start_line, end_line, relative_pos,
                        co.co_varnames, co.co_names, co.co_consts,
                        co.co_cellvars, co.co_freevars,
                        dict(findlinestarts(co)), highlight,
                        start_offset=start_offset, end_offset=end_offset)

def disassemble ( msg , msg_nocr , section , co , lasti = - 1 , start_line = - 1 , end_line = None , relative_pos = False , highlight = 'light' , start_offset = 0 , end_offset = None ) : return disassemble_bytes ( msg , msg_nocr , co . co_code , lasti , co . co_firstlineno , start_line , end_line , relative_pos , co . co_varnames , co . co_names , co . co_consts , co . co_cellvars , co . co_freevars , dict ( findlinestarts ( co ) ) , highlight , start_offset = start_offset , end_offset = end_offset )


def disassemble_bytes(orig_msg, orig_msg_nocr, code, lasti=-1, cur_line=0,
                      start_line=-1, end_line=None, relative_pos=False,
                      varnames=(), names=(), constants=(), cells=(),
                      freevars=(), linestarts={}, highlight='light',
                      start_offset=0, end_offset=None):
    """Disassemble byte string of code. If end_line is negative
    it counts the number of statement linestarts to use."""
    statement_count = 10000
    if end_line is None:
        end_line = 10000
    elif relative_pos:
        end_line += start_line -1
        pass

    labels = findlabels(code)

    null_print = lambda x: None
    if start_line > cur_line:
        msg_nocr = null_print
        msg = null_print
    else:
        msg_nocr = orig_msg_nocr
        msg = orig_msg

    for instr in get_instructions_bytes(code, opc, varnames, names,
                                        constants, cells, linestarts):
        offset = instr.offset
        if end_offset and offset > end_offset:
            break

        if instr.starts_line:
            if offset:
                msg("")

            cur_line = instr.starts_line
            if (start_line and ((start_line > cur_line) or
                                start_offset and start_offset > offset)) :
                msg_nocr = null_print
                msg = null_print
            else:
                statement_count -= 1
                msg_nocr = orig_msg_nocr
                msg = orig_msg
                pass
            if ((cur_line > end_line) or
                (end_offset and offset > end_offset)):
                break
            msg_nocr(format_token(Mformat.LineNumber,
                                  "%4d" % cur_line,
                                  highlight=highlight))
        else:
            if start_offset and offset and start_offset <= offset:
                msg_nocr = orig_msg_nocr
                msg = orig_msg
                pass
            msg_nocr('    ')

        if offset == lasti: msg_nocr(format_token(Mformat.Arrow, '-->',
                                                  highlight=highlight))
        else: msg_nocr('   ')
        if offset in labels: msg_nocr(format_token(Mformat.Arrow, '>>',
                                                   highlight=highlight))
        else: msg_nocr('  ')
        msg_nocr(repr(offset).rjust(4))
        msg_nocr(' ')
        msg_nocr(format_token(Mformat.Opcode,
                              instr.opname.ljust(20),
                              highlight=highlight))
        msg_nocr(repr(instr.arg).ljust(10))
        msg_nocr(' ')
        # Show argval?
        msg(format_token(Mformat.Name,
                         instr.argrepr.ljust(20),
                         highlight=highlight))
        pass

    return code, offset

def
disassemble_bytes
(
orig_msg
,
orig_msg_nocr
,
code
,
lasti
=
1
,
cur_line
=
0
,
start_line
=
1
,
end_line
=
,
relative_pos
=
False
,
varnames
=
(
)
,
names
=
(
)
,
constants
=
(
)
,
cells
=
(
)
,
freevars
=
(
)
,
linestarts
=
{
}
,
highlight
=
'light'
,
start_offset
=
0
,
end_offset
=
)
:
statement_count
=
10000
if
end_line
is
:
end_line
=
10000
elif
relative_pos
:
end_line
+=
start_line
1
pass
labels
=
findlabels
(
code
)
null_print
=
lambda
x
:
if
start_line
>
cur_line
:
msg_nocr
=
null_print
msg
=
null_print
else
:
msg_nocr
=
orig_msg_nocr
msg
=
orig_msg
for
instr
in
get_instructions_bytes
(
code
,
opc
,
varnames
,
names
,
constants
,
cells
,
linestarts
)
:
offset
=
instr
.
offset
if
end_offset
and
offset
>
end_offset
:
break
if
instr
.
starts_line
:
if
offset
:
msg
(
""
)
cur_line
=
instr
.
starts_line
if
(
start_line
and
(
(
start_line
>
cur_line
)
or
start_offset
and
start_offset
>
offset
)
)
:
msg_nocr
=
null_print
msg
=
null_print
else
:
statement_count
-=
1
msg_nocr
=
orig_msg_nocr
msg
=
orig_msg
pass
if
(
(
cur_line
>
end_line
)
or
(
end_offset
and
offset
>
end_offset
)
)
:
break
msg_nocr
(
format_token
(
Mformat
.
LineNumber
,
"%4d"
%
cur_line
,
highlight
=
highlight
)
)
else
:
if
start_offset
and
offset
and
start_offset
<=
offset
:
msg_nocr
=
orig_msg_nocr
msg
=
orig_msg
pass
msg_nocr
(
'    '
)
if
offset
==
lasti
:
msg_nocr
(
format_token
(
Mformat
.
Arrow
,
'
,
highlight
=
highlight
)
)
else
:
msg_nocr
(
'   '
)
if
offset
in
labels
:
msg_nocr
(
format_token
(
Mformat
.
Arrow
,
'>>'
,
highlight
=
highlight
)
)
else
:
msg_nocr
(
'  '
)
msg_nocr
(
repr
(
offset
)
.
rjust
(
4
)
)
msg_nocr
(
' '
)
msg_nocr
(
format_token
(
Mformat
.
Opcode
,
instr
.
opname
.
ljust
(
20
)
,
highlight
=
highlight
)
)
msg_nocr
(
repr
(
instr
.
arg
)
.
ljust
(
10
)
)
msg_nocr
(
' '
)
msg
(
format_token
(
Mformat
.
Name
,
instr
.
argrepr
.
ljust
(
20
)
,
highlight
=
highlight
)
)
pass
return
code
,
offset

Disassemble byte string of code . If end_line is negative it counts the number of statement linestarts to use .


def count_frames(frame, count_start=0):
    "Return a count of the number of frames"
    count = -count_start
    while frame:
        count += 1
        frame = frame.f_back
    return count


def get_call_function_name(frame):
    """If f_back is looking at a call function, return
    the name for it. Otherwise return None"""
    f_back = frame.f_back
    if not f_back: return None
    if 'CALL_FUNCTION' != Mbytecode.op_at_frame(f_back): return None

    co         = f_back.f_code
    code       = co.co_code
    # labels     = dis.findlabels(code)
    linestarts = dict(dis.findlinestarts(co))
    offset     = f_back.f_lasti
    while offset >= 0:
        if offset in linestarts:
            op = code[offset]
            offset += 1
            arg = code[offset]
            # FIXME: put this code in xdis
            extended_arg = 0
            while True:
                if PYTHON_VERSION >= 3.6:
                    if op == opc.EXTENDED_ARG:
                        extended_arg += (arg << 8)
                        continue
                    arg = code[offset] + extended_arg
                    # FIXME: Python 3.6.0a1 is 2, for 3.6.a3 we have 1
                else:
                    if op == opc.EXTENDED_ARG:
                        extended_arg += (arg << 256)
                        continue
                    arg = code[offset] + code[offset+1]*256 + extended_arg
                break

            return co.co_names[arg]
        offset -= 1
        pass
    return None

def get_call_function_name ( frame ) : f_back = frame . f_back if not f_back : return None if 'CALL_FUNCTION' != Mbytecode . op_at_frame ( f_back ) : return None co = f_back . f_code code = co . co_code linestarts = dict ( dis . findlinestarts ( co ) ) offset = f_back . f_lasti while offset >= 0 : if offset in linestarts : op = code [ offset ] offset += 1 arg = code [ offset ] extended_arg = 0 while True : if PYTHON_VERSION >= 3.6 : if op == opc . EXTENDED_ARG : extended_arg += ( arg << 8 ) continue arg = code [ offset ] + extended_arg else : if op == opc . EXTENDED_ARG : extended_arg += ( arg << 256 ) continue arg = code [ offset ] + code [ offset + 1 ] * 256 + extended_arg break return co . co_names [ arg ] offset -= 1 pass return None

If f_back is looking at a call function return the name for it . Otherwise return None


def print_stack_trace(proc_obj, count=None, color='plain', opts={}):
    "Print count entries of the stack trace"
    if count is None:
        n=len(proc_obj.stack)
    else:
        n=min(len(proc_obj.stack), count)
    try:
        for i in range(n):
            print_stack_entry(proc_obj, i, color=color, opts=opts)
    except KeyboardInterrupt:
        pass
    return


def lookup(self, subcmd_prefix):
        """Find subcmd in self.subcmds"""
        for subcmd_name in list(self.subcmds.keys()):
            if subcmd_name.startswith(subcmd_prefix) \
               and len(subcmd_prefix) >= \
               self.subcmds[subcmd_name].__class__.min_abbrev:
                return self.subcmds[subcmd_name]
            pass
        return None

def lookup ( self , subcmd_prefix ) : for subcmd_name in list ( self . subcmds . keys ( ) ) : if subcmd_name . startswith ( subcmd_prefix ) and len ( subcmd_prefix ) >= self . subcmds [ subcmd_name ] . __class__ . min_abbrev : return self . subcmds [ subcmd_name ] pass return None


def short_help(self, subcmd_cb, subcmd_name, label=False):
        """Show short help for a subcommand."""
        entry = self.lookup(subcmd_name)
        if entry:
            if label:
                prefix = entry.name
            else:
                prefix = ''
                pass
            if hasattr(entry, 'short_help'):
                if prefix: prefix += ' -- '
                self.cmd_obj.msg(prefix + entry.short_help)
                pass
            pass
        else:
            self.undefined_subcmd("help", subcmd_name)
            pass
        return

def
short_help
(
self
,
subcmd_cb
,
subcmd_name
,
label
=
False
)
:
entry
=
self
.
lookup
(
subcmd_name
)
if
entry
:
if
label
:
prefix
=
entry
.
name
else
:
prefix
=
''
pass
if
hasattr
(
entry
,
'short_help'
)
:
if
prefix
:
prefix
+=
' -- '
self
.
cmd_obj
.
msg
(
prefix
+
entry
.
short_help
)
pass
pass
else
:
self
.
undefined_subcmd
(
"help"
,
subcmd_name
)
pass
return


def add(self, subcmd_cb):
        """Add subcmd to the available subcommands for this object.
        It will have the supplied docstring, and subcmd_cb will be called
        when we want to run the command. min_len is the minimum length
        allowed to abbreviate the command. in_list indicates with the
        show command will be run when giving a list of all sub commands
        of this object. Some commands have long output like "show commands"
        so we might not want to show that.
        """
        subcmd_name = subcmd_cb.name
        self.subcmds[subcmd_name] = subcmd_cb

        # We keep a list of subcommands to assist command completion
        self.cmdlist.append(subcmd_name)

def add ( self , subcmd_cb ) : subcmd_name = subcmd_cb . name self . subcmds [ subcmd_name ] = subcmd_cb self . cmdlist . append ( subcmd_name )

Add subcmd to the available subcommands for this object . It will have the supplied docstring and subcmd_cb will be called when we want to run the command . min_len is the minimum length allowed to abbreviate the command . in_list indicates with the show command will be run when giving a list of all sub commands of this object . Some commands have long output like show commands so we might not want to show that .


def run(self, subcmd_name, arg):
        """Run subcmd_name with args using obj for the environent"""
        entry=self.lookup(subcmd_name)
        if entry:
            entry['callback'](arg)
        else:
            self.cmdproc.undefined_cmd(entry.__class__.name, subcmd_name)
            pass
        return

def run ( self , subcmd_name , arg ) : entry = self . lookup ( subcmd_name ) if entry : entry [ 'callback' ] ( arg ) else : self . cmdproc . undefined_cmd ( entry . __class__ . name , subcmd_name ) pass return


def debug(dbg_opts=None, start_opts=None, post_mortem=True,
          step_ignore=1, level=0):
    """
Enter the debugger.

Parameters
----------

level : how many stack frames go back. Usually it will be
the default 0. But sometimes though there may be calls in setup to the debugger
that you may want to skip.

step_ignore : how many line events to ignore after the
debug() call. 0 means don't even wait for the debug() call to finish.

param dbg_opts : is an optional "options" dictionary that gets fed
trepan.Debugger(); `start_opts' are the optional "options"
dictionary that gets fed to trepan.Debugger.core.start().

Use like this:

.. code-block:: python

    ... # Possibly some Python code
    import trepan.api # Needed only once
    ... # Possibly some more Python code
    trepan.api.debug() # You can wrap inside conditional logic too
    pass  # Stop will be here.
    # Below is code you want to use the debugger to do things.
    ....  # more Python code
    # If you get to a place in the program where you aren't going
    # want to debug any more, but want to remove debugger trace overhead:
    trepan.api.stop()

Parameter "level" specifies how many stack frames go back. Usually it will be
the default 0. But sometimes though there may be calls in setup to the debugger
that you may want to skip.

Parameter "step_ignore" specifies how many line events to ignore after the
debug() call. 0 means don't even wait for the debug() call to finish.

In situations where you want an immediate stop in the "debug" call
rather than the statement following it ("pass" above), add parameter
step_ignore=0 to debug() like this::

    import trepan.api  # Needed only once
    # ... as before
    trepan.api.debug(step_ignore=0)
    # ... as before

Module variable _debugger_obj_ from module trepan.debugger is used as
the debugger instance variable; it can be subsequently used to change
settings or alter behavior. It should be of type Debugger (found in
module trepan). If not, it will get changed to that type::

   $ python
   >>> from trepan.debugger import debugger_obj
   >>> type(debugger_obj)
   <type 'NoneType'>
   >>> import trepan.api
   >>> trepan.api.debug()
   ...
   (Trepan) c
   >>> from trepan.debugger import debugger_obj
   >>> debugger_obj
   <trepan.debugger.Debugger instance at 0x7fbcacd514d0>
   >>>

If however you want your own separate debugger instance, you can
create it from the debugger _class Debugger()_ from module
trepan.debugger::

  $ python
  >>> from trepan.debugger import Debugger
  >>> dbgr = Debugger()  # Add options as desired
  >>> dbgr
  <trepan.debugger.Debugger instance at 0x2e25320>

`dbg_opts' is an optional "options" dictionary that gets fed
trepan.Debugger(); `start_opts' are the optional "options"
dictionary that gets fed to trepan.Debugger.core.start().
"""
    if not isinstance(Mdebugger.debugger_obj, Mdebugger.Trepan):
        Mdebugger.debugger_obj = Mdebugger.Trepan(dbg_opts)
        Mdebugger.debugger_obj.core.add_ignore(debug, stop)
        pass
    core = Mdebugger.debugger_obj.core
    frame = sys._getframe(0+level)
    core.set_next(frame)
    if start_opts and 'startup-profile' in start_opts and start_opts['startup-profile']:
        dbg_initfiles = start_opts['startup-profile']
        from trepan import options
        options.add_startup_file(dbg_initfiles)
        for init_cmdfile in dbg_initfiles:
            core.processor.queue_startfile(init_cmdfile)

    if not core.is_started():
        core.start(start_opts)
        pass
    if post_mortem:
        debugger_on_post_mortem()
        pass
    if 0 == step_ignore:
        frame                   = sys._getframe(1+level)
        core.stop_reason        = 'at a debug() call'
        old_trace_hook_suspend  = core.trace_hook_suspend
        core.trace_hook_suspend = True
        core.processor.event_processor(frame, 'line', None)
        core.trace_hook_suspend = old_trace_hook_suspend
    else:
        core.step_ignore = step_ignore-1
        pass
    return

def
debug
(
dbg_opts
=
,
start_opts
=
,
post_mortem
=
True
,
step_ignore
=
1
,
level
=
0
)
:
if
not
isinstance
(
Mdebugger
.
debugger_obj
,
Mdebugger
.
Trepan
)
:
Mdebugger
.
debugger_obj
=
Mdebugger
.
Trepan
(
dbg_opts
)
Mdebugger
.
debugger_obj
.
core
.
add_ignore
(
debug
,
stop
)
pass
core
=
Mdebugger
.
debugger_obj
.
core
frame
=
sys
.
_getframe
(
0
+
level
)
core
.
set_next
(
frame
)
if
start_opts
and
'startup-profile'
in
start_opts
and
start_opts
[
'startup-profile'
]
:
dbg_initfiles
=
start_opts
[
'startup-profile'
]
from
trepan
import
options
options
.
add_startup_file
(
dbg_initfiles
)
for
init_cmdfile
in
dbg_initfiles
:
core
.
processor
.
queue_startfile
(
init_cmdfile
)
if
not
core
.
is_started
(
)
:
core
.
start
(
start_opts
)
pass
if
post_mortem
:
debugger_on_post_mortem
(
)
pass
if
0
==
step_ignore
:
frame
=
sys
.
_getframe
(
1
+
level
)
core
.
stop_reason
=
'at a debug() call'
old_trace_hook_suspend
=
core
.
trace_hook_suspend
core
.
trace_hook_suspend
=
True
core
.
processor
.
event_processor
(
frame
,
'line'
,
)
core
.
trace_hook_suspend
=
old_trace_hook_suspend
else
:
core
.
step_ignore
=
step_ignore
1
pass
return


def show_category(self, category, args):
        """Show short help for all commands in `category'."""
        n2cmd = self.proc.commands
        names = list(n2cmd.keys())
        if len(args) == 1 and args[0] == '*':
            self.section("Commands in class %s:" % category)
            cmds = [cmd for cmd in names if category == n2cmd[cmd].category]
            cmds.sort()
            self.msg_nocr(self.columnize_commands(cmds))
            return

        self.msg("%s.\n" % categories[category])
        self.section("List of commands:")
        names.sort()
        for name in names:  # Foo! iteritems() doesn't do sorting
            if category != n2cmd[name].category: continue
            self.msg("%-13s -- %s" % (name, n2cmd[name].short_help,))
            pass
        return

def
show_category
(
self
,
category
,
args
)
:
n2cmd
=
self
.
proc
.
commands
names
=
list
(
n2cmd
.
keys
(
)
)
if
len
(
args
)
==
1
and
args
[
0
]
==
'*'
:
self
.
section
(
"Commands in class %s:"
%
category
)
cmds
=
[
cmd
for
cmd
in
names
if
category
==
n2cmd
[
cmd
]
.
category
]
cmds
.
sort
(
)
self
.
msg_nocr
(
self
.
columnize_commands
(
cmds
)
)
return
self
.
msg
(
"%s.\n"
%
categories
[
category
]
)
self
.
section
(
"List of commands:"
)
names
.
sort
(
)
for
name
in
names
:
if
category
!=
n2cmd
[
name
]
.
category
:
continue
self
.
msg
(
"%-13s -- %s"
%
(
name
,
n2cmd
[
name
]
.
short_help
,
)
)
pass
return

Show short help for all commands in category .


def run(self, args):
        """Current line number in source file"""
        # info line identifier
        if not self.proc.curframe:
            self.errmsg("No line number information available.")
            return
        if len(args) == 3:
            # lineinfo returns (item, file, lineno) or (None,)
            answer = self.lineinfo(args[2])
            if answer[0]:
                item, filename, lineno = answer
                if not os.path.isfile(filename):
                    filename = Mclifns.search_file(filename,
                                                   self.core.search_path,
                                                   self.main_dirname)
                self.msg('Line %s of "%s" <%s>' %
                         (lineno, filename, item))
            return
        filename=self.core.canonic_filename(self.proc.curframe)
        if not os.path.isfile(filename):
            filename = Mclifns.search_file(filename, self.core.search_path,
                                           self.main_dirname)
            pass

        filename = self.core.canonic_filename(self.proc.curframe)
        msg1 = 'Line %d of \"%s\"'  % (inspect.getlineno(self.proc.curframe),
                                       self.core.filename(filename))
        msg2 = ('at instruction %d' % self.proc.curframe.f_lasti)
        if self.proc.event:
            msg2 += ', %s event' % self.proc.event
            pass
        self.msg(Mmisc.wrapped_lines(msg1, msg2, self.settings['width']))
        return False

def
run
(
self
,
args
)
:
if
not
self
.
proc
.
curframe
:
self
.
errmsg
(
"No line number information available."
)
return
if
len
(
args
)
==
3
:
answer
=
self
.
lineinfo
(
args
[
2
]
)
if
answer
[
0
]
:
item
,
filename
,
lineno
=
answer
if
not
os
.
path
.
isfile
(
filename
)
:
filename
=
Mclifns
.
search_file
(
filename
,
self
.
core
.
search_path
,
self
.
main_dirname
)
self
.
msg
(
'Line %s of "%s" <%s>'
%
(
lineno
,
filename
,
item
)
)
return
filename
=
self
.
core
.
canonic_filename
(
self
.
proc
.
curframe
)
if
not
os
.
path
.
isfile
(
filename
)
:
filename
=
Mclifns
.
search_file
(
filename
,
self
.
core
.
search_path
,
self
.
main_dirname
)
pass
filename
=
self
.
core
.
canonic_filename
(
self
.
proc
.
curframe
)
msg1
=
'Line %d of \"%s\"'
%
(
inspect
.
getlineno
(
self
.
proc
.
curframe
)
,
self
.
core
.
filename
(
filename
)
)
msg2
=
(
'at instruction %d'
%
self
.
proc
.
curframe
.
f_lasti
)
if
self
.
proc
.
event
:
msg2
+=
', %s event'
%
self
.
proc
.
event
pass
self
.
msg
(
Mmisc
.
wrapped_lines
(
msg1
,
msg2
,
self
.
settings
[
'width'
]
)
)
return
False


def find_debugged_frame(frame):
    """Find the first frame that is a debugged frame. We do this
    Generally we want traceback information without polluting it with
    debugger frames. We can tell these because those are frames on the
    top which don't have f_trace set. So we'll look back from the top
    to find the fist frame where f_trace is set.
    """
    f_prev = f = frame
    while f is not None and f.f_trace is None:
        f_prev = f
        f = f.f_back
        pass
    if f_prev:
        val = f_prev.f_locals.get('tracer_func_frame')
        if val == f_prev:
            if f_prev.f_back:
                f_prev = f_prev.f_back
                pass
            pass
        pass
    else:
        return frame
    return f_prev

def find_debugged_frame ( frame ) : f_prev = f = frame while f is not None and f . f_trace is None : f_prev = f f = f . f_back pass if f_prev : val = f_prev . f_locals . get ( 'tracer_func_frame' ) if val == f_prev : if f_prev . f_back : f_prev = f_prev . f_back pass pass pass else : return frame return f_prev

Find the first frame that is a debugged frame . We do this Generally we want traceback information without polluting it with debugger frames . We can tell these because those are frames on the top which don t have f_trace set . So we ll look back from the top to find the fist frame where f_trace is set .


def map_thread_names():
    '''Invert threading._active'''
    name2id = {}
    for thread_id in list(threading._active.keys()):
        thread = threading._active[thread_id]
        name = thread.getName()
        if name not in list(name2id.keys()):
            name2id[name] = thread_id
            pass
        pass
    return name2id

def map_thread_names ( ) : name2id = { } for thread_id in list ( threading . _active . keys ( ) ) : thread = threading . _active [ thread_id ] name = thread . getName ( ) if name not in list ( name2id . keys ( ) ) : name2id [ name ] = thread_id pass pass return name2id


def get_int(errmsg, arg, default=1, cmdname=None):
    """If arg is an int, use that otherwise take default."""
    if arg:
        try:
            # eval() is used so we will allow arithmetic expressions,
            # variables etc.
            default = int(eval(arg))
        except (SyntaxError, NameError, ValueError):
            if cmdname:
                errmsg("Command '%s' expects an integer; got: %s." %
                       (cmdname, str(arg)))
            else:
                errmsg('Expecting an integer, got: %s.' % str(arg))
                pass
            raise ValueError
    return default

If arg is an int use that otherwise take default .


def get_onoff(errmsg, arg, default=None, print_error=True):
    """Return True if arg is 'on' or 1 and False arg is 'off' or 0.
    Any other value is raises ValueError."""
    if not arg:
        if default is None:
            if print_error:
                errmsg("Expecting 'on', 1, 'off', or 0. Got nothing.")
                pass
            raise ValueError
        return default
    if arg == '1' or arg == 'on': return True
    if arg == '0' or arg =='off': return False

    if print_error:
        errmsg("Expecting 'on', 1, 'off', or 0. Got: %s." % str(arg))
    raise ValueError

Return True if arg is on or 1 and False arg is off or 0 . Any other value is raises ValueError .


def run_set_bool(obj, args):
    """set a Boolean-valued debugger setting. 'obj' is a generally a
    subcommand that has 'name' and 'debugger.settings' attributes"""
    try:
        if 0 == len(args): args = ['on']
        obj.debugger.settings[obj.name] = get_onoff(obj.errmsg, args[0])
    except ValueError:
        pass
    return

def run_set_bool ( obj , args ) : try : if 0 == len ( args ) : args = [ 'on' ] obj . debugger . settings [ obj . name ] = get_onoff ( obj . errmsg , args [ 0 ] ) except ValueError : pass return

set a Boolean - valued debugger setting . obj is a generally a subcommand that has name and debugger . settings attributes


def run_set_int(obj, arg, msg_on_error, min_value=None, max_value=None):
    """set an Integer-valued debugger setting. 'obj' is a generally a
    subcommand that has 'name' and 'debugger.settings' attributes"""
    if '' == arg.strip():
        obj.errmsg("You need to supply a number.")
        return
    obj.debugger.settings[obj.name] = \
        get_an_int(obj.errmsg, arg, msg_on_error, min_value, max_value)
    return obj.debugger.settings[obj.name]

def
run_set_int
(
obj
,
arg
,
msg_on_error
,
min_value
=
,
max_value
=
)
:
if
''
==
arg
.
strip
(
)
:
obj
.
errmsg
(
"You need to supply a number."
)
return
obj
.
debugger
.
settings
[
obj
.
name
]
=
get_an_int
(
obj
.
errmsg
,
arg
,
msg_on_error
,
min_value
,
max_value
)
return
obj
.
debugger
.
settings
[
obj
.
name
]

set an Integer - valued debugger setting . obj is a generally a subcommand that has name and debugger . settings attributes


def run_show_bool(obj, what=None):
    """Generic subcommand showing a boolean-valued debugger setting.
    'obj' is generally a subcommand that has 'name' and
    'debugger.setting' attributes."""
    val = show_onoff(obj.debugger.settings[obj.name])
    if not what: what = obj.name
    return obj.msg("%s is %s." % (what, val))

def
run_show_bool
(
obj
,
what
=
)
:
val
=
show_onoff
(
obj
.
debugger
.
settings
[
obj
.
name
]
)
if
not
what
:
what
=
obj
.
name
return
obj
.
msg
(
"%s is %s."
%
(
what
,
val
)
)

Generic subcommand showing a boolean - valued debugger setting . obj is generally a subcommand that has name and debugger . setting attributes .


def run_show_int(obj, what=None):
    """Generic subcommand integer value display"""
    val = obj.debugger.settings[obj.name]
    if not what: what = obj.name
    return obj.msg("%s is %d." % (what, val))

def
run_show_int
(
obj
,
what
=
)
:
val
=
obj
.
debugger
.
settings
[
obj
.
name
]
if
not
what
:
what
=
obj
.
name
return
obj
.
msg
(
"%s is %d."
%
(
what
,
val
)
)


def run_show_val(obj, name):
    """Generic subcommand value display"""
    val = obj.debugger.settings[obj.name]
    obj.msg("%s is %s." % (obj.name, obj.cmd.proc._saferepr(val),))
    return False

def
run_show_val
(
obj
,
name
)
:
val
=
obj
.
debugger
.
settings
[
obj
.
name
]
obj
.
msg
(
"%s is %s."
%
(
obj
.
name
,
obj
.
cmd
.
proc
.
_saferepr
(
val
)
,
)
)
return
False


def is_def_stmt(line, frame):
    """Return True if we are looking at a def statement"""
    # Should really also check that operand of 'LOAD_CONST' is a code object
    return (line and _re_def.match(line) and op_at_frame(frame)=='LOAD_CONST'
            and stmt_contains_opcode(frame.f_code, frame.f_lineno,
                                          'MAKE_FUNCTION'))

def is_def_stmt ( line , frame ) : return ( line and _re_def . match ( line ) and op_at_frame ( frame ) == 'LOAD_CONST' and stmt_contains_opcode ( frame . f_code , frame . f_lineno , 'MAKE_FUNCTION' ) )


def is_class_def(line, frame):
    """Return True if we are looking at a class definition statement"""
    return (line and _re_class.match(line)
            and stmt_contains_opcode(frame.f_code, frame.f_lineno,
                                     'BUILD_CLASS'))

def is_class_def ( line , frame ) : return ( line and _re_class . match ( line ) and stmt_contains_opcode ( frame . f_code , frame . f_lineno , 'BUILD_CLASS' ) )


def threaded_quit(self, arg):
        """ quit command when several threads are involved. """
        threading_list = threading.enumerate()
        mythread =  threading.currentThread()
        for t in threading_list:
            if t != mythread:
                ctype_async_raise(t, Mexcept.DebuggerQuit)
                pass
            pass
        raise Mexcept.DebuggerQuit

def threaded_quit ( self , arg ) : threading_list = threading . enumerate ( ) mythread = threading . currentThread ( ) for t in threading_list : if t != mythread : ctype_async_raise ( t , Mexcept . DebuggerQuit ) pass pass raise Mexcept . DebuggerQuit

quit command when several threads are involved .


def set_default_bg():
    """Get bacground from
    default values based on the TERM environment variable
    """
    term = environ.get('TERM', None)
    if term:
        if (term.startswith('xterm',) or term.startswith('eterm')
            or term == 'dtterm'):
            return False
    return True

def set_default_bg ( ) : term = environ . get ( 'TERM' , None ) if term : if ( term . startswith ( 'xterm' , ) or term . startswith ( 'eterm' ) or term == 'dtterm' ) : return False return True


def is_dark_rgb(r, g, b):
    """Pass as parameters R G B values in hex
    On return, variable is_dark_bg is set
    """

    try:
        midpoint = int(environ.get('TERMINAL_COLOR_MIDPOINT', None))
    except:
        pass
    if not midpoint:
        term = environ.get('TERM', None)
        # 117963 = (* .6 (+ 65535 65535 65535))
        # 382.5 = (* .6 (+ 65535 65535 65535))
        print("midpoint", midpoint, 'vs',  (16*5 + 16*g + 16*b))
        midpoint = 383 if term and term == 'xterm-256color' else 117963

    if ( (16*5 + 16*g + 16*b) < midpoint ):
        return True
    else:
        return False

def is_dark_rgb ( r , g , b ) : try : midpoint = int ( environ . get ( 'TERMINAL_COLOR_MIDPOINT' , None ) ) except : pass if not midpoint : term = environ . get ( 'TERM' , None ) print ( "midpoint" , midpoint , 'vs' , ( 16 * 5 + 16 * g + 16 * b ) ) midpoint = 383 if term and term == 'xterm-256color' else 117963 if ( ( 16 * 5 + 16 * g + 16 * b ) < midpoint ) : return True else : return False

Pass as parameters R G B values in hex On return variable is_dark_bg is set


def signature(frame):
    '''return suitable frame signature to key display expressions off of.'''
    if not frame: return None
    code = frame.f_code
    return (code.co_name, code.co_filename, code.co_firstlineno)

def signature ( frame ) : if not frame : return None code = frame . f_code return ( code . co_name , code . co_filename , code . co_firstlineno )

return suitable frame signature to key display expressions off of .


def all(self):
        """List all display items; return 0 if none"""
        found = False
        s = []
        for display in self.list:
            if not found:
                s.append("""Auto-display expressions now in effect:
Num Enb Expression""")
                found = True
                pass
            s.append(display.format())
        return s

def all ( self ) : found = False s = [ ] for display in self . list : if not found : s . append ( ) found = True pass s . append ( display . format ( ) ) return s

List all display items ; return 0 if none


def display(self, frame):
        '''display any items that are active'''
        if not frame: return
        s = []
        sig = signature(frame)
        for display in self.list:
            if display.signature == sig and display.enabled:
                s.append(display.to_s(frame))
                pass
            pass
        return s

def display ( self , frame ) : if not frame : return s = [ ] sig = signature ( frame ) for display in self . list : if display . signature == sig and display . enabled : s . append ( display . to_s ( frame ) ) pass pass return s


def format(self, show_enabled=True):
        '''format display item'''
        what = ''
        if show_enabled:
            if self.enabled:
                what += ' y '
            else:
                what += ' n '
                pass
            pass
        if self.fmt:
            what += self.fmt + ' '
            pass
        what += self.arg
        return '%3d: %s' % (self.number, what)

def
format
(
self
,
show_enabled
=
True
)
:
what
=
''
if
show_enabled
:
if
self
.
enabled
:
what
+=
' y '
else
:
what
+=
' n '
pass
pass
if
self
.
fmt
:
what
+=
self
.
fmt
+
' '
pass
what
+=
self
.
arg
return
'%3d: %s'
%
(
self
.
number
,
what
)


def read_msg(self):
        """Read one message unit. It's possible however that
        more than one message will be set in a receive, so we will
        have to buffer that for the next read.
        EOFError will be raised on EOF.
        """
        if self.state == 'connected':
            if 0 == len(self.buf):
                self.buf = self.inout.recv(Mtcpfns.TCP_MAX_PACKET)
                if 0 == (self.buf):
                    self.state = 'disconnected'
                    raise EOFError
                pass
            self.buf, data = Mtcpfns.unpack_msg(self.buf)
            return data.decode('utf-8')
        else:
            raise IOError("read_msg called in state: %s." % self.state)

def
read_msg
(
self
)
:
if
self
.
state
==
'connected'
:
if
0
==
len
(
self
.
buf
)
:
self
.
buf
=
self
.
inout
.
recv
(
Mtcpfns
.
TCP_MAX_PACKET
)
if
0
==
(
self
.
buf
)
:
self
.
state
=
'disconnected'
raise
EOFError
pass
self
.
buf
,
data
=
Mtcpfns
.
unpack_msg
(
self
.
buf
)
return
data
.
decode
(
'utf-8'
)
else
:
raise
IOError
(
"read_msg called in state: %s."
%
self
.
state
)

Read one message unit . It s possible however that more than one message will be set in a receive so we will have to buffer that for the next read . EOFError will be raised on EOF .


def debug(frame=None):
    """Set breakpoint at current location, or a specified frame"""
    # ???
    if frame is None:
        frame = _frame().f_back

    dbg = RemoteCeleryTrepan()
    dbg.say(BANNER.format(self=dbg))
    # dbg.say(SESSION_STARTED.format(self=dbg))
    trepan.api.debug(dbg_opts=dbg.dbg_opts)

def debug ( frame = None ) : if frame is None : frame = _frame ( ) . f_back dbg = RemoteCeleryTrepan ( ) dbg . say ( BANNER . format ( self = dbg ) ) trepan . api . debug ( dbg_opts = dbg . dbg_opts )

Set breakpoint at current location or a specified frame


def undefined_subcmd(self, cmd, subcmd):
        """Error message when subcommand asked for but doesn't exist"""
        self.proc.intf[-1].errmsg(('Undefined "%s" subcommand: "%s". ' +
                                  'Try "help %s *".') % (cmd, subcmd, cmd))
        return

def
undefined_subcmd
(
self
,
cmd
,
subcmd
)
:
self
.
proc
.
intf
[
1
]
.
errmsg
(
(
'Undefined "%s" subcommand: "%s". '
+
'Try "help %s *".'
)
%
(
cmd
,
subcmd
,
cmd
)
)
return

Error message when subcommand asked for but doesn t exist


def run(self, args):
        '''Run a frame command. This routine is a little complex
        because we allow a number parameter variations.'''

        if len(args) == 1:
            # Form is: "frame" which means "frame 0"
            position_str = '0'
        elif len(args) == 2:
            # Form is: "frame {position | thread}
            name_or_id = args[1]
            frame, thread_id = self.get_from_thread_name_or_id(name_or_id,
                                                               False)
            if frame is None:
                # Form should be: frame position
                position_str = name_or_id
            else:
                # Form should be: "frame thread" which means
                # "frame thread 0"
                position_str = '0'
                self.find_and_set_debugged_frame(frame, thread_id)
                pass
        elif len(args) == 3:
            # Form is: frame <thread> <position>
            name_or_id = args[1]
            position_str = args[2]
            frame, thread_id = self.get_from_thread_name_or_id(name_or_id)
            if frame is None:
                # Error message was given in routine
                return
            self.find_and_set_debugged_frame(frame, thread_id)
            pass
        self.one_arg_run(position_str)
        return False

def run ( self , args ) : if len ( args ) == 1 : position_str = '0' elif len ( args ) == 2 : name_or_id = args [ 1 ] frame , thread_id = self . get_from_thread_name_or_id ( name_or_id , False ) if frame is None : position_str = name_or_id else : position_str = '0' self . find_and_set_debugged_frame ( frame , thread_id ) pass elif len ( args ) == 3 : name_or_id = args [ 1 ] position_str = args [ 2 ] frame , thread_id = self . get_from_thread_name_or_id ( name_or_id ) if frame is None : return self . find_and_set_debugged_frame ( frame , thread_id ) pass self . one_arg_run ( position_str ) return False

Run a frame command . This routine is a little complex because we allow a number parameter variations .


def pprint_simple_array(val, displaywidth, msg_nocr, msg, lineprefix=''):
    '''Try to pretty print a simple case where a list is not nested.
    Return True if we can do it and False if not. '''

    if type(val) != list:
        return False

    numeric = True
    for i in range(len(val)):
        if not (type(val[i]) in [bool, float, int]):
            numeric = False
            if not (type(val[i]) in [bool, float, int, bytes]):
                return False
            pass
        pass
    mess = columnize([repr(v) for v in val],
                     opts={"arrange_array": True,
                           "lineprefix": lineprefix,
                           "displaywidth": int(displaywidth)-3,
                           'ljust': not numeric})
    msg_nocr(mess)
    return True

def pprint_simple_array ( val , displaywidth , msg_nocr , msg , lineprefix = '' ) : if type ( val ) != list : return False numeric = True for i in range ( len ( val ) ) : if not ( type ( val [ i ] ) in [ bool , float , int ] ) : numeric = False if not ( type ( val [ i ] ) in [ bool , float , int , bytes ] ) : return False pass pass mess = columnize ( [ repr ( v ) for v in val ] , opts = { "arrange_array" : True , "lineprefix" : lineprefix , "displaywidth" : int ( displaywidth ) - 3 , 'ljust' : not numeric } ) msg_nocr ( mess ) return True

Try to pretty print a simple case where a list is not nested . Return True if we can do it and False if not .


def lookup_signame(num):
    """Find the corresponding signal name for 'num'. Return None
    if 'num' is invalid."""
    signames = signal.__dict__
    num = abs(num)
    for signame in list(signames.keys()):
        if signame.startswith('SIG') and signames[signame] == num:
            return signame
        pass
    # Something went wrong. Should have returned above
    return None

def lookup_signame ( num ) : signames = signal . __dict__ num = abs ( num ) for signame in list ( signames . keys ( ) ) : if signame . startswith ( 'SIG' ) and signames [ signame ] == num : return signame pass return None

Find the corresponding signal name for num . Return None if num is invalid .


def lookup_signum(name):
    """Find the corresponding signal number for 'name'. Return None
    if 'name' is invalid."""
    uname = name.upper()
    if (uname.startswith('SIG') and hasattr(signal, uname)):
        return getattr(signal, uname)
    else:
        uname = "SIG"+uname
        if hasattr(signal, uname):
            return getattr(signal, uname)
        return None
    return

def lookup_signum ( name ) : uname = name . upper ( ) if ( uname . startswith ( 'SIG' ) and hasattr ( signal , uname ) ) : return getattr ( signal , uname ) else : uname = "SIG" + uname if hasattr ( signal , uname ) : return getattr ( signal , uname ) return None return

Find the corresponding signal number for name . Return None if name is invalid .


def canonic_signame(name_num):
    """Return a signal name for a signal name or signal
    number.  Return None is name_num is an int but not a valid signal
    number and False if name_num is a not number. If name_num is a
    signal name or signal number, the canonic if name is returned."""
    signum = lookup_signum(name_num)
    if signum is None:
        # Maybe signame is a number?
        try:
            num = int(name_num)
            signame = lookup_signame(num)
            if signame is None:
                return None
        except:
            return False
        return signame

    signame = name_num.upper()
    if not signame.startswith('SIG'): return 'SIG'+signame
    return signame

def canonic_signame ( name_num ) : signum = lookup_signum ( name_num ) if signum is None : try : num = int ( name_num ) signame = lookup_signame ( num ) if signame is None : return None except : return False return signame signame = name_num . upper ( ) if not signame . startswith ( 'SIG' ) : return 'SIG' + signame return signame

Return a signal name for a signal name or signal number . Return None is name_num is an int but not a valid signal number and False if name_num is a not number . If name_num is a signal name or signal number the canonic if name is returned .


def set_signal_replacement(self, signum, handle):
        """A replacement for signal.signal which chains the signal behind
        the debugger's handler"""
        signame = lookup_signame(signum)
        if signame is None:
            self.dbgr.intf[-1].errmsg(("%s is not a signal number"
                                       " I know about.")  % signum)
            return False
        # Since the intent is to set a handler, we should pass this
        # signal on to the handler
        self.sigs[signame].pass_along = True
        if self.check_and_adjust_sighandler(signame, self.sigs):
            self.sigs[signame].old_handler = handle
            return True
        return False

def
set_signal_replacement
(
self
,
signum
,
handle
)
:
signame
=
lookup_signame
(
signum
)
if
signame
is
:
self
.
dbgr
.
intf
[
1
]
.
errmsg
(
(
"%s is not a signal number"
" I know about."
)
%
signum
)
return
False
self
.
sigs
[
signame
]
.
pass_along
=
True
if
self
.
check_and_adjust_sighandler
(
signame
,
self
.
sigs
)
:
self
.
sigs
[
signame
]
.
old_handler
=
handle
return
True
return
False

A replacement for signal . signal which chains the signal behind the debugger s handler


def check_and_adjust_sighandlers(self):
        """Check to see if any of the signal handlers we are interested in have
        changed or is not initially set. Change any that are not right. """
        for signame in list(self.sigs.keys()):
            if not self.check_and_adjust_sighandler(signame, self.sigs):
                break
            pass
        return

def check_and_adjust_sighandlers ( self ) : for signame in list ( self . sigs . keys ( ) ) : if not self . check_and_adjust_sighandler ( signame , self . sigs ) : break pass return

Check to see if any of the signal handlers we are interested in have changed or is not initially set . Change any that are not right .


def info_signal(self, args):
        """Print information about a signal"""
        if len(args) == 0: return None
        signame = args[0]
        if signame in ['handle', 'signal']:
            # This has come from dbgr's info command
            if len(args) == 1:
                # Show all signal handlers
                self.dbgr.core.processor.section(self.header)
                for signame in self.siglist:
                    self.print_info_signal_entry(signame)
                return True
            else:
                signame = args[1]
                pass
            pass

        signame = self.is_name_or_number(signame)
        self.dbgr.core.processor.section(self.header)
        self.print_info_signal_entry(signame)
        return True

def info_signal ( self , args ) : if len ( args ) == 0 : return None signame = args [ 0 ] if signame in [ 'handle' , 'signal' ] : if len ( args ) == 1 : self . dbgr . core . processor . section ( self . header ) for signame in self . siglist : self . print_info_signal_entry ( signame ) return True else : signame = args [ 1 ] pass pass signame = self . is_name_or_number ( signame ) self . dbgr . core . processor . section ( self . header ) self . print_info_signal_entry ( signame ) return True


def action(self, arg):
        """Delegate the actions specified in 'arg' to another
        method.
        """
        if not arg:
            self.info_signal(['handle'])
            return True
        args = arg.split()
        signame = args[0]
        signame = self.is_name_or_number(args[0])
        if not signame: return

        if len(args) == 1:
            self.info_signal([signame])
            return True
        # We can display information about 'fatal' signals, but not
        # change their actions.
        if signame in fatal_signals:
            return None

        if signame not in list(self.sigs.keys()):
            if not self.initialize_handler(signame): return None
            pass

        # multiple commands might be specified, i.e. 'nopass nostop'
        for attr in args[1:]:
            if attr.startswith('no'):
                on = False
                attr = attr[2:]
            else:
                on = True
            if 'stop'.startswith(attr):
                self.handle_stop(signame, on)
            elif 'print'.startswith(attr) and len(attr) >= 2:
                self.handle_print(signame, on)
            elif 'pass'.startswith(attr):
                self.handle_pass(signame, on)
            elif 'ignore'.startswith(attr):
                self.handle_ignore(signame, on)
            elif 'stack'.startswith(attr):
                self.handle_print_stack(signame, on)
            else:
                self.dbgr.intf[-1].errmsg('Invalid arguments')
                pass
            pass
        return self.check_and_adjust_sighandler(signame, self.sigs)

def
action
(
self
,
arg
)
:
if
not
arg
:
self
.
info_signal
(
[
'handle'
]
)
return
True
args
=
arg
.
split
(
)
signame
=
args
[
0
]
signame
=
self
.
is_name_or_number
(
args
[
0
]
)
if
not
signame
:
return
if
len
(
args
)
==
1
:
self
.
info_signal
(
[
signame
]
)
return
True
if
signame
in
fatal_signals
:
return
if
signame
not
in
list
(
self
.
sigs
.
keys
(
)
)
:
if
not
self
.
initialize_handler
(
signame
)
:
return
pass
for
attr
in
args
[
1
:
]
:
if
attr
.
startswith
(
'no'
)
:
on
=
False
attr
=
attr
[
2
:
]
else
:
on
=
True
if
'stop'
.
startswith
(
attr
)
:
self
.
handle_stop
(
signame
,
on
)
elif
'print'
.
startswith
(
attr
)
and
len
(
attr
)
>=
2
:
self
.
handle_print
(
signame
,
on
)
elif
'pass'
.
startswith
(
attr
)
:
self
.
handle_pass
(
signame
,
on
)
elif
'ignore'
.
startswith
(
attr
)
:
self
.
handle_ignore
(
signame
,
on
)
elif
'stack'
.
startswith
(
attr
)
:
self
.
handle_print_stack
(
signame
,
on
)
else
:
self
.
dbgr
.
intf
[
1
]
.
errmsg
(
'Invalid arguments'
)
pass
pass
return
self
.
check_and_adjust_sighandler
(
signame
,
self
.
sigs
)

Delegate the actions specified in arg to another method .


def handle_print(self, signame, set_print):
        """Set whether we print or not when this signal is caught."""
        if set_print:
            self.sigs[signame].print_method = self.dbgr.intf[-1].msg
        else:
            self.sigs[signame].print_method = None
            pass
        return set_print

def handle_print ( self , signame , set_print ) : if set_print : self . sigs [ signame ] . print_method = self . dbgr . intf [ - 1 ] . msg else : self . sigs [ signame ] . print_method = None pass return set_print

Set whether we print or not when this signal is caught .


def handle(self, signum, frame):
        """This method is called when a signal is received."""
        if self.print_method:
            self.print_method('\nProgram received signal %s.'
                              % self.signame)
        if self.print_stack:
            import traceback
            strings = traceback.format_stack(frame)
            for s in strings:
                if s[-1] == '\n': s = s[0:-1]
                self.print_method(s)
                pass
            pass
        if self.b_stop:
            core = self.dbgr.core
            old_trace_hook_suspend = core.trace_hook_suspend
            core.trace_hook_suspend = True
            core.stop_reason = ('intercepting signal %s (%d)' %
                                (self.signame, signum))
            core.processor.event_processor(frame, 'signal', signum)
            core.trace_hook_suspend = old_trace_hook_suspend
            pass
        if self.pass_along:
            # pass the signal to the program
            if self.old_handler:
                self.old_handler(signum, frame)
                pass
            pass
        return

def
handle
(
self
,
signum
,
frame
)
:
if
self
.
print_method
:
self
.
print_method
(
'\nProgram received signal %s.'
%
self
.
signame
)
if
self
.
print_stack
:
import
traceback
strings
=
traceback
.
format_stack
(
frame
)
for
s
in
strings
:
if
s
[
1
]
==
'\n'
:
s
=
s
[
0
:
1
]
self
.
print_method
(
s
)
pass
pass
if
self
.
b_stop
:
core
=
self
.
dbgr
.
core
old_trace_hook_suspend
=
core
.
trace_hook_suspend
core
.
trace_hook_suspend
=
True
core
.
stop_reason
=
(
'intercepting signal %s (%d)'
%
(
self
.
signame
,
signum
)
)
core
.
processor
.
event_processor
(
frame
,
'signal'
,
signum
)
core
.
trace_hook_suspend
=
old_trace_hook_suspend
pass
if
self
.
pass_along
:
if
self
.
old_handler
:
self
.
old_handler
(
signum
,
frame
)
pass
pass
return

This method is called when a signal is received .


def file2module(filename):
    """Given a file name, extract the most likely module name. """
    basename = osp.basename(filename)
    if '.' in basename:
        pos = basename.rfind('.')
        return basename[:pos]
    else:
        return basename
    return None

def file2module ( filename ) : basename = osp . basename ( filename ) if '.' in basename : pos = basename . rfind ( '.' ) return basename [ : pos ] else : return basename return None

Given a file name extract the most likely module name .


def search_file(filename, directories, cdir):
    """Return a full pathname for filename if we can find one. path
    is a list of directories to prepend to filename. If no file is
    found we'll return None"""

    for trydir in directories:

        # Handle $cwd and $cdir
        if trydir =='$cwd': trydir='.'
        elif trydir == '$cdir': trydir = cdir

        tryfile = osp.realpath(osp.join(trydir, filename))
        if osp.isfile(tryfile):
            return tryfile
    return None

def search_file ( filename , directories , cdir ) : for trydir in directories : if trydir == '$cwd' : trydir = '.' elif trydir == '$cdir' : trydir = cdir tryfile = osp . realpath ( osp . join ( trydir , filename ) ) if osp . isfile ( tryfile ) : return tryfile return None

Return a full pathname for filename if we can find one . path is a list of directories to prepend to filename . If no file is found we ll return None


def whence_file(py_script, dirnames=None):
    """Do a shell-like path lookup for py_script and return the results.
    If we can't find anything return py_script"""
    if py_script.find(os.sep) != -1:
        # Don't search since this name has path separator components
        return py_script
    if dirnames is None:
        dirnames = os.environ['PATH'].split(os.pathsep)
    for dirname in dirnames:
        py_script_try = osp.join(dirname, py_script)
        if osp.exists(py_script_try):
            return py_script_try
    # Failure
    return py_script

def whence_file ( py_script , dirnames = None ) : if py_script . find ( os . sep ) != - 1 : return py_script if dirnames is None : dirnames = os . environ [ 'PATH' ] . split ( os . pathsep ) for dirname in dirnames : py_script_try = osp . join ( dirname , py_script ) if osp . exists ( py_script_try ) : return py_script_try return py_script

Do a shell - like path lookup for py_script and return the results . If we can t find anything return py_script


def pyfiles(callername, level=2):
    "All python files caller's dir without the path and trailing .py"
    d = os.path.dirname(callername)
    # Get the name of our directory.
    # A glob pattern that will get all *.py files but not __init__.py
    glob(os.path.join(d, '[a-zA-Z]*.py'))
    py_files = glob(os.path.join(d, '[a-zA-Z]*.py'))
    return [ os.path.basename(filename[0:-3]) for filename in py_files ]

All python files caller s dir without the path and trailing . py


def msg(self, msg):
        """ used to write to a debugger that is connected to this
        server; `str' written will have a newline added to it
        """
        if hasattr(self.output, 'writeline'):
            self.output.writeline(msg)
        elif hasattr(self.output, 'writelines'):
            self.output.writelines(msg + "\n")
            pass
        return

def msg ( self , msg ) : if hasattr ( self . output , 'writeline' ) : self . output . writeline ( msg ) elif hasattr ( self . output , 'writelines' ) : self . output . writelines ( msg + "\n" ) pass return

used to write to a debugger that is connected to this server ; str written will have a newline added to it


def run(self, args):
        """Execution status of the program."""
        mainfile = self.core.filename(None)
        if self.core.is_running():
            if mainfile:
                part1 = "Python program '%s' is stopped" % mainfile
            else:
                part1 = 'Program is stopped'
                pass
            if self.proc.event:
                msg = 'via a %s event.' % self.proc.event
            else:
                msg = '.'
            self.msg(Mmisc.wrapped_lines(part1, msg,
                                         self.settings['width']))
            if self.proc.curframe:
                self.msg("PC offset is %d." % self.proc.curframe.f_lasti)

            if self.proc.event == 'return':
                val = self.proc.event_arg
                part1 = 'Return value is'
                self.msg(Mmisc.wrapped_lines(part1, self.proc._saferepr(val),
                                             self.settings['width']))
                pass
            elif self.proc.event == 'exception':
                exc_type, exc_value, exc_tb = self.proc.event_arg
                self.msg('Exception type: %s' %
                         self.proc._saferepr(exc_type))
                if exc_value:
                    self.msg('Exception value: %s' %
                             self.proc._saferepr(exc_value))
                    pass
                pass
            self.msg('It stopped %s.' % self.core.stop_reason)
            if self.proc.event in ['signal', 'exception', 'c_exception']:
                self.msg('Note: we are stopped *after* running the '
                         'line shown.')
                pass
        else:
            if mainfile:
                part1 = "Python program '%s'" % mainfile
                msg   = "is not currently running. "
                self.msg(Mmisc.wrapped_lines(part1, msg,
                                             self.settings['width']))
            else:
                self.msg('No Python program is currently running.')
                pass
            self.msg(self.core.execution_status)
            pass
        return False


def columnize_commands(self, commands):
        """List commands arranged in an aligned columns"""
        commands.sort()
        width = self.debugger.settings['width']
        return columnize.columnize(commands, displaywidth=width,
                                   lineprefix='    ')

def
columnize_commands
(
self
,
commands
)
:
commands
.
sort
(
)
width
=
self
.
debugger
.
settings
[
'width'
]
return
columnize
.
columnize
(
commands
,
displaywidth
=
width
,
lineprefix
=
'    '
)