예제 #1
0
def change_attr_expression(thread_id,
                           frame_id,
                           attr,
                           expression,
                           dbg,
                           value=SENTINEL_VALUE):
    '''Changes some attribute in a given frame.
    '''
    frame = find_frame(thread_id, frame_id)
    if frame is None:
        return

    try:
        expression = expression.replace('@LINE@', '\n')

        if dbg.plugin and value is SENTINEL_VALUE:
            result = dbg.plugin.change_variable(frame, attr, expression)
            if result:
                return result

        if value is SENTINEL_VALUE:
            # It is possible to have variables with names like '.0', ',,,foo', etc in scope by setting them with
            # `sys._getframe().f_locals`. In particular, the '.0' variable name is used to denote the list iterator when we stop in
            # list comprehension expressions. This variable evaluates to 0. by `eval`, which is not what we want and this is the main
            # reason we have to check if the expression exists in the global and local scopes before trying to evaluate it.
            value = frame.f_locals.get(
                expression) or frame.f_globals.get(expression) or eval(
                    expression, frame.f_globals, frame.f_locals)

        if attr[:7] == "Globals":
            attr = attr[8:]
            if is_complex(attr):
                Exec('%s=%s' % (attr, expression), frame.f_globals,
                     frame.f_globals)
                return value
            if attr in frame.f_globals:
                frame.f_globals[attr] = value
                return frame.f_globals[attr]
        else:
            if pydevd_save_locals.is_save_locals_available():
                if is_complex(attr):
                    Exec('%s=%s' % (attr, expression), frame.f_locals,
                         frame.f_locals)
                    return value
                frame.f_locals[attr] = value
                pydevd_save_locals.save_locals(frame)
                return frame.f_locals[attr]

            # default way (only works for changing it in the topmost frame)
            result = value
            Exec('%s=%s' % (attr, expression), frame.f_globals, frame.f_locals)
            return result

    except Exception:
        traceback.print_exc()
예제 #2
0
    def runcode(self, code):
        """Execute a code object.

        When an exception occurs, self.showtraceback() is called to
        display a traceback.  All exceptions are caught except
        SystemExit, which is reraised.

        A note about KeyboardInterrupt: this exception may occur
        elsewhere in this code, and may not always be caught.  The
        caller should be prepared to deal with it.

        """
        try:
            Exec(code, self.frame.f_globals, self.frame.f_locals)
            pydevd_save_locals.save_locals(self.frame)
        except SystemExit:
            raise
        except:
            # In case sys.excepthook called, use original excepthook #PyDev-877: Debug console freezes with Python 3.5+
            # (showtraceback does it on python 3.5 onwards)
            sys.excepthook = sys.__excepthook__
            try:
                self.showtraceback()
            finally:
                sys.__excepthook__ = sys.excepthook
예제 #3
0
def change_attr_expression(thread_id, frame_id, attr, expression, dbg):
    '''Changes some attribute in a given frame.
    '''
    frame = find_frame(thread_id, frame_id)
    if frame is None:
        return

    try:
        expression = expression.replace('@LINE@', '\n')

        if dbg.plugin:
            result = dbg.plugin.change_variable(frame, attr, expression)
            if result:
                return result

        if attr[:7] == "Globals":
            attr = attr[8:]
            if attr in frame.f_globals:
                frame.f_globals[attr] = eval(expression, frame.f_globals,
                                             frame.f_locals)
                return frame.f_globals[attr]
        else:
            if pydevd_save_locals.is_save_locals_available():
                frame.f_locals[attr] = eval(expression, frame.f_globals,
                                            frame.f_locals)
                pydevd_save_locals.save_locals(frame)
                return frame.f_locals[attr]

            # default way (only works for changing it in the topmost frame)
            result = eval(expression, frame.f_globals, frame.f_locals)
            Exec('%s=%s' % (attr, expression), frame.f_globals, frame.f_locals)
            return result

    except Exception:
        traceback.print_exc()
