I am trying to use IronPython log function in C#. Idea is user would write a mathematical script this would be evaluated and answer would be displayed in UI. When I use this method for simple mathematics(addition, subtraction etc.) it works fine. When I need to use log function I try to import math module it fails. My code is:
public double Calculate(string script)
{
ScriptEngine engine = Python.CreateEngine();
ScriptSource source = engine.CreateScriptSourceFromString("import math" + System.Environment.NewLine + script, SourceCodeKind.AutoDetect);
return source.Execute<double>();
}
When I run this code I get exception 'IronPython.Runtime.Exceptions.ImportException No Module named math.
I am calling method as
Calculate("math.log(10)")`
Am I missing any import or dll?
I tried to replicate your issue, however I did not have IronPython installed yet, so I installed the latest stable version (2.7.4) from here. I am not sure if you are using the same version...
When creating a solution, I knew I needed to add some references. My guess is, that this is the source of your 'evil'.
I have added the references 'IronPython' and 'Microsoft.Scripting', which come along with the installation of IronPython. The exact versions are v4.0.30319 (both IronPython and Microsoft Scripting).
So my Windows Forms application has one textBox and one button (it's just a test after all) and I copied in your example method called Calculate, in order to make sure we have the same, here is my version:
public double Calculate(string script)
{
ScriptEngine engine = Python.CreateEngine();
ScriptSource source = engine.CreateScriptSourceFromString("import math" + Environment.NewLine + script, Microsoft.Scripting.SourceCodeKind.AutoDetect);
return source.Execute<double>();
}
In the eventhandler of my button I have placed the following code:
private void button1_Click(object sender, EventArgs e)
{
try
{
double outcome = Calculate("math.log(10)");
tbOutcome.Text = string.Format("Outcome of log(10): {0}", outcome);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error occured...", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
When executing my application, the program does not show an error as yours, but it shows the an outcome that I did expect when calculating log(10) (assuming you are calculating a natural logarithm). My textBox contains:
Outcome of log(10): 2,30258509299405
So there is only one hint, try to find out if you have different versions of your ScriptEngine installed (I know there are a few more than just Microsoft.Scripting) and look at the references in your solution.
Hope it helps!
Python is case sensitive, and, there is no class named just Math.. only System.Math
so to get what you want, you need to use this import statement: from System import Math or import System.Math as Math
both would get you the same result...
Related
I was trying to combine a Python code with C#, to use all those cool libraries like Speech Recognition inside my C# application.
I made two different projects one for python (IronPython) where I've included the module I need (Speech Recognition) through the python environment in VS2017 and the other one is just a console application where I want to call this app.
I thought the point was to change the searchPaths of Ironpython and afterwards it'll work.
Maybe I'm doing something wrong or maybe it just shouldn't work anyway?
C# Code Main.cs:
using IronPython.Hosting;
using System.Collections.Generic;
private static void Main(string[] args)
{
//Using Iron python
var engine = IronPython.Hosting.Python.CreateEngine();
System.Console.WriteLine("Search paths:");
ICollection<string> searchPaths = engine.GetSearchPaths();
foreach (string path in searchPaths)
{
System.Console.WriteLine(path);
}
System.Console.WriteLine();
searchPaths.Add("..\\..");
///Trying to add a searchPath for the place with the module I need
searchPaths.Add(#"C:\Program Files (x86)\Microsoft Visual
Studio\Shared\Anaconda3_64\Lib\site-packages");
engine.SetSearchPaths(searchPaths);
var res = engine.CreateScriptSourceFromFile(
#"D:\Python\Projects\TestSpeechRecognition
\TestForNETinPython\TestForNETinPython.py"
);
engine.ImportModule("speech_recognition");
var result = res.Execute();
}
Python code
import speech_recognition as sr
r = sr.Recognizer()
with sr.Microphone() as source:
print ("Hello: ")
audio = r.listen(source)
try:
print ("I said: " + r.recognize_google(audio))
except sr.UnknownValueError:
print ("Cant't rec")
except sr.RequestError as e:
print ("Can't connect: (0)".format(e))
Exception:
Unhandled Exception:
IronPython.Runtime.Exceptions.ImportException: no module named speech_recognition
at IronPython.Hosting.PythonService.ImportModule(ScriptEngine engine, String name)
at IronPython.Hosting.Python.ImportModule(ScriptEngine engine, String moduleName)
at Test.Program.Main(String[] args) in D:\Python\Projects\TestSpeechRecognition\Test\Program.cs:line 26
I even read some literature about creating the modules like this one http://www.needfulsoftware.com/IronPython/IronPythonCS2 or this one it's for pythonnet and a little bit creepy, but I guess it may be useful (NoteBook).
Hope someone can use it to solve the problem.
I am in a bit of a strange situation. I have been given a fairly large suite of PowerShell modules and functions, and it is my job to tie these together into an executable. The requirements state that this must be a single, standalone executable with no installer and .net 3.5 may be the only dependency. The Windows Management Framework is not an exception and cannot be assumed to exist on the machine. To get around this, I have added System.Management.Automation as a reference and made it an embedded resource, along with all of the PowerShell module files, and load them from reflection at runtime. This seems to work OK, but I have some errors that I cannot seem to figure out and think it might have something to do with this system.
So Here is the issue: When I start to initialize things to run the PowerShell command, I get a strange error that I can't seem to control.
Here is the code:
public static void RunCommand(object objcommand)
{
//create a script block for toolbox once, get the embeded resource, convert from byte array to string, make scriptblock from string
ScriptBlock toolbox = System.Management.Automation.ScriptBlock.Create(System.Text.Encoding.Default.GetString(Properties.Resources.toolbox));
string command = (string)objcommand;
//get the module name
string modname = options.Commands[command]["module"];
//get the module from the embeded resources, convert to string, convert to scriptblock
var module = System.Management.Automation.ScriptBlock.Create(new System.IO.StreamReader(myasm.GetManifestResourceStream("piramids.Resources." + modname + ".psm1")).ReadToEnd());
using (var powerShell = PowerShell.Create())
{
System.Management.Automation.Runspaces.Runspace rs = System.Management.Automation.Runspaces.RunspaceFactory.CreateRunspace(); //i think this line triggers the exception
rs.Open();
powerShell.Runspace = rs;
//make the necesary powershell modules of the command availible
powerShell.AddCommand("new-module").AddParameter("ScriptBlock", toolbox).Invoke();
powerShell.AddCommand("new-module").AddParameter("ScriptBlock", module).Invoke();
//if inethistory, make dlls availible
if (modname.Equals("inethistory"))
{
powerShell.AddCommand("add-type").AddParameter("Path", sqldll).Invoke();
powerShell.AddCommand("add-type").AddParameter("Path", esentdll).Invoke();
}
ICollection<PSObject> output = new List<PSObject>(0);
try {
output = powerShell.AddCommand("get-" + command).AddCommand(format).AddCommand("out-string").Invoke();//pipeline.Invoke();
} catch (System.Management.Automation.RuntimeException e)
{
Console.Error.WriteLine("An Error occured while executing '" + command + "'");
Console.Error.WriteLine(e.Message);
}
//do stuff with the results
and here is the stack trace:
Unhandled Exception: System.ArgumentException: The path is not of a legal form.
at System.IO.Path.NormalizePathFast(String path, Boolean fullCheck)
at System.IO.Path.NormalizePath(String path, Boolean fullCheck)
at System.IO.Path.GetFullPathInternal(String path)
at System.IO.Path.GetFullPath(String path)
at System.Diagnostics.FileVersionInfo.GetFullPathWithAssert(String fileName)
at System.Diagnostics.FileVersionInfo.GetVersionInfo(String fileName)
at System.Management.Automation.PSVersionInfo.GetPSVersionTable()
at System.Management.Automation.PSVersionInfo.get_PSVersion()
at Microsoft.PowerShell.DefaultHost..ctor(CultureInfo currentCulture, CultureInfo currentUICulture)
at System.Management.Automation.Runspaces.RunspaceFactory.CreateRunspace()
at piramids.Program.RunCommand(Object objcommand)
at piramids.Program.Main(String[] args)
I believe this line is where the exception occurs:
System.Management.Automation.Runspaces.Runspace rs = System.Management.Automation.Runspaces.RunspaceFactory.CreateRunspace();
The CreateRunspace method is not documented to throw any exceptions, and this exception comes from so many levels down that I have no idea what kind of path this thing is checking, as I never called a function that asked for a path.
I am stumped. Does anyone have any idea what may be causing this?
EDIT: After some digging, here is what I found. PSVersionTable is a static field of VersionInfo, so the static constructor is called the first time get called for this field. The static constructor calls an internal method called GetBuildVersion, which tries to get the assembly location of PSVersionInfo. According to This documentation page:
If the assembly is loaded from a byte array, such as when using the Load(Byte[]) method overload, the value returned is an empty string ("").
I am loading from a byte array, so this will be an empty string. But then GetBuildVersion uses this location to do FileVersionInfo.GetVersionInfo which verifies the path with Path.GetFullPath. According to This documentation page:
ArgumentException:
the path is a zero-length string
So there is the problem. Now the question is, How do I assign a location to an assembly loaded from a byte array? May God have mercy on me.
I'm not at all convinced this is even remotely reasonable to expect PowerShell code to work without installing WMF. If I were approached with that request I would respond that all code must be rebuilt in another .NET language (that is, C#).
Still, perhaps you can see if it's this static method. You'll have to de-PowerShell the code I'm afraid. The PowerShell accelerator is just a simple way for me to get at the System.Management.Automation assembly. The class is not public and the method on the class is not public either.
$verInfo = [PowerShell].Assembly.GetTypes() | Where-Object Name -eq 'PSVersionInfo'
$verInfo.GetMethod('get_PSVersion', [System.Reflection.BindingFlags]'NonPublic,Static').Invoke($null, [System.Reflection.BindingFlags]'NonPublic,Static', $null, #(), $null)
Chris
I was wondering if there is an online tool that can convert c# code to powershell cmdlet code. I have following code that i need to have it powershell. I dont have visual studio to turn this into an exe or dll. any help or ideas would be great.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;
namespace CopyUsersBetweenGroupsInSharepointByRR
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("This tool will copy the users from one group to another group");
Console.WriteLine("Please enter the URL of the site where your groups are available");
String siteUrl = Console.ReadLine();
using (SPSite site = new SPSite(siteUrl))
{
try
{
SPWeb web = site.OpenWeb();
Console.WriteLine("Please enter the name of the source group");
String sourceGroupName = Console.ReadLine();
Console.WriteLine("Please enter the name of the destination group");
String destinationGroupName = Console.ReadLine();
SPGroup sourceGroup = web.Groups[sourceGroupName];
SPGroup destinationGroup = web.Groups[destinationGroupName];
SPUserCollection sourceUsers = sourceGroup.Users;
SPUserInfo[] sourceUserInfoArray = new SPUserInfo[sourceUsers.Count];
for (int i = 0; i < sourceUsers.Count; i++)
{
sourceUserInfoArray[i] = new SPUserInfo();
sourceUserInfoArray[i].LoginName = sourceUsers[i].LoginName;
sourceUserInfoArray[i].Name = sourceUsers[i].Name;
}
destinationGroup.Users.AddCollection(sourceUserInfoArray);
destinationGroup.Update();
web.Update();
Console.WriteLine("Operation Completed Successfully");
Console.ReadLine();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
Console.ReadLine();
}
}
}
}
}
It's comments like those above that are turning people away from SO in droves. The OP's question was unambiguous and displayed genuine need.
There are several ways to achieve this. Rewriting your entire C# code repository is not one of them.
As already discussed, as of PS 2 you are able to either run C# (or most any other language) inline, or refer to well-formed external file. I've had mixed success with this and I don't believe it's what the OP was really after.
If you genuinely want to convert code (particularly compiled assemblies) then a decompiler like Reflector is able to do this and - with the PowerShell addon - is also able to convert it on-the-fly.
http://blog.lekman.com/2011/10/converting-c-to-powershell.html
If you want your input and output to take place within the PS console then you'd still have to perform some obvious re-writes. But this method has proved incredibly useful to me.
The fastest way to do it is to write the PowerShell code yourself.
Below is how the code will look in PowerShell, i would say that most C# developers should be able to grasp the concepts of converting C# code to PowerShell in a very short time.
Functions can be a little odd at the beginning, since the usual PS syntax is
myFunction Parameter1 Parameter2
Also you really should install PowerShell 3.0 and use the Windows PowerShell ISE tool to develop the code.
Anyways it should not take you more than 1-2 hours to get your C# code running along in PowerShell.
[System.Reflection.Assembly]::LoadWithPartialName(”Microsoft.SharePoint”)
Write-Host "This tool will copy the users from one group to another group"
Write-Host "Please enter the URL of the site where your groups are available"
[string] $siteUrl = [Console]::ReadLine()
$site = new-object Microsoft.SharePoint.SPSite($siteUrl)
try
{
$web = $site.OpenWeb()
Write-Host "Please enter the name of the source group"
[string] $sourceGroupName = [Console]::ReadLine()
Write-Host "Please enter the name of the destination group"
[string] $destinationGroupName = [Console]::ReadLine()
$sourceUsers = $web.Groups[$sourceGroupName]
(and so on)
}
catch
{
Write-Error ("Failed to copy sharepoint users." + $_)
}
I doubt there is anything remotely like that, however Visual Studio is not required to compile c# code. You could compile an exe without VS. The compiler (csc.exe) and msbuild are included as part of framework. They are located in C:\Windows\Microsoft.NET\Framework\{version}.
If you really want to call this from powershell, have a look at the Add-Type cmdlet. You provide it the source code and it will compile the source on the fly, then load the assembly into your session.
Not sure about online tools, but download the free Visual Studio Express & follow this tutorial should have you creating a cmdlet in no time
I'm try to use Vista TaskDialog Wrapper and Emulator and I'm getting the following exception:
"Unable to find an entry point named 'TaskDialogIndirect' in DLL 'ComCtl32'."
...in a simple Console application:
class Program
{
[STAThread]
static void Main(string[] args)
{
System.Threading.Thread.CurrentThread.CurrentUICulture = System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US");
PSTaskDialog.cTaskDialog.MessageBox(
"MessageBox Title",
"The main instruction text for the message box is shown here.",
"The content text for the message box is shown here and the text willautomatically wrap as needed.",
PSTaskDialog.eTaskDialogButtons.YesNo,
PSTaskDialog.eSysIcons.Information
);
}
}
What am I doing wrong?
UPDATE:
Actually, I'm working on an Excel plugin using excel-dna. How can I control what dll Excel loads?
http://exceldna.codeplex.com/discussions/286990#post728888
I haven't been at Office programming in a while, but my guess is that Excel loads both versions of comctl32, so you may need to use the Activation Context API to direct your code to the version that includes TaskDialog. Some ideas for fixing the problem (not solutions as such):
For test purposes, make a temporary enumeration of all modules in the active process - just to check if 6.10 is actually loaded (see below for a simple example of such an enumeration, albeit with a different intent).
Use the Activation Context API to get to the right version. Example of use from C# (for enabling themes by way of comctl32 6.0) here.
Alternatively (I never actually got this to work reliably in a WPF application I worked on), make a dialog abstraction class, which falls back to MessageDlg depending on the version available to you. There may be better ways of doing the check, but...:
FileVersionInfo version = ProcessUtils.GetLoadedModuleVersion("comctl32.dll");
if (version != null && version.FileMajorPart >= 6 && version.FileMinorPart >= 1)
{
// We can use TaskDialog...
}
else
{
// Use old style MessageBox
}
The enumeration of modules:
internal static FileVersionInfo GetLoadedModuleVersion(string name)
{
Process process = Process.GetCurrentProcess();
foreach (ProcessModule module in process.Modules)
{
if (module.ModuleName.ToLower() == name)
{
return module.FileVersionInfo;
}
return null;
}
}
In addition to what all the others are saying: This error will disappear if you set the ForceEmulationMode on PSTaskDialog to true.
My plan:
I'm trying to setup my C# project to communicate with Nodebox to call a certain function which populates a graph and draws it in a new window.
Current situation: [fixed... see Update2]
I have already included all python-modules needed, but im still getting a
Library 'GL' not found
it seems that the pyglet module needs a reference to GL/gl.h, but can't find it due to IronPython behaviour.
Requirement:
The project needs to stay as small as possible without installing new packages. Thats why i have copied all my modules into the project-folder and would like to keep it that or a similar way.
My question:
Is there a certain workaround for my problem or a fix for the library-folder missmatch.
Have read some articles about Tao-Opengl and OpenTK but can't find a good solution.
Update1:
Updated my sourcecode with a small pyglet window-rendering example. Problem is in pyglet and referenced c-Objects. How do i include them in my c# project to be called? No idea so far... experimenting alittle now. Keeping you updated.
SampleCode C#:
ScriptRuntimeSetup setup = Python.CreateRuntimeSetup(null);
ScriptRuntime runtime = new ScriptRuntime(setup);
ScriptEngine engine = Python.GetEngine(runtime);
ScriptSource source = engine.CreateScriptSourceFromFile("test.py");
ScriptScope scope = engine.CreateScope();
source.Execute(scope);
SampleCode Python (test.py):
from nodebox.graphics import *
from nodebox.graphics.physics import Vector, Boid, Flock, Obstacle
flock = Flock(50, x=-50, y=-50, width=700, height=400)
flock.sight(80)
def draw(canvas):
canvas.clear()
flock.update(separation=0.4, cohesion=0.6, alignment=0.1, teleport=True)
for boid in flock:
push()
translate(boid.x, boid.y)
scale(0.5 + boid.depth)
rotate(boid.heading)
arrow(0, 0, 15)
pop()
canvas.size = 600, 300
def main(canvas):
canvas.run(draw)
Update2:
Line 139 [pyglet/lib.py] sys.platform is not win32... there was the error. Fixed it by just using the line:
from pyglet.gl.lib_wgl import link_GL, link_GLU, link_WGL
Now the following Error:
'module' object has no attribute '_getframe'
Kind of a pain to fix it. Updating with results...
Update3:
Fixed by adding following line right after first line in C#-Code:
setup.Options["Frames"] = true;
Current Problem:
No module named unicodedata, but in Python26/DLLs is only a *.pyd file`. So.. how do i implement it now?!
Update4:
Fixed by surfing: link text and adding unicodedata.py and '.pyd to C# Projectfolder.
Current Problem:
'libGL.so not found'... guys.. im almost giving up on nodebox for C#.. to be continued
Update5:
i gave up :/ workaround: c# communicating with nodebox over xml and filesystemwatchers. Not optimal, but case solved.
-X:Frames enables the frames option as runtime (it slows code down a little to have access to the Python frames all the time).
To enable frames when hosting you just need to do:
ScriptRuntimeSetup setup = Python.CreateRuntimeSetup(new Dictionary<string, object>() {
{ "Frames", true }
});
Instead of the null that you're passing now. That's just creating a new dictionary for the options dictionary w/ the contents "Frames" set to true. You can set other options in there as well and in general the -X:Name option is the same here as it is for the command line.