I'm trying to execute a Python script from within a C# application but when it tries to launch the script, I receive the error ImportException was unhandled No module name csv. I checked the Ironpython folder and there is a csv.py file...?
Code I'm using to call the script:
IDictionary<string, object> options = new Dictionary<string, object>();
options["Argument"] = new[] { filePath, profile };
var pyEngine = Python.CreateEngine(options);
var pyScope = pyEngine.CreateScope();
string script = "xccdf-xml2tsv.py";
pyScope.SetVariable(profile, options);
pyEngine.ExecuteFile(script, pyScope);
python file:
#!/usr/bin/env python
###
# (C) 2010 Adam Crosby
# Licensed under:
# http://creativecommons.org/licenses/by-nc-sa/3.0/
##
import csv
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
import xml.etree.ElementTree as ET
xmlns = "http://checklists.nist.gov/xccdf/1.1"
...
The IronPython engine you created is unaware of the standard library implementation it should use. You can specify it by adding something like
var paths = pyEngine.GetSearchPaths();
paths.Add(#"C:\Program Files (x86)\IronPython 2.7\Lib");
pyEngine.SetSearchPaths(paths);
You could either point it to a locally installed iron python (as in my example) or use the appropriate NuGet package to directly add it to your project. You might also have to deploy it to your output folder/installer/...
Please also take note of this answer as well as this answer and comments as they might provide additional information.
Related
I use CAKE 0.21.1.0.
I want to add a task that performs the equivalent of this PowerShell operation:
$dlls = #(${dll1}, ${dll2})
$dlls | % { [Reflection.Assembly]::UnsafeLoadFrom($_) }
[StaticClassFromLocalLibrary]::SomeStaticMethod(SomeArgument)
I have decided not to use the CAKE PowerShell add-in because running the PowerShell script directly throws the error <script>.ps1 is not digitally signed. The script will not execute on the system. Because of my employer's IT policy, I am not permitted to run Set-ExecutionPolicy to circumvent the problem. This is why I want to translate the steps taken in the PowerShell script directly into instructions in CAKE.
Initially, I wrote these lines in my CAKE script:
System.Reflection.Assembly.UnsafeLoadFrom(dll1);
System.Reflection.Assembly.UnsafeLoadFrom(dll2);
StaticClassFromLocalLibrary.SomeStaticMethod(SomeArgument);
However, an exception was thrown, saying that the name StaticClassFromLocalLibrary was not found in the current context.
I then added this line to my CAKE script:
#r #"\\hostName\Folder1\Folder2\Folder3\Folder4\Some.Local.Project.dll"
However, because it was not loaded in an unsafe manner, another exception was thrown, this time informing me that the DLL could not be loaded.
How can I use the #r directive (or any other CAKE command) to specify that I would like the DLL to be loaded in an unsafe manner?
EDIT:
I have solved my problem by consulting this page and adopting the suggestion in the accepted answer.
There's no build in unsafe loading in Cake but as it's just C# what you can do is just convert your PowerShell snippet into C#
var assembly = System.Reflection.Assembly.UnsafeLoadFrom("./tools/Addins/Newtonsoft.Json/lib/net45/Newtonsoft.Json.dll");
var type = assembly.GetType("Newtonsoft.Json.JsonConvert");
var method = type.GetMethod("SerializeObject", new [] {typeof(object) });
var SerializeObject = (Func<object, string>) Delegate.CreateDelegate(
typeof(Func<object, string>), null, method);
var json = SerializeObject(new { Hello = "World"});
Information("{0}", json);
Which will output something like
{"Hello":"World"}
I'm trying to use an embedded python interpreter from C# using pythonnet (the python3 compatible version found at https://github.com/renshawbay/pythonnet)
My interpreter is located in D:\src\scratch\TestPythonNet\TestPythonNet\PythonRuntime and has the "Lib" and "Libs" folder from the python distribution.
I've tested using the following code:
<!-- language: c# -->
PythonEngine.PythonHome = #"D:\src\scratch\TestPythonNet\TestPythonNet\PythonRuntime";
PythonEngine.ProgramName = "PythonRuntime";
PythonEngine.Initialize();
using (Py.GIL())
{
PythonEngine.RunSimpleString("print(1)");
}
But, it doesn't work. I get a "SystemError: PyEvalCodeEx: NULL globals". Everytime I try to get an object from python, the code fails.
What am I doing wrong?
I think I've found the answer. If I add a reference to the "clr" module provided by pythonnet, it does work
PythonEngine.PythonHome = #"D:\src\scratch\TestPythonNet\TestPythonNet\PythonRuntime";
PythonEngine.ProgramName = "PythonRuntime";
PythonEngine.Initialize();
// ==>
PyObject a = PythonEngine.ImportModule("clr");
using (Py.GIL())
{
PythonEngine.RunSimpleString("print(1)");
}
I have an embedded resource in my dll which is a python script. I'd like to make the classes and functions in that resource available to the python engine, so I can execute external .py files (as __main__) which would be able to do something like
import embedded_lib # where embedded_lib is an embedded python script
Is there a way to accomplish this? I was hoping there will be some sort of IronPython.ImportModule('module_name', source) so I've looked through IronPython docs and couldn't find anything, but I'm hoping I'm just bad at looking.. Maybe there is some way to intercept a call to import and load my script that way?
It is possible. You just need to add search paths to ScriptEngine object like this:
var paths = engine.GetSearchPaths();
paths.Add(yourLibsPath); // add directory to search
or
engine.SetSearchPaths(paths);
Then you could use any module in directories, which you add:
import pyFileName # without extension .py
Update
OK. If you want to use embedded resource strings like module, you may use this code:
var scope = engine.CreateScope(); // Create ScriptScope to use it like a module
engine.Execute("import clr\n" +
"clr.AddReference(\"System.Windows.Forms\")\n" +
"import System.Windows.Forms\n" +
"def Hello():\n" +
"\tSystem.Windows.Forms.MessageBox.Show(\"Hello World!\")", scope); // Execute code from string in scope.
Now you have a ScriptScope object (scope in code) containing all executed functions. And you may insert them into another scope like this:
foreach (var keyValuePair in scope.GetItems())
{
if(keyValuePair.Value != null)
anotherScope.SetVariable(keyValuePair.Key, keyValuePair.Value);
}
Or you can execute your scripts right in this ScriptScope:
dynamic executed = engine.ExecuteFile("Filename.py", scope);
executed.SomeFuncInFilename();
And in this script you may use all functions without import:
def SomeFuncInFilename():
Hello() # uses function from your scope
I’m currently testing IronPython (I know a bit C# and a bit CPython). Now I want to use my custom class in a Python script.
I have the following project structure:
Solution IPTest
---Project IPTest
------Namespace IPTest
---------Program class (main)
---------Elem class
------Scripts
---------Worker.py
Where Elem is a simple:
public class Elem {
public string Name;
}
I can use the Python scripts in the .NET program without any problems like:
ScriptEngine engine = Python.CreateEngine();
ScriptSource source = engine.CreateScriptSourceFromFile("./Scripts/Worker.py");
ScriptScope scope = engine.CreateScope();
source.Execute(scope);
// or var worker = Python.CreateRuntime().UseFile("./Scripts/Worker.py");
dynamic Worker = scope.GetVariable("Worker");
dynamic worker = Worker();
var res1 = worker.add(4, 5);
However, I can’t figure out how to reference the hosting Assembly in the Python script. After some research I tried the following:
import sys
import System
sys.path.append(System.IO.Directory.GetCurrentDirectory()) #make sure assembly dir is in sys.path
import clr
clr.AddReference(“IPTest.exe”)
# or clr.AddReferenceToFile(r"IPTest.exe")
# or clr.AddReference(r"<fullpath>\IPTest\bin\Debug\IPTest.exe")
# or clr.AddReference(“../IPTest.exe”) #when not adding workingdir to sys.path
from IPTest import Elem
# or from IPTest.IPTest import Elem
# or import Elem
Neither works. I get two different error messages:
When adding workingdir to sys.path or using relative path or use
AddReferenceToFile: No module named IPTest
When using the absolute path: The given assembly name or codebase
was invalid. (Exception from HRESULT: 0x80131047)
I checked that the Assembly name is really IPTest and tried to use a dll instead of exe - though it should usually not make any difference and surprisingly doesn’t work either.
disclaimer: The solution described here:
engine.Runtime.LoadAssembly(Assembly.GetExecutingAssembly()); //in c#
from IPTest import Elem # in python script
works just fine. However I think it should also work by referencing in the script file (which would be nicer).
Probably I’m missing something obvious, but I just can’t see it so any hint is much appreciated.
Try clr.AddReferenceToFile(r'IPTest.exe') as mentioned in your error:
When adding workingdir to sys.path or using relative path or use AddReferenceToFile: No module named IPTest
I'm using Visual Studio 2010. I have an IronPython console project and a C# console project. This IronPython script works fine when I run it by itself:
import nltk
def Simple():
baconIpsumFile = open('baconipsum.txt', 'r')
baconIpsumCorpus = baconIpsumFile.read()
tokens = nltk.word_tokenize(baconIpsumCorpus)
text = nltk.Text(tokens)
print text
Here is the C# console program, which does not work fine:
using IronPython.Hosting;
namespace IronNLTK.CSharp.Console
{
class Program
{
static void Main(string[] args)
{
var ipy = Python.CreateRuntime();
dynamic test = ipy.UseFile("C:\\Path\\To\\Program.py");
test.Simple();
}
}
}
I get an ImportException: No module named nltk. What am I missing?
sounds like you need to update sys.path to point to wherever NLTK lives.
check this out: Importing external module in IronPython
Awesome news, Visual Studio 2017 is embedded with Anaconda’s Python distribution which has NTLK and other machine learning packages.