예제 #4
0
def console_exec(thread_id, frame_id, expression, dbg):
    """returns 'False' in case expression is partially correct
    """
    frame = pydevd_vars.find_frame(thread_id, frame_id)

    is_multiline = expression.count('@LINE@') > 1
    try:
        expression = str(expression.replace('@LINE@', '\n'))
    except UnicodeEncodeError as e:
        expression = expression.replace('@LINE@', '\n')

    # Not using frame.f_globals because of https://sourceforge.net/tracker2/?func=detail&aid=2541355&group_id=85796&atid=577329
    # (Names not resolved in generator expression in method)
    # See message: http://mail.python.org/pipermail/python-list/2009-January/526522.html
    updated_globals = {}
    updated_globals.update(frame.f_globals)
    updated_globals.update(
        frame.f_locals
    )  # locals later because it has precedence over the actual globals

    if PYTEST_RUN_CONFIG:
        enable_pytest_output()

    if IPYTHON:
        need_more = exec_code(CodeFragment(expression), updated_globals,
                              updated_globals, dbg)
        if not need_more:
            update_frame_local_variables_and_save(frame, updated_globals)
        return need_more

    interpreter = ConsoleWriter()

    if not is_multiline:
        try:
            code = compile_command(expression)
        except (OverflowError, SyntaxError, ValueError):
            # Case 1
            interpreter.showsyntaxerror()
            return False
        if code is None:
            # Case 2
            return True
    else:
        code = expression

    # Case 3

    try:
        # It is important that globals and locals we pass to the exec function are the same object.
        # Otherwise generator expressions can confuse their scope. Passing updated_globals dictionary seems to be a safe option here
        # because it contains globals and locals in the right precedence.
        # See: https://stackoverflow.com/questions/15866398/why-is-a-python-generator-confusing-its-scope-with-global-in-an-execd-script.
        Exec(code, updated_globals, updated_globals)
    except SystemExit:
        raise
    except:
        interpreter.showtraceback()
    else:
        update_frame_local_variables_and_save(frame, updated_globals)
    return False
def console_exec(thread_id, frame_id, expression, dbg):
    """returns 'False' in case expression is partially correct
    """
    frame = pydevd_vars.find_frame(thread_id, frame_id)

    is_multiline = expression.count('@LINE@') > 1
    try:
        expression = str(expression.replace('@LINE@', '\n'))
    except UnicodeEncodeError as e:
        expression = expression.replace('@LINE@', '\n')

    # Not using frame.f_globals because of https://sourceforge.net/tracker2/?func=detail&aid=2541355&group_id=85796&atid=577329
    # (Names not resolved in generator expression in method)
    # See message: http://mail.python.org/pipermail/python-list/2009-January/526522.html
    updated_globals = {}
    updated_globals.update(frame.f_globals)
    updated_globals.update(
        frame.f_locals
    )  # locals later because it has precedence over the actual globals

    if PYTEST_RUN_CONFIG:
        enable_pytest_output()

    if IPYTHON:
        need_more = exec_code(CodeFragment(expression), updated_globals,
                              frame.f_locals, dbg)
        if not need_more:
            pydevd_save_locals.save_locals(frame)
        return need_more

    interpreter = ConsoleWriter()

    if not is_multiline:
        try:
            code = compile_command(expression)
        except (OverflowError, SyntaxError, ValueError):
            # Case 1
            interpreter.showsyntaxerror()
            return False
        if code is None:
            # Case 2
            return True
    else:
        code = expression

    # Case 3

    try:
        Exec(code, updated_globals, frame.f_locals)

    except SystemExit:
        raise
    except:
        interpreter.showtraceback()
    else:
        pydevd_save_locals.save_locals(frame)
    return False
