Messages Protobuf

Version 14.0.0 de la bibliothèque cliente Python introduit un nouveau paramètre de configuration obligatoire appelé use_proto_plus, qui spécifie si vous souhaitez que la bibliothèque messages proto-plus ou messages protobuf. Pour en savoir plus sur comment définir ce paramètre, consultez la documentation sur la configuration.

Cette section décrit les implications sur les performances du choix des types les messages à utiliser. C'est pourquoi nous vous recommandons de lire et de comprendre les options afin de prendre une décision éclairée. Toutefois, si vous souhaitez passer à la version 14.0.0 sans modifier le code, vous pouvez définir use_proto_plus à True pour éviter d'endommager les modifications de l'interface.

Messages proto-plus et messages protobuf

Dans la version 10.0.0, la bibliothèque cliente Python a migré vers un nouveau générateur de code qui intégrait proto-plus comme moyen d'améliorer l'ergonomie de l'interface de message des tampons de protocole en les rendant plus comme les objets Python natifs. La contrepartie de cette amélioration est que proto-plus entraîne une surcharge des performances.

Performances protoplus

L'un des principaux avantages de proto-plus est qu'il convertit les protobufs messages et les types connus pour des types Python natifs via un processus appelé type le marshaling.

Le marshaling se produit lorsqu'un champ est consulté sur une instance de message proto-plus, en particulier lorsqu'un champ est lu ou défini, par exemple dans un tampon de protocole définition:

syntax = "proto3";

message Dog {
  string name = 1;
}

Lorsque cette définition est convertie en une classe proto-plus, elle a l'air comme ceci:

import proto

class Dog(proto.Message):
    name = proto.Field(proto.STRING, number=1)

Vous pouvez ensuite initialiser la classe Dog et accéder à son champ name comme vous le feriez tout autre objet Python:

dog = Dog()
dog.name = "Scruffy"
print(dog.name)

Lors de la lecture et de la définition du champ name, la valeur est convertie à partir d'une valeur native Python str en type string afin que que la valeur est compatible avec l'environnement d'exécution du tampon de protocole.

Dans l'analyse que nous avons menée depuis la sortie de la version 10.0.0, nous avons : nous avons déterminé que le temps passé à effectuer ces types de conversions sur les performances. Il est donc important de donner aux utilisateurs la possibilité d'utiliser les tampons de protocole messages.

Cas d'utilisation des messages proto-plus et protobuf

Cas d'utilisation des messages proto-plus
Proto-plus offre un certain nombre d'améliorations ergonomiques par rapport aux messages protobuf, Elles sont donc idéales pour écrire du code facile à gérer et lisible. Puisqu'ils exposent des objets Python natifs, ils sont plus faciles à utiliser et à comprendre.
Cas d'utilisation des messages Protobuf
Utilisez les tampons de protocole pour les cas d'utilisation sensibles aux performances, en particulier dans les applications qui doivent traiter rapidement des rapports volumineux ou qui créent des demandes mutate avec une variable un grand nombre d'opérations, par exemple BatchJobService ou OfflineUserDataJobService

Modification dynamique des types de messages

Après avoir sélectionné le type de message approprié pour votre application, que vous devez utiliser l'autre type pour un workflow spécifique. Dans ce cas, il s'agit passer facilement d'un type à l'autre de manière dynamique à l'aide des utilitaires proposés par le bibliothèque cliente. Utiliser la même classe de message Dog que ci-dessus:

from google.ads.googleads import util

# Proto-plus message type
dog = Dog()

# Protobuf message type
dog = util.convert_proto_plus_to_protobuf(dog)

# Back to proto-plus message type
dog = util.convert_protobuf_to_proto_plus(dog)

Différences entre l'interface des messages Protobuf

L'interface proto-plus est documentée dans détails, mais nous allons ici souligner Principales différences qui affectent les cas d'utilisation courants du client Google Ads bibliothèque.

Sérialisation des octets

