I'm using the implementation of ironpython 2.6.2 in my application c# 3.5, but I'm getting the following error: "The method or operation is not implemented."
Added references to the DLR and IronPython assemblies (all found in the IronPython install directory, which is “C:\Program Files\IronPython 2.6” on my machine):
IronPython.dll
IronPython.Modules.dll
Microsoft.Scripting.dll
Microsoft.Scripting.Core.dll
follows the code of my application:
ScriptEngine engine = Python.CreateEngine();
//parameter file path
ScriptSource source = engine.CreateScriptSourceFromFile(pathFilePy);
ScriptScope scope = engine.CreateScope();
ObjectOperations op = engine.Operations;
source.Execute(scope); // class object
object classObject = scope.GetVariable("calc"); // get class object
object instance = op.Invoke(classObject); // create instance
object method = op.GetMember(instance, "calc01"); // get method
var result = op.Invoke(method, 10, 20,30); // call method and get result
the code file .py
class calc(object):
def calc01(self,var1,var2,var3):
bla = ((var1+var2+var3)/3)
return bla
The error occurs on this line:
var result = op.Invoke(method, 10, 20,30); // call method and get result
Maybe you should call it with 4 arguments instead of 3 like this:
>>> class calc(object):
... def calc01(self,var1,var2,var3):
... bla = ((var1+var2+var3)/3)
... return bla
...
>>> calc1 = calc()
>>> calc.calc01(calc1,10,20,30)
20
>>>
as was pointed out in the other answer it looks like your method needs 4 parameters and is only being invoked with 3 from the c# code. the question I would ask (not being a python expert) is why your python method has the parameter self at all? I would have thought you need to do 1 of 2 things, both of which will probably solve your problem
1 Redfine your python method not to contain self:
class calc(object):
def calc01(var1,var2,var3):
bla = ((var1+var2+var3)/3)
return bla
2 Invoke the python method using 4 arguments:
...
object classObject = scope.GetVariable("calc"); // get class object
object instance = op.Invoke(classObject); // create instance
object method = op.GetMember(instance, "calc01"); // get method
var result = op.Invoke(method, instance, 10, 20,30); // call method and get result
...
Related
I'm using IronPython v 2.7.8.1 in VS 2017. I've installed Python27, 36 and 37. I've tried switching between the various environments in VS. I've tried adding the search paths to the libraries of these installs. The python code will work if I run it in the interpreter. Trying to run the same code in VS throws: "Microsoft.Scripting.SyntaxErrorException: unexpected token ',' ". If I test a python script that doesn't include imports it will work? Is there a specific way python has to be installed to work IronPython? This is the C# Code:
class CallPython
{
public void PatchParameter(string parameter)
{
var FilePath = (#"C:\Users\Pac\Downloads\MvcAuth\MvcAuth\TwurlPy\TwurlPy\SendDirectMsg.py");
var engine = Python.CreateEngine(); // Extract Python language engine from their grasp
ICollection<string> searchPaths = engine.GetSearchPaths();
searchPaths.Add(#"C:\Users\Pac\AppData\Local\Programs\Python\Python37\Lib");
searchPaths.Add(#"C:\Users\Pac\AppData\Local\Programs\Python\Python37\Lib\site-packages");
engine.SetSearchPaths(searchPaths);
var scope = engine.CreateScope(); // Introduce Python namespace
(scope)
var d = new Dictionary<string, object>
{
{ "text", text},
{ "userID", userID},
};
// Add some sample parameters. Notice that there is no need in
// specifically setting the object type, interpreter will do that part for us
// in the script properly with high probability
scope.SetVariable("params", d); // This will be the name of the
// dictionary in python script, initialized with previously created .NET
// Dictionary
ScriptSource source = engine.CreateScriptSourceFromFile(FilePath);
// Load the script
object result = source.Execute(scope);
parameter = scope.GetVariable<string>("parameter"); // To get the
// finally set variable 'parameter' from the python script
return;
}
}
This is the Python script. If I comment out the import statements it works using IronPython, but of course I need them...
import twitter
import requests
import sys
parameter = "test"
def SendDM(text, userID, access_token, access_secret):
consumer_key = 'YkopsCQjEXccccccccccccccccccZvA9yy'
consumer_secret = 'TQVCoccccccccccccccccccct7y8VfmE'
access_token_key = access_token
access_token_secret = access_secret
api = twitter.Api(
consumer_key=consumer_key,
consumer_secret=consumer_secret,
access_token_key=access_token_key,
access_token_secret=access_token_secret)
send_msg = api.PostDirectMessage(text, user_id=userID)
print (send_msg)
return
SendDM(text, userID, access_token, access_secret)
I want simply use io.py from C# to write a file and I use the following code:
using Microsoft.Scripting.Hosting;
using IronPython.Hosting;
...
System.IO.Directory.SetCurrentDirectory(
Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles) +
"\IronPython\Lib");
ScriptRuntime py = Python.CreateRuntime();
dynamic io = py.UseFile("io.py");
dynamic f = io.open("tmp.txt", "w");
f.writelines("some text...");
f.close();
but when I run the program the runtime give me a:
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException telling that no overload of writelines accept argument '1'
it seems like that method doesn't exists... but into io.py documentation it exists.
P.S. The same is for close method!!!
Any idea?
I can only tell you how to make your code working, however I don't have much experience with IronPython and have no idea why it is done this way (though I try to learn that). First, it seems io module is treated in a special way and there is special (non-dynamic) class for that. When you do io.open what is returned is instance of PythonIOModule._IOBase class. You can do
var f = (PythonIOModule._IOBase) io.open("tmp.txt", "w");
And see for yourself that "writeline" method (which is regular method, not a dynamic one) accepts CodeContext instance as first argument, and second argument is lines. Interesting that this class itself already contains field with that CodeContext, but it is made internal for some reason, and what is even worse - writelines (and other methods) could have been using that CodeContext and not require us to provide external one. Why is it done like this - I have no idea.
So to make your code working, we have to get CodeContext somewhere. One way is do that via reflection:
var context = (CodeContext) f.GetType().GetField("context", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(f);
Another way is to craft it yourself:
var languageContext = HostingHelpers.GetLanguageContext(engine);
var context = new ModuleContext(io._io, new PythonContext(languageContext.DomainManager, new Dictionary<string, object>())).GlobalContext;
Both methods will work and program will successfully write to a file. Full working sample:
static void Main(string[] args) {
System.IO.Directory.SetCurrentDirectory(#"G:\Python27\Lib");
var engine = Python.CreateEngine();
dynamic io = engine.ImportModule("io");
var f = (PythonIOModule._IOBase) io.open("tmp.txt", "w");
var languageContext = HostingHelpers.GetLanguageContext(engine);
var context = new ModuleContext(io._io, new PythonContext(languageContext.DomainManager, new Dictionary<string, object>())).GlobalContext;
f.writelines(context, "some text....");
f.close(context);
}
This SO question provides code to create an instance of a python class in C#.
The following code forces to know the python function name in advance. However I need to specify the class name and the function name to be executed by strings.
ScriptEngine engine = Python.CreateEngine();
ScriptSource source = engine.CreateScriptSourceFromFile("Calculator.py");
ScriptScope scope = engine.CreateScope();
source.Execute(scope);
dynamic class_object = scope.GetVariable("Calculator");
dynamic class_instance = class_object();
int result = class_instance.add(4, 5); // I need to call the function by a string
Easiest way to do that is to install nuget package called Dynamitey. It was designed specifically to call dynamic methods (and doing other useful things) on dynamic objects. After you install it, just do:
static void Main(string[] args)
{
ScriptEngine engine = Python.CreateEngine();
ScriptSource source = engine.CreateScriptSourceFromFile("Calculator.py");
ScriptScope scope = engine.CreateScope();
source.Execute(scope);
dynamic class_object = scope.GetVariable("Calculator");
dynamic class_instance = class_object();
int result = Dynamic.InvokeMember(class_instance, "add", 4, 5);
}
If you want to know what it does under the hood - it uses the same code which is used by C# compiler for dynamic invocations. This is a long story but if you want to read about this, you can do it here for example.
You're looking for the Invoke and InvokeMember IronPython methods:
ScriptEngine engine = Python.CreateEngine();
ScriptSource source = engine.CreateScriptSourceFromFile("Calculator.py");
ScriptScope scope = engine.CreateScope();
source.Execute(scope);
object class_object = scope.GetVariable("Calculator");
object class_instance = engine.Operations.Invoke(class_object);
object[] args = new object[2];
args[0] = 4;
args[1] = 5;
int result = (int)engine.Operations.InvokeMember(class_instance, "add", args); // Method called by string
// "args" is optional for methods which don't require arguments.
I also changed the dynamic type to object, since you won't need it anymore for this code sample, but you are free to keep it, should you need to call some fixed-name methods.
Using Ironpython, I created a .dll from a .py file. It has classes and respective functions that I want to call to be used in c#. I created the .dll so that I can hide the source from the user.
Here is what I have tried:
ScriptEngine engine = Python.CreateEngine();
scope = engine.CreateScope();
engine.Runtime.LoadAssembly(Assembly.LoadFile(fullPath2DLL));
scope = engine.ImportModule("Simulation");
However, it cannot find "Simulation".
Also, I want to import the whole script at once so I can call whatever, whenever [Rather than the class 'Simulation'].
Many things could go wrong, so I'll just show you complete example which works. Let's take this python code that I grabbed in some example:
MyGlobal = 5
class Customer(object):
"""A customer of ABC Bank with a checking account. Customers have the
following properties:
Attributes:
name: A string representing the customer's name.
balance: A float tracking the current balance of the customer's account.
"""
def __init__(self, name, balance=0.0):
"""Return a Customer object whose name is *name* and starting
balance is *balance*."""
self.name = name
self.balance = balance
def withdraw(self, amount):
"""Return the balance remaining after withdrawing *amount*
dollars."""
if amount > self.balance:
raise RuntimeError('Amount greater than available balance.')
self.balance -= amount
return self.balance
def deposit(self, amount):
"""Return the balance remaining after depositing *amount*
dollars."""
self.balance += amount
return self.balance
Now let's open ipy and compile that into dll with:
>>> import clr
>>> clr.CompileModules("path_to.dll", "path_to.py");
Now we have dll. As you see python code contains class definition, and our goal is to create instance of that class in C# and call some methods.
public class Program {
private static void Main(string[] args) {
ScriptEngine engine = Python.CreateEngine();
engine.Runtime.LoadAssembly(Assembly.LoadFile(#"path_to.dll"));
// note how scope is created.
// "test" is just the name of python file from which dll was compiled.
// "test.py" > module named "test"
var scope = engine.Runtime.ImportModule("test");
// fetching global is as easy as this
int g = scope.GetVariable("MyGlobal");
// writes 5
Console.WriteLine(g);
// how class type is grabbed
var customerType = scope.GetVariable("Customer");
// how class is created using constructor with name (note dynamic keyword also)
dynamic customer = engine.Operations.CreateInstance(customerType, "Customer Name");
// calling method on dynamic object
var balance = customer.deposit(10.0m);
// this outputs 10, as it should
Console.WriteLine(balance);
Console.ReadKey();
}
}
I just download the Iron JS and after doing some 2/3 simple programs using the Execute method, I am looking into the ExecuteFile method.
I have a Test.js file whose content is as under
function Add(a,b)
{
var result = a+b;
return result;
}
I want to invoke the same from C# using Iron JS. How can I do so? My code so far
var o = new IronJS.Hosting.CSharp.Context();
dynamic loadFile = o.ExecuteFile(#"d:\test.js");
var result = loadFile.Add(10, 20);
But loadfile variable is null (path is correct)..
How to invoke JS function ,please help... Also searching in google yielded no help.
Thanks
The result of the execution is going to be null, because your script does not return anything.
However, you can access the "globals" object after the script has run to grab the function.
var o = new IronJS.Hosting.CSharp.Context();
o.ExecuteFile(#"d:\test.js");
dynamic globals = o.Globals;
var result = globals.Add(10, 20);
EDIT: That particular version will work with the current master branch, and in an up-coming release, but is not quite what we have working with the NuGet package. The slightly more verbose version that works with IronJS version 0.2.0.1 is:
var o = new IronJS.Hosting.CSharp.Context();
o.ExecuteFile(#"d:\test.js");
var add = o.Globals.GetT<FunctionObject>("Add");
var result = add.Call(o.Globals, 10D, 20D).Unbox<double>();