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: users-boun...@lists.ironpython.com 
[mailto:users-boun...@lists.ironpython.com] 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
Users@lists.ironpython.com
http://lists.ironpython.com/listinfo.cgi/users-ironpython.com

Reply via email to