Messages proto-plus
serialized = type(campaign).serialize(campaign)
deserialized = type(campaign).deserialize(serialized)
Messages Protobuf
serialized = campaign.SerializeToString()
deserialized = campaign.FromString(serialized)

Sérialisation JSON

Messages proto-plus
serialized = type(campaign).to_json(campaign)
deserialized = type(campaign).from_json(serialized)
Messages Protobuf
from google.protobuf.json_format import MessageToJson, Parse

serialized = MessageToJson(campaign)
deserialized = Parse(serialized, campaign)

Masques de champ

La méthode d'assistance de masque de champ fournie par api-core est conçu pour utiliser des tampons de protocole aux instances de message. Ainsi, lorsque vous utilisez des messages proto-plus, convertissez-les en protobuf pour utiliser l'application auxiliaire:

Messages proto-plus
from google.api_core.protobuf_helpers import field_mask

campaign = client.get_type("Campaign")
protobuf_campaign = util.convert_proto_plus_to_protobuf(campaign)
mask = field_mask(None, protobuf_campaign)
Messages Protobuf
from google.api_core.protobuf_helpers import field_mask

campaign = client.get_type("Campaign")
mask = field_mask(None, campaign)

Enums

Les énumérations exposées par les messages proto-plus sont des instances de l'environnement natif Python enum et donc héritent d'un certain nombre de méthodes pratiques.

Récupération du type d'énumération

Lorsque vous utilisez la méthode GoogleAdsClient.get_type pour récupérer des énumérations, les messages qui sont renvoyés sont légèrement différents selon que vous utilisez les messages proto-plus ou protobuf. Exemple :

Messages proto-plus
val = client.get_type("CampaignStatusEnum").CampaignStatus.PAUSED
Messages Protobuf
val = client.get_type("CampaignStatusEnum").PAUSED

Pour simplifier la récupération des énumérations, il existe un attribut de commodité sur GoogleAdsClient instances disposant d'une interface cohérente, quelles que soient que vous utilisez:

val = client.enums.CampaignStatusEnum.PAUSED

Récupération des valeurs d'énumération

Il est parfois utile de connaître la valeur ou l'ID de champ d'une énumération donnée, pour Par exemple, PAUSED sur CampaignStatusEnum correspond à 3:

Messages proto-plus
campaign = client.get_type("Campaign")
campaign.status = client.enums.CampaignStatusEnum.PAUSED
# To read the value of campaign status
print(campaign.status.value)
Messages Protobuf
campaign = client.get_type("Campaign")
status_enum = client.enums.CampaignStatusEnum
campaign.status = status_enum.PAUSED
# To read the value of campaign status
print(status_enum.CampaignStatus.Value(campaign.status))

Récupération des noms d'énumérations

Il est parfois utile de connaître le nom d'un champ d'énumération. Par exemple, lorsque les objets de lecture de l'API, vous pouvez connaître l'état de la campagne La fonction int 3 correspond à:

Messages proto-plus
campaign = client.get_type("Campaign")
campaign.status = client.enums.CampaignStatusEnum.PAUSED
# To read the name of campaign status
print(campaign.status.name)
Messages Protobuf
campaign = client.get_type("Campaign")
status_enum = client.enums.CampaignStatusEnum
# Sets the campaign status to the int value for PAUSED
campaign.status = status_enum.PAUSED
# To read the name of campaign status
status_enum.CampaignStatus.Name(campaign.status)

Champs répétés

Comme décrit dans le document proto-plus d'assistance, Les champs répétés sont généralement équivalents aux listes typées, ce qui signifie qu'ils se comportent presque de la même manière qu'une list.

Ajout à des champs scalaires répétés

