def get_module_attributes(path):
names = {}<EOL>attributes = OrderedDict()<EOL>python2_names = {"<STR_LIT:True>": True, "<STR_LIT:False>": False, "<STR_LIT:None>": None}<EOL>def get_values(source, dest, extra=None):<EOL><INDENT>"""<STR_LIT>"""<EOL>def get_value(value):<EOL><INDENT>"""<STR_LIT>"""<EOL>class_name = value.__class__.__name__<EOL>value_type = AST_LITERAL_TYPES.get(class_name)<EOL>if value_type:<EOL><INDENT>attr_value = getattr(value, value_type)<EOL><DEDENT>else:<EOL><INDENT>if class_name == "<STR_LIT>":<EOL><INDENT>attr_value = dict(<EOL>zip(<EOL>list(map(get_value, value.keys)),<EOL>list(map(get_value, value.values)),<EOL>)<EOL>)<EOL><DEDENT>elif class_name == "<STR_LIT>":<EOL><INDENT>attr_value = list(map(get_value, value.elts))<EOL><DEDENT>elif class_name == "<STR_LIT:Name>":<EOL><INDENT>default = python2_names.get(value.id)<EOL>attr_value = extra.get(value.id, default)<EOL><DEDENT>elif class_name == "<STR_LIT>":<EOL><INDENT>attr_value = tuple(map(get_value, value.elts))<EOL><DEDENT>elif class_name == "<STR_LIT>":<EOL><INDENT>op = value.op.__class__.__name__<EOL>attr_value = get_value(value.operand)<EOL>if op == "<STR_LIT>":<EOL><INDENT>attr_value = -attr_value<EOL><DEDENT>else:<EOL><INDENT>attr_value = "<STR_LIT>" % (class_name, op)<EOL><DEDENT><DEDENT>elif class_name == "<STR_LIT>":<EOL><INDENT>left = get_value(value.left)<EOL>right = get_value(value.right)<EOL>op = value.op.__class__.__name__<EOL>try:<EOL><INDENT>if op == "<STR_LIT>":<EOL><INDENT>attr_value = left + right<EOL><DEDENT>elif op == "<STR_LIT>":<EOL><INDENT>attr_value = left * right<EOL><DEDENT>else:<EOL><INDENT>attr_value = "<STR_LIT>" % (class_name, op)<EOL><DEDENT><DEDENT>except Exception:<EOL><INDENT>attr_value = "<STR_LIT>" % class_name<EOL><DEDENT><DEDENT>else:<EOL><INDENT>attr_value = "<STR_LIT>" % class_name<EOL><DEDENT><DEDENT>return attr_value<EOL><DEDENT>if extra is None:<EOL><INDENT>extra = {}<EOL><DEDENT>for line in source:<EOL><INDENT>if isinstance(line, ast.Assign):<EOL><INDENT>if len(line.targets) == <NUM_LIT:1> and isinstance(line.targets[<NUM_LIT:0>], ast.Name):<EOL><INDENT>attr = line.targets[<NUM_LIT:0>].id<EOL>value = line.value<EOL>dest[attr] = get_value(value)<EOL><DEDENT><DEDENT><DEDENT><DEDENT>with open(path) as f:<EOL><INDENT>tree = ast.parse(f.read(), "<STR_LIT>")<EOL>get_values(tree.body, names)<EOL>for statement in tree.body:<EOL><INDENT>if isinstance(statement, ast.ClassDef) and statement.name == "<STR_LIT>":<EOL><INDENT>get_values(statement.body, attributes, names)<EOL><DEDENT><DEDENT><DEDENT>return attributes<EOL>
Get the attributes from the module from the ast.  We use ast because this
way we can examine modules even if we do not have their required python
modules installed.