diff --git a/lib/python/pyflyby/_interactive.py b/lib/python/pyflyby/_interactive.py index b0c450cc..d4ef152a 100644 --- a/lib/python/pyflyby/_interactive.py +++ b/lib/python/pyflyby/_interactive.py @@ -85,9 +85,6 @@ def _get_or_create_ipython_terminal_app(): pass else: return TerminalIPythonApp.instance() - # The following has been tested on IPython 0.10. - if hasattr(IPython, "ipapi"): - return _IPython010TerminalApplication.instance() raise RuntimeError( "Couldn't get TerminalIPythonApp class. " "Is your IPython version too old (or too new)? " @@ -122,51 +119,6 @@ def _app_is_initialized(app): -class _IPython010TerminalApplication(object): - """ - Shim class that mimics IPython 0.11+ application classes, for use in - IPython 0.10. - """ - - # IPython.ipapi.launch_instance() => IPython.Shell.start() creates an - # instance of "IPShell". IPShell has an attribute named "IP" which is an - # "InteractiveShell". - - _instance = None - - @classmethod - def instance(cls): - if cls._instance is not None: - self = cls._instance - self.init_shell() - return self - import IPython - if not hasattr(IPython, "ipapi"): - raise RuntimeError("Inappropriate version of IPython %r" - % (IPython.__version__,)) - self = cls._instance = cls() - self.init_shell() - return self - - def init_shell(self): - import IPython - ipapi = IPython.ipapi.get() # IPApi instance - if ipapi is not None: - self.shell = ipapi.IP # InteractiveShell instance - else: - self.shell = None - - def initialize(self, argv=None): - import IPython - logger.debug("Creating IPython 0.10 session") - self._session = IPython.ipapi.make_session() # IPShell instance - self.init_shell() - assert self._session is not None - - def start(self): - self._session.mainloop() - - class _DummyIPythonEmbeddedApp(object): """ @@ -412,30 +364,7 @@ def install_in_ipython_config_file(): else: _install_in_ipython_config_file_40() return - # The following has been tested on IPython 0.12, 0.13, 1.0, 1.2, 2.0, 2.1, - # 2.2, 2.3, 2.4, 3.0, 3.1, 3.2, 4.0. - try: - IPython.core.profiledir.ProfileDir.startup_dir - except AttributeError: - pass - else: - _install_in_ipython_config_file_012() - return - # The following has been tested on IPython 0.11. - try: - IPython.core.profiledir.ProfileDir - except AttributeError: - pass - else: - _install_in_ipython_config_file_011() - return - try: - IPython.genutils.get_ipython_dir - except AttributeError: - pass - else: - _install_in_ipython_config_file_010() - return + raise RuntimeError( "Couldn't install pyflyby autoimporter in IPython. " "Is your IPython version too old (or too new)? " @@ -555,96 +484,10 @@ def _install_in_ipython_config_file_40(): logger.info("[DONE] Removed old file %s (moved to %s)", old_fn, trash_fn) -def _install_in_ipython_config_file_012(): - """ - Implementation of `install_in_ipython_config_file` for IPython 0.12+. - Tested with IPython 0.12, 0.13, 1.0, 1.2, 2.0, 2.1, 2.2, 2.3, 2.4, 3.0, - 3.1, 3.2, 4.0. - """ - import IPython - ipython_dir = Filename(IPython.utils.path.get_ipython_dir()) - if not ipython_dir.isdir: - raise RuntimeError( - "Couldn't find IPython config dir. Tried %s" % (ipython_dir,)) - startup_dir = ipython_dir / "profile_default" / "startup" - if not startup_dir.isdir: - raise RuntimeError( - "Couldn't find IPython startup dir. Tried %s" % (startup_dir,)) - fn = startup_dir / "50-pyflyby.py" - if fn.exists: - logger.info("Doing nothing, because %s already exists", fn) - return - argv = sys.argv[:] - argv[0] = os.path.realpath(argv[0]) - argv = ' '.join(argv) - header = ( - "# File: {fn}\n" - "#\n" - "# Generated by {argv}\n" - "#\n" - "# This file causes IPython to enable the Pyflyby Auto Importer.\n" - "#\n" - "# To uninstall, just delete this file.\n" - "#\n" - ).format(**locals()) - contents = header + _generate_enabler_code() - logger.info("Installing pyflyby auto importer in your IPython startup") - logger.info("Writing to %s:\n%s", fn, contents) - atomic_write_file(fn, contents) - - -def _install_in_ipython_config_file_011(): - """ - Implementation of `install_in_ipython_config_file` for IPython 0.11. - """ - import IPython - ipython_dir = Filename(IPython.utils.path.get_ipython_dir()) - fn = ipython_dir / "profile_default" / "ipython_config.py" - if not fn.exists: - raise RuntimeError( - "Couldn't find IPython startup file. Tried %s" % (fn,)) - old_contents = read_file(fn).joined - if re.search(r"^ *(pyflyby[.])?enable_auto_importer[(][)]", old_contents, re.M): - logger.info("Doing nothing, because already installed in %s", fn) - return - header = ( - "\n" - "\n" - "#\n" - "# Enable the Pyflyby Auto Importer.\n" - ) - new_contents = header + _generate_enabler_code() - contents = old_contents.rstrip() + new_contents - logger.info("Installing pyflyby auto importer in your IPython startup") - logger.info("Appending to %s:\n%s", fn, new_contents) - atomic_write_file(fn, contents) -def _install_in_ipython_config_file_010(): - """ - Implementation of `install_in_ipython_config_file` for IPython 0.10. - """ - import IPython - ipython_dir = Filename(IPython.genutils.get_ipython_dir()) - fn = ipython_dir / "ipy_user_conf.py" - if not fn.exists: - raise RuntimeError( - "Couldn't find IPython config file. Tried %s" % (fn,)) - old_contents = read_file(fn).joined - if re.search(r"^ *(pyflyby[.])?enable_auto_importer[(][)]", old_contents, re.M): - logger.info("Doing nothing, because already installed in %s", fn) - return - header = ( - "\n" - "\n" - "#\n" - "# Enable the Pyflyby Auto Importer.\n" - ) - new_contents = header + _generate_enabler_code() - contents = old_contents.rstrip() + new_contents - logger.info("Installing pyflyby auto importer in your IPython startup") - logger.info("Appending to %s:\n%s", fn, new_contents) - atomic_write_file(fn, contents) + + def _ipython_in_multiline(ip): @@ -722,37 +565,6 @@ def get_prompt_rlipython(): else: return ip.separate_in + ip.prompt_in1.format(ip.execution_count) get_prompt = get_prompt_rlipython - elif hasattr(ip, "prompt_manager"): - # IPython >= 0.12 (known to work including up to 1.2, 2.1) - prompt_manager = ip.prompt_manager - def get_prompt_ipython_012(): - pdb_instance = _get_pdb_if_is_in_pdb() - if pdb_instance is not None: - return pdb_instance.prompt - elif _ipython_in_multiline(ip): - return prompt_manager.render("in2") - else: - return ip.separate_in + prompt_manager.render("in") - get_prompt = get_prompt_ipython_012 - elif hasattr(ip.hooks, "generate_prompt"): - # IPython 0.10, 0.11 - generate_prompt = ip.hooks.generate_prompt - def get_prompt_ipython_010(): - pdb_instance = _get_pdb_if_is_in_pdb() - if pdb_instance is not None: - return pdb_instance.prompt - elif _ipython_in_multiline(ip): - return generate_prompt(True) - else: - if hasattr(ip, "outputcache"): - # IPython 0.10 (but not 0.11+): - # Decrement the prompt_count since it otherwise - # auto-increments. (It's hard to avoid the - # auto-increment as it happens as a side effect of - # __str__!) - ip.outputcache.prompt_count -= 1 - return generate_prompt(False) - get_prompt = get_prompt_ipython_010 else: # Too old or too new IPython version? return NullCtx() @@ -818,8 +630,6 @@ def _get_ipython_app(): # No active IPython app/shell. raise NoActiveIPythonAppError("No active IPython application") # The following has been tested on IPython 0.10. - if hasattr(IPython, "ipapi"): - return _IPython010TerminalApplication.instance() raise NoActiveIPythonAppError( "Could not figure out how to get active IPython application for IPython version %s" % (IPython.__version__,)) diff --git a/lib/python/pyflyby/_parse.py b/lib/python/pyflyby/_parse.py index 140bb4c1..acfae92f 100644 --- a/lib/python/pyflyby/_parse.py +++ b/lib/python/pyflyby/_parse.py @@ -346,9 +346,6 @@ def _annotate_ast_nodes(ast_node: ast.AST) -> AnnotatedAst: flags = aast_node.flags startpos = text.startpos _annotate_ast_startpos(aast_node, None, startpos, text, flags) - # Not used for now: - # ast_node.context = AstNodeContext(None, None, None) - # _annotate_ast_context(ast_node) return aast_node @@ -526,29 +523,6 @@ def _annotate_ast_startpos( raise ValueError("Couldn't find exact position of %s" % (ast.dump(ast_node))) -def _annotate_ast_context(ast_node): - """ - Recursively annotate ``context`` on ast nodes, setting ``context`` to - a `AstNodeContext` named tuple with values - ``(parent, field, index)``. - Each aast_node satisfies ``parent.[] is ast_node``. - - For non-list fields, the index part is ``None``. - """ - assert isinstance(ast_node, ast.AST) - for field_name, field_value in ast.iter_fields(ast_node): - if isinstance(field_value, ast.AST): - child_node = field_value - child_node.context = AstNodeContext(ast_node, field_name, None) - _annotate_ast_context(child_node) - elif isinstance(field_value, list): - for i, item in enumerate(field_value): - if isinstance(item, ast.AST): - child_node = item - child_node.context = AstNodeContext(ast_node, field_name, i) - _annotate_ast_context(child_node) - - def _split_code_lines(ast_nodes, text): """ Split the given ``ast_nodes`` and corresponding ``text`` by code/noncode @@ -632,51 +606,6 @@ def _split_code_lines(ast_nodes, text): yield ([], text[endpos:next_startpos]) -def _ast_node_is_in_docstring_position(ast_node): - """ - Given a ``Str`` AST node, return whether its position within the AST makes - it eligible as a docstring. - - The main way a ``Str`` can be a docstring is if it is a standalone string - at the beginning of a ``Module``, ``FunctionDef``, ``AsyncFucntionDef`` - or ``ClassDef``. - - We also support variable docstrings per Epydoc: - - - If a variable assignment statement is immediately followed by a bare - string literal, then that assignment is treated as a docstring for - that variable. - - :type ast_node: - ``ast.Str`` - :param ast_node: - AST node that has been annotated by ``_annotate_ast_nodes``. - :rtype: - ``bool`` - :return: - Whether this string ast node is in docstring position. - """ - if not _is_ast_str_or_byte(ast_node): - raise TypeError - expr_node = ast_node.context.parent - if not isinstance(expr_node, ast.Expr): - return False - assert ast_node.context.field == 'value' - assert ast_node.context.index is None - expr_ctx = expr_node.context - if expr_ctx.field != 'body': - return False - parent_node = expr_ctx.parent - if not isinstance(parent_node, (ast.FunctionDef, ast.ClassDef, ast.Module, AsyncFunctionDef)): - return False - if expr_ctx.index == 0: - return True - prev_sibling_node = parent_node.body[expr_ctx.index-1] - if isinstance(prev_sibling_node, ast.Assign): - return True - return False - - def infer_compile_mode(arg:ast.AST) -> Literal['exec','eval','single']: """ Infer the mode needed to compile ``arg``. @@ -1334,11 +1263,6 @@ def _get_docstring_nodes(self): # - This function yields multiple docstrings (even per ast node) # - This function doesn't raise TypeError on other AST types # - This function doesn't cleandoc - # A previous implementation did - # [n for n in self.string_literals() - # if _ast_node_is_in_docstring_position(n)] - # However, the method we now use is more straightforward, and doesn't - # require first annotating each node with context information. docstring_containers = (ast.FunctionDef, ast.ClassDef, ast.Module, AsyncFunctionDef) for node in _walk_ast_nodes_in_order(self.annotated_ast_node): if not isinstance(node, docstring_containers):