예제 #6
0
def evaluate_expression(dbg, frame, expression, is_exec):
    '''returns the result of the evaluated expression
    @param is_exec: determines if we should do an exec or an eval
    '''
    if frame is None:
        return

    # Not using frame.f_globals because of https://sourceforge.net/tracker2/?func=detail&aid=2541355&group_id=85796&atid=577329
    # (Names not resolved in generator expression in method)
    # See message: http://mail.python.org/pipermail/python-list/2009-January/526522.html
    updated_globals = {}
    updated_globals.update(frame.f_globals)
    updated_globals.update(
        frame.f_locals
    )  # locals later because it has precedence over the actual globals

    try:

        if IS_PY2 and isinstance(expression, unicode):
            expression = expression.replace(u'@LINE@', u'\n')
        else:
            expression = expression.replace('@LINE@', '\n')

        if is_exec:
            try:
                # try to make it an eval (if it is an eval we can print it, otherwise we'll exec it and
                # it will have whatever the user actually did)
                compiled = compile(_expression_to_evaluate(expression),
                                   '<string>', 'eval')
            except:
                Exec(_expression_to_evaluate(expression), updated_globals,
                     frame.f_locals)
                pydevd_save_locals.save_locals(frame)
            else:
                result = eval(compiled, updated_globals, frame.f_locals)
                if result is not None:  # Only print if it's not None (as python does)
                    if IS_PY2 and isinstance(result, unicode):
                        encoding = sys.stdout.encoding
                        if not encoding:
                            encoding = os.environ.get('PYTHONIOENCODING',
                                                      'utf-8')
                        result = result.encode(encoding, 'replace')
                    sys.stdout.write('%s\n' % (result, ))
            return

        else:
            return eval_in_context(expression, updated_globals, frame.f_locals)
    finally:
        # Should not be kept alive if an exception happens and this frame is kept in the stack.
        del updated_globals
        del frame
    def change_variable(self, name, value, py_db, fmt=None):

        children_variable = self.get_child_variable_named(name)
        if children_variable is None:
            return None

        var_data = children_variable.get_var_data()
        evaluate_name = var_data.get('evaluateName')

        if not evaluate_name:
            # Note: right now we only pass control to the resolver in the cases where
            # there's no evaluate name (the idea being that if we can evaluate it,
            # we can use that evaluation to set the value too -- if in the future
            # a case where this isn't true is found this logic may need to be changed).
            _type, _type_name, container_resolver = get_type(self.value)
            if hasattr(container_resolver, 'change_var_from_name'):
                try:
                    new_value = eval(value)
                except:
                    return None
                new_key = container_resolver.change_var_from_name(
                    self.value, name, new_value)
                if new_key is not None:
                    return _ObjectVariable(self.py_db,
                                           new_key,
                                           new_value,
                                           self._register_variable,
                                           evaluate_name=None,
                                           frame=self.frame)

                return None
            else:
                return None

        frame = self.frame
        if frame is None:
            return None

        try:
            # This handles the simple cases (such as dict, list, object)
            Exec('%s=%s' % (evaluate_name, value), frame.f_globals,
                 frame.f_locals)
        except:
            return None

        return self.get_child_variable_named(name, fmt=fmt)
예제 #8
0
def change_attr_expression(thread_id,
                           frame_id,
                           attr,
                           expression,
                           dbg,
                           value=SENTINEL_VALUE):
    '''Changes some attribute in a given frame.
    '''
    frame = find_frame(thread_id, frame_id)
    if frame is None:
        return

    try:
        expression = expression.replace('@LINE@', '\n')

        if dbg.plugin and value is SENTINEL_VALUE:
            result = dbg.plugin.change_variable(frame, attr, expression)
            if result:
                return result

        if attr[:7] == "Globals":
            attr = attr[8:]
            if attr in frame.f_globals:
                if value is SENTINEL_VALUE:
                    value = eval(expression, frame.f_globals, frame.f_locals)
                frame.f_globals[attr] = value
                return frame.f_globals[attr]
        else:
            if '.' not in attr:  # i.e.: if we have a '.', we're changing some attribute of a local var.
                if pydevd_save_locals.is_save_locals_available():
                    if value is SENTINEL_VALUE:
                        value = eval(expression, frame.f_globals,
                                     frame.f_locals)
                    frame.f_locals[attr] = value
                    pydevd_save_locals.save_locals(frame)
                    return frame.f_locals[attr]

            # default way (only works for changing it in the topmost frame)
            if value is SENTINEL_VALUE:
                value = eval(expression, frame.f_globals, frame.f_locals)
            result = value
            Exec('%s=%s' % (attr, expression), frame.f_globals, frame.f_locals)
            return result

    except Exception:
        traceback.print_exc()
예제 #9
0
    def runcode(self, code):
        """Execute a code object.

        When an exception occurs, self.showtraceback() is called to
        display a traceback.  All exceptions are caught except
        SystemExit, which is reraised.

        A note about KeyboardInterrupt: this exception may occur
        elsewhere in this code, and may not always be caught.  The
        caller should be prepared to deal with it.

        """
        try:
            Exec(code, self.frame.f_globals, self.frame.f_locals)
            pydevd_save_locals.save_locals(self.frame)
        except SystemExit:
            raise
        except:
            self.showtraceback()
