[IronPython] Need help to port-dynamic class generation code to IP2
เสกสรรค์
sakesun at boonthavorn.com
Sun Apr 20 15:13:20 CEST 2008
Hi,
Unless I simplify my question, I believe there will be a very
little chance
I will get some help. So, here is my renewed question.
I'm now using IronPython to implement service components in an
application
framework (RemObjects DataAbstract, if that matter) The framework
require that
any service component must meet these requirement
1. Extend from their base class.
2. Its constructor cannot contains any arguments
The framework use Attribute that attached to the base class they
provided
to discover all available services and then instantiate it via the
default
constructor
Since IronPython can extend any .NET base class seamlessly, the
#1
requirement is not an issue. However, the generated IronPython
sub-class
will always equipped with constructor with one argument that link
the
static class to its dynamic type. Here come the trouble.
Motivated by my intensive dynamic language preference, I
struggle
with System.Reflection and IronPython source code and came up with
a solution to subclass any python type to a new class that meet the
#2
requirement. The solution is simply use System.Reflection to emit
the clase like this
// C#
class :
{
public static pyType; // dynamictype is UserType or PythonType
public (): base(pyType) // call base constructor with
pyType as argument
{
}
}
Of course, the "pyType" static field will have to be set to its
base-classd
dynamic type prior to it's usage. (Note that "__init__" won't be
called with
this approach.)
This solution work fine for IronPython 1.1 and allow me to keep
my development
progress until recently that I start exploring IronPython 2.0 (due
to memory
leak problem in 1.1)
Porting from 1.0 to 2.0 require changing UserType to PythonType
instead.
After change, the code can emit valid class without error but the
class
cause the system to halt.
I'm not sure whether my working approach in 1.1 is just a
obscure trick
that should never be rely on, or is it just a bug in 2.0. Hope I
can find
the answer here.
Thanks in advance
Here is the complete code to demonstrate the problem:
### demo.py ###
import clr
clr.AddReference('IronPython')
clr.AddReference('System.Data')
from System.Data import DataTable
from System import Array, Type, Reflection
TypeArray = Array[Type]
# initialize global constants & variables
ASSEMBLY_NAME = 'MyDynamicAssembly'
MODULE_NAME = 'DynamicModule'
from System import AppDomain
_domain = AppDomain.CurrentDomain
_assemblyname = Reflection.AssemblyName()
_assemblyname.Name = ASSEMBLY_NAME
_assembly = _domain.DefineDynamicAssembly(_assemblyname,
Reflection.Emit.AssemblyBuilderAccess.Run)
_module = _assembly.DefineDynamicModule(MODULE_NAME)
# I'm usinge DataTable as an example of the class that need to be
extended
class PyDataTable(DataTable):
def show(self):
print 'Extended !'
def define_type(module, name, base):
attrs = Reflection.TypeAttributes.Public |
Reflection.TypeAttributes.Class |
Reflection.TypeAttributes.AutoClass |
Reflection.TypeAttributes.AnsiClass |
Reflection.TypeAttributes.BeforeFieldInit |
Reflection.TypeAttributes.AutoLayout
return module.DefineType(name, attrs, base)
def define_field(t, name, typ):
attrs = Reflection.FieldAttributes.Public |
Reflection.FieldAttributes.Static
return t.DefineField(name, typ, attrs)
def define_constructor(t):
attrs = Reflection.MethodAttributes.Public |
Reflection.MethodAttributes.HideBySig
return t.DefineConstructor(attrs,
Reflection.CallingConventions.Standard, TypeArray([]))
def common_wrap(BaseClass, name, dynamictype):
# // use System.Reflection.Emit to make a class
# // C#
# class :
# {
# public static pyType; // reference to UserType or
PythonType
# public (): base(pyType) // call base constructor
with pyType as argument
# {
# }
# }
global _module
from IronPython.Runtime import Types
dytype = clr.GetClrType(dynamictype)
base = clr.GetClrType(BaseClass)
t = define_type(_module, name, base)
pyType = define_field(t, 'pyType', dytype)
base_ctor = base.GetConstructor(TypeArray([dytype]))
ctor = define_constructor(t)
g = ctor.GetILGenerator()
from System.Reflection.Emit.OpCodes import Ldarg_0, Ldsfld,
Call, Ret
g.Emit(Ldarg_0)
g.Emit(Ldsfld, pyType)
g.Emit(Call, base_ctor)
g.Emit(Ret)
r = clr.GetPythonType(t.CreateType())
r.pyType = BaseClass
return r
def wrap_1(BaseClass, name):
from IronPython.Runtime import Types
return common_wrap(BaseClass, name, Types.UserType)
def wrap_2(BaseClass, name):
from IronPython.Runtime import Types
return common_wrap(BaseClass, name, Types.PythonType)
def wrap(BaseClass, name):
import sys
if 'IronPython 2.0' in sys.version:
return wrap_2(BaseClass, name)
else:
return wrap_1(BaseClass, name)
WrappedPyDataTable = wrap(PyDataTable, 'WrappedPyDataTable')
w = WrappedPyDataTable()
print 'in 2.0 any action perform to "w" will cause system to halt'
w.show()
-------------------------
Msg sent via @Mail Softnix Messaging Server http://www.softnix.co.th
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/ironpython-users/attachments/20080420/305866cb/attachment.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: ask_for_help.py
Type: application/octet-stream
Size: 3218 bytes
Desc: not available
URL: <http://mail.python.org/pipermail/ironpython-users/attachments/20080420/305866cb/attachment.obj>
More information about the Ironpython-users
mailing list