[Users] [IronPython] IronPython Attribute Workaround

Stefan Dobrev stefan.dobrev at gmail.com
Tue Jul 24 10:44:42 CEST 2007


Can't a Dependency Injection Framework (Spring.NET or Policy Injection
Application Block from Enterprise Library 3.0) be used for injecting the
required attributes. I'm note sure that this will work. Does anyone had used
them with IronPython previously?

2007/7/24, Tim Riley <riltim at gmail.com>:
>
> Michael:
>
> Earlier today I was doing some digging using Lutz Roeder's .NET
> Reflector and it seems that the CommandMethod attribute registers the
> command using the acmgd.Autodesk.AutoCAD.Runtime.ICommandLineCallable
> interface. As I can tap into any other aspect of AutoCAD's .NET api
> via ironpython I'm going to assume that I can somehow tap into this
> and register a command. The only problem is I don't have a clue
> how...yet.
>
> If you want to take a look at what C# code I have so far you can find
> it @ http://pyacaddotnet.googlecode.com/svn/trunk/PyAcadDotNet.cs
>
> Also I have some (lousy) samples that I use for testing IronPython in
> AutoCAD. You can find them here:
> http://pyacaddotnet.googlecode.com/svn/trunk/Samples/
>
> Tim
>
> On 7/23/07, Michael Foord <fuzzyman at voidspace.org.uk> wrote:
> > I'm pretty sure that it is impossible to dynamically generate classes
> > decorated with attributes at runtime using 'pure C#'.
> >
> > The two alternatives are either to use the Reflection.Emit API - which
> > is probably the best way but requires more digging than I have time for
> > at this point in time.
> >
> > Another alternative is to dynamically generate C# and compile to in
> > memory assemblies. This is less memory efficient because it requires an
> > assembly and type object for every command you wish to add. It is a lot
> > faster than you might expect.
> >
> > Attached are two files. One is 'generate.py'. It has a function called
> > 'Generate' which compiles C# using the CodeDom API with the
> > CSharpCodeProvider.
> >
> > As an example I have provided another file - DllImport.py. This uses
> > Generate to compile the C# from my screenshot example :
> >
> > http://www.voidspace.org.uk/ironpython/winforms/part10.shtml
> >
> > It works fine. :-)
> >
> > The specific call is :
> >
> > assembly = Generate(unmanaged_code, 'UnamangedCode', inMemory=True)
> > clr.AddReference(assembly)
> > from UnmanagedCode import User32, GDI32
> >
> > (You can also use it to save assemblies to disk.)
> >
> > For your use you will need to pass in a list of references (absolute
> > file paths) to the AutoCAD DLLs that your C# code is dependent on.
> >
> > I think you need to generate C# code that looks something like:
> >
> >
> > using Autodesk.AutoCAD.ApplicationServices;
> > using Autodesk.AutoCAD.DatabaseServices;
> > using Autodesk.AutoCAD.EditorInput;
> > using Autodesk.AutoCAD.Runtime;
> >
> > namespace AutoCADStuff
> >
> > {
> >   public class AutoCADStuffBase
> >   {
> >     [CommandMethod("myname")]
> >     public void method
> >     {
> >        _method();
> >     }
> >
> >     public virtual void _method
> >     {
> >        return null;
> >     }
> > }
> >
> > In IronPython you can call 'Generate', then import and subclass
> > AutoCADStuffBase and override '_method':
> >
> > class AutoCADStuff(AutoCADStuffBase):
> >     def _method(self):
> >        some code ...
> >
> > I have used this approach with Silverlight assemblies for creating
> > classes with methods marked with attributes.
> >
> > I hope this helps.
> >
> > Please no one post this code as is - I'll write up and post an article
> > shortly. :-)
> >
> > Michael Foord
> >
> > Michael Foord wrote:
> > > Tim Riley wrote:
> > > [snip..]
> > >
> > >>  AutoCAD's .NET API allows
> > >> you to register a command that is callable from the AutoCAD via a
> CommandMethod attribute[1]. Since IP doesn't support attributes I'd like to
> develop some sort of decorator that would clone the functionality of the
> CommandMethod attribute. So I could execute
> > >> python code like:
> > >>
> > >> @commandmethod("test")
> > >> def tester:
> > >>     print "test worked"
> > >>
> > >> and it would register the test command so  I could call it from the
> > >> command line.
> > >>
> > >>
> > >>
> > >
> > > Right - so you want to dynamically create  methods (or functions) with
> > > attributes. The attribute takes the name that the command will be
> > > exposed with.
> > >
> > > I wonder if AutoCAD even supports these being dynamically created?
> > >
> > > If it does I wonder if we can do it by creating an inner class in C#.
> > > The method marked with the attribute would call down to another method
> > > (marked as virtual) that we can override from IronPython.
> > >
> > > I'm not exactly sure of the C# syntax/semantics for inner classes - (a
> > > class factory) - so I'll have to do some digging. (i.e. will it allow
> us
> > > to set the argument to the attribute at runtime rather than compile
> time
> > > and can we return classes or only instances.)
> > >
> > > AFAIK, attributes are normally bound at compile time rather than
> > > runtime, so using C# to create classes in this way may not work.
> > >
> > > The proper way (*sigh*) is to use the Reflection.Emit API to add
> > > attributes. I've experimented Reflection.Emit - but never got as far
> as
> > > adding attributes dynamically. (You need to 'program in bytecode'
> using
> > > this API - which isn't too bad but has a bit of a learning curve
> > > associated.)
> > >
> > > A *third* approach is to dynamically generate C# and compile to in
> > > memory assemblies (using the CodeDOM API if I remember correctly).
> That
> > > turns out to be surprisingly easy.
> > >
> > > Michael Foord
> > > http://www.voidspace.org.uk/ironpython/index.shtml
> > >
> > >
> > >> [1] As an example:
> > >>
> http://through-the-interface.typepad.com/through_the_interface/2007/07/updating-a-spec.html
> > >>
> > >>
> > >> Tim
> > >>
> > >> On 7/23/07, Michael Foord <fuzzyman at voidspace.org.uk> wrote:
> > >>
> > >>
> > >>> Tim Riley wrote:
> > >>>
> > >>>
> > >>>> Michael:
> > >>>>
> > >>>> Thanks for the reply. However when reading it my eyes glazed over.
> Is
> > >>>> there any way you could provide a simple man like myself with some
> > >>>> example code for me to peruse?
> > >>>>
> > >>>>
> > >>>>
> > >>> What do you want to achieve? Write the IronPython code you would
> like -
> > >>> and I will try and provide a C# stub that you can subclass. (You
> will
> > >>> need a C# compiler - Visual Studio Express C# is probably the most
> > >>> straightforward if you are using Windows.)
> > >>>
> > >>> Michael Foord
> > >>> http://www.voidspace.org.uk/ironpython/index.shtml
> > >>>
> > >>>
> > >>>
> > >>>> Tim
> > >>>>
> > >>>> On 7/23/07, Michael Foord <fuzzyman at voidspace.org.uk> wrote:
> > >>>>
> > >>>>
> > >>>>
> > >>>>> Tim Riley wrote:
> > >>>>>
> > >>>>>
> > >>>>>
> > >>>>>> I know that IronPython doesn't support attributes but does anyone
> know
> > >>>>>> of a workaround that will allow IP code to use them?
> > >>>>>>
> > >>>>>>
> > >>>>>>
> > >>>>>>
> > >>>>> The IronPython team are strangely quiet every time someone asks
> this... ;-)
> > >>>>>
> > >>>>> A lot of people would like an answer to this question. Currently
> the
> > >>>>> only way is to use stub C# classes.
> > >>>>>
> > >>>>> Michael Foord
> > >>>>> http://www.voidspace.org.uk/ironpython/index.shtml
> > >>>>>
> > >>>>>
> > >>>>>
> > >>>>>
> > >>>>>
> > >>>>>> _______________________________________________
> > >>>>>> users mailing list
> > >>>>>> users at lists.ironpython.com
> > >>>>>> http://lists.ironpython.com/listinfo.cgi/users-ironpython.com
> > >>>>>>
> > >>>>>>
> > >>>>>>
> > >>>>>>
> > >>>>>>
> > >>>>> _______________________________________________
> > >>>>> users mailing list
> > >>>>> users at lists.ironpython.com
> > >>>>> http://lists.ironpython.com/listinfo.cgi/users-ironpython.com
> > >>>>>
> > >>>>>
> > >>>>>
> > >>>>>
> > >>>> _______________________________________________
> > >>>> Users mailing list
> > >>>> Users at lists.ironpython.com
> > >>>> http://lists.ironpython.com/listinfo.cgi/users-ironpython.com
> > >>>>
> > >>>>
> > >>>>
> > >>>>
> > >>> _______________________________________________
> > >>> Users mailing list
> > >>> Users at lists.ironpython.com
> > >>> http://lists.ironpython.com/listinfo.cgi/users-ironpython.com
> > >>>
> > >>>
> > >>>
> > >> _______________________________________________
> > >> Users mailing list
> > >> Users at lists.ironpython.com
> > >> http://lists.ironpython.com/listinfo.cgi/users-ironpython.com
> > >>
> > >>
> > >>
> > >
> > > _______________________________________________
> > > Users mailing list
> > > Users at lists.ironpython.com
> > > http://lists.ironpython.com/listinfo.cgi/users-ironpython.com
> > >
> > >
> >
> >
> > import clr
> > clr.AddReference('System.Drawing')
> >
> > from System.Drawing import Bitmap, Image
> >
> > from generate import Generate, LoadAssembly
> >
> >
> > unmanaged_code = """
> > using System;
> > using System.Collections.Generic;
> > using System.Text;
> > using System.Runtime.InteropServices;
> >
> > namespace UnmanagedCode
> > {
> >     public class GDI32
> >     {
> >         [DllImport("GDI32.dll")]
> >         public static extern IntPtr CreateCompatibleDC(IntPtr hdc);
> >
> >         [DllImport("GDI32.dll")]
> >         public static extern IntPtr CreateCompatibleBitmap(IntPtr hdc,
> int nWidth,
> >             int nHeight);
> >
> >         [DllImport("GDI32.dll")]
> >         public static extern IntPtr SelectObject(IntPtr hdc, IntPtr
> hgdiobj);
> >
> >         [DllImport("GDI32.dll")]
> >         public static extern bool BitBlt(IntPtr hdcDest, int nXDest, int
> nYDest,
> >                                          int nWidth, int nHeight, IntPtr
> hdcSrc,
> >                                          int nXSrc, int nYSrc, int
> dwRop);
> >
> >         [DllImport("GDI32.dll")]
> >         public static extern bool DeleteDC(IntPtr hdc);
> >
> >         [DllImport("GDI32.dll")]
> >         public static extern bool DeleteObject(IntPtr hObject);
> >     }
> >
> >     public class User32
> >     {
> >         [DllImport("user32.dll")]
> >         public static extern IntPtr GetDesktopWindow();
> >
> >         [DllImport("user32.dll")]
> >         public static extern IntPtr GetTopWindow(IntPtr hWnd);
> >
> >         [DllImport("user32.dll")]
> >         public static extern IntPtr GetWindow(IntPtr hWnd, uint wCmd);
> >
> >         [DllImport("User32.dll")]
> >         public static extern IntPtr GetWindowDC(IntPtr hWnd);
> >
> >         [DllImport("User32.dll")]
> >         public static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hDC);
> >
> >     }
> > }
> > """
> >
> > assembly = Generate(unmanaged_code, 'UnamangedCode', inMemory=True)
> >
> > clr.AddReference(assembly)
> >
> > from UnmanagedCode import User32, GDI32
> >
> > def ScreenCapture(x, y, width, height):
> >     hdcSrc = User32.GetWindowDC(User32.GetDesktopWindow())
> >     hdcDest = GDI32.CreateCompatibleDC(hdcSrc)
> >     hBitmap = GDI32.CreateCompatibleBitmap(hdcSrc, width, height)
> >     GDI32.SelectObject(hdcDest, hBitmap)
> >
> >     # 0x00CC0020 is the magic number for a copy raster operation
> >     GDI32.BitBlt(hdcDest, 0, 0, width, height, hdcSrc, x, y, 0x00CC0020)
> >     result = Bitmap(Image.FromHbitmap(hBitmap))
> >     User32.ReleaseDC(User32.GetDesktopWindow(), hdcSrc)
> >     GDI32.DeleteDC(hdcDest)
> >     GDI32.DeleteObject(hBitmap)
> >     return result
> >
> > image = ScreenCapture(0, 0, 50, 400)
> > for y in range(image.Height):
> >     row = []
> >     for x in range(image.Width):
> >         color = image.GetPixel(x, y)
> >         value = color.R + color.G + color.B
> >         if value > 384:
> >             row.append(' ')
> >         else:
> >             row.append('X')
> >     print ''.join(row)
> >
> > import clr
> >
> > from System.Environment import CurrentDirectory
> > from System.IO import Path, Directory
> >
> > from System.CodeDom import Compiler
> > from Microsoft.CSharp import CSharpCodeProvider
> >
> >
> > def Generate(code, name, references=None, outputDirectory=None,
> inMemory=False):
> >     CompilerParams = Compiler.CompilerParameters()
> >
> >     if outputDirectory is None:
> >         outputDirectory = Directory.GetCurrentDirectory()
> >     if not inMemory:
> >         CompilerParams.OutputAssembly = Path.Combine(outputDirectory,
> name + ".dll")
> >         CompilerParams.GenerateInMemory = False
> >     else:
> >         CompilerParams.GenerateInMemory = True
> >
> >     CompilerParams.TreatWarningsAsErrors = False
> >     CompilerParams.GenerateExecutable = False
> >     CompilerParams.CompilerOptions = "/optimize"
> >
> >     for reference in references or []:
> >         CompilerParams.ReferencedAssemblies.Add(reference)
> >
> >     provider = CSharpCodeProvider()
> >     compile = provider.CompileAssemblyFromSource(CompilerParams, code)
> >
> >     if compile.Errors.HasErrors:
> >         raise Exception("Compile error: %r" % list(compile.Errors.List))
> >
> >     if inMemory:
> >         return compile.CompiledAssembly
> >     return compile.PathToAssembly
> >
> >
> > def LoadAssembly(name, namespace=None):
> >     clr.AddReference(name)
> >     namespace = __import__(namespace or name)
> >     return namespace
> >
> > _______________________________________________
> > Users mailing list
> > Users at lists.ironpython.com
> > http://lists.ironpython.com/listinfo.cgi/users-ironpython.com
> >
> >
> _______________________________________________
> Users mailing list
> Users at lists.ironpython.com
> http://lists.ironpython.com/listinfo.cgi/users-ironpython.com
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/ironpython-users/attachments/20070724/c1d1f1dd/attachment.html>


More information about the Ironpython-users mailing list