LibreOffice(50)オブジェクトから継承図をたどってメソッド一覧を得る

ラベル: ,

前の関連記事:LibreOffice(49)オブジェクトからサービスとインターフェイスの継承関係辞書を生成


前回の続きで今度はサービス名からその属性、インターフェイス名からその属性とメソッドを得る辞書を作成する関数を作成します。

サービス名からその属性へ変換する辞書を作成する関数


関数の引数はXServiceTypeDescription2インターフェイスをもつXTypeDescription型オブジェクトのタプルにします。
def sa_dic_g(lst_std):  # XServiceTypeDescription2インターフェイスをもつオブジェクトのリストから辞書sa_dicを生成。
    sa_dic = dict()  # 辞書sa_dic、key:サービス名、value:サービスの属性のXTypeDescriptionオブジェクトのタプル。
    for std in lst_std:  # 各サービスについて。
        t_sp = std.Properties  # XPropertyTypeDescriptionインターフェイスをもつオブジェクトのタプルを取得。
        if t_sp:
            sa_dic[std.Name] = t_sp  # 辞書sa_dicの項目を追加。
    return sa_dic  # 生成した辞書sa_dicを返す。
com.sun.star.reflection.XPropertyTypeDescriptionインターフェイスからはgetName()メソッドで属性名、getPropertyTypeDescription()メソッドでcom.sun.star.reflection.XPropertyTypeDescriptionインターフェイスをもつXTypeDescription型オブジェクトが得られるのでそこからgetName()メソッドで属性の型名を得ます。
    # print("\n".join([str(k) for k in zip(sa_dic.keys(), [[j.Name for j in i] for i in sa_dic.values()])]))  # 辞書sa_dicの2次元のvalueを展開してName属性のリストを取得して、keyのリストと組み合わせたリストを生成して各要素を改行文字で結合して出力。
    # print("\n".join([str(k) for k in zip(sa_dic.keys(), [[j.PropertyTypeDescription.Name for j in i] for i in sa_dic.values()])]))  # 辞書sa_dicの2次元のvalueを展開してPropertyTypeDescription.Name属性のリストを取得して、keyのリストと組み合わせたリストを生成して各要素を改行文字で結合して出力。
どうやらUNOIDL entityを返すメソッドはgetが省略できるみたいなので省略しています。
('com.sun.star.document.OfficeDocument', ['AutomaticControlFocus', 'ApplyFormDesignMode', 'RuntimeUID', 'InteropGrabBag'])
('com.sun.star.text.GenericTextDocument', ['CharLocale', 'CharacterCount', 'ParagraphCount', 'WordCount', 'WordSeparator', 'IndexAutoMarkFileURL', 'RecordChanges', 'TwoDigitYear'])
('com.sun.star.document.OfficeDocument', ['boolean', 'boolean', 'string', '[]com.sun.star.beans.PropertyValue'])
('com.sun.star.text.GenericTextDocument', ['com.sun.star.lang.Locale', 'long', 'long', 'long', 'string', 'string', 'boolean', 'short'])
Writerドキュメントのサービスの属性を出力してみるとこのようになります。

インターフェイス名をその属性とメソッドに変換する辞書を生成する関数


関数の引数はXInterfaceTypeDescription2インターフェイスをもつXTypeDescription型オブジェクトのタプルにします。
def im_dic_g(lst_itd):  # XInterfaceTypeDescription2インターフェイスをもつオブジェクトのリストから辞書im_dicを生成。
    im_dic = dict()  # 辞書im_dic、key:インターフェイス名、value:インターフェイスのメソッドのXTypeDescriptionオブジェクトのタプル。
    for itd in lst_itd:  # 各インターフェイスについて
        t_im = itd.Members  # XInterfaceMemberTypeDescription型のオブジェクトのタプルを取得。メンバーがメソッドならXInterfaceMethodTypeDescriptionインターフェイスをもつ、属性ならXInterfaceAttributeTypeDescription2 インターフェイスをもつ。
        if t_im:
            im_dic[itd.Name] = t_im  # 辞書im_dicの項目を追加。 
    return im_dic  # 生成した辞書im_dicを返す。
辞書im_dicのvalueに得られるタプルではインターフェイスの属性ならXInterfaceAttributeTypeDescription2インターフェイスをもつオブジェクト、メソッドならXInterfaceMethodTypeDescriptionをもつオブジェクトが得られます。

いずれもXInterfaceMemberTypeDescriptionインターフェイスももちLibreOffice(46)インターフェイス名からその属性とメソッド名一覧を取得と同様の方法で各情報が取り出せます。
    print("\n".join([str(k) for k in zip(im_dic.keys(), [[j.MemberName for j in i] for i in im_dic.values()])]))  # 辞書im_dicの2次元のvalueを展開してMemberName属性のリストを取得して、keyのリストと組み合わせたリストを生成して各要素を改行文字で結合して出力。
