views:

340

answers:

3

I am embedding IronPython in a C# program. I understand that I need to call ScriptEngine.SetSearchPaths with a list of search paths so that my Python code can import modules. In particular I have to let it know where the standard library modules are, which in my case are here:

C:\Program Files (x86)\IronPython 2.0.2\Lib

My question is, how can that path be found programatically?

It evidently can be done because the IronPython Console knows about it:

>>> import sys
>>> sys.path
['C:\\Windows\\system32', 'C:\\Program Files (x86)\\IronPython 2.0.2\\Lib', 'C:\\Program Files (x86)\\IronPython 2.0.2', 'C:\\Program Files (x86)\\IronPython 2.0.2\\lib\\site-packages']
+1  A: 

Try looking at:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{80B8E2FB-A8AB-4CBF-836A-B43DE3B3C3F6}\InstallLocation

The GUID should be the same (I think, atleast for the same version of IronPython), so you should be fine there. This'll give you the installation directory, then you can just append @"\Lib"

Matthew Scharley
+1  A: 

ipy.exe calculates this based upon the EXE which started the process:

Assembly entryAssembly = Assembly.GetEntryAssembly();
// Can be null if called from unmanaged code (VS integration scenario)
if (entryAssembly != null) {
    string entry = Path.GetDirectoryName(entryAssembly.Location);
    string lib = Path.Combine(entry, "Lib");
    ...

You could also look at IronPython.dll's location instead:

Assembly entryAssembly = typeof(Hosting.Python).Assembly;
Dino Viehland
I don't think that will work because the IronPython assemblies will be living in my application's folder. That gives me an idea though ... (I will write it up.)
dangph
+1  A: 

A possible solution would be to ship a copy of the Lib folder with your application. I believe that both the IronPython license (Microsoft Public License (Ms-PL)) and the Python license (Python License) will permit this.

Benefits to this plan:

  1. It will be easy for the app to find the Lib folder.

  2. Installation will be easier since there will be one less installer to deal with.

  3. The total size of the installer will be smaller.

  4. If the IronPython assemblies that the app uses are copied locally, then it makes sense to copy Lib too, so that the two won't get out of sync as they might do if the Lib from Program Files were used.

The licenses don't appear to impose any onerous obligations. The Ms-PL does requires that you include a complete copy of the Ms-PL in the distributions, but that is not a big deal.

Edit : I bring code !

The following is what I did.

The Lib folder is copied in the AfterBuild target of my .csproj file. I couldn't work out how to use the built-in MSBuild copy command because everything to do with MSBuild is designed to maximally painful, so I used robocopy instead. (robocopy is the replacement of xcopy; you could used xcopy instead).

<Target Name="AfterBuild">
  <Exec Command="robocopy $(ProjectDir)..\3rdParty\IronPython\IronPython2.0.2\Lib $(OutputPath)IronPython\Lib /E /XD .svn" IgnoreExitCode="true" />
  <Exec Command="copy $(ProjectDir)..\3rdParty\IronPython\IronPython2.0.2\license.* $(OutputPath)IronPython\" />
</Target>

It copies the license files (as required by the license) and it excludes subversion folders (.svn).

The "3rdParty" folder is at the root level of my Visual Studio solution. It's where I keep third party libraries.

I ignore the exit code for robocopy because <Exec> can't deal with robocopy's exit codes. This is not ideal, but I assume that the plain copy in the next line will pick up any problems.

This is how I find the Lib path in code:

var assemblyPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
var libPath = Path.Combine(assemblyPath, @"IronPython\Lib");

To copy Lib in a unit test, do something like this:

[TestMethod()]
[DeploymentItem(@"3rdParty\IronPython\IronPython2.0.2\Lib", @"IronPython\Lib")]
public void MyTest()
{
    // ...
dangph