Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions DSPythonNet3/DSPythonNet3Evaluator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
internal class DynamoCPythonHandleComparer : IEqualityComparer<DynamoCPythonHandle>
{

public bool Equals(DynamoCPythonHandle x, DynamoCPythonHandle y)

Check warning on line 23 in DSPythonNet3/DSPythonNet3Evaluator.cs

View workflow job for this annotation

GitHub Actions / Build and Test

Nullability of reference types in type of parameter 'y' of 'bool DynamoCPythonHandleComparer.Equals(DynamoCPythonHandle x, DynamoCPythonHandle y)' doesn't match implicitly implemented member 'bool IEqualityComparer<DynamoCPythonHandle>.Equals(DynamoCPythonHandle? x, DynamoCPythonHandle? y)' (possibly because of nullability attributes).

Check warning on line 23 in DSPythonNet3/DSPythonNet3Evaluator.cs

View workflow job for this annotation

GitHub Actions / Build and Test

Nullability of reference types in type of parameter 'x' of 'bool DynamoCPythonHandleComparer.Equals(DynamoCPythonHandle x, DynamoCPythonHandle y)' doesn't match implicitly implemented member 'bool IEqualityComparer<DynamoCPythonHandle>.Equals(DynamoCPythonHandle? x, DynamoCPythonHandle? y)' (possibly because of nullability attributes).
{
return x.PythonObjectID.Equals(y.PythonObjectID);
}
Expand Down Expand Up @@ -74,7 +74,7 @@
try
{
var pyobj = DSPythonNet3Evaluator.globalScope.Get(PythonObjectID.ToString());
return pyobj.ToString();

Check warning on line 77 in DSPythonNet3/DSPythonNet3Evaluator.cs

View workflow job for this annotation

GitHub Actions / Build and Test

Possible null reference return.
}
catch (Exception e)
{
Expand Down Expand Up @@ -143,8 +143,8 @@
{ // Session is null when running unit tests.
if (ExecutionEvents.ActiveSession != null)
{
dynamoLogger = ExecutionEvents.ActiveSession.GetParameterValue(ParameterKeys.Logger) as DynamoLogger;

Check warning on line 146 in DSPythonNet3/DSPythonNet3Evaluator.cs

View workflow job for this annotation

GitHub Actions / Build and Test

Possible null reference assignment.
return dynamoLogger;

Check warning on line 147 in DSPythonNet3/DSPythonNet3Evaluator.cs

View workflow job for this annotation

GitHub Actions / Build and Test

Possible null reference return.
}
return dynamoLogger;
}
Expand Down Expand Up @@ -514,12 +514,17 @@
/// </summary>
private static void InitializeEncoders()
{
var shared = new object[] { new ListEncoderDecoder() };
var encoders = shared.Cast<IPyObjectEncoder>().ToArray();
var decoders = shared.Cast<IPyObjectDecoder>().Concat(new IPyObjectDecoder[]
var listEncoderDecoder = new ListEncoderDecoder();
var encoders = new IPyObjectEncoder[]
{
listEncoderDecoder,
new ConnectionNodeObjectEncoder()
};
var decoders = new IPyObjectDecoder[]
{
listEncoderDecoder,
new DictionaryDecoder()
}).ToArray();
};
Array.ForEach(encoders, e => PyObjectConversions.RegisterEncoder(e));
Array.ForEach(decoders, d => PyObjectConversions.RegisterDecoder(d));
}
Expand Down
73 changes: 73 additions & 0 deletions DSPythonNet3/Encoders/ConnectionNodeObjectEncoder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
using System;
using System.Collections;
using System.Reflection;
using Dynamo.Utilities;
using Python.Runtime;

namespace DSPythonNet3.Encoders
{
/// <summary>
/// Prevents Python.NET from auto-encoding certain IEnumerable-based host objects
/// (notably Dynamo for Revit "ConnectionNode") into Python iterables, which
/// strips away callable .NET members like SubNodesOfSize / ExistingConnections.
/// </summary>
internal sealed class ConnectionNodeObjectEncoder : IPyObjectEncoder
{
private static readonly string[] methodNames = new[]
{
"SubNodesOfSize",
"ExistingConnections"
};

public bool CanEncode(Type type)
{
// Don't intercept common primitives / containers.
if (type == typeof(string))
{
return false;
}

if (!typeof(IEnumerable).IsAssignableFrom(type))
{
return false;
}

// Let our existing List encoder/decoder handle IList.
if (typeof(IList).IsAssignableFrom(type))
{
return false;
}

// Don't interfere with dictionary encoding.
if (typeof(IDictionary).IsAssignableFrom(type))
{
return false;
}

// Target by type name (no hard reference to Revit/DynamoRevit assemblies).
if (type.Name.Contains("ConnectionNode", StringComparison.OrdinalIgnoreCase))
{
return true;
}

// Target by known member names used in graphs.
const BindingFlags flags = BindingFlags.Instance | BindingFlags.Public;
foreach (var name in methodNames)
{
if (type.GetMethod(name, flags) != null)
{
return true;
}
}

return false;
}

public PyObject TryEncode(object value)
{
// Wrap as CLR object so methods remain callable in Python.
return PyObject.FromManagedObject(value);
}
}
}

Loading