Cyclic imports
Chris Angelico
rosuav at gmail.com
Tue Aug 17 14:19:51 EDT 2021
On Wed, Aug 18, 2021 at 4:10 AM Barry Scott <barry at barrys-emacs.org> wrote:
>
> def allImports( self, module_name ):
> for line in f:
> words = line.strip().split()
> if words[0:1] == ['import']:
> all_imports.append( words[1] )
>
This will work for a lot of programs, but it depends too much on
coding style. If you feel like trying something a little more
adventurous, I'd recommend looking into the ast module:
>>> import ast
>>> ast.parse("""
... import foo
... import bar, baz
... from quux import spam
... try: import hello
... except ImportError: import goodbye
... """)
<ast.Module object at 0x7f83b65398d0>
>>> m = _
>>> ast.dump(m)
"Module(body=[Import(names=[alias(name='foo')]),
Import(names=[alias(name='bar'), alias(name='baz')]),
ImportFrom(module='quux', names=[alias(name='spam')], level=0),
Try(body=[Import(names=[alias(name='hello')])],
handlers=[ExceptHandler(type=Name(id='ImportError', ctx=Load()),
body=[Import(names=[alias(name='goodbye')])])], orelse=[],
finalbody=[])], type_ignores=[])"
If you ast.parse() the text of a Python script, you'll get a Module
that has all the top-level code in a list. It's then up to you how
much you dig into that. For instance, a simple try/except like this is
fairly common, but if something's inside a FunctionDef, you might want
to ignore it. Or maybe just ignore everything that isn't an Import or
FromImport, which would be a lot easier, but would miss the try/except
example.
The main advantage of ast.parse() is that it no longer cares about
code layout, and it won't be fooled by an import statement inside a
docstring, or anything like that. It's also pretty easy to handle
multiple variants (note how "import bar, baz" just has two things in
the names list).
ChrisA
More information about the Python-list
mailing list