とりあえす名前だけ取り出してみます。
('com.sun.star.style.XStyleFamiliesSupplier', ['getStyleFamilies'])
('com.sun.star.drawing.XDrawPagesSupplier', ['getDrawPages'])
('com.sun.star.lang.XComponent', ['dispose', 'addEventListener', 'removeEventListener'])
('com.sun.star.sheet.XConsolidatable', ['createConsolidationDescriptor', 'consolidate'])
('com.sun.star.frame.XModel', ['attachResource', 'getURL', 'getArgs', 'connectController', 'disconnectController', 'lockControllers', 'unlockControllers', 'hasControllersLocked', 'getCurrentController', 'setCurrentController', 'getCurrentSelection'])
('com.sun.star.sheet.XDocumentAuditing', ['refreshArrows'])
('com.sun.star.sheet.XSpreadsheetDocument', ['getSheets'])
('com.sun.star.document.XLinkTargetSupplier', ['getLinks'])
('com.sun.star.lang.XMultiServiceFactory', ['createInstance', 'createInstanceWithArguments', 'getAvailableServiceNames'])
('com.sun.star.sheet.XCalculatable', ['calculate', 'calculateAll', 'isAutomaticCalculationEnabled', 'enableAutomaticCalculation'])
('com.sun.star.beans.XPropertySet', ['getPropertySetInfo', 'setPropertyValue', 'getPropertyValue', 'addPropertyChangeListener', 'removePropertyChangeListener', 'addVetoableChangeListener', 'removeVetoableChangeListener'])
('com.sun.star.sheet.XGoalSeek', ['seekGoal'])
('com.sun.star.document.XActionLockable', ['isActionLocked', 'addActionLock', 'removeActionLock', 'setActionLocks', 'resetActionLocks'])
('com.sun.star.util.XProtectable', ['protect', 'unprotect', 'isProtected'])
('com.sun.star.util.XNumberFormatsSupplier', ['getNumberFormatSettings', 'getNumberFormats'])
Calcで実行するとこんな感じになります。

Writerで実行するともっといっぱい結果がでてきます。

コーディングが悪いのかオートメーションが遅いのか結果がでてくるまでちょっと時間がかかります。

これで全ての辞書が揃った


lst_desのリストを起点にs_dicとi_dicでオブジェクトがサポートしている全てのサービスとインターフェイスが得られます。

