I am using protorpc with endpoints-proto-datastore.
I want to build a custom message from a provided structure.
For example, it is the following list of key: ['id1', 'id2', 'id3']
Each key is assigned to a MessageField
named CustomField
.
I would like to herited from Message
and a class containing all key
.
def create_custom_container(key_list):
class cls():
pass
for i, k in enumerate(key_list):
setattr(cls, k, MessageField(CustomField, i))
return cls
class CustomMessage(Message, create_custom_container(key_list)):
pass
But it doesn't work, I got:
MessageDefinitionError: Message types may only inherit from Message
I saw from the protorpc source code that Message
use metaclasses to prevent it to be inherited or have attribut to be modified on the fly.
So, I have no idea how to create my custom message on the fly.
The library goes a long way defining constraints for the Message class - hacking it to force new attributes would probably result in a Message that would not work as expected at all.
Fortunatelly, instead of hardcoding the class body with a class CustomMessage
statement, create your custom class with a call - that allows you to programatically define the contents. That way you don't need to use more than one class on your inheritance tree.
All you have to do is to call Message
's metaclass with the appropriate parameters, instead of the usual call to type
, and pass as the class namespace -
so you can rewrite your body-creating function to:
def create_custom_body(key_list):
dct = {}
for i, k in enumerate(key_list):
dct[k] = MessageField(CustomField, i)
return dct
CustomClass = Message.__class__("CustomClass", (Message,), create_custom_body(key_list))
This will work in this case. If the library's metaclass would use a custom namespace (i.e. it would have a __prepare__
method), though, you'd need to modify this to use types.new_class
and an appropriate callback:
from types import new_class
def create_custom_body(dct, key_list):
for i, k in enumerate(key_list):
dct[k] = MessageField(CustomField, i)
return dct
CustomClass = types.new_class(
"CustomClass", (Message,),
exec_body=(lambda namespace: create_custom_body(namespace, key_list))
)
(check the docs at: https://docs.python.org/3/library/types.html)