We are currently setting up Speckle kits to get our own Python classes to be recognized in Grasshopper, after exchanging them via Speckle. We start from Python, where we dynamically create Speckle classes based on the classes we already defined, during import. For example, we have a
Typology class, for that we dynamically create a
SpeckleTypology class, to which we copy the attributes of
Typology, and that inherits from the Speckle
Base class. Then, when sending to Speckle, we convert all
Typology instances to
SpeckleTypology instances, to send these to the Speckle server.
However, it doesn’t seem possible to dynamically create a Speckle class (using
pydantic.create_model()), with specification of the
speckle_class = pydantic.create_model(speckle_class_name, __base__=base, **fields, speckle_type=(ClassVar, speckle_type))
The issue is that the working of
pydantic.create_model() is sort of clashing with the use of
_RegisteringBase that sets the
speckle_type and registers the type in the internal
speckle_type keyword is namely taken as a field by
create_model and directly added to the attributes of the new class, and is not passed to the
__init_subclass__ method. In the end, this means that the
speckle_class_name will be used to set
speckle_type. The problem is thus that the
speckle_type cannot be set to match the exact type as defined in the C# kit,
Objects.Other.Typology in this case. A possible workaround is to provide this directly as class name, so the
speckle_type will match, but this isn’t very pretty. Another one is to first create the class, to then overrule the
speckle_type and adjust the
_type_registry, also not pretty.
I also tried to create the class using
type(). This did actually work, as it takes a dictionary with attributes, instead of collecting any keyword argument as in
pydantic.create_model(). This namely allows to specify the
speckle_type argument separately, which is then passed all the way to
__init_subclass__. It gives the desired result which you can see in the picture.
speckle_class = type(speckle_class_name, (base, ), fields, speckle_type=speckle_type)
However, apart from this, it is definitely preferable to use pydantic. Therefore I hope that you might have a better suggestion to fix this issue. Of course you can’t change pydantic, but maybe I’m overlooking something there. Another option would be a method in
_RegisteringBase to update the
speckle_type of a class, also updating the registry, though I can imagine this is not something you want to enable. Any advice is welcome!