あとはサービスからsa_dicで属性、インターフェイスからim_dicで属性とメソッドが得られるはずです。
from itertools import chain  # 多次元リストを1次元リストに変換するのに使用。
def libreoffice50():
    obj = XSCRIPTCONTEXT.getDocument()  # 調査対象のオブジェクトを取得。old-styleサービスの例。LibreOfficeドキュメントを開いておく必要がある。
    # obj = XSCRIPTCONTEXT.getDesktop().getCurrentFrame().getContainerWindow().getToolkit() # 調査対象のオブジェクトを取得。new-styleサービスの例。
    # obj = XSCRIPTCONTEXT.getComponentContext()  # 調査対象のオブジェクトを取得。サービスがないオブジェクトの例。
    s_omi = {'com.sun.star.uno.XInterface', 'com.sun.star.uno.XWeak', 'com.sun.star.lang.XTypeProvider'}  # 絶対使わなさそうなインターフェイス名の集合。'com.sun.star.uno.XInterface'は必ず指定が必要。
    tdm = XSCRIPTCONTEXT.getComponentContext().getByName('/singletons/com.sun.star.reflection.theTypeDescriptionManager')  # TypeDescriptionManagerをシングルトンでインスタンス化。
    s_dic = dict()  # key:子サービス名、value:親サービスのタプル。
    i_dic = dict()  # key:子インターフェイス名または子サービス名、value:親インターフェイスのタプル。
    if hasattr(obj, "getSupportedServiceNames"):  # hasattr()は属性の有無をチェックするPythonの組み込み関数。
        t_ss = obj.getSupportedServiceNames()  # サポートしているサービス名のタプルを取得。
        if t_ss:  # サポートしているサービスがある場合。
            lst_std = list(map(tdm.getByHierarchicalName, t_ss))  # t_ssの要素のサービス名からXServiceTypeDescription2インターフェイスをもつオブジェクトのリストを取得。
            for std in lst_std:  # 各サービスについて親のサービスを得る。
                t_std = std.getMandatoryServices()+std.getOptionalServices()  # 直に継承しているサービスのXServiceTypeDescription2インターフェイスをもつオブジェクトのタプルを取得。
                if t_std:  # 直に継承しているサービスがあるのなら
                    s_dic[std.Name] = t_std  # 直に継承しているサービスのTypeDescriptionオブジェクトのタプルを子のサービス名をkeyにしてdicに取得。
            lst_des = [j for j in lst_std if j.Name not in [i.Name for i in chain.from_iterable(s_dic.values())]] # オブジェクトから得たサービスのうち、辞書dicのvalueにない(親になっていない)サービス(=末裔)をリストで取得。
            for std in lst_std:  # 各サービスについてインターフェイスを得て、そのインターフェイスについて順次親を得る。
                if std.isSingleInterfaceBased():  # new-style(single-interface–based)サービスのとき
                    t_itd = std.getInterface(),  # サービスがもつインターフェイスをXInterfaceTypeDescription2インターフェイスをもつオブジェクトでタプルにして取得。
                    if t_itd:  # インターフェイスのタプルがあるとき
                        i_dic[std.Name] = t_itd  # サービス名を子、インターフェイスのタプルを親にしてdicに取得。
                        get_interfaces2(t_itd, i_dic, s_omi)  # 親インターフェイスをたどってi_dicの項目を追加する。
                else:  # old-style(accumulation-based)サービスのとき
                    lst_itd = [i for i in std.getMandatoryInterfaces() + std.getOptionalInterfaces() if i.Name not in s_omi]  # o_omiを除いてサービスがもつインターフェイスをXInterfaceTypeDescription2インターフェイスをもつオブジェクトのリストを取得。
                    if lst_itd:  # 親インターフェイスが存在するとき。
                        i_dic[std.Name] = lst_itd  # サービス名を子、インターフェイスのタプルを親にしてdicに取得。
                        get_interfaces2(lst_itd, i_dic, s_omi)  # 親インターフェイスをたどってi_dicの項目を追加する。
            # print([i.Name for i in chain.from_iterable(s_dic.values())])  # 2次元になっている辞書のvalueを1次元に展開し、各要素についてName属性のリストを出力。
            # print("\n".join([str(k) for k in zip(s_dic.keys(), [[j.Name for j in i] for i in s_dic.values()])]))  # s_dicの2次元のvalueを展開してName属性のリストを取得して、keyのリストと組み合わせたリストを生成して各要素を改行文字で結合して出力。
            # print([i.Name for i in lst_des])  # 末裔のリストを出力。
            # print("\n".join([str(k) for k in zip(i_dic.keys(), [[j.Name for j in i] for i in i_dic.values()])]))  # i_dicの2次元のvalueを展開してName属性のリストを取得して、keyのリストと組み合わせたリストを生成して各要素を改行文字で結合して出力。
            sa_dic = sa_dic_g(lst_std)  # サポートするサービスのリストを元に辞書sa_dicを生成。key:サービス名、value:サービスの属性のXTypeDescriptionオブジェクトのタプル。
            im_dic = im_dic_g(chain.from_iterable(i_dic.values()))  # 辞書i_dicのvalueのインターフェイスのタプルを展開してイテレーターのまま渡して辞書im_dicを生成。key:インターフェイス名、value:インターフェイスのメソッドのXTypeDescriptionオブジェクトのタプル。
    else:  # サポートしているサービスがないときはインターフェイス名一覧を得る。
        if hasattr(obj, "getTypes"):
            lst_si = [i.typeName for i in obj.getTypes()]  # インターフェイス名のリストを取得。<Type instance インターフェイス名 (<uno.Enum com.sun.star.uno.TypeClass ('INTERFACE')>)>、といったものが返ってきますが型不明。
            s_si = set(lst_si)  # インターフェイス名一覧を集合型に変換。
            lst_des = s_si.intersection(s_si ^ s_omi)  # 絶対使わなさそうなインターフェイス名を除いてインターフェイス名(=末裔)をリストで取得。
            lst_des = list(map(tdm.getByHierarchicalName, lst_des))  # lst_siの要素のインターフェイス名からXInterfaceTypeDescription2インターフェイスをもつオブジェクトのリストを取得。
            if lst_des:  # インターフェイスのタプルがあるとき
                get_interfaces2(lst_des, i_dic, s_omi)  # 親インターフェイスをたどってi_dicの項目を追加する。
            # print([i.Name for i in lst_des])  # 末裔のリストを出力。
            # print("\n".join([str(k) for k in zip(i_dic.keys(), [[j.Name for j in i] for i in i_dic.values()])]))  # i_dicの2次元のvalueを展開してName属性のリストを取得して、keyのリストと組み合わせたリストを生成して各要素を改行文字で結合して出力。
            lst_itd = lst_des + list(chain.from_iterable(i_dic.values()))  #  サポートするインターフェイスのリストと辞書i_dicのvalueのインターフェイスのタプルを展開したリストを結合。
            im_dic = im_dic_g(lst_itd)  # 辞書im_dicを生成。key:インターフェイス名、value:インターフェイスのメソッドのXTypeDescriptionオブジェクトのタプル。
    # print("\n".join([str(k) for k in zip(im_dic.keys(), [[j.MemberName for j in i] for i in im_dic.values()])]))  # 辞書im_dicの2次元のvalueを展開してMemberName属性のリストを取得して、keyのリストと組み合わせたリストを生成して各要素を改行文字で結合して出力。
    # print("\n".join([str(k) for k in zip(sa_dic.keys(), [[j.Name for j in i] for i in sa_dic.values()])]))  # 辞書sa_dicの2次元のvalueを展開してName属性のリストを取得して、keyのリストと組み合わせたリストを生成して各要素を改行文字で結合して出力。
    # print("\n".join([str(k) for k in zip(sa_dic.keys(), [[j.PropertyTypeDescription.Name for j in i] for i in sa_dic.values()])]))  # 辞書sa_dicの2次元のvalueを展開してPropertyTypeDescription.Name属性のリストを取得して、keyのリストと組み合わせたリストを生成して各要素を改行文字で結合して出力。
def get_interfaces2(t_itd, i_dic, s_omi):  # 親インターフェイスをs_omiにあるインターフェイスの手前まで取得する。
    u = get_interfaces(t_itd, i_dic, s_omi)  # インターフェイスのリストからさらに親のインターフェイスのタプルをdicに得る。戻り値は追加されたインターフェイスのタプルのリスト。
    while u:  # dicに新たに追加された値がある間は実行。
        for t_itd in u:  # 新たに追加されたTypeDescriptionオブジェクトのタプルについて。
            u = get_interfaces(t_itd, i_dic, s_omi) # インターフェイスのタプルからさらに親のインターフェイスのタプルをdicに得る。