예제 #10
0
def custom_operation(thread_id, frame_id, scope, attrs, style, code_or_file, operation_fn_name):
    """
    We'll execute the code_or_file and then search in the namespace the operation_fn_name to execute with the given var.

    code_or_file: either some code (i.e.: from pprint import pprint) or a file to be executed.
    operation_fn_name: the name of the operation to execute after the exec (i.e.: pprint)
    """
    expressionValue = getVariable(thread_id, frame_id, scope, attrs)

    try:
        namespace = {'__name__': '<custom_operation>'}
        if style == "EXECFILE":
            namespace['__file__'] = code_or_file
            execfile(code_or_file, namespace, namespace)
        else:  # style == EXEC
            namespace['__file__'] = '<customOperationCode>'
            Exec(code_or_file, namespace, namespace)

        return str(namespace[operation_fn_name](expressionValue))
    except:
        traceback.print_exc()
예제 #11
0
def change_attr_expression(frame, attr, expression, dbg, value=SENTINEL_VALUE):
    '''Changes some attribute in a given frame.
    '''
    if frame is None:
        return

    try:
        expression = expression.replace('@LINE@', '\n')

        if dbg.plugin and value is SENTINEL_VALUE:
            result = dbg.plugin.change_variable(frame, attr, expression)
            if result:
                return result

        if attr[:7] == "Globals":
            attr = attr[8:]
            if attr in frame.f_globals:
                if value is SENTINEL_VALUE:
                    value = eval(expression, frame.f_globals, frame.f_locals)
                frame.f_globals[attr] = value
                return frame.f_globals[attr]
        else:
            if '.' not in attr:  # i.e.: if we have a '.', we're changing some attribute of a local var.
                if pydevd_save_locals.is_save_locals_available():
                    if value is SENTINEL_VALUE:
                        value = eval(expression, frame.f_globals,
                                     frame.f_locals)
                    frame.f_locals[attr] = value
                    pydevd_save_locals.save_locals(frame)
                    return frame.f_locals[attr]

            # i.e.: case with '.' or save locals not available (just exec the assignment in the frame).
            if value is SENTINEL_VALUE:
                value = eval(expression, frame.f_globals, frame.f_locals)
            result = value
            Exec('%s=%s' % (attr, expression), frame.f_globals, frame.f_locals)
            return result

    except Exception:
        pydev_log.exception()
예제 #12
0
def evaluate_expression(thread_id, frame_id, expression, doExec):
    '''returns the result of the evaluated expression
    @param doExec: determines if we should do an exec or an eval
    '''
    frame = find_frame(thread_id, frame_id)
    if frame is None:
        return

    # Not using frame.f_globals because of https://sourceforge.net/tracker2/?func=detail&aid=2541355&group_id=85796&atid=577329
    # (Names not resolved in generator expression in method)
    # See message: http://mail.python.org/pipermail/python-list/2009-January/526522.html
    updated_globals = {}
    updated_globals.update(frame.f_globals)
    updated_globals.update(
        frame.f_locals
    )  # locals later because it has precedence over the actual globals

    try:
        expression = str(expression.replace('@LINE@', '\n'))

        if doExec:
            try:
                # try to make it an eval (if it is an eval we can print it, otherwise we'll exec it and
                # it will have whatever the user actually did)
                compiled = compile(expression, '<string>', 'eval')
            except:
                Exec(expression, updated_globals, frame.f_locals)
                pydevd_save_locals.save_locals(frame)
            else:
                result = eval(compiled, updated_globals, frame.f_locals)
                if result is not None:  # Only print if it's not None (as python does)
                    sys.stdout.write('%s\n' % (result, ))
            return

        else:
            return eval_in_context(expression, updated_globals, frame.f_locals)
    finally:
        # Should not be kept alive if an exception happens and this frame is kept in the stack.
        del updated_globals
        del frame
