Как protobuf генерирует этот метод и невозможно ли для него добиться автозаполнения?

Я просматривал базу кода (API мониторинга GCP SDK), пытаясь углубиться, чтобы ознакомиться с некоторыми методами, но здесь я уперся в стену: https://cloud.google.com/monitoring/custom-metrics/creating -metrics#monitoring_create_metric-python

Конкретно эта строчка descriptor = ga_metric.MetricDescriptor(). Как генерируется MetricDescriptor()?

Согласно комментариям в metric_pb2 (ga_metric — это его псевдоним), этот файл был создан protobuf. Однако в этом файле модуля я не вижу определения MetricDescriptor(). Как я могу вызвать ga_metric.MetricDescriptor()? Какая часть кода здесь генерирует метод MetricDescriptor(), который я могу вызвать?

# metric_pb2.py
"""Generated protocol buffer code."""
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
from google.protobuf.internal import builder as _builder

# @@protoc_insertion_point(imports)

_sym_db = _symbol_database.Default()


from google.api import label_pb2 as google_dot_api_dot_label__pb2
from google.api import launch_stage_pb2 as google_dot_api_dot_launch__stage__pb2
from google.protobuf import duration_pb2 as google_dot_protobuf_dot_duration__pb2


DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(
    b'\n\x17google/api/metric.proto\x12\ngoogle.api\x1a\x16google/api/label.proto\x1a\x1dgoogle/api/launch_stage.proto\x1a\x1egoogle/protobuf/duration.proto"\x9f\x06\n\x10MetricDescriptor\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0c\n\x04type\x18\x08 \x01(\t\x12+\n\x06labels\x18\x02 \x03(\x0b\x32\x1b.google.api.LabelDescriptor\x12<\n\x0bmetric_kind\x18\x03 \x01(\x0e\x32\'.google.api.MetricDescriptor.MetricKind\x12:\n\nvalue_type\x18\x04 \x01(\x0e\x32&.google.api.MetricDescriptor.ValueType\x12\x0c\n\x04unit\x18\x05 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x06 \x01(\t\x12\x14\n\x0c\x64isplay_name\x18\x07 \x01(\t\x12G\n\x08metadata\x18\n \x01(\x0b\x32\x35.google.api.MetricDescriptor.MetricDescriptorMetadata\x12-\n\x0claunch_stage\x18\x0c \x01(\x0e\x32\x17.google.api.LaunchStage\x12 \n\x18monitored_resource_types\x18\r \x03(\t\x1a\xb0\x01\n\x18MetricDescriptorMetadata\x12\x31\n\x0claunch_stage\x18\x01 \x01(\x0e\x32\x17.google.api.LaunchStageB\x02\x18\x01\x12\x30\n\rsample_period\x18\x02 \x01(\x0b\x32\x19.google.protobuf.Duration\x12/\n\x0cingest_delay\x18\x03 \x01(\x0b\x32\x19.google.protobuf.Duration"O\n\nMetricKind\x12\x1b\n\x17METRIC_KIND_UNSPECIFIED\x10\x00\x12\t\n\x05GAUGE\x10\x01\x12\t\n\x05\x44\x45LTA\x10\x02\x12\x0e\n\nCUMULATIVE\x10\x03"q\n\tValueType\x12\x1a\n\x16VALUE_TYPE_UNSPECIFIED\x10\x00\x12\x08\n\x04\x42OOL\x10\x01\x12\t\n\x05INT64\x10\x02\x12\n\n\x06\x44OUBLE\x10\x03\x12\n\n\x06STRING\x10\x04\x12\x10\n\x0c\x44ISTRIBUTION\x10\x05\x12\t\n\x05MONEY\x10\x06"u\n\x06Metric\x12\x0c\n\x04type\x18\x03 \x01(\t\x12.\n\x06labels\x18\x02 \x03(\x0b\x32\x1e.google.api.Metric.LabelsEntry\x1a-\n\x0bLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x42_\n\x0e\x63om.google.apiB\x0bMetricProtoP\x01Z7google.golang.org/genproto/googleapis/api/metric;metric\xa2\x02\x04GAPIb\x06proto3'
)