def get_interfaces(t_itd, i_dic, s_omi):  # 辞書i_dicにkey:子インターフェイス名、value:親インターフェイスのリストを追加。
    v = list()  # 新たに追加になったdicのvalue(インターフェイスのタプル)を入れるリスト。
    for itd in t_itd:  # 各インターフェイスについて親のインターフェイスを得る。
        lst_itd = [i for i in itd.getBaseTypes()+itd.getOptionalBaseTypes() if i.Name not in s_omi]  # o_omiを除くインターフェイスのリストを取得。
        if lst_itd:  # 親インターフェイスのリストがあるとき
            i_dic[itd.Name] = lst_itd # インターフェイス名を子にして親のインターフェイスのタプルをdicに取得。
            v.append(i_dic[itd.Name])  # dicに新たに追加したインターフェイスのタプルをリストuに追加。
    return v  # vを戻り値で返す。
def sa_dic_g(lst_std):  # XServiceTypeDescription2インターフェイスをもつオブジェクトのリストから辞書sa_dicを生成。
    sa_dic = dict()  # 辞書sa_dic、key:サービス名、value:サービスの属性のXTypeDescriptionオブジェクトのタプル。
    for std in lst_std:  # 各サービスについて。
        t_sp = std.Properties  # XPropertyTypeDescriptionインターフェイスをもつオブジェクトのタプルを取得。
        if t_sp:
            sa_dic[std.Name] = t_sp  # 辞書sa_dicの項目を追加。
    return sa_dic  # 生成した辞書sa_dicを返す。
def im_dic_g(lst_itd):  # XInterfaceTypeDescription2インターフェイスをもつオブジェクトのリストから辞書im_dicを生成。
    im_dic = dict()  # 辞書im_dic、key:インターフェイス名、value:インターフェイスのメソッドのXTypeDescriptionオブジェクトのタプル。
    for itd in lst_itd:  # 各インターフェイスについて
        t_im = itd.Members  # XInterfaceMemberTypeDescription型のオブジェクトのタプルを取得。メンバーがメソッドならXInterfaceMethodTypeDescriptionインターフェイスをもつ、属性ならXInterfaceAttributeTypeDescription2 インターフェイスをもつ。
        if t_im:
            im_dic[itd.Name] = t_im  # 辞書im_dicの項目を追加。 
    return im_dic  # 生成した辞書im_dicを返す。
if __name__ == "__main__":
    import unopy
    XSCRIPTCONTEXT = unopy.connect()
    if not XSCRIPTCONTEXT:
        print("Failed to connect.")
        import sys
        sys.exit(0)
    libreoffice50()