예제 #13
0
    def apply(self):
        mod = self.mod
        self._on_finish_callbacks = []
        try:
            # Get the module name, e.g. 'foo.bar.whatever'
            modname = mod.__name__
            # Get the module namespace (dict) early; this is part of the type check
            modns = mod.__dict__
            # Parse it into package name and module name, e.g. 'foo.bar' and 'whatever'
            i = modname.rfind(".")
            if i >= 0:
                pkgname, modname = modname[:i], modname[i + 1:]
            else:
                pkgname = None
            # Compute the search path
            if pkgname:
                # We're not reloading the package, only the module in it
                pkg = sys.modules[pkgname]
                path = pkg.__path__  # Search inside the package
            else:
                # Search the top-level module path
                pkg = None
                path = None  # Make find_module() uses the default search path
            # Find the module; may raise ImportError
            (stream, filename, (suffix, mode,
                                kind)) = imp.find_module(modname, path)
            # Turn it into a code object
            try:
                # Is it Python source code or byte code read from a file?
                if kind not in (imp.PY_COMPILED, imp.PY_SOURCE):
                    # Fall back to built-in reload()
                    notify_error('Could not find source to reload (mod: %s)' %
                                 (modname, ))
                    return
                if kind == imp.PY_SOURCE:
                    source = stream.read()
                    code = compile(source, filename, "exec")
                else:
                    import marshal
                    code = marshal.load(stream)
            finally:
                if stream:
                    stream.close()
            # Execute the code.  We copy the module dict to a temporary; then
            # clear the module dict; then execute the new code in the module
            # dict; then swap things back and around.  This trick (due to
            # Glyph Lefkowitz) ensures that the (readonly) __globals__
            # attribute of methods and functions is set to the correct dict
            # object.
            new_namespace = modns.copy()
            new_namespace.clear()
            new_namespace["__name__"] = modns["__name__"]
            Exec(code, new_namespace)
            # Now we get to the hard part
            oldnames = set(modns)
            newnames = set(new_namespace)

            # Create new tokens (note: not deleting existing)
            for name in newnames - oldnames:
                notify_info0('Added:', name, 'to namespace')
                self.found_change = True
                modns[name] = new_namespace[name]

            # Update in-place what we can
            for name in oldnames & newnames:
                self._update(modns, name, modns[name], new_namespace[name])

            self._handle_namespace(modns)

            for c in self._on_finish_callbacks:
                c()
            del self._on_finish_callbacks[:]
        except:
            pydev_log.exception()
예제 #14
0
def evaluate_expression(py_db, frame, expression, is_exec):
    '''
    There are some changes in this function depending on whether it's an exec or an eval.

    When it's an exec (i.e.: is_exec==True):
        This function returns None.
        Any exception that happens during the evaluation is reraised.
        If the expression could actually be evaluated, the variable is printed to the console if not None.

    When it's an eval (i.e.: is_exec==False):
        This function returns the result from the evaluation.
        If some exception happens in this case, the exception is caught and a ExceptionOnEvaluate is returned.
        Also, in this case we try to resolve name-mangling (i.e.: to be able to add a self.__my_var watch).

    :param is_exec: determines if we should do an exec or an eval.
    '''
    if frame is None:
        return

    # This is very tricky. Some statements can change locals and use them in the same
    # call (see https://github.com/microsoft/debugpy/issues/815), also, if locals and globals are
    # passed separately, it's possible that one gets updated but apparently Python will still
    # try to load from the other, so, what's done is that we merge all in a single dict and
    # then go on and update the frame with the results afterwards.

    # -- see tests in test_evaluate_expression.py

    # This doesn't work because the variables aren't updated in the locals in case the
    # evaluation tries to set a variable and use it in the same expression.
    # updated_globals = frame.f_globals
    # updated_locals = frame.f_locals

    # This doesn't work because the variables aren't updated in the locals in case the
    # evaluation tries to set a variable and use it in the same expression.
    # updated_globals = {}
    # updated_globals.update(frame.f_globals)
    # updated_globals.update(frame.f_locals)
    #
    # updated_locals = frame.f_locals

    # This doesn't work either in the case where the evaluation tries to set a variable and use
    # it in the same expression (I really don't know why as it seems like this *should* work
    # in theory but doesn't in practice).
    # updated_globals = {}
    # updated_globals.update(frame.f_globals)
    #
    # updated_locals = {}
    # updated_globals.update(frame.f_locals)

    # This is the only case that worked consistently to run the tests in test_evaluate_expression.py
    # It's a bit unfortunate because although the exec works in this case, we have to manually
    # put the updates in the frame locals afterwards.
    updated_globals = {}
    updated_globals.update(frame.f_globals)
    updated_globals.update(frame.f_locals)

    initial_globals = updated_globals.copy()

    updated_locals = None

    try:
        expression = expression.replace('@LINE@', '\n')

        if is_exec:
            try:
                # try to make it an eval (if it is an eval we can print it, otherwise we'll exec it and
                # it will have whatever the user actually did)
                compiled = compile_as_eval(expression)
            except Exception:
                compiled = None

            if compiled is None:
                try:
                    Exec(_expression_to_evaluate(expression), updated_globals,
                         updated_locals)
                finally:
                    # Update the globals even if it errored as it may have partially worked.
                    _update_globals_and_locals(updated_globals,
                                               initial_globals, frame)
            else:
                result = eval(compiled, updated_globals, updated_locals)
                if result is not None:  # Only print if it's not None (as python does)
                    sys.stdout.write('%s\n' % (result, ))
            return

        else:
            ret = eval_in_context(expression, updated_globals, updated_locals)
            try:
                is_exception_returned = ret.__class__ == ExceptionOnEvaluate
            except:
                pass
            else:
                if not is_exception_returned:
                    # i.e.: by using a walrus assignment (:=), expressions can change the locals,
                    # so, make sure that we save the locals back to the frame.
                    _update_globals_and_locals(updated_globals,
                                               initial_globals, frame)
            return ret
    finally:
        # Should not be kept alive if an exception happens and this frame is kept in the stack.
        del updated_globals
        del updated_locals
        del initial_globals
        del frame
