I'm embedding IronPython (2.6.1) in a C# assembly and exposing several objects to scripts which are executed with PythonEngine.ExecuteFile. I expose them either with
scope.SetVariable("SomeObject", new SomeObject())
or
engine.Execute("from MyNamespace import SomeObject", scope)
depending on how the scripts use them. My application assembly is added to the engine with
engine.Runtime.LoadAssembly(Assembly.GetExecutingAssembly())
Now a script can execute help(SomeObject)
and dump the nice little help info(*), however it's incomplete. None of the object's events or properties (public of course) show up and many of the 'built-in' members are missing as well.
Here's the odd part; If I fire up ipy.exe and execute the following:
import sys
sys.path.append('<location of my app>')
import clr
clr.AddReferenceToFile('myapp.exe')
from MyNamespace import SomeObject
help(SomeObject)
I get a different dump, complete with all the missing members!
Why do the two differ?
Bonus question: Assuming I get it working correctly, is it possible to add descriptive text on my CLR objects to the output of help()? Like you can from within the script, on your python-native types? My first guess was the DescriptionAttribute, but that didn't work.
(*) Obviously a final, working script wouldn't do this but it is exceedingly helpful while writing/testing the script.
Answered
Here is a complete console program that illustrates how to import the site which replaces the usless internal help() with the standard python library help().
using System;
using System.Collections.Generic;
using System.Reflection;
using IronPython.Hosting;
using IronPython.Runtime;
using Microsoft.Scripting.Hosting.Providers;
namespace MyApp
{
class Program
{
static void Main(string[] args)
{
// Work around issue w/ pydoc - piping to more doesn't work so instead indicate that we're a dumb terminal
if (Environment.GetEnvironmentVariable("TERM") == null)
Environment.SetEnvironmentVariable("TERM", "dumb");
var engine = Python.CreateEngine();
// Add standard Python library path (is there a better way to do this??)
PythonContext context = HostingHelpers.GetLanguageContext(engine) as PythonContext;
ICollection<string> paths = context.GetSearchPaths();
paths.Add(@"C:\Program Files (x86)\IronPython 2.6\Lib");
context.SetSearchPaths(paths);
// Import site module
engine.ImportModule("site");
engine.Runtime.LoadAssembly(Assembly.GetEntryAssembly());
var scope = engine.CreateScope();
scope.SetVariable("SomeObject", new SomeObject());
engine.Execute("help(SomeObject)", scope);
}
}
/// <summary>
/// Description of SomeObject.
/// </summary>
public class SomeObject
{
/// <summary>
/// Description of SomeProperty.
/// </summary>
public int SomeProperty { get; set; }
/// <summary>
/// Description of SomeMethod.
/// </summary>
public void SomeMethod() { }
/// <summary>
/// Description of SomeEvent.
/// </summary>
public event EventHandler SomeEvent;
}
}