_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "google.api.metric_pb2", _globals)
if _descriptor._USE_C_DESCRIPTORS == False:
    DESCRIPTOR._options = None
    DESCRIPTOR._serialized_options = b"\n\016com.google.apiB\013MetricProtoP\001Z7google.golang.org/genproto/googleapis/api/metric;metric\242\002\004GAPI"
    _METRICDESCRIPTOR_METRICDESCRIPTORMETADATA.fields_by_name[
        "launch_stage"
    ]._options = None
    _METRICDESCRIPTOR_METRICDESCRIPTORMETADATA.fields_by_name[
        "launch_stage"
    ]._serialized_options = b"\030\001"
    _METRIC_LABELSENTRY._options = None
    _METRIC_LABELSENTRY._serialized_options = b"8\001"
    _globals["_METRICDESCRIPTOR"]._serialized_start = 127
    _globals["_METRICDESCRIPTOR"]._serialized_end = 926
    _globals["_METRICDESCRIPTOR_METRICDESCRIPTORMETADATA"]._serialized_start = 554
    _globals["_METRICDESCRIPTOR_METRICDESCRIPTORMETADATA"]._serialized_end = 730
    _globals["_METRICDESCRIPTOR_METRICKIND"]._serialized_start = 732
    _globals["_METRICDESCRIPTOR_METRICKIND"]._serialized_end = 811
    _globals["_METRICDESCRIPTOR_VALUETYPE"]._serialized_start = 813
    _globals["_METRICDESCRIPTOR_VALUETYPE"]._serialized_end = 926
    _globals["_METRIC"]._serialized_start = 928
    _globals["_METRIC"]._serialized_end = 1045
    _globals["_METRIC_LABELSENTRY"]._serialized_start = 1000
    _globals["_METRIC_LABELSENTRY"]._serialized_end = 1045
# @@protoc_insertion_point(module_scope)

Согласно DazWilkin, мне удалось найти все пакеты с файлами прототипов и сгенерировать для них файлы pyi. Это работает достаточно хорошо. pylance их находит (а pylint нет?). Кроме того, в protoc есть какая-то серьезная ошибка, и мне пришлось запустить ее grpc_tools, чтобы она заработала.

packages_paths = site.getsitepackages()[0]
proto_folders: list[str] = []
for name in glob.glob(f"{packages_paths}/**/*.proto", recursive=True):
    proto_folder = os.path.dirname(name)
    proto_folders.append(proto_folder)
proto_folders = list(set(proto_folders))
    
for proto_folder in proto_folders:
    os.chdir(proto_folder)

    # If we wildcard and there is a single failure the rest are skipped
    # So just loop over each file and run protoc for each one
    for proto_file in glob.glob(f"{proto_folder}/*.proto", recursive=True):
        file_name = os.path.basename(proto_file)
        cmd = f"python -m grpc_tools.protoc --proto_path=. --pyi_out=. {file_name}"
        < RUN CMD >
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
0
60
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Посмотрите эти три строки:

_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "google.api.metric_pb2", _globals)

globals() возвращает dict, реализующий пространство имен текущего модуля, поэтому в области модуля следующие действия эквивалентны:

foo = "asdf"
# equivalent:
globals()["foo"] = "asdf"

Передавая возвращаемое значение globals() двум функциям _builder.Build..., код позволяет сборщику добавлять имена в текущий модуль. Вот как функции builder.Build... могут определять такие имена, как MetricDescriptor.

Заставить автозаполнение работать, несмотря на все махинации, — непростая задача. При работе с protobufs мне нравится просматривать файл .proto, из которого сгенерирован файл _pb2.py (вероятно, metric.proto будет генерировать metric_pb2.py), а также Google Руководство по сгенерированному коду Python.

Особенность кода Python, сгенерированного компилятором буфера протокола (protoc), заключается в том, что он создает метаклассы, что затрудняет расшифровку получаемых классов и их методов, но, в ответ @byvire, вы можете вывести типы Python (классы|методы) из источник protobuf MetricDescriptor или вы можете использовать protoc --pyi_out для получения интерфейсов Python

DazWilkin 28.06.2024 00:29

У меня возникли проблемы с поиском примеров того, как я мог бы запустить protoc --pyi_out с помощью API Google. Что поставить во входные файлы? Мне нужно копаться в пакетах сайта или что-то в этом роде?

red888 10.07.2024 22:15

Но я все еще в замешательстве: почему бы Google не просто сгенерировать файлы pyi и не включить их в ootb вместе с кодом, сгенерированным protobuf? Являюсь ли я родным с этим ожиданием?

red888 10.07.2024 23:47

Другие вопросы по теме