@@ -49,11 +49,10 @@ func pythonValueString(value interface{}) (string, error) {
4949 return pythonSetString (v )
5050 case * pythonArgumentsObject :
5151 return pythonArgumentsString (v )
52- case * types. GenericClass :
52+ case * genericClass :
5353 return fmt .Sprintf ("%s.%s" , v .Module , v .Name ), nil
54- case * types.GenericObject :
55- s , _ := pythonValueString (v .Class )
56- return fmt .Sprintf ("%s(?)" , s ), nil
54+ case * genericObject :
55+ return pythonGenericObjectString (v )
5756 default :
5857 return "" , fmt .Errorf ("unsupported Python value: %T" , value )
5958 }
@@ -181,6 +180,42 @@ func pythonArgumentsString(a *pythonArgumentsObject) (string, error) {
181180 }
182181 }
183182
183+ b .WriteByte (')' )
184+ return b .String (), nil
185+ }
186+
187+ func pythonGenericObjectString (o * genericObject ) (string , error ) {
188+ var b strings.Builder
189+ b .WriteString (o .class .Name )
190+ b .WriteByte ('(' )
191+
192+ for i , e := 0 , o .dict .List .Front (); e != nil ; i ++ {
193+ if i > 0 {
194+ b .WriteString (", " )
195+ }
196+ entry := e .Value .(* types.OrderedDictEntry )
197+
198+ var keyStr string
199+ if s , ok := entry .Key .(string ); ok {
200+ keyStr = s
201+ } else {
202+ var err error
203+ keyStr , err = pythonValueString (entry .Key )
204+ if err != nil {
205+ return "" , err
206+ }
207+ }
208+ b .WriteString (kwargStyle .Render (keyStr + "=" ))
209+
210+ valueStr , err := pythonValueString (entry .Value )
211+ if err != nil {
212+ return "" , err
213+ }
214+ b .WriteString (valueStr )
215+
216+ e = e .Next ()
217+ }
218+
184219 b .WriteByte (')' )
185220 return b .String (), nil
186221
@@ -191,8 +226,12 @@ func findPythonClass(module, name string) (interface{}, error) {
191226 if module == "dispatch.proto" && name == "Arguments" {
192227 return & pythonArgumentsClass {}, nil
193228 }
229+ // If a custom class is encountered, we don't have enough information
230+ // to be able to format it. In many cases though (e.g. dataclasses),
231+ // it's sufficient to collect and format the module/name of the class,
232+ // and then data that arrives through PyDictSettable interface.
194233 slog .Debug ("parsing Python value" , "module" , module , "name" , name )
195- return types .NewGenericClass ( module , name ) , nil
234+ return & genericClass { & types.GenericClass { Module : module , Name : name }} , nil
196235}
197236
198237type pythonArgumentsClass struct {}
@@ -224,3 +263,21 @@ func (a *pythonArgumentsObject) PyDictSet(key, value interface{}) error {
224263 }
225264 return nil
226265}
266+
267+ type genericClass struct {
268+ * types.GenericClass
269+ }
270+
271+ func (c * genericClass ) PyNew (args ... interface {}) (interface {}, error ) {
272+ return & genericObject {c , types .NewOrderedDict ()}, nil
273+ }
274+
275+ type genericObject struct {
276+ class * genericClass
277+ dict * types.OrderedDict
278+ }
279+
280+ func (o * genericObject ) PyDictSet (key , value interface {}) error {
281+ o .dict .Set (key , value )
282+ return nil
283+ }
0 commit comments