無駄にループしているところなど見つけたので改善したのが下記。
from itertools import chain  # 多次元リストを1次元リストに変換するのに使用。
def libreoffice50():
    obj = XSCRIPTCONTEXT.getDocument()  # 調査対象のオブジェクトを取得。old-styleサービスの例。LibreOfficeドキュメントを開いておく必要がある。
    # obj = XSCRIPTCONTEXT.getDesktop().getCurrentFrame().getContainerWindow().getToolkit() # 調査対象のオブジェクトを取得。new-styleサービスの例。
    # obj = XSCRIPTCONTEXT.getComponentContext()  # 調査対象のオブジェクトを取得。サービスがないオブジェクトの例。
    s_omi = {'com.sun.star.uno.XInterface', 'com.sun.star.uno.XWeak', 'com.sun.star.lang.XTypeProvider'}  # 結果を出力しないインターフェイス名の集合。'com.sun.star.uno.XInterface'は必ず指定が必要。
    tdm = XSCRIPTCONTEXT.getComponentContext().getByName('/singletons/com.sun.star.reflection.theTypeDescriptionManager')  # TypeDescriptionManagerをシングルトンでインスタンス化。
    s_dic = dict()  # key:子サービス名、value:親サービスのタプル。
    i_dic = dict()  # key:子インターフェイス名または子サービス名、value:親インターフェイスのタプル。
    if hasattr(obj, "getSupportedServiceNames"):  # hasattr()は属性の有無をチェックするPythonの組み込み関数。
        t_ss = obj.getSupportedServiceNames()  # サポートしているサービス名のタプルを取得。
        if t_ss:  # サポートしているサービスがある場合。
            lst_std = list(map(tdm.getByHierarchicalName, t_ss))  # t_ssの要素のサービス名からXServiceTypeDescription2インターフェイスをもつオブジェクトのリストを取得。
            for std in lst_std:  # 各サービスについて親のサービスを得る。
                t_std = std.getMandatoryServices()+std.getOptionalServices()  # 直に継承しているサービスのXServiceTypeDescription2インターフェイスをもつオブジェクトのタプルを取得。
                if t_std:  # 直に継承しているサービスがあるのなら
                    s_dic[std.Name] = t_std  # 直に継承しているサービスのTypeDescriptionオブジェクトのタプルを子のサービス名をkeyにしてdicに取得。
                if std.isSingleInterfaceBased():  # new-style(single-interface–based)サービスのとき
                    lst_itd = [std.getInterface()]  # サービスがもつインターフェイスをXInterfaceTypeDescription2インターフェイスをもつオブジェクトでリストにして取得。
                else:  # old-style(accumulation-based)サービスのとき
                    lst_itd = [i for i in std.getMandatoryInterfaces() + std.getOptionalInterfaces() if i.Name not in s_omi]  # o_omiを除いてサービスがもつインターフェイスをXInterfaceTypeDescription2インターフェイスをもつオブジェクトのリストを取得。
                if lst_itd:  # 親インターフェイスが存在するとき。
                    i_dic[std.Name] = lst_itd  # サービス名を子、インターフェイスのタプルを親にしてdicに取得。
                    get_interfaces2(lst_itd, i_dic, s_omi)  # 親インターフェイスをたどってi_dicの項目を追加する。
            lst_des = [j for j in lst_std if j.Name not in [i.Name for i in chain.from_iterable(s_dic.values())]] # オブジェクトから得たサービスのうち、辞書dicのvalueにない(親になっていない)サービス(=末裔)をリストで取得。
            sa_dic = sa_dic_g(lst_std)  # サポートするサービスのリストを元に辞書sa_dicを生成。key:サービス名、value:サービスの属性のXTypeDescriptionオブジェクトのタプル。
            lst_itd = chain.from_iterable(i_dic.values())  # 辞書i_dicのvalueのインターフェイスのタプルを展開してイテレーターのまま取得。
    else:  # サポートしているサービスがないときはインターフェイス名一覧を得る。
        if hasattr(obj, "getTypes"):
            lst_si = [i.typeName for i in obj.getTypes()]  # インターフェイス名のリストを取得。<Type instance インターフェイス名 (<uno.Enum com.sun.star.uno.TypeClass ('INTERFACE')>)>、といったものが返ってきますが型不明。
            if lst_si:  # サポートしているインターフェイスがあるとき。
                s_si = set(lst_si)  # インターフェイス名一覧を集合型に変換。
                lst_des = s_si.intersection(s_si ^ s_omi)  # s_omiのインターフェイス名を除いてインターフェイス名(=末裔)をリストで取得。
                if lst_des:  # 残ったインターフェイスのリストがあるとき
                    lst_des = list(map(tdm.getByHierarchicalName, lst_des))  # lst_siの要素のインターフェイス名からXInterfaceTypeDescription2インターフェイスをもつオブジェクトのリストを取得。
                    get_interfaces2(lst_des, i_dic, s_omi)  # 親インターフェイスをたどってi_dicの項目を追加する。
                    lst_itd = lst_des + list(chain.from_iterable(i_dic.values()))  #  サポートするインターフェイスのリストと辞書i_dicのvalueのインターフェイスのタプルを展開したリストを結合。
    if lst_itd:  # オブジェクトの全てのインターフェイスのリストがあるとき。
        im_dic = im_dic_g(lst_itd)  # 辞書im_dicを生成。key:インターフェイス名、value:インターフェイスのメソッドのXTypeDescriptionオブジェクトのタプル。
    # print([i.Name for i in chain.from_iterable(s_dic.values())])  # 2次元になっている辞書のvalueを1次元に展開し、各要素についてName属性のリストを出力。
    # print("\n".join([str(k) for k in zip(s_dic.keys(), [[j.Name for j in i] for i in s_dic.values()])]))  # s_dicの2次元のvalueを展開してName属性のリストを取得して、keyのリストと組み合わせたリストを生成して各要素を改行文字で結合して出力。
    # print("\n".join([str(k) for k in zip(i_dic.keys(), [[j.Name for j in i] for i in i_dic.values()])]))  # i_dicの2次元のvalueを展開してName属性のリストを取得して、keyのリストと組み合わせたリストを生成して各要素を改行文字で結合して出力。
    # print([i.Name for i in lst_des])  # 末裔のリストを出力。
    # print("\n".join([str(k) for k in zip(im_dic.keys(), [[j.MemberName for j in i] for i in im_dic.values()])]))  # 辞書im_dicの2次元のvalueを展開してMemberName属性のリストを取得して、keyのリストと組み合わせたリストを生成して各要素を改行文字で結合して出力。
    # print("\n".join([str(k) for k in zip(sa_dic.keys(), [[j.Name for j in i] for i in sa_dic.values()])]))  # 辞書sa_dicの2次元のvalueを展開してName属性のリストを取得して、keyのリストと組み合わせたリストを生成して各要素を改行文字で結合して出力。
    # print("\n".join([str(k) for k in zip(sa_dic.keys(), [[j.PropertyTypeDescription.Name for j in i] for i in sa_dic.values()])]))  # 辞書sa_dicの2次元のvalueを展開してPropertyTypeDescription.Name属性のリストを取得して、keyのリストと組み合わせたリストを生成して各要素を改行文字で結合して出力。
def get_interfaces2(t_itd, i_dic, s_omi):  # 親インターフェイスをs_omiにあるインターフェイスの手前まで取得する。
    u = get_interfaces(t_itd, i_dic, s_omi)  # インターフェイスのリストからさらに親のインターフェイスのタプルをdicに得る。戻り値は追加されたインターフェイスのタプルのリスト。
    while u:  # dicに新たに追加された値がある間は実行。
        for t_itd in u:  # 新たに追加されたTypeDescriptionオブジェクトのタプルについて。
            u = get_interfaces(t_itd, i_dic, s_omi) # インターフェイスのタプルからさらに親のインターフェイスのタプルをdicに得る。
