Skip to content

Commit ecdecce

Browse files
cursoragentipetrov
andcommitted
Add Python.NET 3 compatibility shim for node-first static methods
Co-authored-by: ipetrov <[email protected]>
1 parent e8a86ed commit ecdecce

File tree

1 file changed

+44
-0
lines changed

1 file changed

+44
-0
lines changed

DSPythonNet3/DSPythonNet3Evaluator.cs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -794,6 +794,47 @@ private static bool IsMarkedToSkipConversion(PyObject pyObj)
794794
public override event EvaluationFinishedEventHandler EvaluationFinished;
795795

796796
private bool registeredUnwrapMarshaler;
797+
private const string ConnectionNodeCompatSentinel = "__dspynet3_connnode_compat__";
798+
799+
/// <summary>
800+
/// Compatibility shim for "node-first" static methods exposed by some Dynamo/Revit libraries.
801+
/// In older engines these could be invoked like instance methods (e.g. node.SubNodesOfSize(2)).
802+
/// Python.NET 3 binds static methods strictly, so we patch a small set of known APIs to keep
803+
/// existing graphs working.
804+
/// </summary>
805+
private static string ConnectionNodeCompatPatchCode()
806+
{
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.
809+
return $@"
810+
import builtins as __builtins__
811+
if not getattr(__builtins__, '{ConnectionNodeCompatSentinel}', False):
812+
try:
813+
from AdvanceSteel.ConnectionAutomation.Nodes import ConnectionNode as __ConnectionNode
814+
815+
def __bind_node_first_static(__name):
816+
try:
817+
__orig = getattr(__ConnectionNode, __name)
818+
except Exception:
819+
return
820+
821+
def __inst(self, *args, __orig=__orig, **kwargs):
822+
return __orig(self, *args, **kwargs)
823+
824+
try:
825+
setattr(__ConnectionNode, __name, __inst)
826+
except Exception:
827+
# Some runtimes may forbid setting attributes on CLR types.
828+
pass
829+
830+
__bind_node_first_static('SubNodesOfSize')
831+
__bind_node_first_static('ExistingConnections')
832+
833+
setattr(__builtins__, '{ConnectionNodeCompatSentinel}', True)
834+
except Exception:
835+
pass
836+
";
837+
}
797838

798839
/// <summary>
799840
/// Called immediately before evaluation starts
@@ -839,6 +880,9 @@ private void OnEvaluationBegin(PyModule scope,
839880

840881
registeredUnwrapMarshaler = true;
841882
}
883+
884+
// Apply compatibility shims (safe no-op if unavailable).
885+
scope.Exec(ConnectionNodeCompatPatchCode());
842886
}
843887

844888
/// <summary>

0 commit comments

Comments
 (0)