This article describes how to work with the SystemWeaver Client API with Python in Ubuntu. Running it on other flavors of Linux should work in a similar way although it has not been tested.


Prerequisites

  • Installation of Ubuntu (testing was done with version 18.04.1 on a virtual machine, e.g., Hyper V)
  • Installation of dotnet core (example: sudo apt-get install dotnet-sdk-2.2)
  • Installation of Python or IronPython (testing was done with Ironpython (version netcoreapp2.1) which is an open-source implementation of the Python programming language tightly integrated with the .NET Framework. IronPython can use the .NET Framework and Python libraries, and other .NET languages can use Python code just as easily. It can be found here https://github.com/IronLanguages/ironpython2
  • Installation of git (example: sudo apt install git)
  • Various SystemWeaver files which can be obtained from the SystemWeaver.Connection.Core NuGet package

Preparing IronPython and SystemWeaver Dlls

  1. To get started, download the source code of IronPython and build it. In our example, all of the code from git is placed in ironpythongit/ironpython2.
    mkdir ironpythongit
    cd ironpythongit
    git clone https://github.com/IronLanguages/ironpython2.git
    git submodule init
    git submodule update
  2. Next, build IronPython. You can use powershell to do this. Example: 
    Install powershell:
    sudo snap install powershell --classic

    Build Ironpython
    powershell
    cd ironpython2
    ./make.ps1 package
  3. You can then create paths for IronPython, or just run it from the Release folder. In the Release folder for netcoreapp2.1, there is a file called ipy.sh which can be used to run IronPython.
  4. Copy the following SystemWeaver files to the Release folder (ironpython2/bin/Release/netcoreapp2.1)
    • SystemWeaver.ClientAPI.dll
    • SystemWeaver.Common.dll
    • SystemWeaver.Connection.dll
    • DotNetZip.dll
    • NLog.dll
    • K4os.Compression.LZ4.dll
    • System.Memory.dll

The above files can be copied from the SystemWeaver.Connection.Core NuGet package.


Running Python Script

You are now ready to run your python script. 


Example Script

"first_test.py"

~/ironpythongit/ironpython2/bin/Release/netcoreapp2.1/ipy.sh first_test.py x04000000000014CA

Below is a Python test script. It loads the SystemWeaver client API. Indata for the script is a SystemWeaver item handle (e.g., x04000000000014CA). The script looks for some part-types and traverses down a tree.


It is important to include "import clr" in the script which makes it possible for Ironpython to interop with .Net.


After that, add references to SystemWeaver API modules. 


Finally, import namespaces from the SystemWeaver API so that you can use them in Python code ("import SystemWeaverAPI as sw").


import clr
clr.AddReference('SystemWeaver.Connection')
clr.AddReference('SystemWeaver.Common')
clr.AddReference('SystemWeaver.ClientAPI')
import SystemWeaverAPI as sw
import SystemWeaver.Common as swc


In the python code, you can call SystemWeaver API methods by using "sw" (see below example of imported SystemWeaverAPI:

sw.SWConnection.Instance.LoginName = "student"


#! python
'''first python script'''

import sys
import clr
clr.AddReference('SystemWeaver.Connection')
clr.AddReference('SystemWeaver.Common')
clr.AddReference('SystemWeaver.ClientAPI')
import SystemWeaverAPI as sw
import SystemWeaver.Common as swc

def status_string(str_val):
    '''Status string'''
    return {
        0: 'Work',
        1: 'Frozen',
        2: 'Released',
        3: 'CSReleased',
        4: 'CheckedOut',
        5: 'NoAccess'
    }[str_val]

def datatype_name(dt_name):
    '''Datatypes'''
    return {
        0: 'Custom',
        1: 'Boolean',
        2: 'Computed',
        3: 'Custom',
        4: 'Date',
        5: 'Enumeration',
        6: 'ExtRef',
        7: 'Float',
        8: 'Identity',
        9: 'Integer',
        10: 'RVF',
        11: 'String',
        12: 'Text',
        13: 'User',
        14: 'XML'
    }[dt_name]

def attribute_type(attr):
    '''Attribute type'''
    attr_type = attr.AttributeType
    return attr_type.Name + ' ' + attr_type.Info + ' ' + datatype_name(attr_type.DataType)

def print_level(instr, level):
    '''Print with indent'''
    space = ' '
    print(level*2*space + instr)

def attribute_has_data(attr):
    '''Has attribute data'''
    return attr.IsNil != True

def print_attribute(item, level):
    '''Display attribute'''
    attr_sid = 'ADDT'
    attr = item.Attribute(attr_sid)
    if attribute_has_data(attr):
        print_level(attribute_type(attr))
    attr_sid = 'ABUN'
    attr = item.Attribute(attr_sid)
    if attribute_has_data(attr):
        print_level(attribute_type(attr) + ' ' + attr.ValueAsString, level)

def print_item(item, level):
    '''Display 1 item at a certain indentation - level'''
    print_level('item '+item.Name+' '+item.Version+' '+ item.CreatedBy.RealName+' '+
                item.CreationDate.Date.ToShortDateString() + ' '
                + swc.SWItemStatusExtensions.DisplayString(item.Status) + ' '
                + item.swItemType.SID, level)

def print_part(part, level):
    '''Display 1 part at a certain indentation - level'''
    print_level('part '+part.Name+' '
                + part.swPartType.SID, level)

def print_tree(parent, item_dictionary, level):
    '''Display tree'''
    if parent.HandleStr in item_dictionary:
        return
    item_dictionary[parent.HandleStr] = parent
    part_sids =  ['ITAP', 'ITDC', 'ITFC', 'ITIS', 'ITOS', 'DEMA']
    for part_sid in part_sids:
        parts = parent.GetParts(part_sid)
        for part in parts:
            item = part.DefObj
            print_part(part, level)
            print_item(item, level)
            print_attribute(item, level)
            print_tree(item, item_dictionary, level+1)

def load(handle_str):    
    """print a tree with handle as top item"""
    handle = swc.SWHandleUtility.ToHandle(handle_str)
    item_dictionary = dict()

    sw.SWConnection.Instance.LoginName = "student"
    sw.SWConnection.Instance.Password = "student"
    sw.SWConnection.Instance.ServerMachineName = "testServerIpAdress"
    sw.SWConnection.Instance.ServerPort = 1769
    sw.SWConnection.Instance.Login()

    sw.SWConnection.Instance.Broker.Ping()
    item = sw.SWConnection.Instance.Broker.GetItem(handle)
    print('---top---  \n' + item.Name)
    print_tree(item, item_dictionary, 1)


if __name__ == "__main__":
    load(sys.argv[1])