Running python functions using IronPython in C# - c#

Im trying to import use a python script in C# by using IronPython but an error keeps coming up which I don't understand, seems like it had problems importing the module. The python file runs fine by itself and i tested a simple script that prints "hello" and it worked so I might just be importing the module wrong somehow.
An unhandled exception of type 'System.MissingMemberException' occurred in Microsoft.Dynamic.dll
Additional information: 'module' object has no attribute 'setup'
Error Image
This is the code im trying to run on my C# program
var engine = Python.CreateEngine();
ICollection<string> paths = engine.GetSearchPaths();
string modulePath = #"D:\Python\Lib";
paths.Add(modulePath);
string modulePath2 = #"D:\Python\Lib\site-packages";
paths.Add(modulePath2);
engine.SetSearchPaths(paths);
dynamic py = engine.ExecuteFile(#"broadlink.py");
This is the code in my python
import broadlink
broadlink.setup('*****', '*****', 3)
devices = broadlink.discover(timeout=5)

Related

Importing Pyro in IronPython ScriptEngine

So I am having some troubles importing Pyro or Pyro4 while using IronPython as a C# ScriptEngine.
The import works fine if run directly in the ipy interpreter, but I receive the following error when ipy is initialized as a script engine from a c# script.
TypeErrorException: sequence item 0: expected bytes or byte array, str found
IronPython.Runtime.Operations.ByteOps.AppendJoin (System.Object value, Int32 index, System.Collections.Generic.List`1 byteList)
IronPython.Runtime.Bytes.join (System.Object sequence)
Microsoft.Scripting.Interpreter.FuncCallInstruction`3[IronPython.Runtime.Bytes,System.Object,IronPython.Runtime.Bytes].Run (Microsoft.Scripting.Interpreter.InterpretedFrame frame)
Microsoft.Scripting.Interpreter.Interpreter.Run (Microsoft.Scripting.Interpreter.InterpretedFrame frame)
I am passing the -X:FullFrames and -X:Frames parameters to ipy at it's initialization already, so I believe I have ruled that out. In fact, this error happens whether or not I initialize with this parameters.
Here is my code in c#:
// Set the fullframes parameter in a dict
var options = new Dictionary<string, object>();
options["Frames"] = true;
options["FullFrames"] = true;
// create the engine
var ScriptEngine = IronPython.Hosting.Python.CreateEngine(options);
// and the scope (ie, the python namespace)
var ScriptScope = ScriptEngine.CreateScope();
//set the python file to execute
string scriptPath = "Assets\\test.py";
var ScriptSource = ScriptEngine.CreateScriptSourceFromFile(scriptPath);
And, of course, in the python script, I am receiving this error upon import of Pyro.
import Pyro
This error is typically obtuse for working with IPY, and I am stumped.
Any insight at all, including any techniques to get a little more traceback would be of great help.
Thanks in advance!
The issue was I was using dlls from IPY 2.7.4 and the site-lib modules for 2.7.7.
One step further, and I discovered that 2.7.4 has issues with Pyro as described here:
http://pyro-core.narkive.com/0G88Usma/bug-typeerror-expected-pointer-got-int64
If you can see your full traceback from IPY, you can see the line in Pyro that causes the issue, and a hacky fix is to comment out the method.

IronPython - MissingMemberException trying to import xml.etree.ElementTree

I'm not at all familiar with Python, hoping someone can help and guide me to find what's going wrong here.
This is the error message:
MissingMemberException: 'LightException' object has no attribute 'etree'
This is the python code that throws it:
import xml.etree.ElementTree as ET
We're using IronPython 2.7.3 in a c# project, the python code is executed using our Execute() method:
private void Execute(string code, ScriptScope scope)
{
try
{
PythonByteCode compiled = (PythonByteCode)Compile(code, SourceCodeType.AutoDetect);
compiled.Execute(scope);
}
catch (Exception e)
{
throw new PythonParseException(e);
}
}
It is quite easy. When you running your engine it does not know about default assemblies location (on my machine it is "C:\Program Files (x86)\IronPython 2.7"). So it is tries to get modules from current working directory and then - Lib subdirectory of working directory. Of course it cannot find modules there.
What you should do:
Get path of IronPython distribution. Actually you need Lib subdirectory content. May be you should think how to deploy it on target machine so your release version may also find it.
Add it to python search path using code below
string dir = Path.GetDirectoryName(scriptPath);
ICollection<string> paths = engine.GetSearchPaths();
if (!string.IsNullOrEmptydir))
{
paths.Add(dir);
}
else
{
paths.Add(Environment.CurrentDirectory);
}
engine.SetSearchPaths(paths);

No module named difflib

I want to execute python code from C# with following code.
static void Main(string[] args)
{
ScriptEngine engine = Python.CreateEngine();
ScriptSource source = engine.CreateScriptSourceFromFile(#"F:\Script\extracter.py");
source.Execute();
}
I have the problem at line source.Execute(), I got error "No module named difflib".
What is wrong in my code?
This is my python code (extracter.py).
import re
import itertools
import difflib
print "Hello"
This looks like your engine does not have access to Python standard library - it does not see difflib.py. Either fix the sys.path or copy difflib.py from Python 2.6 to f:\script folder.
re and itertools modules are written in C# and are part of IronPython.modules.dll - that's why importing them work.

Embedding IronPython in a C# application - import error on urllib

I have a Python file with as content:
import re
import urllib
class A(object):
def __init__(self, x):
self.x = x
def getVal(self):
return self.x
def __str__(self):
return "instance of A with value '%s'" % (self.getVal())
I also have a simple C# console project with the following code:
engine = Python.CreateEngine();
ScriptSource source = engine.CreateScriptSourceFromFile("test.py");
ScriptScope scope = engine.CreateScope();
ObjectOperations op = engine.Operations;
source.Execute(scope); // class object created
object klaz = scope.GetVariable("A"); // get the class object
object instance = op.Call(klaz, "blabla waarde"); // create the instance
object method = op.GetMember(instance, "getVal"); // get a method
string result = (string)op.Call(method); // call method and get result (9)
Console.WriteLine("Result: " + result); //output: 'Result: blabla waarde'
(I got this from this stackoverflow querstion and answer)
If I leave out the the import urllib statement in the Python file everything works fine. (meaning it finds the re module)
But as soon as i either add import urllib or import urllib2 I get the following exception:
ImportException was unhandled
No module named urllib
So somehow it can't find the urllib. I checked the IronPython lib folder and both urllib and urllib 2 are definitely there.
The same exception gets thrown when I import urllib in the C# code. (engine.ImportModule("urllib");)
Any ideas?
I'd like to manage the imports in the python code and not in the C# code.
(So I'd like to avoid stuff like this: engine.ImportModule("urllib");)
Edit:
Some extra info on what I'm actually going to use this for (maybe someone has an alternative):
I will have a main C# application and the python scripts will be used as extensions or plugins for the main application.
I'm using Python so that I don't need to compile any of the plugins.
I believe that 'Lib' being on sys.path from the interactive console is actually done inside ipy.exe - and when embedding you will have to add the path manually. Either the engine or the runtime has a 'SetSourcePaths' (or similar) method that will allow you to do this.
I face the same problem. Following "Tom E's" suggestion in the comments to fuzzyman's reply I could successfully resolve the issue. The issue seems to be it is not able resolve the location of the urllib.py. We need to set it.
You can check the following link for the question and answer.
The version of CPython you're importing from must match your IronPython version. Use CPython v2.5 for IronPython 2.0, or v2.6 for IronPython 2.6.
Try this:
import sys
sys.path.append(r'\c:\python26\lib') # adjust to whatever version of CPython you have installed.
import urllib

Simplfying DSL written for a C# app with IronPython

Thanks to suggestions from a previous question, I'm busy trying out IronPython, IronRuby and Boo to create a DSL for my C# app. Step one is IronPython, due to the larger user and knowledge base. If I can get something to work well here, I can just stop.
Here is my problem:
I want my IronPython script to have access to the functions in a class called Lib. Right now I can add the assembly to the IronPython runtime and import the class by executing the statement in the scope I created:
// load 'ScriptLib' assembly
Assembly libraryAssembly = Assembly.LoadFile(libraryPath);
_runtime.LoadAssembly(libraryAssembly);
// import 'Lib' class from 'ScriptLib'
ScriptSource imports = _engine.CreateScriptSourceFromString("from ScriptLib import Lib", SourceCodeKind.Statements);
imports.Execute(_scope);
// run .py script:
ScriptSource script = _engine.CreateScriptSourceFromFile(scriptPath);
script.Execute(_scope);
If I want to run Lib::PrintHello, which is just a hello world style statement, my Python script contains:
Lib.PrintHello()
or (if it's not static):
library = new Lib()
library.PrintHello()
How can I change my environment so that I can just have basic statments in the Python script like this:
PrintHello
TurnOnPower
VerifyFrequency
TurnOffPower
etc...
I want these scripts to be simple for a non-programmer to write. I don't want them to have to know what a class is or how it works. IronPython is really just there so that some basic operations like for, do, if, and a basic function definition don't require my writing a compiler for my DSL.
You should be able to do something like:
var objOps = _engine.Operations;
var lib = new Lib();
foreach (string memberName in objOps.GetMemberNames(lib)) {
_scope.SetVariable(memberName, objOps.GetMember(lib, memberName));
}
This will get all of the members from the lib objec and then inject them into the ScriptScope. This is done w/ the Python ObjectOperations class so that the members you get off will be Python members. So if you then do something similar w/ IronRuby the same code should basically work.

Categories