Just beware that if you use this same mechanism to introspect CLR objects, it 
can return member names for static and protected members in addition to the 
public instance members (and attempts to access those members might fail). To 
work around this, I first use reflection to get a list of static or protected 
CLR members and then exclude those member names from the list returned by 
Operations.GetMemberNames(). For Python objects, this doesn't seem to cause any 
complications, since reflection does not know anything about the dynamic 
members.

Doing it that way allows the same code to operate correctly in a heterogeneous 
environment, where some objects might originate from a dynamic scope while 
others originate from a static managed scope.

Example (I am sure there are ways to tighten this up, but it gets the job done):

IEnumerable<string> GetMemberNames(dynamic obj)
{
    // use reflection first so we can exclude anything that will just fail 
under the dynamic context
    var objType = ((object)obj).GetType();
    var staticMembers = objType.GetMembers(BindingFlags.FlattenHierarchy | 
BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
    var privateMembers = objType.GetMembers(BindingFlags.Instance | 
BindingFlags.NonPublic);
    var excludedMembers = staticMembers.Union(privateMembers).Select(member => 
member.Name).OrderBy(name => name).Distinct();

    var langContext = 
HostingHelpers.GetLanguageContext(_scriptService.GetScriptEngine());
    try
    {
        IList<string> members;

        try
        {
            members = langContext.Operations.GetMemberNames(obj);
        }
        catch (AmbiguousMatchException)
        {
            members = langContext.Operations.GetMemberNames((object)obj);
        }

        members = members.Except(excludedMembers).ToList();

        // ... I do some more work here to filter out members that start with 
underbar
        // character or that resolve to types that don't make sense for my 
purposes (events, etc)

        return members;
    }
    catch (Exception)
    {
        return new string[] { };
    }
}


Keith Rome
Senior Consultant and Architect
MCPD-EAD, MCSD, MCDBA, MCTS-WPF, MCTS-TFS, MCTS-WSS
Wintellect | 770.617.4016 | kr...@wintellect.com
www.wintellect.com


-----Original Message-----
From: ironpython-users-bounces+rome=wintellect....@python.org 
[mailto:ironpython-users-bounces+rome=wintellect....@python.org] On Behalf Of 
Hernán Foffani
Sent: Tuesday, September 27, 2011 6:43 AM
Cc: ironpython-users@python.org
Subject: Re: [Ironpython-users] instropection in an embedded engine

You are right. It was the all the Operations thing what I was missing 
altogether, silly me.
Now it all make sense.
Thanks a lot.
 
El 26/09/2011, a las 19:57, Keith Rome escribió:

> If you are just trying to enumerate members of a python object, and possibly 
> invoke them, then wouldn't a LanguageContext's DynamicOperations get the job 
> done? Perhaps I am misunderstanding your objectives though.
> 
> HostingHelpers.GetLanguageContext(ScriptEngine) to get the LanguageContext, 
> and then just use the Operations property from that. This gives you 
> introspection methods for GetMemberNames() and a number of invocation 
> mechanisms. All you need is a reference to an object to inspect and the 
> language engine that owns it (or one that is compatible with it).
> 
> In my implementation of a Watches/Locals/Modules UI for a python debugger, I 
> use that procedure as the basis for routines that populate the inspector 
> grids. Basically, whenever the user reaches a breakpoint via my settrace() 
> hook, I inspect the members of all variables in the current scope and refresh 
> a visual tree (really a grid with indentation), and as they drill down into 
> those objects I just walk down one step further into the data structure. It 
> isn't the fastest thing in the world, but then again it doesn't have to be - 
> the script is effectively paused until I allow the breakpoint to resume.
> 
> 
> Keith Rome
> Senior Consultant and Architect
> MCPD-EAD, MCSD, MCDBA, MCTS-WPF, MCTS-TFS, MCTS-WSS Wintellect | 
> 770.617.4016 | kr...@wintellect.com www.wintellect.com
> 
> 
> -----Original Message-----
> From: ironpython-users-bounces+rome=wintellect....@python.org 
> [mailto:ironpython-users-bounces+rome=wintellect....@python.org] On 
> Behalf Of Hernán Foffani
> Sent: Monday, September 26, 2011 1:36 PM
> To: ironpython-users@python.org
> Subject: Re: [Ironpython-users] instropection in an embedded engine
> 
> Thanks, I'm getting closer.
> Now I'm trying to find how to get a (new? current?) CodeContext to, for 
> instance, call DictProxy.keys(..) The public constructor of CodeContext 
> signature (a PythonDictionary and a ModuleContext) doesn't match the examples 
> I could find (ScriptScope, LanguageContext).
> 
> Does anyone know of any examples of introspection of a hosted IP scripting 
> from C#?
> Evidently there's a lot I'm missing here and would like to do the due 
> homework first.
> 
> I'm using NET 4 and don't need 2.x compatibility.
> 
> Regards,
> -Hernán
> 
> El 23/09/2011, a las 21:43, Dino Viehland escribió:
> 
>> __class__ exists on object in python and is then inherited by the 
>> other types.  When accessing a member from C# you get its view of the world 
>> which doesn't include Python object members.  To get the Python type I 
>> suggest calling DynamicHelpers.GetPythonType.
>> 
>> Sent from my Windows Phone
>> 
>> -----Original Message-----
>> From: Hernán Foffani
>> Sent: Friday, September 23, 2011 9:12 AM
>> To: ironpython-users@python.org
>> Subject: [Ironpython-users] instropection in an embedded engine
>> 
>> 
>> Having the following Python code:
>> 
>>   class Plugin:
>>     def method(self):
>>       pass
>>   plugin = Plugin()
>> 
>> and an embedded ScriptScope instance in my .NET application, the 
>> following C# works fine
>> 
>>  dynamic plugin = pythonEngine.GetVariable("plugin");
>>  var attrs = plugin.__class__.__dict__;
>> 
>> if Plugin python class was defined as an old-style class, but fails 
>> if Plugin inherits from object (__class__ non existent).
>> 
>> Under the VS debugger the dynamic object plugin shows as having three 
>> attributes .class, .dict and .slots_and_weakref (with dots in their
>> names) but no __class__ or __dict__.
>> 
>> I found that I could do something like 
>> plugin.method.im_class.__dict__ but I'd rather stick with the common idiom.
>> 
>> Is it a known issue? Something related to the way I'm using the engine?
>> 
>> Thanks in advance,
>> -Hernán.
>> 
>> _______________________________________________
>> Ironpython-users mailing list
>> Ironpython-users@python.org
>> http://mail.python.org/mailman/listinfo/ironpython-users
>> 
> 
> _______________________________________________
> Ironpython-users mailing list
> Ironpython-users@python.org
> http://mail.python.org/mailman/listinfo/ironpython-users
> 
> 

_______________________________________________
Ironpython-users mailing list
Ironpython-users@python.org
http://mail.python.org/mailman/listinfo/ironpython-users


_______________________________________________
Ironpython-users mailing list
Ironpython-users@python.org
http://mail.python.org/mailman/listinfo/ironpython-users

Reply via email to