Invoking C# 'dynamic' object from Python

Jun 14, 2010 at 6:11 PM
Edited Jun 14, 2010 at 6:34 PM
Hello,

I am having trouble dynamically invoking a C# 'dynamic' object from an IronPython script.

I defined a class in C# that derives from DynamicObject. This class has a method called 'Foo()', which prints a trace message when called, plus it override all available methods from DynamicObject and it prints a trace messages when any of them are called as well.

I created an instance of this type and assigned to a variable of type 'dynamic'. Using this new object, I can call 'Foo()' and I can call 'MissingMethod()' in C# and I get the behaviour I expect (I can see it trying to find the method dynamically before failing).

However, when I pass this variable to a Python script scope, it does not work as I expected. When I call 'Foo()' from Python, that works, but when I call 'MissingMethod()', I just get the following exception: "'MyDynamicObject' object has no attribute 'MissingMethod'" instead of getting the expected traces in my dynamics object.

I'm pretty sure this should be possible, and I am just doing something wrong. I would appreciate any pointers anyone has.

Thanks very much,
Andrew



P.S. Here is a sample console application to test this out

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Dynamic;
using System.Linq;
using System.Text;

using IronPython.Hosting;
using IronPython.Runtime;
using Microsoft.Scripting;
using Microsoft.Scripting.Hosting;

namespace TestDynamicInvokeFromPython
{
   class Program
   {
      static void Main(string[] args)
      {
         dynamic myDynamicObject = new MyDynamicObject();

         //first tey calling this object from C#, it should call Foo() and they try to call MissingMethod();
         Console.WriteLine("C# Test...");
         try
         {
            myDynamicObject.Foo();
            myDynamicObject.MissingMethod();
         }
         catch (Exception ex)
         {
            Console.WriteLine("Got C# exception: " + ex.Message);
         }


         ScriptEngine pythonEngine = Python.CreateEngine();
         ScriptScope scriptScope = pythonEngine.CreateScope();

         string pythonScript = SetPythonScript();
         ScriptSource script = pythonEngine.CreateScriptSourceFromString(pythonScript, SourceCodeKind.Statements);

         scriptScope.SetVariable("myDynamicObject", myDynamicObject);

         //Now do the same thing from python, I expect to get the same behaviour as from C# (but I don't)
         Console.WriteLine("\r\nScript Test...");
         try
         {
            script.Execute(scriptScope);
         }
         catch (Exception ex)
         {
            Console.WriteLine("Got script exception: " + ex.Message);
         }


         Console.ReadKey();
      }

      static string SetPythonScript()
      {
         string s = "";
         s += "import clr"                               + "\r\n";
         s += "clr.AddReference('mscorlib')"             + "\r\n";

         s += "myDynamicObject.Foo();"                   + "\r\n";
         s += "myDynamicObject.MissingMethod();"         + "\r\n";

         return s;
      }
   }


   class MyDynamicObject : DynamicObject
   {
      public void Foo()
      {
         Console.WriteLine("Foo() Called");
      }

      public override DynamicMetaObject GetMetaObject(System.Linq.Expressions.Expression parameter)
      {
         Console.WriteLine("GetMetaObject() Called");
         return base.GetMetaObject(parameter);
      }

      public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
      {
         Console.WriteLine("TryInvokeMember() Called");
         return base.TryInvokeMember(binder, args, out result);
      }

      public override bool TryGetMember(GetMemberBinder binder, out object result)
      {
         Console.WriteLine("TryGetMember() Called");
         return base.TryGetMember(binder, out result);
      }

      //#region AllOtherOverridees
      // ...
      //#endregion //AllOtherOverridees

   }
}



P.P.S Here is the output this produces, I expected to see equivalent behaviour from both C# and Python:
C:\Junk\TestDynamicInvokeFromPython\bin\Debug>TestDynamicInvokeFromPython.exe
C# Test...
GetMetaObject() Called
Foo() Called
GetMetaObject() Called
TryInvokeMember() Called
TryGetMember() Called
Got C# exception: 'TestDynamicInvokeFromPython.MyDynamicObject' does not contain
 a definition for 'MissingMethod'
GetMetaObject() Called

Script Test...
Foo() Called
Got script exception: 'MyDynamicObject' object has no attribute 'MissingMethod'

C:\Junk\TestDynamicInvokeFromPython\bin\Debug>