Examples

Simple example: One file

let’s view an example (my native language is German, so I use this with translation):

Ex1.py:

#!/usr/bin/env python3
# vim: expandtab:ts=4:sw=4:noai
"""Example 1"""
import sys
from pcs_argpass.Param import Param #, Translation_de_DE
from pcs_argpass.GPL3 import LGPL_Preamble_DE, GPL3_2007, LGPL_Preamble, LGPL3_2007

MyParam:Param = None              # to produce an error if not initialized!

Def_LogMqtt = {                             # This is the declaration of the command-line
                                            # options
    'Help':                                 # This is the key value for this Option
                                            # must be str and of couse unique
        {
        's': 'h',                           # the short option for this (e.g. -h)
                                            # if more characters are given all of
                                            # them are matched.
        'l': 'help',                        # the long option(s) (e.g. --help). Long
                                            # options can be abbrevated to minimal 2
                                            # characters as long as the abbrevation
                                            # is unique within all long options,
                                            # so also --he or --hel is supported. If this
                                            # entry is a list or tuple then any of this
                                            # entries match.
        'm': 'H',                           # The modus for this option (see details
                                            # in "SetDef" function)
                                            # 'H' means this is one of the "help"
                                            # entries. Since "Help" is a "special" case
                                            # as also "Export" os "Licence" are it is
                                            # possible to have more than one such entry
                                            # in the definition
        'd': 'Show this text and quit.'     # the help-text for this option. Can of
                                            # course be also multi-line.
        },
    'MqttBroker':
        {
        's': 'm',
        'l': 'mqttbroker',
        'm': 't',                           # this is a text-entry
        'r': True,                          # it is required
        'o': True,                          # it needs an parameter ("-m" allone makes
                                            # no sense, must be "-m 10.11.12.13" or
                                            # --mqtt=10.11.12.13)
        'v': 'localhost',                   # the default value used if this is not on the
                                            # command-line
        'd': 'Address of MQTT-Broker',
        },
    'MqttPort':
        {
        's': 'p',
        'l': 'port',
        'm': 'i',                           # This is an integer
        'L': 1024,                          # lower limit. The entered value must
                                            # be >= this value
                                            # (works also for float and str)
        'U': 32766,                         # upper limit. The entered value must
                                            # be <= this value
        'r': True,
        'o': True,
        'v': 1883,
        'd': 'Port of MQTT-Broker',
        },
    'Topic':
        {
        's': 't',
        'l': 'topic',
        'm': 't',                           # also a text entry
        'o': True,
        'M': True,                          # but allow multiple occurences.
                                            # The variable in the resulting
                                            # dictionary is a list!
        'v': [],
        'd': 'Topic to dump',
        },
    'OutFile':
        {
        's': 'f',
        'l': 'file',
        'm': 'p',                           # this is a path, not a file, because
                                            # a file (mode = f) must exist. File is
                                            # used for input-files, path for non
                                            # existing output (file or dir). It is
                                            # only tested if the format is valid
                                            # on this operating system.
        'o': True,
        'v': '',
        'd': 'Output path',
        },
    'License':
        {
        's': '§l',                          # here we have 2 possible short options
        'l': 'license',
        'm': '§',                           # This will show the "short" license
        'd': 'Show license and exit'
        },
    'GPL':
        {
        's': 'g',
        'l': ('gpl','GPL','Gpl'),           # here all of this entries are valid
                                            # on the command-line
        'm': 'L',                           # This will show the complete license
                                            # in this example realy a lot of text.
        'd': 'Show complete license and exit'
        },
}

Version = "1.0.0"
try:                                            # catch illegal definitions
    MyParam = Param(Def=Def_LogMqtt,
                    Desc="dump MQTT-Topics to file",
                    AllParams=True,
                    Version=Version,
#                    translation=Translation_de_DE, # remove this line for english
                                                    # messages
                    License=('\\nCopyright (c) 2022 <your name>\\n' + LGPL_Preamble_DE,
                        LGPL_Preamble,
                        LGPL3_2007,
                        GPL3_2007),
                    )

    if not MyParam.Process():                   # This does the "REAL" processing of
                                                # the command-line args. return True
                                                # if everything is done and the program
                                                # should exit (e.g. Help etc.)

# do your work here.

        # You can use the Param-class like a normal dictionary,
        # so this is perfectly legal
        if len(MyParam['Topic']) == 0:          # no topics given
            MyParam['Topic'].append('#')        # use "ALL" topics

        # if you want to display the given command line options do the following:
        print(MyParam.ParamStr())   # this function returns the
                                                # complete parameters entered

except Param.ParamError as RunExc:      # here we catch any parameter errors and inform the user
    print(f"{RunExc }",file=sys.stderr)
    sys.exit(1)
sys.exit(0)

Try start this program with “-h” and next time with “-§” or “-L”. Try start it with illegal parameters and look what happens.

If you start the program without any parameters the result will be:

------------------------------------------------------------
global
------------------------------------------------------------
global -> MqttBroker (-m, --mqttbroker) : 'localhost'
global -> MqttPort   (-p, --port)       : 1883
global -> OutFile    (-f, --file)       : ''
global -> Topic      (-t, --topic)      : ['#']

If you give “-h” or “–help” the result is:

Version:: 1.0.0
Usage:

    Ex1 [OPTIONS ...]

dump MQTT-Topics to file
Options:

-h   --help                Show this text and quit.

-m   --mqttbroker=value    Default: 'localhost'
                           Address of MQTT-Broker

-p   --port=value          (1024 ... 32766), Default: 1883
                           Port of MQTT-Broker

-t   --topic=value         Topic to dump

-f   --file=value          Output path

-§   --license             Show license and exit
-l

-g   --gpl                 Show complete license and exit
     --GPL
     --Gpl

The module will enshure that you get all requested parameter at least initiated with the default values. All not requested options are found in UnusedArgs. If you prefer to not having keys that are not on the command-line set AllParams to False. An error will be raised in this case if a “required” parameter (‘r’ is True) is not given.

It is up to you if you check yourselve for a default value (e.g. ‘’ at OutFile) or let the module check if the parameter is given.

If you simply set the output to sys.stdout if not given you MUST set AllParams to True and test the resultvalue yourselfe.

Normal but still simple example: Two files

Normally you put the parameter definition in its own file to make the program more readable:

1.) Ex2_Args.py

#!/usr/bin/env python3
# vim: expandtab:ts=4:sw=4:noai
"""Example 2 Args"""
Def_LogMqtt = {
    'Help':
        {
        's': 'h',
        'l': 'help',
        'm': 'H',
        'd': 'Show this text and quit.'
        },
    'MqttBroker':
        {
        's': 'm',
        'l': 'mqttbroker',
        'm': 't',
        'r': True,
        'o': True,
        'v': 'localhost',
        'd': 'Address of MQTT-Broker',
        },
    'MqttPort':
        {
        's': 'p',
        'l': 'port',
        'm': 'i',
        'L': 1024,
        'U': 32766,
        'r': True,
        'o': True,
        'v': 1883,
        'd': 'Port of MQTT-Broker',
        },
    'Topic':
        {
        's': 't',
        'l': 'topic',
        'm': 't',
        'o': True,
        'M': True,
        'v': [],
        'd': 'Topic to dump',
        },
    'OutFile':
        {
        's': 'f',
        'l': 'file',
        'm': 'p',
        'o': True,
        'd': 'Output path',
        },
    'License':
        {
        's': '§l',
        'l': 'license',
        'm': '§',
        'd': 'Show license and exit'
        },
    'GPL':
        {
        's': 'g',
        'l': ('gpl','GPL','Gpl'),
        'm': 'L',
        'd': 'Show complete license and exit'
        },
}

2.) Ex2.py

#!/usr/bin/env python3
# vim: expandtab:ts=4:sw=4:noai
"""Example 2"""
import sys
from pcs_argpass.Param import Param #, Translation_de_DE
from pcs_argpass.GPL3 import LGPL_Preamble_DE, GPL3_2007, LGPL_Preamble, LGPL3_2007
from Ex2_Args import Def_LogMqtt

MyParam:Param = None              # to produce an error if not initialized!
Version = "1.0.0"

def main():
    """ Do your work here """
    print(MyParam.ParamStr())       # only to do something

if __name__ == '__main__':
    try:                                            # catch illegal definitions
        MyParam = Param(Def=Def_LogMqtt,
                        Desc="dump MQTT-Topics to file",
                        AllParams=True,
                        Version=Version,
#                        translation=Translation_de_DE, # remove this line for english messages
                        License=('\\nCopyright (c) 2022 <your name>\\n' + LGPL_Preamble_DE,
                            LGPL_Preamble, LGPL3_2007, GPL3_2007))
        if not MyParam.Process():
            main()
    except Param.ParamError as RunExc:      # here we catch any parameter errors and inform the user
        print(f"{RunExc }",file=sys.stderr)
        sys.exit(1)
    sys.exit(0)

Now we see that the program is very clear and short as long as it is only for parameter handling.

More complex usage

Let’s assume you write a program that uses some type of data handling.

Let’s say there is a part that adds a person to some datastructure another part that send the data to an file and at least a possibility to delete this person by an id returned at the time we add it.

We can define a switch for adding, another for printing and so on. The definition will not be very clear to the user. Now we split this in to 4 parts.

1.) Ex3_Args.py

#!/usr/bin/env python3
# vim: expandtab:ts=4:sw=4:noai
"""Example 2 Args"""
Def_Main = {
    'Help':
        {
        's': 'h',
        'l': 'help',
        'm': 'H',
        'd': 'Show this text and quit.'
        },
    'License':
        {
        's': '§',
        'l': 'licence',
        'm': '§',
        'd': 'Show license text and quit.'
        },
    'GPL':
        {
        's': 'g',
        'l': 'gpl',
        'm': 'L',
        'd': 'Show full license text and quit.'
        },
    'Verbose': {
        's': 'v',
        'l': 'verbose',
        'r': False,
        'm': 'C',
        'd': "Be more verbose in logging"
        },
}

Def_Add = {
    'Help':
        {
        'l': 'help',
        'm': 'H',
        'd': 'Show this text and quit.'
        },
    'Add':
        {
        's': 'a',
        'l': 'add',
        'm': 't',
        'r': True,
        'o': True,
        'v': '',
        'd': 'Name to add',
        },
    'Department':
        {
        'l': 'department',
        'm': 't',
        'r': False,
        'o': True,
        'v': '',
        'd': 'Optional department',
        },
}

Def_Print = {
    'Print':
        {
        's': 'p',
        'l': 'print',
        'm': 'b',
        'v' : False,
        'd': 'Print values'
        },
}

Def_Del = {
    'Del':
        {
        's': 'd',
        'l': 'del',
        'm': 'i',
        'L': 1,
        'r': True,
        'o': True,
        'v': 0,
        'd': 'Id to delete',
        },
}

Child_Def = {
    'add':
        {
        'Desc': 'Add a new name with optional department',
        'Def': Def_Add,
        },
    'del':
        {
        'Desc': 'delete an Id',
        'Def': Def_Del,
        },
    'print':
        {
        'Desc': 'Print values',
        'Def': Def_Print,
        },
}

2.) Ex3.py

#!/usr/bin/env python3
# vim: expandtab:ts=4:sw=4:noai
"""Example 3"""

import sys
from Ex3_Args import Def_Main, Child_Def
from pcs_argpass.Param import Param
from pcs_argpass.GPL3 import GPL3_2007, GPL_Preamble


MyParam:Param = None              # to produce an error if not initialized!
Version = "1.0.0"

def main():
    """ Do your work here """
    print(MyParam.ParamStr())       # only to do something

    AddPar = MyParam.Child['add']   # you can get a sub-part of your definitions
    for key,value in AddPar.items():
        print(f"{key} -> {value}")

if __name__ == '__main__':
    try:                                            # catch illegal definitions
        MyParam = Param(Def=Def_Main,
                        Desc="Manage names",
                        AllParams=True,
                        Children=Child_Def,
                        Version=Version,
                        ShowPrefixOnHelp=False,
#                        translation=Translation_de_DE, # remove this line for english messages
                        License=('\nCopyright (c) 2022 <your name>\n' + GPL_Preamble, GPL3_2007))
        print(MyParam.TestCommandLineParameter)
        if not MyParam.Process():
            main()
    except Param.ParamError as RunExc:      # here we catch any parameter errors and inform the user
        print(f"{RunExc }",file=sys.stderr)
        sys.exit(1)
    sys.exit(0)

If you invoke this program with “-h” then the output look like this:

Version:: 1.0.0
Usage:

    Ex3 [OPTIONS ...]

Manage names
Options:

-h   --help             Show this text and quit.

-§   --licence          Show license text and quit.

-g   --gpl              Show full license text and quit.

-v   --verbose=value    Be more verbose in logging


    Add a new name with optional department

         --[add.]help                Show this text and quit.

    -a   --[add.]add=value           Name to add

         --[add.]department=value    Optional department


    delete an Id

    -d   --[del.]del=value    (1 ...)
                                Id to delete


    Print values

    -p   --[print.]print          Print values

As you see the different options are grouped and (in this simple case not relly necassary) vied as “function groups”. But all keys are accessible by their names from the normal Param instance.

Look at –[add.]help:

this means there is a second help entry within this declaration. It only has a “long” option an can therefore be invoked by

Ex3.py --add.help

in this case the folowing output is generated:

#------------------------------------------------------------
# add
#------------------------------------------------------------


Add a new name with optional department

     --[add.]help                Show this text and quit.

-a   --[add.]add=value           Name to add

     --[add.]department=value    Optional department

I know this is not a great benefit for THIS application but if you have a lot of parameters in an big cli it is helpfull. It is up to you if you put a separate “help”-entry in your definition, but the rest is done by the module.

It is possible to get the sub-instances by the “Child” property and work with them exact the same way as with the main instance. It is also possible to nest this system ad infinitum.

Remember:

All sub-instances inherit the keys of all of their parents! A parent has also all keys of all of his children, grandchilden and so on.

If you run this program without any parameter the result is:

------------------------------------------------------------
global
------------------------------------------------------------
global    -> Verbose    (-v, --verbose) : 0
    ------------------------------------------------------------
    add
    ------------------------------------------------------------
    add   -> Add        (-a, --add)     : ''
    add   -> Department (--department)  : ''
    add   -> Verbose                    : 0
    ------------------------------------------------------------
    del
    ------------------------------------------------------------
    del   -> Del        (-d, --del)     : 0
    del   -> Verbose                    : 0
    ------------------------------------------------------------
    print
    ------------------------------------------------------------
    print -> Print      (-p, --print)   : False
    print -> Verbose                    : 0
Add ->
Department ->
Verbose -> 0

Now we see that all children have the Verbose option of their parent also within their keys, but that are no copies but only references to their parent. So the key-linking is up and down the tree.

The last 3 lines is the result of the printing of the clild-instance in the main function. It is exactly what we expect!