Skip to content

Instantly share code, notes, and snippets.

@kawa-kokosowa
Last active November 16, 2015 23:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kawa-kokosowa/3900761c601568f5ac1e to your computer and use it in GitHub Desktop.
Save kawa-kokosowa/3900761c601568f5ac1e to your computer and use it in GitHub Desktop.
Retreive __version__ from a package's __init__.py, without executing or using regular expressions.
"""Demo the ability to use Abstract Syntax Trees to
retrieve the value of __version__ from a package's
__init__.py, without executing __init__.py or using
regular expressions.
Works in Python 2 and Python 3.
See Also:
* https://greentreesnakes.readthedocs.org/en/latest/tofrom.html
* http://eli.thegreenplace.net/2009/11/28/python-internals-working-with-python-asts/
"""
import ast
class MyVisitor(ast.NodeVisitor):
"""This visitor traverses the nodes in an
__init__.py file to find the __version__.
This is useful particularly in setup cases
when you want to fetch __version__ from
the package __init__.py without executing it.
Example:
>>> with open('fakepkg/__init__.py') as source_file:
... tree = ast.parse(source_file.read())
>>> visitor = MyVisitor()
>>> visitor.visit(tree)
>>> visitor.version_found
'0.3.0'
Attributes:
version_found (str): If __version__ assignment
is found, the value will be reflected here.
"""
version_found = None
def visit_Assign(self, node):
"""This function is called when a node is
traversed which is an ast.Assign object.
The ast.Assign object represents a variable
assignment, in the form of a list of (variable)
names and respective values. This is because
you can set multiple variables in one assignment
in Python.
>>> a, b = (1, 2)
>>> z = "boo!"
For our case, we only check the first variable
name available (ala note.targets[0]) and if it
matches "__version__" we want the assignment's
value (i.e., node.value.s).
When the __version__ is found, its value is
copied to the self.version_found attribute.
Warning:
This presumes __version__ is set only
once, it does not check global-only.
This means if __version__ is set twice, the
last value will be used for version_found.
"""
if node.targets[0].id == '__version__':
self.version_found = node.value.s
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment