Python

XMLSERVICE.Python History

Hide minor edits - Show changes to output

Changed lines 4-2114 from:
The Python is a Python wrapper over the XMLSERVICE open source project from IBM.
This python .whl/.egg is now jointly maintained by IBM and the KrengelTech Litmis team.

!!! Python toolkit source
* https://bitbucket.org/litmis/python-itoolkit

!!! IBM project link
* [[https://www.ibm.com/developerworks/community/wikis/home?lang=en#!/wiki/IBM%20i%20Technology%20Updates/page/Python]]
* [[https://www.ibm.com/developerworks/community/wikis/home?lang=en#!/wiki/IBM%20i%20Technology%20Updates/page/Python%20PTFs]]

!!! Download .whl (test only).
Versions:\\
2017-12-18 - [[ Attach:python3-itoolkit-1.3.zip | python3-itoolkit-1.3.zip]] - change iLibCall - fix UnicodeDecodeError: ascii codec cannot decode byte 0xc3\\
[@
pip3 install dist/*cp34m*.whl
@]


!!! Download .whl/.egg (or use IBM PTFs).
Versions:\\
2016-05-27 - [[ Attach:python-itoolkit-1.2.zip | python-itoolkit-1.2.zip]]

!!! Interesting learning example with QTEMP.
A person using python iLibCall() in-memory driver to call RPG programs with ExecSql and native access mixed noticed after call python ibm_db the program did not work. The reason for the failure is QTEMP 'moved' to a different job after python ibm_db.

Why?

# Python ibm_db uses CLI 'server mode' to allow multiple translations with multiple user profiles. In fact, all new IBM i languages use CLI 'server mode' (php, nodejs, etc.). Briefly, CLI 'server mode' uses proxy QSQSRVR jobs attached to the main python job to process all DB2 work. Therein, QTEMP, moves away from python job #1 and into proxy QSQSRVR job #2.
# RPG ExecSql programs follow 'sever mode'. That is. after ibm_db entered server mode, any ExecSql actions in a called RPG program in job #1 also went to the QSQSRVR job #2. However, natvive access like setll, chain, remained in the main job #1.
# Under these conditions, RPG ExecSql inserted into QTEMP in QSQSRVR job #2, but, RPG native access continued to look for QTEMP results in main job #1. There was no QTEMP date in job #1, so the iLibCall in-memory call to the RPG program failed.
# The fix was to use the iDb2Call transport protocol, so all of operations RPG ExecSql and native could share same QTEMP with ibm_db in QSQSRVR job #2.

!!! Quick link classes and samples
(:table border=1 width=100%:)
(:cellnr colspan=2 align=center style='background-color: #CCCCCC;':)[++Index++]
(:cellnr:)[++Classes++]
(:cell:)[++Sample++]

(:cellnr:)
[[#iBase|iBase]]
[[#iCmd|iCmd]]
[[#iSh|iSh]]
[[#iCmd5250|iCmd5250]]
[[#iPgm|iPgm]]
[[#iSrvPgm|iSrvPgm]]
[[#iParm|iParm]]
[[#iRet|iRet]]
[[#iDS|iDS]]
[[#iData|iData]]
[[#iSqlQuery|iSqlQuery]]
[[#iSqlPrepare|iSqlPrepare]]
[[#iSqlExecute|iSqlExecute]]
[[#iSqlFetch|iSqlFetch]]
[[#iSqlParm|iSqlParm]]
[[#iSqlFree|iSqlFree]]
[[#iXml|iXml]]
[[#iToolKit|iToolKit]]
[[#iDB2Call|iDB2Call]]
[[#iLibCall|iLibCall]]
[[#iRestCall|iRestCall]]
(:cell:)
[[#config.py|config.py]]
[[#icmd5250_dspsyssts.py|icmd5250_dspsyssts.py]]
[[#icmd_rtvjoba.py|icmd_rtvjoba.py]]
[[#ipase_ps.py|ipase_ps.py]]
[[#ipgm_bad_trace_db2.py|ipgm_bad_trace_db2.py]]
[[#ipgm_bad_trace_file.py|ipgm_bad_trace_file.py]]
[[#ipgm_bad_trace_rest.py|ipgm_bad_trace_rest.py]]
[[#ipgm_bad_trace_terminal.py|ipgm_bad_trace_terminal.py]]
[[#ipgm_zzcall.py|ipgm_zzcall.py]]
[[#isleep_rest_async.py|isleep_rest_async.py]]
[[#isql_callproc.py|isql_callproc.py]]
[[#isql_prepare.py|isql_prepare.py]]
[[#isql_query.py|isql_query.py]]
[[#isql_rest_async.py|isql_rest_async.py]]
[[#isrvpgm_qgyrhrl.py|isrvpgm_qgyrhrl.py]]
[[#isrvpgm_zzarray.py|isrvpgm_zzarray.py]]
[[#istop_msg_qsysopr_before_pgm_call.py|istop_msg_qsysopr_before_pgm_call.py]]
[[#ixml_diag.py|ixml_diag.py]]
[[#ixml_zzvary.py|ixml_zzvary.py]]

(:tableend:)

!!! Overview

[@

IBM i python toolkit.

The toolkit runs both local and remote to IBM i using iDB2Call or iRestCall.
However, class iLibCall process local calls will only work on IBM i (similar to IBM i CL).

Transport classes:
  class iLibCall:            Transport XMLSERVICE direct job call (within job/process calls).
  class iDB2Call:            Transport XMLSERVICE calls over DB2 connection.
  class iRestCall:            Transport XMLSERVICE calls over standard HTTP rest.

XMLSERVICE classes:
  Base:
  class iToolKit:            Main iToolKit XMLSERVICE collector and output parser.
  class iBase:                IBM i XMLSERVICE call addable operation(s).

  *CMDs:
  class iCmd(iBase):          IBM i XMLSERVICE call *CMD not returning *OUTPUT.

  PASE:
  class iSh(iBase):          IBM i XMLSERVICE call 5250 *CMD returning *OUTPUT.
  class iCmd5250(iSh):        IBM i XMLSERVICE call PASE utilities.

  *PGM or *SRVPGM:
  class iPgm (iBase):        IBM i XMLSERVICE call *PGM.
  class iSrvPgm (iPgm):      IBM i XMLSERVICE call *SRVPGM.
  class iParm (iBase):        Parameter child node for iPgm or iSrvPgm
  class iRet (iBase):        Return structure child node for iSrvPgm
  class iDS (iBase):          Data structure child node for iPgm, iSrvPgm,
                              or nested iDS data structures.
  class iData (iBase):        Data value child node for iPgm, iSrvPgm,
                              or iDS data structures.

  DB2:
  class iSqlQuery (iBase):    IBM i XMLSERVICE call DB2 execute direct SQL statment.
  class iSqlPrepare (iBase):  IBM i XMLSERVICE call DB2 prepare SQL statment.
  class iSqlExecute (iBase):  IBM i XMLSERVICE call execute a DB2 prepare SQL statment.
  class iSqlFetch (iBase):    IBM i XMLSERVICE call DB2 fetch results/rows of SQL statment.
  class iSqlParm (iBase):    Parameter child node for iSqlExecute.
  class iSqlFree (iBase):    IBM i XMLSERVICE call DB2 free open handles.

  Anything (XMLSERVICE XML, if no class exists):
  class iXml(iBase):          IBM i XMLSERVICE raw xml input.

Import:
  1) XMLSERVICE direct call (current job) - local only
  from itoolkit import *
  from itoolkit.lib.ilibcall import *
  itransport = iLibCall()

  2) XMLSERVICE db2 call (QSQSRVR job) - local/remote
  from itoolkit import *
  from itoolkit.db2.idb2call import *
  itransport = iDB2Call(user,password)
  -- or -
  conn = ibm_db.connect(database, user, password)
  itransport = iDB2Call(conn)

  3) XMLSERVICE http/rest/web call (Apache job) - local/remote
  from itoolkit import *
  from itoolkit.rest.irestcall import *
  itransport = iRestCall(url,user,password)

Samples (itoolkit/sample):
  > cd /QOpenSys/QIBM/ProdData/OPS/Python3.4/lib/python3.4/site-packages/itoolkit/sample
  > python3 icmd5250_dspsyssts.py

  > cd /QOpenSys/QIBM/ProdData/OPS/Python2.7/lib/python2.7/site-packages/itoolkit/sample
  > python2 icmd5250_dspsyssts.py

Install:
  =====
  IBM pythons (PTF):
  =====
  pip3 uninstall itoolkit
  pip3 install dist/itoolkit*34m-os400*.whl
  pip2 uninstall itoolkit
  pip2 install dist/itoolkit*27m-os400*.whl
  ======
  perzl pythons
  ======
  rm  -R /opt/freeware/lib/python2.6/site-packages/itoolkit*
  easy_install dist/itoolkit*2.6-os400*.egg
  rm  -R /opt/freeware/lib/python2.7/site-packages/itoolkit*
  easy_install-2.7 dist/itoolkit*2.7-os400*.egg
  ======
  laptop/remote pythons
  ======
  pip uninstall itoolkit
  pip install dist/itoolkit-lite*py2-none*.whl
  -- or --
  easy_install dist/itoolkit-lite*2.7.egg

Configure:
  Requires XMLSERVICE library installed.
  1) IBM i DGO PTFs ship QXMLSERV library (Apache PTFs)
  -- or --
  2) see following link installation
    http://yips.idevcloud.com/wiki/index.php/XMLService/XMLSERVICE
    (use crtxml for XMLSERVICE library)

Environment variables (optional):
  export XMLSERVICE=QXMLSERV  (default)
  -- or --
  export XMLSERVICE=XMLSERVICE
  -- or --
  export XMLSERVICE=ZENDSVR6
  -- so on --

License:
  BSD (LICENSE)
  -- or --
  http://yips.idevcloud.com/wiki/index.php/XMLService/LicenseXMLService

Links:
  https://www.ibm.com/developerworks/community/wikis/home?lang=en#!/wiki/IBM%20i%20Technology%20Updates/page/Python


@]

[[#iBase]]
!!! class iBase
[@
   
    IBM i XMLSERVICE call addable operation(s).

      Args:
        iopt (dict): user options (see descendents)
        idft (dict): default options (see descendents)

      Example:
        itransport = iLibCall()
        itool = iToolKit()
        itool.add(iCmd('chglibl', 'CHGLIBL LIBL(XMLSERVICE)'))
        itool.add(iSh('ps', 'ps -ef'))
        ... so on ...
        itool.call(itransport)

      Returns:
        iBase (obj)

      Notes:
        iopt  (dict): XMLSERVICE elements, attributes and values
                      'k' - element <x>
                      'v' - value <x>value</x>
                      'i' - attribute <x var='ikey'>
                      'c' - iBase children
                      ... many more idft + iopt ...
                      'error' - <x 'error'='fast'>


    def __init__(self, iopt={}, idft={}):


    def add(self, obj):
        Additional mini dom xml child nodes.

        Args:
          obj (iBase) : additional child object

        Example:
          itool = iToolKit()
          itool.add(
            iPgm('zzcall','ZZCALL')            <--- child of iToolkit
            .addParm(iData('INCHARA','1a','a')) <--- child of iPgm
            )

        Returns:
          (void)


    def xml_in(self):
        Return XML string of collected mini dom xml child nodes.

        Args:
          none

        Returns:
          XML (str)


    def make(self):
        Assemble coherent mini dom xml, including child nodes.

        Args:
          none

        Returns:
          xml.dom.minidom (obj)

@]

[[#iCmd]]
!!! class iCmd(iBase)
[@
   
    IBM i XMLSERVICE call *CMD not returning *OUTPUT.

    Args:
      ikey  (str): XML <ikey>...operation ...</ikey> for parsing output.
      icmd  (str): IBM i command no output (see 5250 command prompt).
      iopt (dict): option - dictionay of options (below)
        {'error':'on|off|fast'}  : optional - XMLSERVICE error choice {'error':'fast'}
        {'exec':cmd|system|rexx'} : optional - XMLSERVICE command execute choice {'exec':'cmd'}
                                                              RTVJOBA CCSID(?N)      {'exec':'rex'}
    Example:
      iCmd('chglibl', 'CHGLIBL LIBL(XMLSERVICE) CURLIB(XMLSERVICE)')
      iCmd('rtvjoba', 'RTVJOBA CCSID(?N) OUTQ(?)')

    Returns:
      iCmd (obj)

    Notes:
      Special commands returning output parameters are allowed.
      (?)  - indicate string return
      (?N) - indicate numeric return

      <cmd [exec='cmd|system|rexx'                        (default exec='cmd')
            hex='on' before='cc1/cc2/cc3/cc4' after='cc4/cc3/cc2/cc1'  (1.6.8)
            error='on|off|fast'                                        (1.7.6)
            ]>IBM i command</cmd>


    def __init__(self, ikey, icmd, iopt={}):

@]

[[#iSh]]
!!! class iSh(iBase)
[@
   
    IBM i XMLSERVICE call PASE utilities.

    Args:
      ikey  (str): XML <ikey>...operation ...</ikey> for parsing output.
      icmd  (str): IBM i PASE script/utility (see call qp2term).
      iopt (dict): option - dictionay of options (below)
        {'error':'on|off|fast'}  : optional - XMLSERVICE error choice {'error':'fast'}
        {'row':'on|off'}        : optional - XMLSERVICE <row>line output</row> choice {'row':'off'}

    Example:
      iSh('ls /home/xml/master | grep -i xml')

    Returns:
      iSh (obj)

    Notes:
      XMLSERVICE perfoms standard PASE shell popen calls,
      therefore, additional job will be forked,
      utilities will be exec'd, and stdout will
      be collected to be returned.

      Please note, this is a relatively slow operation,
      use sparingly on high volume web sites. 

      <sh [rows='on|off'
          hex='on' before='cc1/cc2/cc3/cc4' after='cc4/cc3/cc2/cc1' (1.7.4)
          error='on|off|fast'                                      (1.7.6)
          ]>(PASE utility)</sh>


    def __init__(self, ikey, icmd, iopt={}):

@]

[[#iCmd5250]]
!!! class iCmd5250(iSh)
[@
   
    IBM i XMLSERVICE call 5250 *CMD returning *OUTPUT.

    Args:
      ikey  (str): XML <ikey>...operation ...</ikey> for parsing output.
      icmd  (str): IBM i PASE script/utility (see call qp2term).
      iopt (dict): option - dictionay of options (below)
        {'error':'on|off|fast'}  : optional - XMLSERVICE error choice {'error':'fast'}
        {'row':'on|off'}        : optional - XMLSERVICE <row>line output</row> choice {'row':'off'}

    Example:
      iCmd5250('dsplibl','dsplibl')
      iCmd5250('wrkactjob','wrkactjob')

    Returns:
      iCmd5250 (obj)

    Notes:
      This is a subclass of iSh, therefore XMLSERVICE perfoms
      standard PASE shell popen fork/exec calls.

      /QOpenSys/usr/bin/system 'wrkactjob'

      Please note, this is a relatively slow operation,
      use sparingly on high volume web sites. 

      <sh [rows='on|off'
          hex='on' before='cc1/cc2/cc3/cc4' after='cc4/cc3/cc2/cc1' (1.7.4)
          error='on|off|fast'                                      (1.7.6)
          ]>(PASE utility)</sh>


    def __init__(self, ikey, icmd, iopt={}):

@]

[[#iPgm]]
!!! class iPgm (iBase)
[@
   
    IBM i XMLSERVICE call *PGM.

    Args:
      ikey  (str): XML <ikey>...operation ...</ikey> for parsing output.
      iname (str): IBM i *PGM or *SRVPGM name
      iopt (dict): option - dictionay of options (below)
        {'error':'on|off|fast'} : optional - XMLSERVICE error choice {'error':'fast'}
        {'func':'MYFUNC'}      : optional - IBM i *SRVPGM function export.
        {'lib':'mylib'}        : optional - IBM i library name
        {'mode':'opm|ile'}      : optional - XMLSERVICE error choice {'mode':'ile'}

    Example:
    iPgm('zzcall','ZZCALL')
    .addParm(iData('var1','1a','a'))
    .addParm(iData('var2','1a','b'))
    .addParm(iData('var3','7p4','32.1234'))
    .addParm(iData('var4','12p2','33.33'))
    .addParm(
      iDS('var5')
      .addData(iData('d5var1','1a','a'))
      .addData(iData('d5var2','1a','b'))
      .addData(iData('d5var3','7p4','32.1234'))
      .addData(iData('d5var4','12p2','33.33'))
      )

    Returns:
      iPgm (obj)

    Notes:
      pgm:
        <pgm name=''
          [lib=''
          func=''
          mode='opm|ile'
          error='on|off|fast'                        (1.7.6)
          ]> ... </pgm>


    def __init__(self, ikey, iname, iopt={}):


    def addParm(self, obj):
        Add a parameter child node.

        Args:
          obj  (obj): iData object or iDs object.

        Returns:
          (void)

@]

[[#iSrvPgm]]
!!! class iSrvPgm (iPgm)
[@
   
    IBM i XMLSERVICE call *SRVPGM.

    Args:
      ikey  (str): XML <ikey>...operation ...</ikey> for parsing output.
      iname (str): IBM i *PGM or *SRVPGM name
      ifunc (str): IBM i *SRVPGM function export.
      iopt (dict): option - dictionay of options (below)
        {'error':'on|off|fast'} : optional - XMLSERVICE error choice {'error':'fast'}
        {'lib':'mylib'}        : optional - IBM i library name
        {'mode':'opm|ile'}      : optional - XMLSERVICE error choice {'mode':'ile'}

    Example:
      see iPgm

    Returns:
      iSrvPgm (obj)

    Notes:
      pgm:
        <pgm name=''
          [lib=''
          func=''
          mode='opm|ile'
          error='on|off|fast'                        (1.7.6)
          ]> ... </pgm>


    def __init__(self, ikey, iname, ifunc, iopt={}):


    def addRet(self, obj):
        Add a return structure child node.

        Args:
          obj  (obj): iData object or iDs object.

        Returns:
          (void)

@]

[[#iParm]]
!!! class iParm (iBase)
[@
   
    Parameter child node for iPgm or iSrvPgm (see iPgm.addParm)

    Args:
      ikey  (str): ikey  (str): XML <parm ... var="ikey"> for parsing output.
      iopt (dict): option - dictionay of options (below)
        {'io':'in|out|both|omit'} : optional - XMLSERVICE param type {'io':both'}.

    Example:
      see iPgm

    Returns:
      iParm (obj)

    Notes:
      This class is not used directly, but is used by iPgm.addParm
      or iSrvPgm.addParm.

      pgm parameters:
        <pgm>
        <parm [io='in|out|both|omit'                  (omit 1.2.3)
              by='val|ref'
              ]>(see <ds> and <data>)</parm>
        </pgm>


    def __init__(self, ikey, iopt={}):

@]

[[#iRet]]
!!! class iRet (iBase)
[@
   
    Return structure child node for iSrvPgm (see iSrvPgm.addRet)

    Args:
      ikey  (str): XML <return ... var="ikey"> for parsing output.

    Example:
      see iPgm

    Returns:
      iRet (obj)

    Notes:
      This class is not used directly, but is used by iSrvPgm.addRet.

      pgm return:
        <pgm>
        <return>(see <ds> and <data>)</return>
        </pgm>


    def __init__(self, ikey):

@]

[[#iDS]]
!!! class iDS (iBase)
[@
   
    Data structure child node for iPgm, iSrvPgm,
    or nested iDS data structures.

    Args:
      ikey  (str): XML <ds ... var="ikey"> for parsing output.
      iopt (dict): option - dictionay of options (below)
        {'dim':'n'}    : optional - XMLSERVICE dimension/occurs number.
        {'dou':'label'} : optional - XMLSERVICE do until label.
        {'len':'label'} : optional - XMLSERVICE calc length label.

    Example:
      see iPgm

    Returns:
      iDS (obj)

    Notes:
      pgm data structure:
        <ds [dim='n' dou='label'
            len='label'                                (1.5.4)
            data='records'                              (1.7.5)
            ]>(see <data>)</ds>


    def __init__(self, ikey, iopt={}):


    def addData(self, obj):
        Add a iData or iDS child node.

        Args:
          obj  (obj): iData object or iDs object.

        Returns:
          (void)

@]

[[#iData]]
!!! class iData (iBase)
[@
   
    Data value child node for iPgm, iSrvPgm,
    or iDS data structures.

    Args:
      ikey  (str): XML <data ... var="ikey"> for parsing output.
      itype (obj): data type [see XMLSERVICE types, '3i0', ...].
      ival  (obj): data type value.
      iopt (dict): option - dictionay of options (below)
        {'dim':'n'}              : optional - XMLSERVICE dimension/occurs number.
        {'varying':'on|off|2|4'}  : optional - XMLSERVICE varying {'varying':'off'}.
        {'hex':'on|off'}          : optional - XMLSERVICE hex chracter data {'hex':'off'}.
        {'enddo':'label'}        : optional - XMLSERVICE enddo until label.
        {'setlen':'label'}        : optional - XMLSERVICE set calc length label.
        {'offset':'n'}            : optional - XMLSERVICE offset label.
        {'next':'label'}          : optional - XMLSERVICE next offset label (value).

    Example:
      see iPgm

    Returns:
      iData (obj)

    Notes:
      pgm data elements:
        <data type='data types'
          [dim='n'
            varying='on|off|2|4'
            enddo='label'
            setlen='label'                                                (1.5.4)
            offset='label'
            hex='on|off' before='cc1/cc2/cc3/cc4' after='cc4/cc3/cc2/cc1' (1.6.8)
            trim='on|off'                                                (1.7.1)
            next='nextoff'                                                (1.9.2)
            ]>(value)</data>

      C types          RPG types                    XMLSERVICE types                                  SQL types
      ===============  ============================  ================================================  =========
      int8/byte        D myint8    3i 0              <data type='3i0'/>                                TINYINT  (unsupported DB2)
      int16/short      D myint16  5i 0 (4b 0)      <data type='5i0'/>                                SMALLINT
      int32/int        D myint32  10i 0 (9b 0)      <data type='10i0'/>                                INTEGER
      int64/longlong  D myint64  20i 0              <data type='20i0'/>                                BIGINT
      uint8/ubyte      D myuint8  3u 0              <data type='3u0'/>
      uint16/ushort    D myuint16  5u 0              <data type='5u0'/>
      uint32/uint      D myuint32 10u 0              <data type='10u0'/>
      uint64/ulonglong D myuint64 20u 0              <data type='20u0'/>
      char            D mychar  32a                <data type='32a'/>                                CHAR(32)
      varchar2        D myvchar2 32a  varying      <data type='32a' varying='on'/>                    VARCHAR(32)
      varchar4        D myvchar4 32a  varying(4)  <data type='32a' varying='4'/>
      packed          D mydec    12p 2              <data type='12p2'/>                                DECIMAL(12,2)
      zoned            D myzone  12s 2              <data type='12s2'/>                                NUMERIC(12,2)
      float            D myfloat  4f                <data type='4f2'/>                                FLOAT
      real/double      D myreal    8f                <data type='8f4'/>                                REAL
      binary          D mybin    (any)              <data type='9b'>F1F2F3</data>                      BINARY
      hole (no out)    D myhole  (any)              <data type='40h'/>
      boolean          D mybool    1n                <data type='4a'/>                                  CHAR(4)
      time            D mytime    T  timfmt(*iso) <data type='8A'>09.45.29</data>                    TIME
      timestamp        D mystamp    Z                <data type='26A'>2011-12-29-12.45.29.000000</data> TIMESTAMP
      date            D mydate    D  datfmt(*iso) <data type='10A'>2009-05-11</data>                DATE


    def __init__(self, ikey, itype, ival, iopt={}):

@]

[[#iSqlQuery]]
!!! class iSqlQuery (iBase)
[@
   
    IBM i XMLSERVICE call DB2 execute direct SQL statment.

    Args:
      ikey  (str): XML <ikey>...operation ...</ikey> for parsing output.
      isql  (str): IBM i query (see 5250 strsql).
      iopt (dict): option - dictionay of options (below)
        {'error':'on|off|fast'} : optional - XMLSERVICE error choice {'error':'fast'}
        {'conn':'label'}        : optional - XMLSERVICE connection label
        {'stmt':'label'}        : optional - XMLSERVICE stmt label
        {'options':'label'}    : optional - XMLSERVICE options label

    Example:
      iSqlQuery('custquery', "select * from QIWS.QCUSTCDT where LSTNAM='Jones' or LSTNAM='Vine'")
      iSqlFetch('custfetch')

    Returns:
      iSqlQuery (obj)

    Notes:
      <sql><query [conn='label' stmt='label' options='label' error='on|off|fast']></sql>


    def __init__(self, ikey, isql, iopt={}):

@]

[[#iSqlPrepare]]
!!! class iSqlPrepare (iBase)
[@
   
    IBM i XMLSERVICE call DB2 prepare SQL statment.

    Args:
      ikey  (str): XML <ikey>...operation ...</ikey> for parsing output.
      isql  (str): IBM i query (see 5250 strsql).
      iopt (dict): option - dictionay of options (below)
        {'error':'on|off|fast'} : optional - XMLSERVICE error choice {'error':'fast'}
        {'conn':'label'}        : optional - XMLSERVICE connection label
        {'stmt':'label'}        : optional - XMLSERVICE stmt label
        {'options':'label'}    : optional - XMLSERVICE options label

    Example:
      iSqlPrepare('callprep', "call mylib/mycall(?,?,?)")
      iSqlExecute('callexec')
      .addParm(iSqlParm('var1','a'))
      .addParm(iSqlParm('var2','b'))
      .addParm(iSqlParm('var3','32.1234'))
      iSqlFetch('callfetch')
      iSqlFree('alldone')

    Returns:
      iSqlPrepare (obj)

    Notes:
      <sql><prepare [conn='label' stmt='label' options='label' error='on|off|fast']></sql>


    def __init__(self, ikey, isql, iopt={}):

@]

[[#iSqlExecute]]
!!! class iSqlExecute (iBase)
[@
   
    IBM i XMLSERVICE call execute a DB2 prepare SQL statment.

    Args:
      ikey  (str): XML <ikey>...operation ...</ikey> for parsing output.
      iopt (dict): option - dictionay of options (below)
        {'error':'on|off|fast'} : optional - XMLSERVICE error choice {'error':'fast'}
        {'conn':'label'}        : optional - XMLSERVICE connection label
        {'stmt':'label'}        : optional - XMLSERVICE stmt label
        {'options':'label'}    : optional - XMLSERVICE options label

    Example:
      see iSqlPrepare

    Returns:
      iSqlExecute (obj)

    Notes:
      <sql><execute [stmt='label'  error='on|off|fast']></sql>


    def __init__(self, ikey, iopt={}):


    def addParm(self, obj):
        Add a iSqlParm child node.

        Args:
          obj  (obj): iSqlParm object.

        Returns:
          (void)

@]

[[#iSqlFetch]]
!!! class iSqlFetch (iBase)
[@
   
    IBM i XMLSERVICE call DB2 fetch results/rows of SQL statment.

    Args:
      ikey  (str): XML <ikey>...operation ...</ikey> for parsing output.
      iopt (dict): option - dictionay of options (below)
        {'error':'on|off|fast'} : optional - XMLSERVICE error choice {'error':'fast'}
        {'stmt':'label'}        : optional - XMLSERVICE stmt label
        {'block':'all|n'}      : optional - XMLSERVICE block records {'block':'all'}
        {'desc':'on|off'}      : optional - XMLSERVICE block records {'desc':'on'}
        {'rec':'n'}            : optional - XMLSERVICE block records

    Example:
      see iSqlPrepare or iSqlQuery

    Returns:
      none

    Notes:
      <sql>
      <fetch [stmt='label' block='all|n' rec='n' desc='on|off' error="on|off|fast"/>
                          (default=all)        (default=on)  (default='off')
      </sql>


    def __init__(self, ikey, iopt={}):

@]

[[#iSqlParm]]
!!! class iSqlParm (iBase)
[@
   
    Parameter child node for iSqlExecute (see iSqlExecute.addParm)

    Args:
      ikey  (str): XML <parm ... var="ikey"> for parsing output.
      ival  (str): data value.
      iopt (dict): option - dictionay of options (below)
        {'io':'in|out|both|omit'} : optional - XMLSERVICE param type {'io':both'}.

    Example:
      see iSqlPrepare

    Returns:
      iSqlParm (obj)

    Notes:
      This class is not used directly, but is used by iSqlExecute.addParm.

      <sql>
      <execute>
      <parm [io='in|out|both']>val</parm>
      </execute>
      <sql>


    def __init__(self, ikey, ival, iopt={}):

@]

[[#iSqlFree]]
!!! class iSqlFree (iBase)
[@
   
    IBM i XMLSERVICE call DB2 free open handles.

    Args:
      ikey  (str): XML <ikey>...operation ...</ikey> for parsing output.
      iopt (dict): option - dictionay of options (below)
        {'error':'on|off|fast'} : optional - XMLSERVICE error choice {'error':'fast'}
        {'conn':'all|label'}    : optional - XMLSERVICE free connection label
        {'cstmt':'label'}      : optional - XMLSERVICE free connection label statements
        {'stmt':'all|label'}    : optional - XMLSERVICE free stmt label
        {'options':'all|label'} : optional - XMLSERVICE free options label

    Example:
      see iSqlPrepare

    Returns:
      iSqlFree (obj)

    Notes:
      <sql>
      <free [conn='all|label'
        cstmt='label'
        stmt='all|label'
        options='all|label'
        error='on|off|fast']/>
      </sql>


    def __init__(self, ikey, iopt={}):

@]

[[#iXml]]
!!! class iXml(iBase)
[@
   
    IBM i XMLSERVICE raw xml input.

    Args:
      ixml  (str): custom XML for XMLSERVICE operation.

    Example:
      iXml("<cmd>CHGLIBL LIBL(XMLSERVICE)</cmd>")
      iXml("<sh>ls /tmp</sh>")

    Returns:
      iXml (obj)

    Notes:
      Not commonly used, but ok when other classes fall short.


    def __init__(self, ixml):


    def add(self, obj):
        add input not allowed.

        Returns:
          raise except


    def make(self):
        Assemble coherent mini dom xml.

        Args:
          none

        Returns:
          xml.dom.minidom (obj)

@]

[[#iToolKit]]
!!! class iToolKit
[@
   
    Main iToolKit XMLSERVICE collector and output parser.

    Args:
      iparm (num): include xml node parm output (0-no, 1-yes).
      iret  (num): include xml node return output (0-no, 1-yes).
      ids  (num): include xml node ds output (0-no, 1-yes).
      irow  (num): include xml node row output (0-no, 1-yes).
   
    Returns:
      iToolKit (obj)


    def __init__(self, iparm=0, iret=0, ids=1, irow=1):


    def clear(self):
        Clear collecting child objects.

        Args:
          none

        Returns:
          (void)

        Notes:
          <?xml version='1.0'?>
          <xmlservice>


    def add(self, obj):
        Add additional child object.

        Args:
          none

        Returns:
          none

        Notes:
          <?xml version='1.0'?>
          <xmlservice>


    def xml_in(self):
        return raw xml input.

        Args:
          none

        Returns:
          xml


    def xml_out(self):
        return raw xml output.

        Args:
          none

        Returns:
          xml


    def list_out(self,ikey=-1):
        return list output.

        Args:
          ikey  (num): select list from index [[0],[1],,,,].

        Returns:
          list [value]


    def dict_out(self,ikey=0):
        return dict output.

        Args:
          ikey  (str): select 'key' from {'key':'value'}.

        Returns:
          dict {'key':'value'}


    def hybrid_out(self,ikey=0):
        return hybrid output.

        Args:
          ikey  (str): select 'key' from {'key':'value'}.

        Returns:
          hybrid {key:{'data':[list]}}


    def trace_open(self,iname='*terminal'):
        Open trace *terminal or file /tmp/python_toolkit_(iname).log (1.2+)

        Args:
          iname  (str): trace *terminal or file /tmp/python_toolkit_(iname).log

        Returns:
          (void)


    def trace_write(self,itext):
        Write trace text (1.2+)

        Args:
          itext  (str): trace text

        Returns:
          (void)


    def trace_hexdump(self,itext):
        Write trace hexdump (1.2+)
        Args:
          itext  (str): trace text
        Returns:
          (void)


    def trace_close(self):
        End trace (1.2+)

        Args:
          none

        Returns:
          (void)


    def call(self, itrans):
        Call xmlservice with accumulated input XML.

        Args:
          itrans (obj): XMLSERVICE transport (iRestCall, iDB2Call, etc.)

        Returns:
          none


    def _dom_out(self):
        return xmlservice dom output.

        Args:
          none

        Returns:
          xml.dom


    def _parseXmlList(self, parent, values):
        return dict output.

        Args:
          parent (obj): parent xml.dom
          values (obj): accumulate list []

        Returns:
          list [value]


    def _parseXmlDict(self, parent, values):
        return dict output.

        Args:
          parent (obj): parent xml.dom
          values (obj): accumulate dict{}

        Returns:
          dict {'key':'value'}


    def _parseXmlHybrid(self, parent, values):
        return dict output.

        Args:
          parent (obj): parent xml.dom
          values (obj): accumulate hybrid{}

        Returns:
          hybrid {key:{'data':[list]}}

@]

[[#iDB2Call]]
!!! class iDB2Call
[@
   
    Transport XMLSERVICE calls over DB2 connection.

    Args:
      iuid  (str): Database user profile name or database connection
      ipwd  (str): optional - Database user profile password
                              -- or --
                              env var PASSWORD (export PASSWORD=mypass)
      idb2  (str): optional - Database (WRKRDBDIRE *LOCAL)
      ictl  (str): optional - XMLSERVICE control ['*here','*sbmjob']
      ipc    (str): optional - XMLSERVICE xToolkit job route for *sbmjob ['/tmp/myunique42']
      isiz  (int): optional - XMLSERVICE expected max XML output size, required for DB2
      ilib  (str): optional - XMLSERVICE library compiled (default QXMLSERV)

    Example:
      from itoolkit.db2.idb2call import *
      itransport = iDB2Call(user,password)
      -- or --
      conn = ibm_db.connect(database, user, password)
      itransport = iDB2Call(conn)

    Returns:
      (obj)


    def __init__(self, iuid, ipwd=0, idb2=0, ictl=0, ipc=0, isiz=0, ilib=0):


    def trace_data(self):
        Return trace driver data.

        Args:
          none

        Returns:
          initialization data


    def call(self, itool):
        Call xmlservice with accumulated input XML.

        Args:
          itool  - iToolkit object

        Returns:
          xml

@]

[[#iLibCall]]
!!! class iLibCall
[@
   
    Transport XMLSERVICE direct job call (within job/process calls).

    Args:
      ictl  (str): optional - XMLSERVICE control ['*here','*sbmjob']
      ipc    (str): optional - XMLSERVICE xToolkit job route for *sbmjob ['/tmp/myunique42']
      iccsid (int): optional - XMLSERVICE EBCDIC CCSID [0,37,...] 0 = default jobccsid (1.2+)
      pccsid (int): optional - XMLSERVICE ASCII CCSID [0,1208, ...] 0 = default 1208 (1.2+)

    Returns:
      none


    def __init__(self, ictl=0, ipc=0, iccsid=0, pccsid=0):


    def trace_data(self):
        Return trace driver data.

        Args:
          none

        Returns:
          initialization data


    def call(self, itool):
        Call xmlservice with accumulated input XML.

        Args:
          itool  - iToolkit object

        Returns:
          xml

@]

[[#iRestCall]]
!!! class iRestCall
[@
   
    Transport XMLSERVICE calls over standard HTTP rest.

    Args:
      iurl  (str): XMLSERVICE url (https://common1.frankeni.com:47700/cgi-bin/xmlcgi.pgm).
      iuid  (str): Database user profile name
      ipwd  (str): optional - Database user profile password
                              -- or --
                              env var PASSWORD (export PASSWORD=mypass)
      idb2  (str): optional - Database (WRKRDBDIRE *LOCAL)
      ictl  (str): optional - XMLSERVICE control ['*here','*sbmjob']
      ipc    (str): optional - XMLSERVICE xToolkit job route for *sbmjob ['/tmp/myunique42']
      isiz  (str): optional - XMLSERVICE expected max XML output size, required for DB2

    Example:
      from itoolkit.rest.irestcall import *
      itransport = iRestCall(url,user,password)

    Returns:
      none


    def __init__(self, iurl, iuid, ipwd=0, idb2=0, ictl=0, ipc=0, isiz=0):


    def trace_data(self):
        Return trace driver data.

        Args:
          none

        Returns:
          initialization data


    def call(self, itool):
        Call xmlservice with accumulated input XML.

        Args:
          itool  - iToolkit object

        Returns:
          xml

@]

[[#config.py]]
!!! itoolkit/sample/config.py
[@
"""
Configure:
  Requires XMSLERVICE library installed, see following link installation
  http://yips.idevcloud.com/wiki/index.php/XMLService/XMLSERVICE

Transports:
  1) XMLSERVICE direct call (current job)
  from itoolkit.lib.ilibcall import *
  itransport = iLibCall()

  2) XMLSERVICE db2 call (QSQSRVR job)
  from itoolkit.db2.idb2call import *
  itransport = iDB2Call(config.user,config.password)
  -- or --
  conn = ibm_db.connect(database, user, password)
  itransport = iDB2Call(conn)

  3) XMLSERVICE http/rest/web call (Apache job)
  from itoolkit.rest.irestcall import *
  itransport = iRestCall(url, user, password)
"""
from itoolkit.lib.ilibcall import *
itransport = iLibCall()
# itransport = iLibCall("*here *cdata *debug") # i will stop, inquiry message qsysopr


@]

[[#icmd5250_dspsyssts.py]]
!!! itoolkit/sample/icmd5250_dspsyssts.py
[@
#                                                                        Bottom
# Type command, press Enter.
# ===> dspsyssts                                                               
#                            Display System Status                    LP0364D
#                                                            06/22/15  15:22:28
# % CPU used . . . . . . . :        .1    Auxiliary storage:
# Elapsed time . . . . . . :  00:00:01      System ASP . . . . . . :    176.2 G
# Jobs in system . . . . . :        428      % system ASP used  . . :    75.6481
import config
from itoolkit import *

itool = iToolKit()
itool.add(iCmd5250('dspsyssts', 'dspsyssts'))

# xmlservice
itool.call(config.itransport)

# output
dspsyssts = itool.dict_out('dspsyssts')
if 'error' in dspsyssts:
  print (dspsyssts['error'])
  exit()
else:
  print (dspsyssts['dspsyssts'])


@]

[[#icmd_rtvjoba.py]]
!!! itoolkit/sample/icmd_rtvjoba.py
[@
# RTVJOBA can't issue from command line,
# but works with itoolkit
import config
from itoolkit import *

# modify iToolKit not include row node
itool = iToolKit(iparm=0, iret=0, ids=1, irow=0)
itool.add(iCmd('rtvjoba', 'RTVJOBA USRLIBL(?) SYSLIBL(?) CCSID(?N) OUTQ(?)'))

# xmlservice
itool.call(config.itransport)

# output
rtvjoba = itool.dict_out('rtvjoba')
print (rtvjoba)
if 'error' in rtvjoba:
  print (rtvjoba['error'])
  exit()
else:
  print('USRLIBL = ' + rtvjoba['USRLIBL'])
  print('SYSLIBL = ' + rtvjoba['SYSLIBL'])
  print('CCSID  = ' + rtvjoba['CCSID'])
  print('OUTQ    = ' + rtvjoba['OUTQ'])


@]

[[#ipase_ps.py]]
!!! itoolkit/sample/ipase_ps.py
[@
# > ps -ef
#      UID  PID  PPID  C    STIME    TTY  TIME CMD
#  qsecofr    12    11  0  May 08      -  8:33 /QOpenSys/QIBM/ProdData/JavaVM/jdk60/32bit/jre/lib/ppc/jvmStartPase 566
# qtmhhttp    31    1  0  May 08      -  0:00 /usr/local/zendsvr/bin/watchdog -c /usr/local/zendsvr/etc/watchdog-monitor.ini -s monitor
import config
from itoolkit import *

itool = iToolKit()
itool.add(iSh('ps', 'ps -ef'))

# xmlservice
itool.call(config.itransport)

# output
ps = itool.dict_out('ps')
if 'error' in ps:
  print (ps['error'])
  exit()
else:
  print (ps['ps'])


@]

[[#ipgm_bad_trace_db2.py]]
!!! itoolkit/sample/ipgm_bad_trace_db2.py
[@
from itoolkit import *
from itoolkit.db2.idb2call import *

itransport = iDB2Call('adc') # export PASSWORD=mypass

itool = iToolKit()
itool.add(
 iPgm('zzcall','ZZCALLNOT')
 .addParm(iData('INCHARA','1a','a'))
 )

# xmlservice write trace log to *terminal
itool.trace_open()
itool.call(itransport)
itool.trace_close()

zzcall = itool.dict_out('zzcall')
if 'success' in zzcall:
  print (zzcall['success'])
else:
  print (zzcall['error'])
  exit()



@]

[[#ipgm_bad_trace_file.py]]
!!! itoolkit/sample/ipgm_bad_trace_file.py
[@
import config
from itoolkit import *
itool = iToolKit()
itool.add(
 iPgm('zzcall','ZZCALLNOT')
 .addParm(iData('INCHARA','1a','a'))
 )

# xmlservice write trace log to /tmp/python_toolkit_(tonyfile).log
itool.trace_open('tonyfile')
itool.call(config.itransport)
itool.trace_close()

zzcall = itool.dict_out('zzcall')
if 'success' in zzcall:
  print (zzcall['success'])
else:
  print (zzcall['error'])
  exit()



@]

[[#ipgm_bad_trace_rest.py]]
!!! itoolkit/sample/ipgm_bad_trace_rest.py
[@
from itoolkit.rest.irestcall import *
from itoolkit import *

itransport = iRestCall('http://yips.idevcloud.com/cgi-bin/xmlcgi.pgm','*NONE','*NONE')

itool = iToolKit()
itool.add(
 iPgm('zzcall','ZZCALLNOT')
 .addParm(iData('INCHARA','1a','a'))
 )

# xmlservice write trace log to *terminal
itool.trace_open()
itool.call(itransport)
itool.trace_close()

zzcall = itool.dict_out('zzcall')
if 'success' in zzcall:
  print (zzcall['success'])
else:
  print (zzcall['error'])
  exit()



@]

[[#ipgm_bad_trace_terminal.py]]
!!! itoolkit/sample/ipgm_bad_trace_terminal.py
[@
import config
from itoolkit import *
itool = iToolKit()
itool.add(
 iPgm('zzcall','ZZCALLNOT')
 .addParm(iData('INCHARA','1a','a'))
 )

# xmlservice write trace log to *terminal
itool.trace_open()
itool.call(config.itransport)
itool.trace_close()

zzcall = itool.dict_out('zzcall')
if 'success' in zzcall:
  print (zzcall['success'])
else:
  print (zzcall['error'])
  exit()



@]

[[#ipgm_zzcall.py]]
!!! itoolkit/sample/ipgm_zzcall.py
[@
import config
from itoolkit import *
# XMLSERVICE/ZZCALL:
#    D  INCHARA        S              1a
#    D  INCHARB        S              1a
#    D  INDEC1        S              7p 4       
#    D  INDEC2        S            12p 2
#    D  INDS1          DS                 
#    D  DSCHARA                      1a
#    D  DSCHARB                      1a         
#    D  DSDEC1                      7p 4     
#    D  DSDEC2                      12p 2           
#      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#      * main(): Control flow
#      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#    C    *Entry        PLIST                 
#    C                  PARM                    INCHARA
#    C                  PARM                    INCHARB
#    C                  PARM                    INDEC1
#    C                  PARM                    INDEC2
#    C                  PARM                    INDS1
itool = iToolKit()
itool.add(iCmd('chglibl', 'CHGLIBL LIBL(XMLSERVICE)'))
itool.add(
 iPgm('zzcall','ZZCALL')
 .addParm(iData('INCHARA','1a','a'))
 .addParm(iData('INCHARB','1a','b'))
 .addParm(iData('INDEC1','7p4','32.1234'))
 .addParm(iData('INDEC2','12p2','33.33'))
 .addParm(
  iDS('INDS1')
  .addData(iData('DSCHARA','1a','a'))
  .addData(iData('DSCHARB','1a','b'))
  .addData(iData('DSDEC1','7p4','32.1234'))
  .addData(iData('DSDEC2','12p2','33.33'))
  )
 )

# xmlservice
itool.call(config.itransport)

# output
chglibl = itool.dict_out('chglibl')
if 'success' in chglibl:
  print (chglibl['success'])
else:
  print (chglibl['error'])
  exit()

zzcall = itool.dict_out('zzcall')
if 'success' in zzcall:
  print (zzcall['success'])
  print ("    INCHARA      : " + zzcall['INCHARA'])
  print ("    INCHARB      : " + zzcall['INCHARB'])
  print ("    INDEC1      : " + zzcall['INDEC1'])
  print ("    INDEC2      : " + zzcall['INDEC2'])
  print ("    INDS1.DSCHARA: " + zzcall['INDS1']['DSCHARA'])
  print ("    INDS1.DSCHARB: " + zzcall['INDS1']['DSCHARB'])
  print ("    INDS1.DSDEC1 : " + zzcall['INDS1']['DSDEC1'])
  print ("    INDS1.DSDEC2 : " + zzcall['INDS1']['DSDEC2'])
else:
  print (zzcall['error'])
  exit()



@]

[[#isleep_rest_async.py]]
!!! itoolkit/sample/isleep_rest_async.py
[@
try:
  import queue
except ImportError:
  import Queue as queue
import threading
import urllib
from itoolkit.rest.irestcall import *
from itoolkit import *
class iShSleep():
  def __init__(self, icmd):
      self.itran = iRestCall('http://yips.idevcloud.com/cgi-bin/xmlcgi.pgm','*NONE','*NONE')
      self.itool = iToolKit()
      self.itool.add(iSh('igo',icmd))
  def go(self):
      self.itool.call(self.itran)
      return self.itool.dict_out('igo')
def get_url(q, icmd):
    q.put(iShSleep(icmd).go())
theshs = ["echo 'thing 1==>';date;sleep 10;date",
          "echo 'thing 2==>';date;sleep 5;date"]
q = queue.Queue()
for u in theshs:
    t = threading.Thread(target=get_url, args = (q,u))
    t.daemon = True
    t.start()
# q.join()
for u in theshs:
    s = q.get()
    print(s)


@]

[[#isql_callproc.py]]
!!! itoolkit/sample/isql_callproc.py
[@
import config
from itoolkit import *

itool = iToolKit(iparm=1)
sql  = "DROP PROCEDURE XMLSERVICE/FLUBBER\n"
itool.add(iSqlQuery('crt', sql))
itool.add(iSqlFree('free0'))
sql = "CREATE PROCEDURE XMLSERVICE/FLUBBER(IN first_name VARCHAR(128), INOUT any_name VARCHAR(128))\n"
sql += "LANGUAGE SQL\n"
sql += "BEGIN\n"
sql += "SET any_name = 'Flubber';\n"
sql += "END\n"
itool.add(iSqlQuery('crt', sql))
itool.add(iSqlFree('free1'))
itool.add(iSqlPrepare('callflubber', "call XMLSERVICE/FLUBBER(?,?)"))
itool.add(
 iSqlExecute('exec')
 .addParm(iSqlParm('myin','Jones'))
 .addParm(iSqlParm('myout','jjjjjjjjjjjjjjjjjjjjjuuuuuuuuuuuuuuuunnnnnnnnnkkkkkkkkkkkk'))
)
itool.add(iSqlFree('free2'))
# print(itool.xml_in())
# exit()

# xmlservice
itool.call(config.itransport)
# print(itool.xml_out())

# output
FLUBBER = itool.dict_out('exec')
if 'error' in FLUBBER:
  print (FLUBBER['error'])
  exit()
else:
  print ('myout = ' + FLUBBER['myout']['data'])


@]

[[#isql_prepare.py]]
!!! itoolkit/sample/isql_prepare.py
[@
# strsql
#
# ===> select * from QIWS/QCUSTCDT where LSTNAM='Jones' or LSTNAM='Vine'

#                                  Display Data   
#                                              Data width . . . . . . :    102
# Position to line  . . . . .              Shift to column  . . . . . .       
# ....+....1....+....2....+....3....+....4....+....5....+....6....+....7....+....
#  CUSNUM  LSTNAM    INIT  STREET        CITY    STATE  ZIPCOD  CDTLMT  CHGCO
# 839,283  Jones    B D  21B NW 135 St  Clay    NY    13,041      400      1
# 392,859  Vine      S S  PO Box 79      Broton  VT    5,046      700      1
# ********  End of data  ********
import config
from itoolkit import *

itool = iToolKit()
itool.add(iSqlPrepare('cust2prep', "select * from QIWS/QCUSTCDT where LSTNAM=? or LSTNAM=?"))
itool.add(
 iSqlExecute('cust2exec')
 .addParm(iSqlParm('pm1','Jones'))
 .addParm(iSqlParm('pm2','Vine'))
)
itool.add(iSqlFetch('cust2fetch'))
itool.add(iSqlFree('cust2free'))

# xmlservice
itool.call(config.itransport)

# output
QCUSTCDT = itool.dict_out('cust2fetch')
# print(QCUSTCDT)
if 'error' in QCUSTCDT:
  print (QCUSTCDT['error'])
  exit()
else:
  for row in QCUSTCDT['row']:
    print('row:')
    print(' CDTDUE :' + row['CDTDUE'])
    print(' CDTLMT :' + row['CDTLMT'])
    print(' CUSNUM :' + row['CUSNUM'])
    print(' CHGCOD :' + row['CHGCOD'])
    print(' STREET :' + row['STREET'])
    print(' INIT  :' + row['INIT'])
    print(' BALDUE :' + row['BALDUE'])
    print(' LSTNAM :' + row['LSTNAM'])
    print(' ZIPCOD :' + row['ZIPCOD'])
    print(' CITY  :' + row['CITY'])
    print(' STATE  :' + row['STATE'])


@]

[[#isql_query.py]]
!!! itoolkit/sample/isql_query.py
[@
# strsql
#
# ===> select * from QIWS/QCUSTCDT where LSTNAM='Jones' or LSTNAM='Vine'

#                                  Display Data   
#                                              Data width . . . . . . :    102
# Position to line  . . . . .              Shift to column  . . . . . .       
# ....+....1....+....2....+....3....+....4....+....5....+....6....+....7....+....
#  CUSNUM  LSTNAM    INIT  STREET        CITY    STATE  ZIPCOD  CDTLMT  CHGCO
# 839,283  Jones    B D  21B NW 135 St  Clay    NY    13,041      400      1
# 392,859  Vine      S S  PO Box 79      Broton  VT    5,046      700      1
# ********  End of data  ********
import config
from itoolkit import *

itool = iToolKit()
itool.add(iSqlQuery('custquery', "select * from QIWS/QCUSTCDT where LSTNAM='Jones' or LSTNAM='Vine'"))
itool.add(iSqlFetch('custfetch'))
itool.add(iSqlFree('custfree'))

# xmlservice
itool.call(config.itransport)

# output
QCUSTCDT = itool.dict_out('custfetch')
# print(QCUSTCDT)
if 'error' in QCUSTCDT:
  print (QCUSTCDT['error'])
  exit()
else:
  for row in QCUSTCDT['row']:
    print('row:')
    print(' CDTDUE :' + row['CDTDUE'])
    print(' CDTLMT :' + row['CDTLMT'])
    print(' CUSNUM :' + row['CUSNUM'])
    print(' CHGCOD :' + row['CHGCOD'])
    print(' STREET :' + row['STREET'])
    print(' INIT  :' + row['INIT'])
    print(' BALDUE :' + row['BALDUE'])
    print(' LSTNAM :' + row['LSTNAM'])
    print(' ZIPCOD :' + row['ZIPCOD'])
    print(' CITY  :' + row['CITY'])
    print(' STATE  :' + row['STATE'])


@]

[[#isql_rest_async.py]]
!!! itoolkit/sample/isql_rest_async.py
[@
try:
  import queue
except ImportError:
  import Queue as queue
import threading
import urllib
from itoolkit.rest.irestcall import *
from itoolkit import *
class iDB2Async():
  def __init__(self, isql):
      self.itran = iRestCall('http://yips.idevcloud.com/cgi-bin/xmlcgi.pgm','*NONE','*NONE')
      self.itool = iToolKit()
      self.itool.add(iSqlQuery('iqry', isql))
      self.itool.add(iSqlFetch('ifch'))
      self.itool.add(iSqlFree('ifre'))
  def go(self):
      self.itool.call(self.itran)
      return self.itool.dict_out('ifch')
def get_url(q, icmd):
    q.put(iDB2Async(icmd).go())
thedb2s = ["select CUSNUM from QIWS/QCUSTCDT where LSTNAM='Jones'",
          "select CUSNUM from QIWS/QCUSTCDT where LSTNAM='Johnson'"]
q = queue.Queue()
for u in thedb2s:
    t = threading.Thread(target=get_url, args = (q,u))
    t.daemon = True
    t.start()
# q.join()
for u in thedb2s:
    s = q.get()
    print(s)


@]

[[#isrvpgm_qgyrhrl.py]]
!!! itoolkit/sample/isrvpgm_qgyrhrl.py
[@
import config
from itoolkit import *
# Retrieve Hardware Resource List (QGYRHRL, QgyRtvHdwRscList) API
# Service Program: QGYRHR
# Default Public Authority: *USE
# Threadsafe: No
# Required Parameter Group:
#  Output Char(*)..............Receiver variable (RHRL0100, RHRL0110)
#  Input Binary(4).............Length of receiver variable
#  Input Char(8)...............Format name
#  Input Binary(4).............Resource category (see hardware resource category)
#  I/O Char(*).................Error code
# RHRL0100 Format
#  BINARY(4)...................Bytes returned
#  BINARY(4)...................Bytes available
#  BINARY(4)...................Number of resources returned
#  BINARY(4)...................Length of resource entry
#  CHAR(*).....................Resource entries
#  These fields repeat for each resource.
#  BINARY(4)...................Resource category
#  BINARY(4)...................Family level
#  BINARY(4)...................Line type
#  CHAR(10)....................Resource name
#  CHAR(4).....................Type number
#  CHAR(3).....................Model number
#  CHAR(1).....................Status
#  CHAR(8).....................System to which adapter is connected
#  CHAR(12)....................Adapter address
#  CHAR(50)....................Description
#  CHAR(24)....................Resource kind (liar, liar, pants on fire ... binary, not char)
#  hardware resource category:
#  1  All hardware resources (does not include local area network resources)
#  2  Communication resources
#  3  Local work station resources
#  4  Processor resources
#  5  Storage device resources
#  6  Coupled system adapter resources
#  7  Local area network resources
#  8  Cryptographic resources
#  9  Tape and optical resources
#  10 Tape resources
#  11 Optical resources
itool = iToolKit()
itool.add(
 iSrvPgm('qgyrhr','QGYRHR','QgyRtvHdwRscList')
 .addParm(
  iDS('RHRL0100_t',{'len':'rhrlen'})
  .addData(iData('rhrRet','10i0',''))
  .addData(iData('rhrAvl','10i0',''))
  .addData(iData('rhrNbr','10i0','',{'enddo':'mycnt'}))
  .addData(iData('rhrLen','10i0',''))
  .addData(iDS('res_t',{'dim':'999','dou':'mycnt'})
          .addData(iData('resCat','10i0',''))
          .addData(iData('resLvl','10i0',''))
          .addData(iData('resLin','10i0',''))
          .addData(iData('resNam','10a',''))
          .addData(iData('resTyp','4a',''))
          .addData(iData('resMod','3a',''))
          .addData(iData('resSts','1a',''))
          .addData(iData('resSys','8a',''))
          .addData(iData('resAdp','12a',''))
          .addData(iData('resDsc','50a',''))
          .addData(iData('resKnd','24b',''))
          )
 )
 .addParm(iData('rcvlen','10i0','',{'setlen':'rhrlen'}))
 .addParm(iData('fmtnam','10a','RHRL0100'))
 .addParm(iData('rescat','10i0','3')) #  3  Local work station resources
 .addParm(
  iDS('ERRC0100_t',{'len':'errlen'})
  .addData(iData('errRet','10i0',''))
  .addData(iData('errAvl','10i0',''))
  .addData(iData('errExp','7A','',{'setlen':'errlen'}))
  .addData(iData('errRsv','1A',''))
 )
)
# xmlservice
itool.call(config.itransport)
#output
qgyrhr = itool.dict_out('qgyrhr')
if 'success' in qgyrhr:
  print (qgyrhr['success'])
  print ("    Length of receiver variable......" + qgyrhr['rcvlen'])
  print ("    Format name......................" + qgyrhr['fmtnam'])
  print ("    Resource category................" + qgyrhr['rescat'])
  RHRL0100_t = qgyrhr['RHRL0100_t']
  print ('    RHRL0100_t:')
  print ("      Bytes returned................." + RHRL0100_t['rhrRet'])
  print ("      Bytes available................" + RHRL0100_t['rhrAvl'])
  print ("      Number of resources returned..." + RHRL0100_t['rhrNbr'])
  print ("      Length of resource entry......." + RHRL0100_t['rhrLen'])
  if int(RHRL0100_t['rhrNbr']) > 0:
    res_t = RHRL0100_t['res_t']
    for rec in res_t:
      print ("        --------------------------------------------------------")
      keys = rec.keys()
      print ("        Resource category............" + rec['resCat'])
      print ("        Family level................." + rec['resLvl'])
      print ("        Line type...................." + rec['resLin'])
      print ("        Resource name................" + rec['resNam'])
      print ("        Type number.................." + rec['resTyp'])
      print ("        Model number................." + rec['resMod'])
      print ("        Status......................." + rec['resSts'])
      print ("        System adapter connected....." + rec['resSys'])
      print ("        Adapter address.............." + rec['resAdp'])
      print ("        Description.................." + rec['resDsc'])
      print ("        Resource kind................" + rec['resKnd'])
else:
  print (qgyrhr['error'])
  exit()




@]

[[#isrvpgm_zzarray.py]]
!!! itoolkit/sample/isrvpgm_zzarray.py
[@
import config
from itoolkit import *
#    D ARRAYMAX        c                  const(999)
#    D dcRec_t        ds                  qualified based(Template)
#    D  dcMyName                    10A
#    D  dcMyJob                    4096A
#    D  dcMyRank                    10i 0
#    D  dcMyPay                      12p 2
#      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#      * zzarray: check return array aggregate
#      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#    P zzarray        B                  export
#    D zzarray        PI                  likeds(dcRec_t) dim(ARRAYMAX)
#    D  myName                      10A
#    D  myMax                        10i 0
#    D  myCount                      10i 0
itool = iToolKit()
itool.add(iCmd('chglibl', 'CHGLIBL LIBL(XMLSERVICE)'))
itool.add(
 iSrvPgm('zzarray','ZZSRV','ZZARRAY')
 .addParm(iData('myName','10a','ranger'))
 .addParm(iData('myMax','10i0','8'))
 .addParm(iData('myCount','10i0','',{'enddo':'mycnt'}))
 .addRet(
  iDS('dcRec_t',{'dim':'999','dou':'mycnt'})
  .addData(iData('dcMyName','10a',''))
  .addData(iData('dcMyJob','4096a',''))
  .addData(iData('dcMyRank','10i0',''))
  .addData(iData('dcMyPay','12p2',''))
  )
 )

# xmlservice
itool.call(config.itransport)

# output
# print(itool.xml_out())
chglibl = itool.dict_out('chglibl')
if 'success' in chglibl:
  print (chglibl['success'])
else:
  print (chglibl['error'])
  exit()

zzarray = itool.dict_out('zzarray')
# print(zzarray)
if 'success' in zzarray:
  print (zzarray['success'])
  print ("    myName      : " + zzarray['myName'])
  print ("    myMax        : " + zzarray['myMax'])
  print ("    myCount      : " + zzarray['myCount'])
  dcRec_t = zzarray['dcRec_t']
  for rec in dcRec_t:
    print ('    dcRec_t:')
    print ("      dcMyName : " + rec['dcMyName'])
    print ("      dcMyJob  : " + rec['dcMyJob'])
    print ("      dcMyRank : " + rec['dcMyRank'])
    print ("      dcMyPay  : " + rec['dcMyPay'])
else:
  print (zzarray['error'])
  exit()



@]

[[#istop_msg_qsysopr_before_pgm_call.py]]
!!! itoolkit/sample/istop_msg_qsysopr_before_pgm_call.py
[@
from itoolkit import *
from itoolkit.lib.ilibcall import *

print("********************")
print("********************")
print("Hey user,")
print("Using '*debug' transport parameter allows debug halt before run.")
print ("\n  itransport = iLibCall('*here *debug')\n")
print("Expect qsysopr inquire message, you must answer to continue script.")
print("You may attach a debugger before you answer the inquiry.")
print("\n  dspmsg qsysopr\n")
print("  Reply inquiry message any character.")
print("    From  . . . :  ADC            06/25/15  14:08:07")
print("    Debug client 362262/QSECOFR/QP0ZSPWP")
print("      Reply . . :  c\n")
print("Script continues to run after answer (call PGM, etc.)")
print("********************")
print("********************")

itransport = iLibCall("*here *debug") # i will stop, inquiry message qsysopr
itool = iToolKit()
itool.add(iCmd('chglibl', 'CHGLIBL LIBL(XMLSERVICE)'))
itool.add(
 iPgm('zzcall','ZZCALL')
 .addParm(iData('INCHARA','1a','a'))
 .addParm(iData('INCHARB','1a','b'))
 .addParm(iData('INDEC1','7p4','32.1234'))
 .addParm(iData('INDEC2','12p2','33.33'))
 .addParm(
  iDS('INDS1')
  .addData(iData('DSCHARA','1a','a'))
  .addData(iData('DSCHARB','1a','b'))
  .addData(iData('DSDEC1','7p4','32.1234'))
  .addData(iData('DSDEC2','12p2','33.33'))
  )
 )

# xmlservice
itool.call(itransport)

# output
chglibl = itool.dict_out('chglibl')
if 'success' in chglibl:
  print (chglibl['success'])
else:
  print (chglibl['error'])
  exit()

zzcall = itool.dict_out('zzcall')
if 'success' in zzcall:
  print (zzcall['success'])
  print ("    INCHARA      : " + zzcall['INCHARA'])
  print ("    INCHARB      : " + zzcall['INCHARB'])
  print ("    INDEC1      : " + zzcall['INDEC1'])
  print ("    INDEC2      : " + zzcall['INDEC2'])
  print ("    INDS1.DSCHARA: " + zzcall['INDS1']['DSCHARA'])
  print ("    INDS1.DSCHARB: " + zzcall['INDS1']['DSCHARB'])
  print ("    INDS1.DSDEC1 : " + zzcall['INDS1']['DSDEC1'])
  print ("    INDS1.DSDEC2 : " + zzcall['INDS1']['DSDEC2'])
else:
  print (zzcall['error'])
  exit()



@]

[[#ixml_diag.py]]
!!! itoolkit/sample/ixml_diag.py
[@
import config
from itoolkit import *

# from itoolkit.lib.ilibcall import *
# itransport = iLibCall("*here *debug") # i will stop, inquiry message qsysopr

itool = iToolKit()
itool.add(iCmd('chglibl2', 'CHGLIBL LIBL(QTEMP XMLSERVICE)'))
itool.add(iCmd('chglibl3', 'CHGLIBL LIBL(SOMEBAD42)'))
myxml  = "<diag/>"
itool.add(iXml(myxml))

print(itool.xml_in())


# xmlservice
itool.call(config.itransport)
# itool.call(itransport)

# output
print(itool.xml_out())
diag = itool.dict_out()
if 'version' in diag:
  print ("version  : "+diag['version'])
print ("job      : "+diag['jobnbr']+'/'+diag['jobuser']+'/'+diag['jobname'])
print ("jobipc    : "+diag['jobipc'])
print ("curuser  : "+diag['curuser'])
print ("ccsid    : "+diag['ccsid'])
print ("dftccsid  : "+diag['dftccsid'])
print ("paseccsid : "+diag['paseccsid'])
print ("syslibl  : "+diag['syslibl'])
print ("usrlibl  : "+diag['usrlibl'])
joblog = diag['joblog'].replace("\n"," ")
cpflist = ""
for word in joblog.split(' '):
  if word[:3] == 'CPF' or word[:3] == 'MCH':
    cpflist += word + " "
    if diag['jobcpf'] == "":
      diag['jobcpf'] = word
print ("jobcpf    : "+diag['jobcpf'] + " ( " + cpflist + ")")
print ("joblog    :\n" + diag['joblog'])


@]

[[#ixml_zzvary.py]]
!!! itoolkit/sample/ixml_zzvary.py
[@
import config
from itoolkit import *
# XMLSERVICE/ZZSRV.ZZVARY:
#    P zzvary          B                  export
#    D zzvary          PI            20A  varying
#    D  myName                      10A  varying
itool = iToolKit()
itool.add(iXml("<cmd var='chglibl'>CHGLIBL LIBL(XMLSERVICE)</cmd>"))
myxml  = "<pgm name='ZZSRV' func='ZZVARY' var='zzvary'>"
myxml += "<parm io='in'>"
myxml += "<data var='myName' type='10A' varying='on'><![CDATA[<Ranger>]]></data>"
myxml += "</parm>"
myxml += "<return>"
myxml += "<data var='myNameis' type='20A' varying='on'><![CDATA[<Mud>]]></data>"
myxml += "</return>"
myxml += "</pgm>"
itool.add(iXml(myxml))

# xmlservice
itool.call(config.itransport)

# output
chglibl = itool.dict_out('chglibl')
if 'success' in chglibl:
  print (chglibl['success'])
else:
  print (chglibl['error'])
  exit()

zzvary = itool.dict_out('zzvary')
if 'success' in zzvary:
  print (zzvary['success'])
  # print ("    myName      : " + zzvary['myName']) ... input only, no output
  print ("    myNameis    : " + zzvary['myNameis'])
else:
  print (zzvary['error'])
  exit()



@]

to:
The Python is a Python wrapper over the XMLSERVICE open source project from IBM: https://github.com/IBM/python-itoolkit
Changed lines 16-19 from:
2017-12-18 - [[ Attach:python3-itoolkit-1.3.zip | python3-itoolkit-1.3.zip]] - change iLibCall - fix UnicodeDecodeError: ascii codec cannot decode byte 0xc3
to:
2017-12-18 - [[ Attach:python3-itoolkit-1.3.zip | python3-itoolkit-1.3.zip]] - change iLibCall - fix UnicodeDecodeError: ascii codec cannot decode byte 0xc3\\
[@
pip3 install dist/*cp34m*.whl
@]
Added lines 13-17:

!!! Download .whl (test only).
Versions:\\
2017-12-18 - [[ Attach:python3-itoolkit-1.3.zip | python3-itoolkit-1.3.zip]] - change iLibCall - fix UnicodeDecodeError: ascii codec cannot decode byte 0xc3