""" The API basically only provides one class. You can create a :class:`Script` and use its methods. Additionally you can add a debug function with :func:`set_debug_function`. Alternatively, if you don't need a custom function and are happy with printing debug messages to stdout, simply call :func:`set_debug_function` without arguments. """ import os import sys import warnings from functools import wraps import parso from parso.python import tree from jedi._compatibility import force_unicode, cast_path, is_py3 from jedi.parser_utils import get_executable_nodes from jedi import debug from jedi import settings from jedi import cache from jedi.file_io import KnownContentFileIO from jedi.api import classes from jedi.api import interpreter from jedi.api import helpers from jedi.api.helpers import validate_line_column from jedi.api.completion import Completion, search_in_module from jedi.api.keywords import KeywordName from jedi.api.environment import InterpreterEnvironment from jedi.api.project import get_default_project, Project from jedi.api.errors import parso_to_jedi_errors from jedi.api import refactoring from jedi.api.refactoring.extract import extract_function, extract_variable from jedi.inference import InferenceState from jedi.inference import imports from jedi.inference.references import find_references from jedi.inference.arguments import try_iter_content from jedi.inference.helpers import infer_call_of_leaf from jedi.inference.sys_path import transform_path_to_dotted from jedi.inference.syntax_tree import tree_name_to_values from jedi.inference.value import ModuleValue from jedi.inference.base_value import ValueSet from jedi.inference.value.iterable import unpack_tuple_to_dict from jedi.inference.gradual.conversion import convert_names, convert_values from jedi.inference.gradual.utils import load_proper_stub_module from jedi.inference.utils import to_list # Jedi uses lots and lots of recursion. By setting this a little bit higher, we # can remove some "maximum recursion depth" errors. sys.setrecursionlimit(3000) def _no_python2_support(func): # TODO remove when removing Python 2/3.5 @wraps(func) def wrapper(self, *args, **kwargs): if self._inference_state.grammar.version_info < (3, 6) or sys.version_info < (3, 6): raise NotImplementedError( "No support for refactorings/search on Python 2/3.5" ) return func(self, *args, **kwargs) return wrapper class Script(object): """ A Script is the base for completions, goto or whatever you want to do with Jedi. The counter part of this class is :class:`Interpreter`, which works with actual dictionaries and can work with a REPL. This class should be used when a user edits code in an editor. You can either use the ``code`` parameter or ``path`` to read a file. Usually you're going to want to use both of them (in an editor). The Script's ``sys.path`` is very customizable: - If `project` is provided with a ``sys_path``, that is going to be used. - If `environment` is provided, its ``sys.path`` will be used (see :func:`Environment.get_sys_path `); - Otherwise ``sys.path`` will match that of the default environment of Jedi, which typically matches the sys path that was used at the time when Jedi was imported. Most methods have a ``line`` and a ``column`` parameter. Lines in Jedi are always 1-based and columns are always zero based. To avoid repetition they are not always documented. You can omit both line and column. Jedi will then just do whatever action you are calling at the end of the file. If you provide only the line, just will complete at the end of that line. .. warning:: By default :attr:`jedi.settings.fast_parser` is enabled, which means that parso reuses modules (i.e. they are not immutable). With this setting Jedi is **not thread safe** and it is also not safe to use multiple :class:`.Script` instances and its definitions at the same time. If you are a normal plugin developer this should not be an issue. It is an issue for people that do more complex stuff with Jedi. This is purely a performance optimization and works pretty well for all typical usages, however consider to turn the setting off if it causes you problems. See also `this discussion `_. :param code: The source code of the current file, separated by newlines. :type code: str :param line: Deprecated, please use it directly on e.g. ``.complete`` :type line: int :param column: Deprecated, please use it directly on e.g. ``.complete`` :type column: int :param path: The path of the file in the file system, or ``''`` if it hasn't been saved yet. :type path: str or None :param encoding: Deprecated, cast to unicode yourself. The encoding of ``code``, if it is not a ``unicode`` object (default ``'utf-8'``). :type encoding: str :param sys_path: Deprecated, use the project parameter. :type sys_path: typing.List[str] :param Environment environment: Provide a predefined :ref:`Environment ` to work with a specific Python version or virtualenv. :param Project project: Provide a :class:`.Project` to make sure finding references works well, because the right folder is searched. There are also ways to modify the sys path and other things. """ def __init__(self, code=None, line=None, column=None, path=None, encoding=None, sys_path=None, environment=None, project=None, source=None): self._orig_path = path # An empty path (also empty string) should always result in no path. self.path = os.path.abspath(path) if path else None if encoding is None: encoding = 'utf-8' else: warnings.warn( "Deprecated since version 0.17.0. You should cast to valid " "unicode yourself, especially if you are not using utf-8.", DeprecationWarning, stacklevel=2 ) if line is not None: warnings.warn( "Providing the line is now done in the functions themselves " "like `Script(...).complete(line, column)`", DeprecationWarning, stacklevel=2 ) if column is not None: warnings.warn( "Providing the column is now done in the functions themselves " "like `Script(...).complete(line, column)`", DeprecationWarning, stacklevel=2 ) if source is not None: code = source warnings.warn( "Use the code keyword argument instead.", DeprecationWarning, stacklevel=2 ) if code is None: # TODO add a better warning than the traceback! with open(path, 'rb') as f: code = f.read() if sys_path is not None and not is_py3: sys_path = list(map(force_unicode, sys_path)) if project is None: # Load the Python grammar of the current interpreter. project = get_default_project( os.path.dirname(self.path) if path else None ) # TODO deprecate and remove sys_path from the Script API. if sys_path is not None: project._sys_path = sys_path warnings.warn( "Deprecated since version 0.17.0. Use the project API instead, " "which means Script(project=Project(dir, sys_path=sys_path)) instead.", DeprecationWarning, stacklevel=2 ) self._inference_state = InferenceState( project, environment=environment, script_path=self.path ) debug.speed('init') self._module_node, code = self._inference_state.parse_and_get_code( code=code, path=self.path, encoding=encoding, use_latest_grammar=path and path.endswith('.pyi'), cache=False, # No disk cache, because the current script often changes. diff_cache=settings.fast_parser, cache_path=settings.cache_directory, ) debug.speed('parsed') self._code_lines = parso.split_lines(code, keepends=True) self._code = code self._pos = line, column cache.clear_time_caches() debug.reset_time() # Cache the module, this is mostly useful for testing, since this shouldn't # be called multiple times. @cache.memoize_method def _get_module(self): names = None is_package = False if self.path is not None: import_names, is_p = transform_path_to_dotted( self._inference_state.get_sys_path(add_parent_paths=False), self.path ) if import_names is not None: names = import_names is_package = is_p if self.path is None: file_io = None else: file_io = KnownContentFileIO(cast_path(self.path), self._code) if self.path is not None and self.path.endswith('.pyi'): # We are in a stub file. Try to load the stub properly. stub_module = load_proper_stub_module( self._inference_state, file_io, names, self._module_node ) if stub_module is not None: return stub_module if names is None: names = ('__main__',) module = ModuleValue( self._inference_state, self._module_node, file_io=file_io, string_names=names, code_lines=self._code_lines, is_package=is_package, ) if names[0] not in ('builtins', '__builtin__', 'typing'): # These modules are essential for Jedi, so don't overwrite them. self._inference_state.module_cache.add(names, ValueSet([module])) return module def _get_module_context(self): return self._get_module().as_context() def __repr__(self): return '<%s: %s %r>' % ( self.__class__.__name__, repr(self._orig_path), self._inference_state.environment, ) @validate_line_column def complete(self, line=None, column=None, **kwargs): """ Completes objects under the cursor. Those objects contain information about the completions, more than just names. :param fuzzy: Default False. Will return fuzzy completions, which means that e.g. ``ooa`` will match ``foobar``. :return: Completion objects, sorted by name. Normal names appear before "private" names that start with ``_`` and those appear before magic methods and name mangled names that start with ``__``. :rtype: list of :class:`.Completion` """ return self._complete(line, column, **kwargs) def _complete(self, line, column, fuzzy=False): # Python 2... with debug.increase_indent_cm('complete'): completion = Completion( self._inference_state, self._get_module_context(), self._code_lines, (line, column), self.get_signatures, fuzzy=fuzzy, ) return completion.complete() def completions(self, fuzzy=False): warnings.warn( "Deprecated since version 0.16.0. Use Script(...).complete instead.", DeprecationWarning, stacklevel=2 ) return self.complete(*self._pos, fuzzy=fuzzy) @validate_line_column def infer(self, line=None, column=None, **kwargs): """ Return the definitions of under the cursor. It is basically a wrapper around Jedi's type inference. This method follows complicated paths and returns the end, not the first definition. The big difference between :meth:`goto` and :meth:`infer` is that :meth:`goto` doesn't follow imports and statements. Multiple objects may be returned, because depending on an option you can have two different versions of a function. :param only_stubs: Only return stubs for this method. :param prefer_stubs: Prefer stubs to Python objects for this method. :rtype: list of :class:`.Name` """ with debug.increase_indent_cm('infer'): return self._infer(line, column, **kwargs) def goto_definitions(self, **kwargs): warnings.warn( "Deprecated since version 0.16.0. Use Script(...).infer instead.", DeprecationWarning, stacklevel=2 ) return self.infer(*self._pos, **kwargs) def _infer(self, line, column, only_stubs=False, prefer_stubs=False): pos = line, column leaf = self._module_node.get_name_of_position(pos) if leaf is None: leaf = self._module_node.get_leaf_for_position(pos) if leaf is None or leaf.type == 'string': return [] context = self._get_module_context().create_context(leaf) values = helpers.infer(self._inference_state, context, leaf) values = convert_values( values, only_stubs=only_stubs, prefer_stubs=prefer_stubs, ) defs = [classes.Name(self._inference_state, c.name) for c in values] # The additional set here allows the definitions to become unique in an # API sense. In the internals we want to separate more things than in # the API. return helpers.sorted_definitions(set(defs)) def goto_assignments(self, follow_imports=False, follow_builtin_imports=False, **kwargs): warnings.warn( "Deprecated since version 0.16.0. Use Script(...).goto instead.", DeprecationWarning, stacklevel=2 ) return self.goto(*self._pos, follow_imports=follow_imports, follow_builtin_imports=follow_builtin_imports, **kwargs) @validate_line_column def goto(self, line=None, column=None, **kwargs): """ Goes to the name that defined the object under the cursor. Optionally you can follow imports. Multiple objects may be returned, depending on an if you can have two different versions of a function. :param follow_imports: The method will follow imports. :param follow_builtin_imports: If ``follow_imports`` is True will try to look up names in builtins (i.e. compiled or extension modules). :param only_stubs: Only return stubs for this method. :param prefer_stubs: Prefer stubs to Python objects for this method. :rtype: list of :class:`.Name` """ with debug.increase_indent_cm('goto'): return self._goto(line, column, **kwargs) def _goto(self, line, column, follow_imports=False, follow_builtin_imports=False, only_stubs=False, prefer_stubs=False): tree_name = self._module_node.get_name_of_position((line, column)) if tree_name is None: # Without a name we really just want to jump to the result e.g. # executed by `foo()`, if we the cursor is after `)`. return self.infer(line, column, only_stubs=only_stubs, prefer_stubs=prefer_stubs) name = self._get_module_context().create_name(tree_name) # Make it possible to goto the super class function/attribute # definitions, when they are overwritten. names = [] if name.tree_name.is_definition() and name.parent_context.is_class(): class_node = name.parent_context.tree_node class_value = self._get_module_context().create_value(class_node) mro = class_value.py__mro__() next(mro) # Ignore the first entry, because it's the class itself. for cls in mro: names = cls.goto(tree_name.value) if names: break if not names: names = list(name.goto()) if follow_imports: names = helpers.filter_follow_imports(names, follow_builtin_imports) names = convert_names( names, only_stubs=only_stubs, prefer_stubs=prefer_stubs, ) defs = [classes.Name(self._inference_state, d) for d in set(names)] # Avoid duplicates return list(set(helpers.sorted_definitions(defs))) @_no_python2_support def search(self, string, **kwargs): """ Searches a name in the current file. For a description of how the search string should look like, please have a look at :meth:`.Project.search`. :param bool all_scopes: Default False; searches not only for definitions on the top level of a module level, but also in functions and classes. :yields: :class:`.Name` """ return self._search(string, **kwargs) # Python 2 ... def _search(self, string, all_scopes=False): return self._search_func(string, all_scopes=all_scopes) @to_list def _search_func(self, string, all_scopes=False, complete=False, fuzzy=False): names = self._names(all_scopes=all_scopes) wanted_type, wanted_names = helpers.split_search_string(string) return search_in_module( self._inference_state, self._get_module_context(), names=names, wanted_type=wanted_type, wanted_names=wanted_names, complete=complete, fuzzy=fuzzy, ) def complete_search(self, string, **kwargs): """ Like :meth:`.Script.search`, but completes that string. If you want to have all possible definitions in a file you can also provide an empty string. :param bool all_scopes: Default False; searches not only for definitions on the top level of a module level, but also in functions and classes. :param fuzzy: Default False. Will return fuzzy completions, which means that e.g. ``ooa`` will match ``foobar``. :yields: :class:`.Completion` """ return self._search_func(string, complete=True, **kwargs) @validate_line_column def help(self, line=None, column=None): """ Used to display a help window to users. Uses :meth:`.Script.goto` and returns additional definitions for keywords and operators. Typically you will want to display :meth:`.BaseName.docstring` to the user for all the returned definitions. The additional definitions are ``Name(...).type == 'keyword'``. These definitions do not have a lot of value apart from their docstring attribute, which contains the output of Python's :func:`help` function. :rtype: list of :class:`.Name` """ definitions = self.goto(line, column, follow_imports=True) if definitions: return definitions leaf = self._module_node.get_leaf_for_position((line, column)) if leaf is not None and leaf.type in ('keyword', 'operator', 'error_leaf'): def need_pydoc(): if leaf.value in ('(', ')', '[', ']'): if leaf.parent.type == 'trailer': return False if leaf.parent.type == 'atom': return False grammar = self._inference_state.grammar # This parso stuff is not public, but since I control it, this # is fine :-) ~dave reserved = grammar._pgen_grammar.reserved_syntax_strings.keys() return leaf.value in reserved if need_pydoc(): name = KeywordName(self._inference_state, leaf.value) return [classes.Name(self._inference_state, name)] return [] def usages(self, **kwargs): warnings.warn( "Deprecated since version 0.16.0. Use Script(...).get_references instead.", DeprecationWarning, stacklevel=2 ) return self.get_references(*self._pos, **kwargs) @validate_line_column def get_references(self, line=None, column=None, **kwargs): """ Lists all references of a variable in a project. Since this can be quite hard to do for Jedi, if it is too complicated, Jedi will stop searching. :param include_builtins: Default ``True``. If ``False``, checks if a reference is a builtin (e.g. ``sys``) and in that case does not return it. :param scope: Default ``'project'``. If ``'file'``, include references in the current module only. :rtype: list of :class:`.Name` """ def _references(include_builtins=True, scope='project'): if scope not in ('project', 'file'): raise ValueError('Only the scopes "file" and "project" are allowed') tree_name = self._module_node.get_name_of_position((line, column)) if tree_name is None: # Must be syntax return [] names = find_references(self._get_module_context(), tree_name, scope == 'file') definitions = [classes.Name(self._inference_state, n) for n in names] if not include_builtins or scope == 'file': definitions = [d for d in definitions if not d.in_builtin_module()] return helpers.sorted_definitions(definitions) return _references(**kwargs) def call_signatures(self): warnings.warn( "Deprecated since version 0.16.0. Use Script(...).get_signatures instead.", DeprecationWarning, stacklevel=2 ) return self.get_signatures(*self._pos) @validate_line_column def get_signatures(self, line=None, column=None): """ Return the function object of the call under the cursor. E.g. if the cursor is here:: abs(# <-- cursor is here This would return the ``abs`` function. On the other hand:: abs()# <-- cursor is here This would return an empty list.. :rtype: list of :class:`.Signature` """ pos = line, column call_details = helpers.get_signature_details(self._module_node, pos) if call_details is None: return [] context = self._get_module_context().create_context(call_details.bracket_leaf) definitions = helpers.cache_signatures( self._inference_state, context, call_details.bracket_leaf, self._code_lines, pos ) debug.speed('func_call followed') # TODO here we use stubs instead of the actual values. We should use # the signatures from stubs, but the actual values, probably?! return [classes.Signature(self._inference_state, signature, call_details) for signature in definitions.get_signatures()] @validate_line_column def get_context(self, line=None, column=None): """ Returns the scope context under the cursor. This basically means the function, class or module where the cursor is at. :rtype: :class:`.Name` """ pos = (line, column) leaf = self._module_node.get_leaf_for_position(pos, include_prefixes=True) if leaf.start_pos > pos or leaf.type == 'endmarker': previous_leaf = leaf.get_previous_leaf() if previous_leaf is not None: leaf = previous_leaf module_context = self._get_module_context() n = tree.search_ancestor(leaf, 'funcdef', 'classdef') if n is not None and n.start_pos < pos <= n.children[-1].start_pos: # This is a bit of a special case. The context of a function/class # name/param/keyword is always it's parent context, not the # function itself. Catch all the cases here where we are before the # suite object, but still in the function. context = module_context.create_value(n).as_context() else: context = module_context.create_context(leaf) while context.name is None: context = context.parent_context # comprehensions definition = classes.Name(self._inference_state, context.name) while definition.type != 'module': name = definition._name # TODO private access tree_name = name.tree_name if tree_name is not None: # Happens with lambdas. scope = tree_name.get_definition() if scope.start_pos[1] < column: break definition = definition.parent() return definition def _analysis(self): self._inference_state.is_analysis = True self._inference_state.analysis_modules = [self._module_node] module = self._get_module_context() try: for node in get_executable_nodes(self._module_node): context = module.create_context(node) if node.type in ('funcdef', 'classdef'): # Resolve the decorators. tree_name_to_values(self._inference_state, context, node.children[1]) elif isinstance(node, tree.Import): import_names = set(node.get_defined_names()) if node.is_nested(): import_names |= set(path[-1] for path in node.get_paths()) for n in import_names: imports.infer_import(context, n) elif node.type == 'expr_stmt': types = context.infer_node(node) for testlist in node.children[:-1:2]: # Iterate tuples. unpack_tuple_to_dict(context, types, testlist) else: if node.type == 'name': defs = self._inference_state.infer(context, node) else: defs = infer_call_of_leaf(context, node) try_iter_content(defs) self._inference_state.reset_recursion_limitations() ana = [a for a in self._inference_state.analysis if self.path == a.path] return sorted(set(ana), key=lambda x: x.line) finally: self._inference_state.is_analysis = False def get_names(self, **kwargs): """ Returns names defined in the current file. :param all_scopes: If True lists the names of all scopes instead of only the module namespace. :param definitions: If True lists the names that have been defined by a class, function or a statement (``a = b`` returns ``a``). :param references: If True lists all the names that are not listed by ``definitions=True``. E.g. ``a = b`` returns ``b``. :rtype: list of :class:`.Name` """ names = self._names(**kwargs) return [classes.Name(self._inference_state, n) for n in names] def get_syntax_errors(self): """ Lists all syntax errors in the current file. :rtype: list of :class:`.SyntaxError` """ return parso_to_jedi_errors(self._inference_state.grammar, self._module_node) def _names(self, all_scopes=False, definitions=True, references=False): # Set line/column to a random position, because they don't matter. module_context = self._get_module_context() defs = [ module_context.create_name(name) for name in helpers.get_module_names( self._module_node, all_scopes=all_scopes, definitions=definitions, references=references, ) ] return sorted(defs, key=lambda x: x.start_pos) @_no_python2_support def rename(self, line=None, column=None, **kwargs): """ Renames all references of the variable under the cursor. :param new_name: The variable under the cursor will be renamed to this string. :raises: :exc:`.RefactoringError` :rtype: :class:`.Refactoring` """ return self._rename(line, column, **kwargs) def _rename(self, line, column, new_name): # Python 2... definitions = self.get_references(line, column, include_builtins=False) return refactoring.rename(self._inference_state, definitions, new_name) @_no_python2_support def extract_variable(self, line, column, **kwargs): """ Moves an expression to a new statemenet. For example if you have the cursor on ``foo`` and provide a ``new_name`` called ``bar``:: foo = 3.1 x = int(foo + 1) the code above will become:: foo = 3.1 bar = foo + 1 x = int(bar) :param new_name: The expression under the cursor will be renamed to this string. :param int until_line: The the selection range ends at this line, when omitted, Jedi will be clever and try to define the range itself. :param int until_column: The the selection range ends at this column, when omitted, Jedi will be clever and try to define the range itself. :raises: :exc:`.RefactoringError` :rtype: :class:`.Refactoring` """ return self._extract_variable(line, column, **kwargs) # Python 2... @validate_line_column def _extract_variable(self, line, column, new_name, until_line=None, until_column=None): if until_line is None and until_column is None: until_pos = None else: if until_line is None: until_line = line if until_column is None: until_column = len(self._code_lines[until_line - 1]) until_pos = until_line, until_column return extract_variable( self._inference_state, self.path, self._module_node, new_name, (line, column), until_pos ) @_no_python2_support def extract_function(self, line, column, **kwargs): """ Moves an expression to a new function. For example if you have the cursor on ``foo`` and provide a ``new_name`` called ``bar``:: global_var = 3 def x(): foo = 3.1 x = int(foo + 1 + global_var) the code above will become:: global_var = 3 def bar(foo): return int(foo + 1 + global_var) def x(): foo = 3.1 x = bar(foo) :param new_name: The expression under the cursor will be replaced with a function with this name. :param int until_line: The the selection range ends at this line, when omitted, Jedi will be clever and try to define the range itself. :param int until_column: The the selection range ends at this column, when omitted, Jedi will be clever and try to define the range itself. :raises: :exc:`.RefactoringError` :rtype: :class:`.Refactoring` """ return self._extract_function(line, column, **kwargs) # Python 2... @validate_line_column def _extract_function(self, line, column, new_name, until_line=None, until_column=None): if until_line is None and until_column is None: until_pos = None else: if until_line is None: until_line = line if until_column is None: until_column = len(self._code_lines[until_line - 1]) until_pos = until_line, until_column return extract_function( self._inference_state, self.path, self._get_module_context(), new_name, (line, column), until_pos ) @_no_python2_support def inline(self, line=None, column=None): """ Inlines a variable under the cursor. This is basically the opposite of extracting a variable. For example with the cursor on bar:: foo = 3.1 bar = foo + 1 x = int(bar) the code above will become:: foo = 3.1 x = int(foo + 1) :raises: :exc:`.RefactoringError` :rtype: :class:`.Refactoring` """ names = [d._name for d in self.get_references(line, column, include_builtins=True)] return refactoring.inline(self._inference_state, names) class Interpreter(Script): """ Jedi's API for Python REPLs. Implements all of the methods that are present in :class:`.Script` as well. In addition to completions that normal REPL completion does like ``str.upper``, Jedi also supports code completion based on static code analysis. For example Jedi will complete ``str().upper``. >>> from os.path import join >>> namespace = locals() >>> script = Interpreter('join("").up', [namespace]) >>> print(script.complete()[0].name) upper All keyword arguments are same as the arguments for :class:`.Script`. :param str code: Code to parse. :type namespaces: typing.List[dict] :param namespaces: A list of namespace dictionaries such as the one returned by :func:`globals` and :func:`locals`. """ _allow_descriptor_getattr_default = True def __init__(self, code, namespaces, **kwds): try: namespaces = [dict(n) for n in namespaces] except Exception: raise TypeError("namespaces must be a non-empty list of dicts.") environment = kwds.get('environment', None) if environment is None: environment = InterpreterEnvironment() else: if not isinstance(environment, InterpreterEnvironment): raise TypeError("The environment needs to be an InterpreterEnvironment subclass.") super(Interpreter, self).__init__(code, environment=environment, project=Project(os.getcwd()), **kwds) self.namespaces = namespaces self._inference_state.allow_descriptor_getattr = self._allow_descriptor_getattr_default @cache.memoize_method def _get_module_context(self): tree_module_value = ModuleValue( self._inference_state, self._module_node, file_io=KnownContentFileIO(self.path, self._code), string_names=('__main__',), code_lines=self._code_lines, ) return interpreter.MixedModuleContext( tree_module_value, self.namespaces, ) def names(source=None, path=None, encoding='utf-8', all_scopes=False, definitions=True, references=False, environment=None): warnings.warn( "Deprecated since version 0.16.0. Use Script(...).get_names instead.", DeprecationWarning, stacklevel=2 ) return Script(source, path=path, encoding=encoding).get_names( all_scopes=all_scopes, definitions=definitions, references=references, ) def preload_module(*modules): """ Preloading modules tells Jedi to load a module now, instead of lazy parsing of modules. This can be useful for IDEs, to control which modules to load on startup. :param modules: different module names, list of string. """ for m in modules: s = "import %s as x; x." % m Script(s, path=None).complete(1, len(s)) def set_debug_function(func_cb=debug.print_to_stdout, warnings=True, notices=True, speed=True): """ Define a callback debug function to get all the debug messages. If you don't specify any arguments, debug messages will be printed to stdout. :param func_cb: The callback function for debug messages. """ debug.debug_function = func_cb debug.enable_warning = warnings debug.enable_notice = notices debug.enable_speed = speed