protocolbuffers / protocolbuffers/protobuf
python: pylint no-name-in-module
@anandolee is already working on this.
Since Dec 1, 2023.
- Dominant language
- C++
- Stars
- 72k
- Forks
- 16.3k
- Avg merge
- 1d 17h
- Merged PRs (30d)
- 140
Description
Since v3.20.0 generated protobuf files trigger pylint no-name-in-module when importing the message types.
Compiling foo.proto (see below) on two different protobuf versions obviously different results, however the old (3.19.x) can be pylinted successfully, but the new (3.20.x) result cannot be pylinted.
Compilation command: python3 -m grpc_tools.protoc -I . --python_out=. foo.proto
syntax = "proto3";
package foo;
// Foo service
service Foo {
// Say Foo
rpc SayFoo(SayFooRequest) returns (SayFooResponse) {}
}
// Say Foo Request
message SayFooRequest {}
// Say Foo Response
message SayFooResponse {}
libprotoc 3.19.4 output
$ python3 -m grpc_tools.protoc --version libprotoc 3.19.4
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: foo.proto
"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import message as _message
from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\tfoo.proto\x12\x03\x66oo\"\x0f\n\rSayFooRequest\"\x10\n\x0eSayFooResponse2:\n\x03\x46oo\x12\x33\n\x06SayFoo\x12\x12.foo.SayFooRequest\x1a\x13.foo.SayFooResponse\"\x00\x62\x06proto3')
_SAYFOOREQUEST = DESCRIPTOR.message_types_by_name['SayFooRequest']
_SAYFOORESPONSE = DESCRIPTOR.message_types_by_name['SayFooResponse']
SayFooRequest = _reflection.GeneratedProtocolMessageType('SayFooRequest', (_message.Message,), {
'DESCRIPTOR' : _SAYFOOREQUEST,
'__module__' : 'foo_pb2'
# @@protoc_insertion_point(class_scope:foo.SayFooRequest)
})
_sym_db.RegisterMessage(SayFooRequest)
SayFooResponse = _reflection.GeneratedProtocolMessageType('SayFooResponse', (_message.Message,), {
'DESCRIPTOR' : _SAYFOORESPONSE,
'__module__' : 'foo_pb2'
# @@protoc_insertion_point(class_scope:foo.SayFooResponse)
})
_sym_db.RegisterMessage(SayFooResponse)
_FOO = DESCRIPTOR.services_by_name['Foo']
if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None
_SAYFOOREQUEST._serialized_start=18
_SAYFOOREQUEST._serialized_end=33
_SAYFOORESPONSE._serialized_start=35
_SAYFOORESPONSE._serialized_end=51
_FOO._serialized_start=53
_FOO._serialized_end=111
# @@protoc_insertion_point(module_scope)
libprotoc 3.20.1 output
$ python3 -m grpc_tools.protoc --version libprotoc 3.20.1
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: foo.proto
"""Generated protocol buffer code."""
from google.protobuf.internal import builder as _builder
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import symbol_database as _symbol_database
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\tfoo.proto\x12\x03\x66oo\"\x0f\n\rSayFooRequest\"\x10\n\x0eSayFooResponse2:\n\x03\x46oo\x12\x33\n\x06SayFoo\x12\x12.foo.SayFooRequest\x1a\x13.foo.SayFooResponse\"\x00\x62\x06proto3')
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'foo_pb2', globals())
if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None
_SAYFOOREQUEST._serialized_start=18
_SAYFOOREQUEST._serialized_end=33
_SAYFOORESPONSE._serialized_start=35
_SAYFOORESPONSE._serialized_end=51
_FOO._serialized_start=53
_FOO._serialized_end=111
# @@protoc_insertion_point(module_scope)
Test file (test.py)
from foo_pb2 import SayFooRequest, SayFooResponse
Running pylint --disable=all --enable=no-name-in-module test.py
With 3.19.x generated code
-------------------------------------------------------------------- Your code has been rated at 10.00/10 (previous run: 0.00/10, +10.00)
With 3.20.x generated code
************* Module test test.py:1:0: E0611: No name 'SayFooRequest' in module 'foo_pb2' (no-name-in-module) test.py:1:0: E0611: No name 'SayFooResponse' in module 'foo_pb2' (no-name-in-module) ---------------------------------------------------------------------- Your code has been rated at -90.00/10 (previous run: -90.00/10, +0.00)
Clearly this is due to the abuse of globals() when using the builder to inject the descriptors into the module context.
However, this is dynamically generated code, why does it have to be so clever (c.f.: obfuscated) that industry standard tooling can't ensure that your code is integrating with the library code properly?
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.