def test_eqne_1(): m1a = ModuleHandle("foo.bar") m1b = ModuleHandle("foo.bar") m2 = ModuleHandle("foo.baz") assert (m1a == m1b) assert not (m1a != m1b) assert not (m1a == m2) assert (m1a != m2)
def describe_xref(identifier, container): module = ModuleHandle(str(container.defining_module.canonical_name)) assert module.filename == Filename(container.defining_module.filename) linenos = get_string_linenos( module, "(L{|<)%s" % (identifier,), container.docstring) return (module, linenos, str(container.canonical_name), identifier)
def check_xref(self, identifier, container): """ Check that ``identifier`` cross-references a proper symbol. Look in modules that we weren't explicitly asked to look in, if needed. """ if identifier in builtins.__dict__: return True def check_container(): if self.expanded_docindex.find(identifier, container) is not None: return True if isinstance(container, RoutineDoc): tcontainer = self.expanded_docindex.get_vardoc( container.canonical_name) doc = self.expanded_docindex.find(identifier, tcontainer) while (doc is not None and tcontainer not in (None, UNKNOWN) and tcontainer.overrides not in (None, UNKNOWN)): tcontainer = tcontainer.overrides doc = self.expanded_docindex.find(identifier, tcontainer) return doc is not None return False def check_defining_module(x): if x is None: return False defining_module_name = remove_epydoc_sym_suffix(str( x.defining_module.canonical_name)) if defining_module_name in ASSUME_MODULES_OK: return True if self.expanded_docindex.add_module(defining_module_name): if check_container(): return True return False if check_container(): return True if (isinstance(container, RoutineDoc) and identifier in container.all_args()): return True if check_defining_module(container): return True # If the user has imported foo.bar.baz as baz and now uses # ``baz.quux``, we need to add the module foo.bar.baz. for prefix in reversed(list(prefixes( DottedIdentifier(remove_epydoc_sym_suffix(identifier))))): if check_defining_module( self.docindex.find(str(prefix), container)): return True try: module = ModuleHandle.containing(identifier) except ImportError: pass else: if str(module.name) in ASSUME_MODULES_OK: return True if self.expanded_docindex.add_module(module): if check_container(): return True return False
def get_string_linenos(module, searchstring, within_string): """ Return the line numbers (1-indexed) within C{filename} that contain C{searchstring}. Only consider string literals (i.e. not comments). First look for exact matches of C{within_string} (modulo indenting) and then search within that. Only if the C{within_string} is not found, search the entire file. [If there's a comment on the same line as a string that also contains the searchstring, we'll get confused.] """ module = ModuleHandle(module) regexp = re.compile(searchstring) map = map_strings_to_line_numbers(module) results = [] def scan_within_string(results, start_lineno, orig_full_string): for i, line in enumerate(orig_full_string.splitlines()): if regexp.search(line): results.append(start_lineno + i) try: lineno, orig_full_string = map[within_string.strip()] except KeyError: pass else: # We found the larger string exactly within the ast. scan_within_string(results, lineno, orig_full_string) if results: return tuple(results) # We could continue down if this ever happened. raise Exception( "Found superstring in %r but not substring %r within superstring" % (module.filename, searchstring)) # Try a full text search. for lineno, orig_full_string in map.values(): scan_within_string(results, lineno, orig_full_string) if results: return tuple(sorted(results)) raise Exception("Could not find %r anywhere in %r" % (searchstring, module.filename))
def add_module(self, module): """ Adds ``module`` and recreates the DocIndex with the updated set of modules. :return: Whether anything was added. """ module = ModuleHandle(module) for prefix in module.ancestors: if prefix in self.modules: # The module, or a prefix of it, was already added. return False for existing_module in sorted(self.modules): if existing_module.startswith(module): # This supersedes an existing module. assert existing_module != module self.modules.remove(existing_module) logger.debug("Expanding docindex to include %r", module) self.modules.add(module) del self.docindex return True
def replace_star_imports(codeblock, params=None): r""" Replace lines such as:: from foo.bar import * with from foo.bar import f1, f2, f3 Note that this requires involves actually importing C{foo.bar}, which may have side effects. (TODO: rewrite to avoid this?) The result includes all imports from the C{email} module. The result excludes shadowed imports. In this example: 1. The original C{MIMEAudio} import is shadowed, so it is removed. 2. The C{MIMEImage} import in the C{email} module is shadowed by a subsequent import, so it is omitted. >>> codeblock = PythonBlock('from keyword import *', filename="/tmp/x.py") >>> print replace_star_imports(codeblock) [PYFLYBY] /tmp/x.py: replaced 'from keyword import *' with 2 imports from keyword import iskeyword, kwlist <BLANKLINE> Usually you'll want to remove unused imports after replacing star imports. @type codeblock: L{PythonBlock} or convertible (C{str}) @rtype: L{PythonBlock} """ from pyflyby._modules import ModuleHandle params = ImportFormatParams(params) codeblock = PythonBlock(codeblock) filename = codeblock.filename transformer = SourceToSourceFileImportsTransformation(codeblock) for block in transformer.import_blocks: # Iterate over the import statements in C{block.input}. We do this # instead of using C{block.importset} because the latter doesn't # preserve the order of inputs. The order is important for # determining what's shadowed. imports = [ imp for s in block.input.statements for imp in ImportStatement(s).imports ] # Process "from ... import *" statements. new_imports = [] for imp in imports: if imp.split.member_name != "*": new_imports.append(imp) elif imp.split.module_name.startswith("."): # The source contains e.g. "from .foo import *". Right now we # don't have a good way to figure out the absolute module # name, so we can't get at foo. That said, there's a decent # chance that this is inside an __init__ anyway, which is one # of the few justifiable use cases for star imports in library # code. logger.warning( "%s: can't replace star imports in relative import: %s", filename, imp.pretty_print().strip()) new_imports.append(imp) else: module = ModuleHandle(imp.split.module_name) try: with ImportPathForRelativeImportsCtx(codeblock): exports = module.exports except Exception as e: logger.warning( "%s: couldn't import '%s' to enumerate exports, " "leaving unchanged: '%s'. %s: %s", filename, module.name, imp, type(e).__name__, e) new_imports.append(imp) continue if not exports: # We found nothing in the target module. This probably # means that module itself is just importing things from # other modules. Currently we intentionally exclude those # imports since usually we don't want them. TODO: do # something better here. logger.warning("%s: found nothing to import from %s, ", "leaving unchanged: '%s'", filename, module, imp) new_imports.append(imp) else: new_imports.extend(exports) logger.info("%s: replaced %r with %d imports", filename, imp.pretty_print().strip(), len(exports)) block.importset = ImportSet(new_imports, ignore_shadowed=True) return transformer.output(params=params)
def __init__(self, modules): self.modules = set([ModuleHandle(m) for m in modules])
def test_find_bad_doc_cross_references_1(): result = find_bad_doc_cross_references([xrefs]) expected = ( (ModuleHandle('tests.xrefs'), (3, ), 'tests.xrefs', u'undefined_xref_from_module'), (ModuleHandle('tests.xrefs'), (18, ), 'tests.xrefs.FooClass', u'undefined_xref_from_class'), # TODO: undefined_xref_from_class_attribute (ModuleHandle('tests.xrefs'), (30, ), 'tests.xrefs.FooClass.foo_method', u'undefined_xref_from_method'), (ModuleHandle('tests.xrefs'), (37, ), 'tests.xrefs.FooClass.foo_wrapped_method', u'undefined_xref_from_wrapped_method'), (ModuleHandle('tests.xrefs'), (40, ), 'tests.xrefs.FooClass.foo_wrapped_method', u'undefined_xref_from_param'), (ModuleHandle('tests.xrefs'), (42, ), 'tests.xrefs.FooClass.foo_wrapped_method', u'undefined_xref_from_type'), (ModuleHandle('tests.xrefs'), (44, ), 'tests.xrefs.FooClass.foo_wrapped_method', u'undefined_xref_from_args_param'), (ModuleHandle('tests.xrefs'), (46, ), 'tests.xrefs.FooClass.foo_wrapped_method', u'undefined_xref_from_args_type'), (ModuleHandle('tests.xrefs'), (48, ), 'tests.xrefs.FooClass.foo_wrapped_method', u'undefined_xref_from_kwargs_param'), (ModuleHandle('tests.xrefs'), (50, ), 'tests.xrefs.FooClass.foo_wrapped_method', u'undefined_xref_from_kwargs_type'), (ModuleHandle('tests.xrefs'), (52, ), 'tests.xrefs.FooClass.foo_wrapped_method', u'undefined_xref_from_rtype'), (ModuleHandle('tests.xrefs'), (60, 63), 'tests.xrefs.FooClass.foo_property', u'undefined_xref_from_property'), (ModuleHandle('tests.xrefs'), (63, ), '??.foo_property', u'undefined_xref_from_property_rtype'), (ModuleHandle('tests.xrefs'), (70, ), 'tests.xrefs.FooClass.__foo_private_method', u'undefined_xref_from_private_method'), (ModuleHandle('tests.xrefs'), (76, ), 'tests.xrefs.foo_global_function', u'undefined_xref_from_global_function'), ) assert result == expected
def test_module_1(): m = ModuleHandle("logging") assert m.module is logging
def test_filename_init_1(): fn = logging.__file__ fn = Filename(re.sub("[.]pyc$", ".py", fn)).real m = ModuleHandle("logging") assert m.filename.real == fn assert m.filename.base == "__init__.py"
def test_ModuleHandle_from_module_1(): m = ModuleHandle(logging.handlers) assert m == ModuleHandle("logging.handlers") assert m.name == DottedIdentifier("logging.handlers")
def test_ModuleHandle_dotted_1(): m = ModuleHandle("logging.handlers") assert m.name == DottedIdentifier("logging.handlers")
def test_ModuleHandle_1(): m = ModuleHandle("sys") assert m.name == DottedIdentifier("sys")
def test_find_bad_doc_cross_references_1(): from pyflyby._docxref import find_bad_doc_cross_references from pyflyby._modules import ModuleHandle result = find_bad_doc_cross_references([xrefs]) expected = ( (ModuleHandle('tests.xrefs'), (3, ), 'tests.xrefs', u'undefined_xref_from_module'), (ModuleHandle('tests.xrefs'), (19, ), 'tests.xrefs.FooClass', u'undefined_xref_from_class'), # TODO: undefined_xref_from_class_attribute (ModuleHandle('tests.xrefs'), (31, ), 'tests.xrefs.FooClass.foo_method', u'undefined_xref_from_method'), (ModuleHandle('tests.xrefs'), (38, ), 'tests.xrefs.FooClass.foo_wrapped_method', u'undefined_xref_from_wrapped_method'), (ModuleHandle('tests.xrefs'), (41, ), 'tests.xrefs.FooClass.foo_wrapped_method', u'undefined_xref_from_param'), (ModuleHandle('tests.xrefs'), (43, ), 'tests.xrefs.FooClass.foo_wrapped_method', u'undefined_xref_from_type'), (ModuleHandle('tests.xrefs'), (45, ), 'tests.xrefs.FooClass.foo_wrapped_method', u'undefined_xref_from_args_param'), (ModuleHandle('tests.xrefs'), (47, ), 'tests.xrefs.FooClass.foo_wrapped_method', u'undefined_xref_from_args_type'), (ModuleHandle('tests.xrefs'), (49, ), 'tests.xrefs.FooClass.foo_wrapped_method', u'undefined_xref_from_kwargs_param'), (ModuleHandle('tests.xrefs'), (51, ), 'tests.xrefs.FooClass.foo_wrapped_method', u'undefined_xref_from_kwargs_type'), (ModuleHandle('tests.xrefs'), (53, ), 'tests.xrefs.FooClass.foo_wrapped_method', u'undefined_xref_from_rtype'), (ModuleHandle('tests.xrefs'), (61, 64), 'tests.xrefs.FooClass.foo_property', u'undefined_xref_from_property'), (ModuleHandle('tests.xrefs'), (64, ), '??.foo_property', u'undefined_xref_from_property_rtype'), (ModuleHandle('tests.xrefs'), (71, ), 'tests.xrefs.FooClass.__foo_private_method', u'undefined_xref_from_private_method'), (ModuleHandle('tests.xrefs'), (77, ), 'tests.xrefs.foo_global_function', u'undefined_xref_from_global_function'), ) assert result == expected