Hello @izzylys @gjedlicska,
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_type
argument:
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 __init_subclass__
in _RegisteringBase
that sets the speckle_type
and registers the type in the internal _type_registry
. The 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!