@@ -3,6 +3,7 @@ package cli
33import (
44 "bytes"
55 "fmt"
6+ "log/slog"
67 "strings"
78
89 "github.com/charmbracelet/lipgloss"
@@ -48,11 +49,10 @@ func pythonValueString(value interface{}) (string, error) {
4849 return pythonSetString (v )
4950 case * pythonArgumentsObject :
5051 return pythonArgumentsString (v )
51- case * types. GenericClass :
52+ case * genericClass :
5253 return fmt .Sprintf ("%s.%s" , v .Module , v .Name ), nil
53- case * types.GenericObject :
54- s , _ := pythonValueString (v .Class )
55- return fmt .Sprintf ("%s(?)" , s ), nil
54+ case * genericObject :
55+ return pythonGenericObjectString (v )
5656 default :
5757 return "" , fmt .Errorf ("unsupported Python value: %T" , value )
5858 }
@@ -180,6 +180,42 @@ func pythonArgumentsString(a *pythonArgumentsObject) (string, error) {
180180 }
181181 }
182182
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+
183219 b .WriteByte (')' )
184220 return b .String (), nil
185221
@@ -190,7 +226,12 @@ func findPythonClass(module, name string) (interface{}, error) {
190226 if module == "dispatch.proto" && name == "Arguments" {
191227 return & pythonArgumentsClass {}, nil
192228 }
193- return types .NewGenericClass (module , name ), nil
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.
233+ slog .Debug ("deserializing Python class" , "module" , module , "name" , name )
234+ return & genericClass {& types.GenericClass {Module : module , Name : name }}, nil
194235}
195236
196237type pythonArgumentsClass struct {}
@@ -222,3 +263,21 @@ func (a *pythonArgumentsObject) PyDictSet(key, value interface{}) error {
222263 }
223264 return nil
224265}
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