6. Common tasks

6.1. Configuration files

6.1.1. In Perl

What we're trying to accomplish ist the Python equivalent of
%config={};
open(CFG,"testfile.txt");
while (<CFG>){
    s/#.*//;
    if (/(\w+)=(.*)/){
        $config{$1}=$2;
        print "config{$1}=$2; $config{$1}\n";
    }
}

So, a simple configuration file, with comments and simple a=b assignments. While reding, we also want some sanity-checks, whitch is done by the matching of the regular expressions. The result should be some form of hash/dictionary in which we can lookup the values by text.

6.1.2. configobj

The Python-way seems to be to google if there is a module that does it for you and then use that module. There are a number of modules that read config files, and configobj seems the most simple one.

If it would work.

Try 1:
import configobj
config=configobj.configobj("testfile.txt")

Result:
Traceback (most recent call last):
  File "configobj.py", line 2, in <module>
      import configobj
    File "/home/ljm/src/learning_python/configobj.py", line 3, in <module>
      config=configobj.configobj("testfile.txt")
  TypeError: 'module' object is not callable

The type of configobj.configobj is a module. That is a bit unexpected. Especially since many answers on the Internet suggest that configobj is the module and configobj.configobj should be the way to use it. But apparently, it is not.
import configobj
print type(configobj)
print type(configobj.configobj)
print type(configobj.configobj.configobj)

gives:
<type 'module'>
<type 'module'>
<type 'module'>
<type 'module'>
<type 'module'>
<type 'module'>

Try 2:
from configobj import configobj

which gives:
Traceback (most recent call last):
  File "configobj.py", line 2, in <module>
      from configobj import configobj
    File "/home/ljm/src/learning_python/configobj.py", line 2, in <module>
      from configobj import configobj
  ImportError: cannot import name configobj

Camel-humping the config obj results in yet another import error:
Traceback (most recent call last):
  File "configobj.py", line 2, in <module>
    from configobj import ConfiGobj
  File "/home/ljm/src/learning_python/configobj.py", line 2, in <module>
    from configobj import ConfiGobj
ImportError: cannot import name ConfiGobj

This also means that none of the configobj examples work. And because I don't understand what is happening (behavior does not comply with any of the solutions that I got), I will abandon this module.

6.1.3. ConfigParser

Another module that does the configuration is ConfigParser. It requires a more complicates configuration file.
import ConfigParser
config = ConfigParser.RawConfigParser()
config.read('testfile.txt')
a=config.get('notes',"do")
print a

You must have a [section header] in the file, otherwise the module will fail.
Traceback (most recent call last):
  File "configparser.py", line 4, in <module>
     config.read('testfile.txt')
    File "/usr/lib64/python2.7/ConfigParser.py", line 305, in read
     self._read(fp, filename)
    File "/usr/lib64/python2.7/ConfigParser.py", line 512, in _read
     raise MissingSectionHeaderError(fpname, lineno, line)
  ConfigParser.MissingSectionHeaderError: File contains no section headers.
  file: testfile.txt, line: 1

eventhough the module is documented ( https://docs.python.org/2/library/configparser.html ), there is still a lot unclear about its workings. Ah well, that also seems to be the Python way.

6.1.4. Import

There are some that suggest that using import and creating valid python code as config file is a good idea. It is not.

Ofcourse, if everything is completely under control, and your users won't put code in the config file, then it may not be so bad. But if your user is anyone else but yourself, don't do this.

6.2. Command line arguments

6.2.1. Sys.argv

If you want to interact with anything beyond the most simplset, you need to import sys. In sys there is an array sys.argv that contains the arguments. Like everywhere else, sys.argv[0] contains the name of the script or program.

6.2.2. Getopt

A more or less standard way of parsing arguments is getopt. This is available in C, Perl, Bashe and many others, and also in Python. However, because it is standard, Python doesn't like it. The official stance is that getopt is not deprecated, but argparse is more actively maintained and should be used for new development.

The following sniplet shows the use of getopt:
#!/usr/bin/python
import sys, getopt
try:
    opts, args = getopt.gnu_getopt(sys.argv[1:],"he:q:",["question=","exclamation="])
except getopt.GetoptError:
   print sys.argv[0], '[-e excalamation ] [ -q question ]'
   sys.exit(2)
for opt, arg in opts:
   if opt == '-h':
      print sys.argv[0], '[-e excalamation ] [ -q question ]'
      sys.exit()
   elif opt in ("-q", "--question"):
      print arg,'?'
   elif opt in ("-e", "--exclamation"):
      print arg,'!'
print 'arg=',args

Note that getopt.gnu_getopt gets sys.argv[1:] as list of options. sys.argv[0] contains the name of the script and would therefore mess-up the argument parsing.

We used gnu_getopt because otherwise, parsing of the flags stops when the first non-flag argument is encoutered.

The result is shown below.
$ python getops.py -q question answer --exclamation yes  oh
question ?
yes !
arg= ['answer', 'oh']

6.2.3. agparse

Agparse is at the moment the prefered option to parse command line arguments. It is more advanced than getops, and it has a nice self-documenting feature.

6.3. Regular expression matching

If there's anything Perl is good in, it is handling regular expressions. In Python, this is made complicated. As if the goal is to discourage the use.

First: it is not standard in Python. It is an add-on that needs to be imported.