Skip to content

Commit

Permalink
When evaluating enable setting to None, deleting variables and using …
Browse files Browse the repository at this point in the history
…globals(). Fixes #1142 Fixes #1138
  • Loading branch information
fabioz committed Dec 9, 2022
1 parent bf5c644 commit 1c79248
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ def save_locals_ctypes_impl(frame):

save_locals_impl = make_save_locals_impl()

_SENTINEL = [] # Any mutable will do.


def update_globals_and_locals(updated_globals, initial_globals, frame):
# We don't have the locals and passed all in globals, so, we have to
Expand All @@ -83,14 +85,29 @@ def update_globals_and_locals(updated_globals, initial_globals, frame):
# one that enabled creating and using variables during the same evaluation.
assert updated_globals is not None
f_locals = None

removed = set(initial_globals).difference(updated_globals)

for key, val in updated_globals.items():
if initial_globals.get(key) is not val:
if val is not initial_globals.get(key, _SENTINEL):
if f_locals is None:
# Note: we call f_locals only once because each time
# we call it the values may be reset.
f_locals = frame.f_locals

f_locals[key] = val

if removed:
if f_locals is None:
# Note: we call f_locals only once because each time
# we call it the values may be reset.
f_locals = frame.f_locals

for key in removed:
try:
del f_locals[key]
except KeyError:
pass

if f_locals is not None:
save_locals(frame)
4 changes: 4 additions & 0 deletions src/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_vars.py
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,10 @@ def method():
updated_globals = {}
updated_globals.update(frame.f_globals)
updated_globals.update(frame.f_locals)
if 'globals' not in updated_globals:
# If the user explicitly uses 'globals()' then we provide the
# frame globals (unless he has shadowed it already).
updated_globals['globals'] = lambda: frame.f_globals

initial_globals = updated_globals.copy()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,47 @@ def check(frame):
assert 'email' not in sys._getframe().f_globals


def test_evaluate_expression_access_globals(disable_critical_log):
from _pydevd_bundle.pydevd_vars import evaluate_expression

def check(frame):
eval_txt = '''globals()['global_variable'] = 22'''
evaluate_expression(None, frame, eval_txt, is_exec=True)
assert 'global_variable' not in frame.f_locals
assert 'global_variable' in frame.f_globals

check(next(iter(obtain_frame())))
assert 'global_variable' in sys._getframe().f_globals
assert 'global_variable' not in sys._getframe().f_locals


def test_evaluate_expression_create_none(disable_critical_log):
from _pydevd_bundle.pydevd_vars import evaluate_expression

def check(frame):
eval_txt = 'x = None'
evaluate_expression(None, frame, eval_txt, is_exec=True)
assert 'x' in frame.f_locals
assert 'x' not in frame.f_globals

check(next(iter(obtain_frame())))


def test_evaluate_expression_delete_var(disable_critical_log):
from _pydevd_bundle.pydevd_vars import evaluate_expression

def check(frame):
eval_txt = 'x = 22'
evaluate_expression(None, frame, eval_txt, is_exec=True)
assert 'x' in frame.f_locals

eval_txt = 'del x'
evaluate_expression(None, frame, eval_txt, is_exec=True)
assert 'x' not in frame.f_locals

check(next(iter(obtain_frame())))


def test_evaluate_expression_5(disable_critical_log):
from _pydevd_bundle.pydevd_vars import evaluate_expression

Expand Down

0 comments on commit 1c79248

Please sign in to comment.