@@ -804,33 +804,61 @@ private static bool IsMarkedToSkipConversion(PyObject pyObj)
804804 /// </summary>
805805 private static string ConnectionNodeCompatPatchCode ( )
806806 {
807- // Keep this snippet extremely defensive: it should be a no-op if the library isn't present
808- // or if the runtime forbids monkey-patching reflected CLR types.
807+ // Keep this snippet extremely defensive: it should be a no-op if the library isn't present.
808+ // IMPORTANT: Many runtimes forbid setting attributes on CLR *types*. However, Python.NET
809+ // typically allows attaching attributes to CLR *instances* via the wrapper's __dict__.
810+ // So we patch instances coming in through IN (recursively for nested lists).
809811 return $@ "
810812import builtins as __builtins__
811- if not getattr(__builtins__, '{ ConnectionNodeCompatSentinel } ', False):
812- try:
813- from AdvanceSteel.ConnectionAutomation.Nodes import ConnectionNode as __ConnectionNode
814813
815- def __bind_node_first_static(__name):
814+ try:
815+ from AdvanceSteel.ConnectionAutomation.Nodes import ConnectionNode as __ConnectionNode
816+ except Exception:
817+ __ConnectionNode = None
818+
819+ if __ConnectionNode is not None:
820+ if not getattr(__builtins__, '{ ConnectionNodeCompatSentinel } ', False):
821+ def __dspynet3__patch_connnode_instance(__obj):
822+ # Attach instance-callable wrappers for node-first static methods.
816823 try:
817- __orig = getattr(__ConnectionNode, __name)
824+ if not isinstance(__obj, __ConnectionNode):
825+ return
826+
827+ # Only patch if missing or still the raw reflected method.
828+ def __subnodes(__n, __obj=__obj):
829+ return __ConnectionNode.SubNodesOfSize(__obj, __n)
830+
831+ def __existing(__obj=__obj):
832+ return __ConnectionNode.ExistingConnections(__obj)
833+
834+ try:
835+ setattr(__obj, 'SubNodesOfSize', __subnodes)
836+ except Exception:
837+ pass
838+ try:
839+ setattr(__obj, 'ExistingConnections', __existing)
840+ except Exception:
841+ pass
818842 except Exception:
819- return
820-
821- def __inst(self, *args, __orig=__orig, **kwargs):
822- return __orig(self, *args, **kwargs)
843+ pass
823844
845+ def __dspynet3__walk_and_patch(__x):
824846 try:
825- setattr(__ConnectionNode, __name, __inst)
847+ if isinstance(__x, (list, tuple)):
848+ for __i in __x:
849+ __dspynet3__walk_and_patch(__i)
850+ else:
851+ __dspynet3__patch_connnode_instance(__x)
826852 except Exception:
827- # Some runtimes may forbid setting attributes on CLR types.
828853 pass
829854
830- __bind_node_first_static('SubNodesOfSize')
831- __bind_node_first_static('ExistingConnections')
832-
855+ setattr(__builtins__, '__dspynet3__walk_and_patch_connnode', __dspynet3__walk_and_patch)
833856 setattr(__builtins__, '{ ConnectionNodeCompatSentinel } ', True)
857+
858+ # Patch current inputs for this evaluation (IN exists in the module scope).
859+ try:
860+ __inp = globals().get('IN', None)
861+ __builtins__.__dspynet3__walk_and_patch_connnode(__inp)
834862 except Exception:
835863 pass
836864" ;
0 commit comments