[IronPython] Komodo .NET intellisense

Brian Quinlan brian at sweetapp.com
Wed Aug 25 07:24:31 PDT 2004


Attached is my script for modifying the ActiveState Komodo intellisense 
database to provide intellisense for Windows forms. The script presumes 
that you've copied

<komodo-dir>\python\Lib\site-packages\codeintel\python.cix TO
<komodo-dir>\python\Lib\site-packages\codeintel\python-orig.cix

Once you've done that, there are three paths that you'll have to change 
near the end of the script. Now run the script.

Now you'll have to delete the Komodo database file (or fix my script to 
provide correct time stamps) from:

C:\Documents and Settings\Brian Quinlan\Application 
Data\ActiveState\Komodo\3.0\<hostname>\codeintel.db

Then launch Komodo and rebuild the Komodo intellisense database (see 
"Preferences...").

Let me know if you need any help or what the prebuilt file (it's half a 
meg compressed so I'm not going to post it to the list).

Cheers,
Brian
-------------- next part --------------
from System.Reflection import Assembly
from System.Xml import XmlImplementation
import time

def intersect_dicts(d1, d2):
    intersect_dict = {}
    for key in [k for k in d1 if k in d2]:
        if d1[key].ParameterType != d2[key].ParameterType:
            print '--> %s %s %s %s' % (d1[key].Name, d1[key].ParameterType, d2[key].Name, d2[key].ParameterType)
        intersect_dict[key] = d1[key]

    return intersect_dict

def difference_dicts(d1, d2):
    diff_dict = {}
    for key in [k for k in d1 if k not in d2]:
        diff_dict[key] = d1[key]
    for key in [k for k in d2 if k not in d1]:
        diff_dict[key] = d2[key]

    return diff_dict

def _build_signature_and_doc(paramlists):
    if len(paramlists) == 0:
        return [], '', ''

    # build a list containing dictionaries where each dictionary
    # represents one signature of an identically named method. The
    # dictionary keys are the argument names and the values of
    # .NET ParamInfo classes
    
    dicts = []
    for params in paramlists:
        dicts.append(dict([(param.Name, param) for param in params]))

    # determine the intersection and difference between these argument
    # lists - the intersection is the "required" paramters and the
    # different is the "optional" parameters. This is only an
    # approximation used because Komodo only supports one signature
    # per method name
    
    intersection_dict = dict(dicts[0])
    difference_dict = {}
    
    for d in dicts:
        # XXX These don't actually seem to get built correctly
        # see MessageBox.Show(
        difference_dict = difference_dicts(intersection_dict, d)
        intersection_dict = intersect_dicts(intersection_dict, d)
        
    def sorted(params):
        params = [(p.Position, p.Name, p) for p in params]
        params.sort()
        return [p[2] for p in params]

    doc = ""
    sig = ""

    for param in sorted(intersection_dict.values()):
        if doc != "":
#            assert sig != ""

            doc = doc + ", "
            sig = sig + ", "

        sig = sig + param.Name
        doc = doc + str(param.ParameterType)

    for param in sorted(difference_dict.values()):
        if doc != "":
 #           assert sig != ""

            doc = doc + ", "
            sig = sig + ", "

        sig = '%s%s?' % (sig, param.Name)
        doc = '%s%s?' % (doc, param.ParameterType)
        
    return intersection_dict.keys(), sig, doc


class MethodInfo(object):
    def __init__(self, methodinfo):
        # XXX need to accept a list of methodinfos with the
        # same .Name
        self.name = methodinfo.Name
        self.args, sig, doc = _build_signature_and_doc(
            [methodinfo.GetParameters()])

        self.doc = "%s(%s)" % (self.name, doc)
        self.signature = "%s(%s)" % (self.name, sig)
        
class ClassInfo(object):
    def __init__(self, typ):
        splitname = typ.FullName.split('.')
        self.name = splitname[-1]
        self.namespace = '.'.join(splitname[:-1])

        constructor_param_lists = []
        for ctors in typ.GetConstructors():
            constructor_param_lists.append(ctors.GetParameters())

        self.args, sig, doc = _build_signature_and_doc(constructor_param_lists)
        
        self.doc = "%s(%s)" % (self.name, doc)
        self.signature = "%s(%s)" % (self.name, sig)
        
        self.methodsinfo = []        
        for method in typ.GetMethods():
            self.methodsinfo.append(MethodInfo(method))
            
def create_namespace_from_assembly(assembly):
    namespace = {}
    types = assembly.GetTypes()
    
    for t in types:    
        cls = ClassInfo(t)
        namespace.setdefault(cls.namespace, []).append(cls)

    return namespace

def create_namespace_from_dll(path):
    create_namespace_from_assembly(
        Assembly.LoadFrom(path))
    
def merge_namespace_lists(ns_lists):
    merged_ns = {}

    for ns in ns_lists:    
        for name, contents in ns.items():
            merged_ns.setdefault(name, []).extend(contents) 

    return merged_ns     

def create_ctor_element(document_node, class_info):
    init_element = document_node.CreateElement('function')

    init_element.SetAttribute('attributes', '__ctor__')
    init_element.SetAttribute('name', '__init__')
    init_element.SetAttribute('signature', class_info.signature)

    doc_element = document_node.CreateElement('doc')
    doc_element.AppendChild(document_node.CreateTextNode('XXX not used'))
    init_element.AppendChild(doc_element)

    return init_element

def create_argument_element(document_node, arg_name):
    arg_element = document_node.CreateElement('argument')
    arg_element.SetAttribute('name', arg_name)
    return arg_element

def append_argument_elements(document_node, node, args):
    for arg in args:
        node.AppendChild(create_argument_element(document_node, arg))
        
def create_method_element(document_node, method_info):
    function_element = document_node.CreateElement('function')

    function_element.SetAttribute('name', method_info.name)
    function_element.SetAttribute('signature', method_info.signature)
    
    doc_element = document_node.CreateElement('doc')
    doc_element.AppendChild(document_node.CreateTextNode(method_info.doc))
    function_element.AppendChild(doc_element)

    append_argument_elements(document_node, function_element, method_info.args)
    return function_element

def create_class_element(document_node, class_info):
    class_element = document_node.CreateElement('class')
    
    class_element.SetAttribute('name', class_info.name)
    doc_element = document_node.CreateElement('doc')
    doc_element.AppendChild(document_node.CreateTextNode(class_info.doc))
    class_element.AppendChild(doc_element)
    append_argument_elements(document_node, class_element, class_info.args)

    class_element.AppendChild(
        create_ctor_element(document_node, class_info))  
    
    for method_info in class_info.methodsinfo:
        class_element.AppendChild(
            create_method_element(document_node, method_info))
        
    return class_element

def create_module_element(document_node, module_name, classes):
    module_element = document_node.CreateElement('module')

    module_element.SetAttribute('name', module_name)
    for c in classes:
        module_element.AppendChild(
            create_class_element(document_node, c))

    return module_element

def modify_and_write_dom(document_node, namespace, path):
    file_node = document_node.SelectSingleNode('//file')

    modules = namespace.keys()
    for module_name, classes in namespace.items():
        file_node.AppendChild(
            create_module_element(document_node, module_name, classes))

        """
        XXX is this needed?
        for childnamespace in [n for n in namespaces if namespace in n]:
            importelement = doc.CreateElement('import')
            moduleelement.AppendChild(importelement)
        
            importelement.SetAttribute('alias', modules[childnamespace][0].name)
            importelement.SetAttribute('line', '1')
            importelement.SetAttribute('module', childnamespace)
        """

    document_node.Save(path)
 
    

document_node = XmlImplementation().CreateDocument()
document_node.Load(r'file://C:\Program%20Files\ActiveState%20Komodo%203.0\python\Lib\site-packages\codeintel\python-orig.cix')
assembly = Assembly.LoadFrom(r'C:/WINDOWS/Microsoft.NET/Framework/v1.0.3705/System.Windows.Forms.dll')
namespace = create_namespace_from_assembly(assembly)
# XXX if you want multible assemblies to be loaded, create namespaces for each
# and then use merge_namespace_lists() [not tested]

modify_and_write_dom(
    document_node,
    namespace,
    r'C:\Program Files\ActiveState Komodo 3.0\python\Lib\site-packages\codeintel\python.cix')


More information about the users-ironpython.com mailing list