@@ -799,6 +799,61 @@ private static bool IsMarkedToSkipConversion(PyObject pyObj)
799799 public override event EvaluationFinishedEventHandler EvaluationFinished ;
800800
801801 private bool registeredUnwrapMarshaler ;
802+ private const string ConnectionNodeCompatSentinel = "__dspynet3_connnode_compat__" ;
803+
804+ /// <summary>
805+ /// Compatibility shim for "node-first" static methods exposed by some Dynamo/Revit libraries.
806+ /// In older engines these could be invoked like instance methods (e.g. node.SubNodesOfSize(2)).
807+ /// Python.NET 3 binds static methods strictly, so we patch a small set of known APIs to keep
808+ /// existing graphs working.
809+ /// </summary>
810+ private static string ConnectionNodeCompatPatchCode ( )
811+ {
812+ return $@ "
813+ import builtins as __builtins__
814+ try:
815+ from AdvanceSteel.ConnectionAutomation.Nodes import ConnectionNode as __ConnectionNode
816+ except Exception:
817+ __ConnectionNode = None
818+ if __ConnectionNode is not None:
819+ if not getattr(__builtins__, '{ ConnectionNodeCompatSentinel } ', False):
820+ def __dspynet3__patch_connnode_instance(__obj):
821+ # Attach instance-callable wrappers for node-first static methods.
822+ try:
823+ if not isinstance(__obj, __ConnectionNode):
824+ return
825+ def __subnodes(__n, *args, __obj=__obj, **kwargs):
826+ return __ConnectionNode.SubNodesOfSize(__obj, __n, *args, **kwargs)
827+ def __existing(*args, __obj=__obj, **kwargs):
828+ return __ConnectionNode.ExistingConnections(__obj, *args, **kwargs)
829+ try:
830+ setattr(__obj, 'SubNodesOfSize', __subnodes)
831+ except Exception:
832+ pass
833+ try:
834+ setattr(__obj, 'ExistingConnections', __existing)
835+ except Exception:
836+ pass
837+ except Exception:
838+ pass
839+ def __dspynet3__walk_and_patch(__x):
840+ try:
841+ if isinstance(__x, (list, tuple)):
842+ for __i in __x:
843+ __dspynet3__walk_and_patch(__i)
844+ else:
845+ __dspynet3__patch_connnode_instance(__x)
846+ except Exception:
847+ pass
848+ setattr(__builtins__, '__dspynet3__walk_and_patch_connnode', __dspynet3__walk_and_patch)
849+ setattr(__builtins__, '{ ConnectionNodeCompatSentinel } ', True)
850+ try:
851+ __inp = globals().get('IN', None)
852+ __builtins__.__dspynet3__walk_and_patch_connnode(__inp)
853+ except Exception:
854+ pass
855+ " ;
856+ }
802857
803858 /// <summary>
804859 /// Called immediately before evaluation starts
@@ -844,6 +899,8 @@ private void OnEvaluationBegin(PyModule scope,
844899
845900 registeredUnwrapMarshaler = true ;
846901 }
902+
903+ scope . Exec ( ConnectionNodeCompatPatchCode ( ) ) ;
847904 }
848905
849906 /// <summary>
0 commit comments