nelfin / pylint-protobuf

A plugin for making Pylint aware of the fields of protobuf-generated classes
MIT License
29 stars 12 forks source link

Support Outer Scope Enum #11

Closed TimKingNF closed 5 years ago

TimKingNF commented 5 years ago

It's seem likes not support outer scope Enum. In addressbook.proto, I add something like this.

message Person {
 ...
  optional PhoneNumber phone = 5;
}
...
enum Gender {
  MALE = 0;
  FEMALE = 1;
}

And I try to exec pylint <follow_file>

from addressbook_pb2 import Person, Gender
# from addressbook_pb2 import Person, Gender, MALE  # raise
# from addressbook_pb2 import *  # raise Exception

man = Person()
print(man.phone.number)
# print(Gender)  # raise
# print(Gender.MALE)  # raise
# print(MALE)  # raise
# print(Gender.Value("MALE"))  # raise

Finally I try to modifies __init__.py like this. Const Value import is ok. But Enum import raise error.

def _extract_fields(node, module_globals, inner_fields, qualname):
  ...
  call = node.parent.value

    # import Enum Item
    if isinstance(call, astroid.Const):
        return {node.name: TypeClass(call.pytype())}

    # import Enum
    elif isinstance(call, astroid.Call) and call.func.attrname == "EnumTypeWrapper":
        # TODO: how to collect Enum values
        pass

    # import Message
    elif isinstance(call, astroid.Call) and call.func.attrname == "GeneratedProtocolMessageType":
        type_dict = call.args[2]
        if isinstance(type_dict, astroid.Call):
            for kw in type_dict.keywords:
                if kw.arg == 'DESCRIPTOR':
                    var = kw.value
                    return parse_name(var)
        elif isinstance(type_dict, astroid.Dict):
            for key, var in type_dict.items:
                if getattr(key, 'value', None) == 'DESCRIPTOR':
                    return parse_name(var)
    return None

Look Todo, I don't know how to write the following code.

Do you have any good ideas? Thanks very much.

nelfin commented 5 years ago

Hey @TimKingNF, thanks for taking a stab at it already. I'll write some tests based off your examples and then we can work through fixing them.

nelfin commented 5 years ago

The latest changes should fix all the cases you referenced except for *-import and building an enum from an invalid name like Enum.Value("DOES_NOT_EXIST"), which raises ValueError at runtime. I might leave the second case for now, but I'll fix the * import before pushing a new release.

TimKingNF commented 5 years ago

Thanks for your commits. This answers my questions.