I started writing up some documentation around this as part of our push to
actually have useful documentation :) Here's the current version of that - if
you have any feedback or additional questions it'd be great to hear to improve
the docs.
1. Implementing new modules in .NET
When creating a new module usually you would just implement it in IronPython
its self. But sometimes you may have requirements that preclude implementing it
in IronPython. These could be due to needing a .NET library which IronPython
cannot fully or easily consume (because it requires attributes, for example),
due to performance, or other reasons. When you run into this road block you
have one of two options.
First, you can simply expose this functionality as a normal .NET library and
allow the user to interact with it through the normal IronPython .NET interop
mechanisms. Alternately you can implement a Python module in your favorite .NET
language. If you're not entirely sure which one to choose you're lucky because
there's not much difference between the two - but in this section we'll cover
how to implement a Python module.
The first thing to do is to create a new project, or open an existing one, and
add a reference to IronPython.dll.
The next step is to define a new class and add an assembly level
PythonModuleAttribute which points at the class giving the module name and
type. After doing this you should have a file which looks like:
C# example:
using System;
using IronPython.Runtime;
[assembly: PythonModule("my_module", typeof(MyModule))]
public static class MyModule {
}
VB.NET example:
Imports System
Imports IronPython.Runtime
<Assembly: PythonModule("my_module", GetType(MyModule))>
Public Module MyModule
End Module
Consuming from Python:
>>> import clr
>>> clr.AddReference('test')
>>> import my_module
>From here you just need to start implementing the functionality of your
>module. You can start to add methods, fields, properties, or types. All the
>member must be static as there will not be an instance of the module created.
Here's an example where we define a method, a property, and a couple of fields.
One of the fields is a literal and the other is a static field. One important
detail to note is that modules are entirely read-only. Even if you implement a
property or a mutable field IronPython will never set a value into the property
or field. Instead the updated field will always be stored in the modules
dictionary.
C# example:
using System;
using IronPython.Runtime;
[assembly: PythonModule("my_module", typeof(MyModule))]
public static class MyModule {
public static void hello_world() {
Console.WriteLine("hello world");
}
public static string foo {
get {
return "foo";
}
}
public const string bar = "bar";
public static readonly string baz = "baz";
}
VB.NET example:
Imports System
Imports IronPython.Runtime
<Assembly: PythonModule("my_module", GetType(MyModule))>
Public Module MyModule
Public Sub hello_world()
Console.WriteLine("Hello World")
End Sub
Public ReadOnly Property foo As String
Get
Return "foo"
End Get
End Property
Public Const bar As String = "bar"
Public ReadOnly baz As String = "baz"
End Module
Consuming from Python:
>>> import clr
>>> clr.AddReference('test')
>>> import my_module
>>> my_module.hello_world()
hello world
>>> my_module.foo
'foo'
>>> my_module.bar
'bar'
>>> my_module.baz
'baz'
1.1. Initialization / Reloading
If your module requires to run specific code to be initialized you can provide
a method marked with SpecialNameAttribute which receives the PythonContext the
module is running in as well as the PythonDictionary where the module members
will live.
This example will make "some_name" available in the module and it will have the
value "Hello World".
C# example:
using System;
using System.Runtime.CompilerServices;
using IronPython.Runtime;
[assembly: PythonModule("my_module", typeof(MyModule))]
public static class MyModule {
[SpecialName]
public static void PerformModuleReload(PythonContext context,
PythonDictionary dict) {
dict["some_name"] = "Hello World";
}
}
VB.NET example:
Imports System
Imports IronPython.Runtime
Imports System.Runtime.CompilerServices
<Assembly: PythonModule("my_module", GetType(MyModule))>
Public Module MyModule
<SpecialName> _
Public Sub PerformModuleReload(ByVal context As PythonContext, ByVal dict
As PythonDictionary)
dict("some_name") = "Hello World"
End Sub
End Module
Consuming from Python:
>>> import clr
>>> clr.AddReference('test')
>>> import my_module
>>> my_module.some_value
'Hello World'
>>>
1.2. Per-Runtime State
Because modules are static classes you need to have somewhere you can store
state for the current IronPython runtime instance. If you were to store it in a
static field this state would bleed between IronPython runtimes in the same app
domain. To accomodate this the PythonContext has a set of APIs which are
specifically designed for storing state for Python modules. These APIs can be
used either in the PerformModuleReload method or in methods which receive
CodeContext as their first parameter. The CodeContext object will automatically
be flowed in and from it you can get the PythonContext from the LanguageContext
property.
C# example:
using System;
using IronPython.Runtime;
[assembly: PythonModule("my_module", typeof(MyModule))]
public static class MyModule {
private static readonly object _stateKey = new object();
public static object get_state(CodeContext context, object value) {
object prev_value = null;
if (context.LanguageContext.HasModuleState(_stateKey)) {
prev_value = context.LanguageContext.GetModuleState(_stateKey);
}
context.LanguageContext.SetModuleState(_stateKey, value);
return prev_value;
}
}
VB.NET example:
Imports System
Imports IronPython.Runtime
<Assembly: PythonModule("my_module", GetType(MyModule))>
Public Module MyModule
dim _stateKey as object = new object()
Public Function get_state(ByVal context As CodeContext, ByVal value As
Object) As Object
Dim moduleState As Object = Nothing
If context.LanguageContext.HasModuleState(MyModule._stateKey) Then
moduleState =
context.LanguageContext.GetModuleState(MyModule._stateKey)
End If
context.LanguageContext.SetModuleState(MyModule._stateKey, value)
Return moduleState
End Function
End Module
Consuming from Python:
>>> import clr
>>> clr.AddReference('test')
>>> from my_module import get_state
>>> get_state(42)
>>> get_state(23)
42
1.2.1. Runtime State API Reference
public object GetModuleState(object key)
Gets per-runtime state used by a module. The module should have a unique key
for each piece of state it needs to store.
public void SetModuleState(object key, object value)
Sets per-runtime state used by a module. The module should have a unique key
for each piece of state it needs to store.
public object GetSetModuleState(object key, object value)
Sets per-runtime state used by a module and returns the previous value. The
module should have a unique key for each piece of state it needs to store.
public T GetOrCreateModuleState<T>(object key, Func<T> value)
Gets the the module state if a value already exists. If one does not exist then
calls the provided delegate to create the new value. The module should have a
unique key for each piece of state it needs to store.
bool HasModuleState(object key)
Checks to see if module state has the current value stored already.
1.3. Deploying Modules
So far in all of the examples we've seen the Python consumer has been required
to call clr.AddReference on the module containing the DLL before it can be
used. Obviously this is less than ideal as it both requires import clr (which
has the side effect of making .NET members available) as well as requiring the
AddReference call itself.
ipy.exe also supports automatically loading modules which have been deployed to
a directory named "DLLs" next to ipy.exe. Therefore once you've finished
developing your module you can copy it over and it will always be available.
From: [email protected]
[mailto:[email protected]] On Behalf Of Slide
Sent: Sunday, November 22, 2009 9:04 PM
To: Discussion of IronPython
Subject: [IronPython] built-in modules
Are there any tutorials on writing modules that appear as built-ins? does it
have to be part of the IronPython.Modules assembly to be loaded correctly?
thanks,
slide
--
slide-o-blog
http://slide-o-blog.blogspot.com/
_______________________________________________
Users mailing list
[email protected]
http://lists.ironpython.com/listinfo.cgi/users-ironpython.com