def get_interfaces(t_itd, i_dic, s_omi):  # 辞書i_dicにkey:子インターフェイス名、value:親インターフェイスのリストを追加。
    v = list()  # 新たに追加になったdicのvalue(インターフェイスのタプル)を入れるリスト。
    for itd in t_itd:  # 各インターフェイスについて親のインターフェイスを得る。
        lst_itd = [i for i in itd.getBaseTypes()+itd.getOptionalBaseTypes() if i.Name not in s_omi]  # o_omiを除くインターフェイスのリストを取得。
        if lst_itd:  # 親インターフェイスのリストがあるとき
            i_dic[itd.Name] = lst_itd # インターフェイス名を子にして親のインターフェイスのタプルをdicに取得。
            v.append(i_dic[itd.Name])  # dicに新たに追加したインターフェイスのタプルをリストuに追加。
    return v  # vを戻り値で返す。
def sa_dic_g(lst_std):  # XServiceTypeDescription2インターフェイスをもつオブジェクトのリストから辞書sa_dicを生成。
    sa_dic = dict()  # 辞書sa_dic、key:サービス名、value:サービスの属性のXTypeDescriptionオブジェクトのタプル。
    for std in lst_std:  # 各サービスについて。
        t_sp = std.Properties  # XPropertyTypeDescriptionインターフェイスをもつオブジェクトのタプルを取得。
        if t_sp:
            sa_dic[std.Name] = t_sp  # 辞書sa_dicの項目を追加。
    return sa_dic  # 生成した辞書sa_dicを返す。
def im_dic_g(lst_itd):  # XInterfaceTypeDescription2インターフェイスをもつオブジェクトのリストから辞書im_dicを生成。
    im_dic = dict()  # 辞書im_dic、key:インターフェイス名、value:インターフェイスのメソッドのXTypeDescriptionオブジェクトのタプル。
    for itd in lst_itd:  # 各インターフェイスについて
        t_im = itd.Members  # XInterfaceMemberTypeDescription型のオブジェクトのタプルを取得。メンバーがメソッドならXInterfaceMethodTypeDescriptionインターフェイスをもつ、属性ならXInterfaceAttributeTypeDescription2 インターフェイスをもつ。
        if t_im:
            im_dic[itd.Name] = t_im  # 辞書im_dicの項目を追加。 
    return im_dic  # 生成した辞書im_dicを返す。
if __name__ == "__main__":
    import unopy
    XSCRIPTCONTEXT = unopy.connect()
    if not XSCRIPTCONTEXT:
        print("Failed to connect.")
        import sys
        sys.exit(0)
    libreoffice50()

多重ループの内包表記は一番内側の中身を先頭にもってくるだけ


リストの内包表記を使っても2次元配列にしか展開できなかったので上ではitertools.chain(*iterables)を使いました。

Pythonでリストの内包表記を使って2次元リストを1次元リストにする - こんにちはこんにちはmonmonです!

これを読んでリストの内包表記だけで辞書のvalueのリストを展開する方法がわかりました。
 内包表記の中に for や if が複数回現れる場合、左側の for, if が、内包表記ではなくループで書いた場合の外側のブロックになります。
5. データ構造 — Python 2.7ja1 documentation
Python2.7ja1ドキュメントにはこう書いてありますね。
>>> # flatten a list using a listcomp with two 'for'
>>> vec = [[1,2,3], [4,5,6], [7,8,9]]
>>> [num for elem in vec for num in elem]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
5. データ構造 — Python 3.3.3 ドキュメント
Python3.3.3ドキュメントにも例が載っていますがよくわからなかったのですよね。

for文を書いたときの一番内側に来るものを一番最初にもってくればそれが内包表記になるようです。
            lst_des = [j for j in lst_std if j.Name not in [i.Name for i in chain.from_iterable(s_dic.values())]] # オブジェクトから得たサービスのうち、辞書dicのvalueにない(親になっていない)サービス(=末裔)をリストで取得。
これの[i.Name for i in chain.from_iterable(s_dic.values())]をリストの内包表記だけを使って書き換えます。 辞書s_dicのvalueにはタプルが入っていますのでs_dic.values()はタプルのリストが返ってきます。
for i in s_dic.values():
    for j in i:
        j.Name
普通にfor文を書けばこうやって展開すればよいので先頭に一番内側のループのj.Nameをもってきてあとはコロンをはずして全部一行にくっつければよいわけです。
[j.Name for i in s_dic.values() for j in i]
これで同じ結果が得られました。
[[j.Name for j in i] for i in s_dic.values()]
私は最初こういう2次元のリストにする方法しか思いつかなくてitertools.chain(*iterables)を使っていました。

