| 31 | |
| 32 | |
| 33 | def lint_enum(python_file): |
| 34 | # type: (str) -> Iterator[str] |
| 35 | |
| 36 | with open(python_file) as fp: |
| 37 | root = ast.parse(fp.read(), python_file) |
| 38 | |
| 39 | unsealed_enums = OrderedDict() # type: OrderedDict[str, str] |
| 40 | for top_level_node in ast.iter_child_nodes(root): |
| 41 | if ( |
| 42 | unsealed_enums |
| 43 | and isinstance(top_level_node, ast.Expr) |
| 44 | and isinstance(top_level_node.value, ast.Call) |
| 45 | and isinstance(top_level_node.value.func, ast.Attribute) |
| 46 | and isinstance(top_level_node.value.func.value, ast.Name) |
| 47 | and top_level_node.value.func.value.id in unsealed_enums |
| 48 | and "seal" == top_level_node.value.func.attr |
| 49 | ): |
| 50 | unsealed_enums.pop(top_level_node.value.func.value.id) |
| 51 | logger.debug( |
| 52 | "Linted Enum {name} in {file} successfully.".format( |
| 53 | name=colors.green(top_level_node.value.func.value.id), |
| 54 | file=colors.cyan(python_file), |
| 55 | ) |
| 56 | ) |
| 57 | continue |
| 58 | |
| 59 | if not isinstance(top_level_node, ast.ClassDef): |
| 60 | continue |
| 61 | |
| 62 | if any(isinstance(base, ast.Name) and "Enum" == base.id for base in top_level_node.bases): |
| 63 | yield ( |
| 64 | "line {line} col {col}: class {name} subclasses Enum but does not parametrize the " |
| 65 | "Enum.Value type.".format( |
| 66 | line=top_level_node.lineno, |
| 67 | col=top_level_node.col_offset, |
| 68 | name=top_level_node.name, |
| 69 | ) |
| 70 | ) |
| 71 | else: |
| 72 | enum_bases = [ |
| 73 | base |
| 74 | for base in top_level_node.bases |
| 75 | if isinstance(base, ast.Subscript) |
| 76 | and isinstance(base.value, ast.Name) |
| 77 | and "Enum" == base.value.id |
| 78 | ] |
| 79 | if not enum_bases: |
| 80 | continue |
| 81 | if len(enum_bases) > 1: |
| 82 | yield ( |
| 83 | "line {line} col {col}: class {name} subclasses Enum multiple times but only " |
| 84 | "one Enum base is allowed.".format( |
| 85 | line=top_level_node.lineno, |
| 86 | col=top_level_node.col_offset, |
| 87 | name=top_level_node.name, |
| 88 | ) |
| 89 | ) |
| 90 | enum_base = enum_bases[0] |