Track import statements from executed code
(self, code: str)
| 877 | self.loaded_modules.update(newly_loaded_modules) |
| 878 | |
| 879 | def _track_imports_from_code(self, code: str) -> None: |
| 880 | """Track import statements from executed code""" |
| 881 | try: |
| 882 | tree = ast.parse(code) |
| 883 | |
| 884 | for node in ast.walk(tree): |
| 885 | # Handle "from X import Y" style imports |
| 886 | if isinstance(node, ast.ImportFrom): |
| 887 | mod = node.module |
| 888 | |
| 889 | # Skip relative imports that don't have a module name |
| 890 | if mod is None: |
| 891 | continue |
| 892 | |
| 893 | for name in node.names: |
| 894 | # name.name is going to be actual name that we want to import from module |
| 895 | # name.asname is Z in the case of from X import Y as Z |
| 896 | # we should update Z in the shell in this situation, so track it too. |
| 897 | original_name = name.name |
| 898 | resolved_name = name.asname if name.asname else name.name |
| 899 | |
| 900 | # Since the code executed successfully, we know this import is valid |
| 901 | self._reloader.import_from_tracker.add_import( |
| 902 | mod, original_name, resolved_name |
| 903 | ) |
| 904 | except (SyntaxError, ValueError): |
| 905 | # If there's a syntax error, skip import tracking |
| 906 | # (though this shouldn't happen since the code already executed successfully) |
| 907 | pass |
| 908 | |
| 909 | |
| 910 | def load_ipython_extension(ip): |
no test coverage detected