Run source code in closure so code object created within source can find variables in locals correctly returns True if the source is executed, False otherwise
(self, source, globals, locals)
| 813 | return |
| 814 | |
| 815 | def _exec_in_closure(self, source, globals, locals): |
| 816 | """ Run source code in closure so code object created within source |
| 817 | can find variables in locals correctly |
| 818 | |
| 819 | returns True if the source is executed, False otherwise |
| 820 | """ |
| 821 | |
| 822 | # Determine if the source should be executed in closure. Only when the |
| 823 | # source compiled to multiple code objects, we should use this feature. |
| 824 | # Otherwise, we can just raise an exception and normal exec will be used. |
| 825 | |
| 826 | code = compile(source, "<string>", "exec") |
| 827 | if not any(isinstance(const, CodeType) for const in code.co_consts): |
| 828 | return False |
| 829 | |
| 830 | # locals could be a proxy which does not support pop |
| 831 | # copy it first to avoid modifying the original locals |
| 832 | locals_copy = dict(locals) |
| 833 | |
| 834 | locals_copy["__pdb_eval__"] = { |
| 835 | "result": None, |
| 836 | "write_back": {} |
| 837 | } |
| 838 | |
| 839 | # If the source is an expression, we need to print its value |
| 840 | try: |
| 841 | compile(source, "<string>", "eval") |
| 842 | except SyntaxError: |
| 843 | pass |
| 844 | else: |
| 845 | source = "__pdb_eval__['result'] = " + source |
| 846 | |
| 847 | # Add write-back to update the locals |
| 848 | source = ("try:\n" + |
| 849 | textwrap.indent(source, " ") + "\n" + |
| 850 | "finally:\n" + |
| 851 | " __pdb_eval__['write_back'] = locals()") |
| 852 | |
| 853 | # Build a closure source code with freevars from locals like: |
| 854 | # def __pdb_outer(): |
| 855 | # var = None |
| 856 | # def __pdb_scope(): # This is the code object we want to execute |
| 857 | # nonlocal var |
| 858 | # <source> |
| 859 | # return __pdb_scope.__code__ |
| 860 | source_with_closure = ("def __pdb_outer():\n" + |
| 861 | "\n".join(f" {var} = None" for var in locals_copy) + "\n" + |
| 862 | " def __pdb_scope():\n" + |
| 863 | "\n".join(f" nonlocal {var}" for var in locals_copy) + "\n" + |
| 864 | textwrap.indent(source, " ") + "\n" + |
| 865 | " return __pdb_scope.__code__" |
| 866 | ) |
| 867 | |
| 868 | # Get the code object of __pdb_scope() |
| 869 | # The exec fills locals_copy with the __pdb_outer() function and we can call |
| 870 | # that to get the code object of __pdb_scope() |
| 871 | ns = {} |
| 872 | try: |