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()
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
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()
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
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)
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()
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()
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()
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()
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
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()
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
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
def do_change_variable(): Exec('%s=%s' % (attr, value), self.get_namespace(), self.get_namespace())