これだと2次元のリストが返ってきてしまいます。
def libreoffice50():
    obj = XSCRIPTCONTEXT.getDocument()  # 調査対象のオブジェクトを取得。old-styleサービスの例。LibreOfficeドキュメントを開いておく必要がある。
    # obj = XSCRIPTCONTEXT.getDesktop().getCurrentFrame().getContainerWindow().getToolkit() # 調査対象のオブジェクトを取得。new-styleサービスの例。
    # obj = XSCRIPTCONTEXT.getComponentContext()  # 調査対象のオブジェクトを取得。サービスがないオブジェクトの例。
    s_omi = {'com.sun.star.uno.XInterface', 'com.sun.star.uno.XWeak', 'com.sun.star.lang.XTypeProvider'}  # 結果を出力しないインターフェイス名の集合。'com.sun.star.uno.XInterface'は必ず指定が必要。
    tdm = XSCRIPTCONTEXT.getComponentContext().getByName('/singletons/com.sun.star.reflection.theTypeDescriptionManager')  # TypeDescriptionManagerをシングルトンでインスタンス化。
    s_dic = dict()  # key:子サービス名、value:親サービスのタプル。
    i_dic = dict()  # key:子インターフェイス名または子サービス名、value:親インターフェイスのタプル。
    if hasattr(obj, "getSupportedServiceNames"):  # hasattr()は属性の有無をチェックするPythonの組み込み関数。
        t_ss = obj.getSupportedServiceNames()  # サポートしているサービス名のタプルを取得。
        if t_ss:  # サポートしているサービスがある場合。
            lst_std = list(map(tdm.getByHierarchicalName, t_ss))  # t_ssの要素のサービス名からXServiceTypeDescription2インターフェイスをもつオブジェクトのリストを取得。
            for std in lst_std:  # 各サービスについて親のサービスを得る。
                t_std = std.getMandatoryServices()+std.getOptionalServices()  # 直に継承しているサービスのXServiceTypeDescription2インターフェイスをもつオブジェクトのタプルを取得。
                if t_std:  # 直に継承しているサービスがあるのなら
                    s_dic[std.Name] = t_std  # 直に継承しているサービスのTypeDescriptionオブジェクトのタプルを子のサービス名をkeyにしてdicに取得。
                if std.isSingleInterfaceBased():  # new-style(single-interface–based)サービスのとき
                    lst_itd = [std.getInterface()]  # サービスがもつインターフェイスをXInterfaceTypeDescription2インターフェイスをもつオブジェクトでリストにして取得。
                else:  # old-style(accumulation-based)サービスのとき
                    lst_itd = [i for i in std.getMandatoryInterfaces() + std.getOptionalInterfaces() if i.Name not in s_omi]  # o_omiを除いてサービスがもつインターフェイスをXInterfaceTypeDescription2インターフェイスをもつオブジェクトのリストを取得。
                if lst_itd:  # 親インターフェイスが存在するとき。
                    i_dic[std.Name] = lst_itd  # サービス名を子、インターフェイスのタプルを親にしてdicに取得。
                    get_interfaces2(lst_itd, i_dic, s_omi)  # 親インターフェイスをたどってi_dicの項目を追加する。
            lst_des = [j for j in lst_std if j.Name not in [j.Name for i in s_dic.values() for j in i]] # オブジェクトから得たサービスのうち、辞書dicのvalueにない(親になっていない)サービス(=末裔)をリストで取得。
            sa_dic = sa_dic_g(lst_std)  # サポートするサービスのリストを元に辞書sa_dicを生成。key:サービス名、value:サービスの属性のXTypeDescriptionオブジェクトのタプル。
            lst_itd = [j for i in i_dic.values() for j in i]  # 辞書i_dicのvalueのインターフェイスのタプルを展開して取得。
            # print([j.Name for i in s_dic.values() for j in i])  # 2次元になっている辞書のvalueを1次元に展開し、各要素についてName属性のリストを出力。
            # print("\n".join([str(k) for k in zip(s_dic.keys(), [[j.Name for j in i]for i in s_dic.values()])]))  # s_dicの2次元のvalueを展開してName属性のリストを取得して、keyのリストと組み合わせたリストを生成して各要素を改行文字で結合して出力。
    else:  # サポートしているサービスがないときはインターフェイス名一覧を得る。
        if hasattr(obj, "getTypes"):
            lst_si = [i.typeName for i in obj.getTypes()]  # インターフェイス名のリストを取得。<Type instance インターフェイス名 (<uno.Enum com.sun.star.uno.TypeClass ('INTERFACE')>)>、といったものが返ってきますが型不明。
            if lst_si:  # サポートしているインターフェイスがあるとき。
                s_si = set(lst_si)  # インターフェイス名一覧を集合型に変換。
                lst_des = s_si.intersection(s_si ^ s_omi)  # s_omiのインターフェイス名を除いてインターフェイス名(=末裔)をリストで取得。
                if lst_des:  # 残ったインターフェイスのリストがあるとき
                    lst_des = list(map(tdm.getByHierarchicalName, lst_des))  # lst_siの要素のインターフェイス名からXInterfaceTypeDescription2インターフェイスをもつオブジェクトのリストを取得。
                    get_interfaces2(lst_des, i_dic, s_omi)  # 親インターフェイスをたどってi_dicの項目を追加する。
                    lst_itd = lst_des + [j for i in i_dic.values() for j in i]  #  サポートするインターフェイスのリストと辞書i_dicのvalueのインターフェイスのタプルを展開したリストを結合。
    if lst_itd:  # オブジェクトの全てのインターフェイスのリストがあるとき。
        im_dic = im_dic_g(lst_itd)  # 辞書im_dicを生成。key:インターフェイス名、value:インターフェイスのメソッドのXTypeDescriptionオブジェクトのタプル。
    # print("\n".join([str(k) for k in zip(i_dic.keys(), [[j.Name for j in i] for i in i_dic.values()])]))  # i_dicの2次元のvalueを展開してName属性のリストを取得して、keyのリストと組み合わせたリストを生成して各要素を改行文字で結合して出力。
    # print([i.Name for i in lst_des])  # 末裔のリストを出力。
    # print("\n".join([str(k) for k in zip(im_dic.keys(), [[j.MemberName for j in i] for i in im_dic.values()])]))  # 辞書im_dicの2次元のvalueを展開してMemberName属性のリストを取得して、keyのリストと組み合わせたリストを生成して各要素を改行文字で結合して出力。
    # print("\n".join([str(k) for k in zip(sa_dic.keys(), [[j.Name for j in i] for i in sa_dic.values()])]))  # 辞書sa_dicの2次元のvalueを展開してName属性のリストを取得して、keyのリストと組み合わせたリストを生成して各要素を改行文字で結合して出力。
    # print("\n".join([str(k) for k in zip(sa_dic.keys(), [[j.PropertyTypeDescription.Name for j in i] for i in sa_dic.values()])]))  # 辞書sa_dicの2次元のvalueを展開してPropertyTypeDescription.Name属性のリストを取得して、keyのリストと組み合わせたリストを生成して各要素を改行文字で結合して出力。