Lorsque vous ajoutez des valeurs à des valeurs scalaires répétées type (par exemple, string ou int64, l'interface est la même, quel que soit le message type:

Messages proto-plus
ad.final_urls.append("https://www.example.com")
Messages Protobuf
ad.final_urls.append("https://www.example.com")

Cela inclut également toutes les autres méthodes list courantes, par exemple extend:

Messages proto-plus
ad.final_urls.extend(["https://www.example.com", "https://www.example.com/2"])
Messages Protobuf
ad.final_urls.extend(["https://www.example.com", "https://www.example.com/2"])

Ajouter des types de messages à des champs répétés

Si le champ répété n'est pas de type scalaire type, le comportement appliqué lors de leur ajout avec les champs répétés est légèrement différente:

Messages proto-plus
frequency_cap = client.get_type("FrequencyCapEntry")
frequency_cap.cap = 100
campaign.frequency_caps.append(frequency_cap)
Messages Protobuf
# The add method initializes a message and adds it to the repeated field
frequency_cap = campaign.frequency_caps.add()
frequency_cap.cap = 100

Attribuer des champs répétés

Pour les champs répétés scalaires et non scalaires, vous pouvez attribuer des listes au de différentes manières:

Messages proto-plus
# In proto-plus it's possible to use assignment.
urls = ["https://www.example.com"]
ad.final_urls = urls
Messages Protobuf
# Protobuf messages do not allow assignment, but you can replace the
# existing list using slice syntax.
urls = ["https://www.example.com"]
ad.final_urls[:] = urls

Messages vides

Il est parfois utile de savoir si une instance de message contient ou si l'un de ses champs est défini.

Messages proto-plus
# When using proto-plus messages you can simply check the message for
# truthiness.
is_empty = bool(campaign)
is_empty = not campaign
Messages Protobuf
is_empty = campaign.ByteSize() == 0

Copie du message

Pour les messages proto-plus et protobuf, nous vous recommandons d'utiliser copy_from sur la GoogleAdsClient:

client.copy_from(campaign, other_campaign)

Champs du message vides

Le processus pour définir des champs de message vides est le même, quelle que soit la que vous utilisez. Il vous suffit de copier un message vide dans le champ en question. Consultez les sections Texte du message et Message vide Champs. Voici un exemple de la façon dont pour définir un champ de message vide:

client.copy_from(campaign.manual_cpm, client.get_type("ManualCpm"))

Noms de champs contenant des mots réservés

Lors de l'utilisation de messages proto-plus, les noms de champs apparaissent automatiquement avec une un trait de soulignement à la fin si le nom est également un mot réservé en Python. Voici un exemple d'utilisation d'une instance Asset:

asset = client.get_type("Asset")
asset.type_ = client.enums.AssetTypeEnum.IMAGE

La liste complète des noms est construite dans la gapique generator. Il peut s'agir également de manière programmatique.

Commencez par installer le module:

python -m pip install gapic-generator

Ensuite, dans un REPL ou un script Python:

import gapic.utils
print(gapic.utils.reserved_names.RESERVED_NAMES)

Présence sur le terrain

Comme les champs des instances de message protobuf ont des valeurs par défaut, il n'est pas toujours intuitive de savoir si un champ a été défini ou non.

Messages proto-plus
# Use the "in" operator.
has_field = "name" in campaign
Messages Protobuf
campaign = client.get_type("Campaign")
# Determines whether "name" is set and not just an empty string.
campaign.HasField("name")

Protobuf Message comporte une méthode HasField qui détermine si le champ d'une a été défini, même s'il a été défini sur une valeur par défaut.

Méthodes de message Protobuf

L'interface de message protobuf comprend quelques méthodes pratiques qui ne sont pas de l'interface proto-plus ; Toutefois, il est facile d'y accéder convertir un message proto-plus en son équivalent protobuf:

# Accessing the ListFields method
protobuf_campaign = util.convert_protobuf_to_proto_plus(campaign)
print(campaign.ListFields())

# Accessing the Clear method
protobuf_campaign = util.convert_protobuf_to_proto_plus(campaign)
print(campaign.Clear())

Outil de suivi des problèmes

Si vous avez des questions sur ces modifications ou si vous rencontrez des problèmes lors de la migration vers version 14.0.0 de la bibliothèque, envoyez une problème sur notre coach électronique.