예제 #15
0
def evaluate_expression(py_db, frame, expression, is_exec):
    '''
    There are some changes in this function depending on whether it's an exec or an eval.

    When it's an exec (i.e.: is_exec==True):
        This function returns None.
        Any exception that happens during the evaluation is reraised.
        If the expression could actually be evaluated, the variable is printed to the console if not None.

    When it's an eval (i.e.: is_exec==False):
        This function returns the result from the evaluation.
        If some exception happens in this case, the exception is caught and a ExceptionOnEvaluate is returned.
        Also, in this case we try to resolve name-mangling (i.e.: to be able to add a self.__my_var watch).

    :param is_exec: determines if we should do an exec or an eval.
    '''
    if frame is None:
        return

    # Note: not using frame.f_globals directly because we need variables to be mutated in that
    # context to support generator expressions (i.e.: the case below doesn't work unless
    # globals=locals) because a generator expression actually creates a new function context.
    # i.e.:
    # global_vars = {}
    # local_vars = {'ar':["foo", "bar"], 'y':"bar"}
    # print eval('all((x == y for x in ar))', global_vars, local_vars)
    # See: https://mail.python.org/pipermail/python-list/2009-January/522213.html

    updated_globals = {}
    updated_globals.update(frame.f_globals)
    updated_globals.update(
        frame.f_locals
    )  # locals later because it has precedence over the actual globals

    try:
        if IS_PY2 and isinstance(expression, unicode):
            expression = expression.replace(u'@LINE@', u'\n')
        else:
            expression = expression.replace('@LINE@', '\n')

        if is_exec:
            try:
                # try to make it an eval (if it is an eval we can print it, otherwise we'll exec it and
                # it will have whatever the user actually did)
                compiled = compile(_expression_to_evaluate(expression),
                                   '<string>', 'eval')
            except Exception:
                Exec(_expression_to_evaluate(expression), updated_globals,
                     frame.f_locals)
                pydevd_save_locals.save_locals(frame)
            else:
                result = eval(compiled, updated_globals, frame.f_locals)
                if result is not None:  # Only print if it's not None (as python does)
                    if IS_PY2 and isinstance(result, unicode):
                        encoding = sys.stdout.encoding
                        if not encoding:
                            encoding = os.environ.get('PYTHONIOENCODING',
                                                      'utf-8')
                        result = result.encode(encoding, 'replace')
                    sys.stdout.write('%s\n' % (result, ))
            return

        else:
            return eval_in_context(expression, updated_globals, frame.f_locals)
    finally:
        # Should not be kept alive if an exception happens and this frame is kept in the stack.
        del updated_globals
        del frame
예제 #16
0
 def do_change_variable():
     Exec('%s=%s' % (attr, value), self.get_namespace(),
          self.get_namespace())