[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