def get_interfaces2(t_itd, i_dic, s_omi):  # 親インターフェイスをs_omiにあるインターフェイスの手前まで取得する。
    u = get_interfaces(t_itd, i_dic, s_omi)  # インターフェイスのリストからさらに親のインターフェイスのタプルをdicに得る。戻り値は追加されたインターフェイスのタプルのリスト。
    while u:  # dicに新たに追加された値がある間は実行。
        for t_itd in u:  # 新たに追加されたTypeDescriptionオブジェクトのタプルについて。
            u = get_interfaces(t_itd, i_dic, s_omi) # インターフェイスのタプルからさらに親のインターフェイスのタプルをdicに得る。
def get_interfaces(t_itd, i_dic, s_omi):  # 辞書i_dicにkey:子インターフェイス名、value:親インターフェイスのリストを追加。
    v = list()  # 新たに追加になったdicのvalue(インターフェイスのタプル)を入れるリスト。
    for itd in t_itd:  # 各インターフェイスについて親のインターフェイスを得る。
        lst_itd = [i for i in itd.getBaseTypes()+itd.getOptionalBaseTypes() if i.Name not in s_omi]  # o_omiを除くインターフェイスのリストを取得。
        if lst_itd:  # 親インターフェイスのリストがあるとき
            i_dic[itd.Name] = lst_itd # インターフェイス名を子にして親のインターフェイスのタプルをdicに取得。
            v.append(i_dic[itd.Name])  # dicに新たに追加したインターフェイスのタプルをリストuに追加。
    return v  # vを戻り値で返す。
def sa_dic_g(lst_std):  # XServiceTypeDescription2インターフェイスをもつオブジェクトのリストから辞書sa_dicを生成。
    sa_dic = dict()  # 辞書sa_dic、key:サービス名、value:サービスの属性のXTypeDescriptionオブジェクトのタプル。
    for std in lst_std:  # 各サービスについて。
        t_sp = std.Properties  # XPropertyTypeDescriptionインターフェイスをもつオブジェクトのタプルを取得。
        if t_sp:
            sa_dic[std.Name] = t_sp  # 辞書sa_dicの項目を追加。
    return sa_dic  # 生成した辞書sa_dicを返す。
def im_dic_g(lst_itd):  # XInterfaceTypeDescription2インターフェイスをもつオブジェクトのリストから辞書im_dicを生成。
    im_dic = dict()  # 辞書im_dic、key:インターフェイス名、value:インターフェイスのメソッドのXTypeDescriptionオブジェクトのタプル。
    for itd in lst_itd:  # 各インターフェイスについて
        t_im = itd.Members  # XInterfaceMemberTypeDescription型のオブジェクトのタプルを取得。メンバーがメソッドならXInterfaceMethodTypeDescriptionインターフェイスをもつ、属性ならXInterfaceAttributeTypeDescription2 インターフェイスをもつ。
        if t_im:
            im_dic[itd.Name] = t_im  # 辞書im_dicの項目を追加。 
    return im_dic  # 生成した辞書im_dicを返す。
if __name__ == "__main__":
    import unopy
    XSCRIPTCONTEXT = unopy.connect()
    if not XSCRIPTCONTEXT:
        print("Failed to connect.")
        import sys
        sys.exit(0)
    libreoffice50()
これでitertoolsモジュールを使わずにできましたね。

辞書のvalueに関数を適用するmap()のようなものがあればいいと思ったのですが標準モジュールにはないようです。(omoplatta: [python] 辞書にmap()のような走査関数を適用したい

参考にしたサイト


LibreOffice: com::sun::star Module Reference
LibreOffice 4.2 SDK API Reference

Pythonでリストの内包表記を使って2次元リストを1次元リストにする - こんにちはこんにちはmonmonです!
itertools.chain(*iterables)を使わずに1次元にできます。

omoplatta: [python] 辞書にmap()のような走査関数を適用したい
標準モジュールにはmap()に相当するものはないようです。

次の関連記事:LibreOffice(51)クラスにすると関数の引数が減らせた

PR

0 件のコメント:

コメントを投稿