Search code examples
pythongitpython-2.7tabspython-3.3

How to stop Python 2.7 RawConfigParser throwing ParsingError on tabs?


I am writing a package compatible with both Python 2.7.13 and Python 3.3, and using the following:

try:
    import configparser
except:
    from six.moves import configparser

But when I load my .gitmodules file on Python 2.7:

    configParser   = configparser.RawConfigParser( allow_no_value=True )
    configFilePath = os.path.join( current_directory, '.gitmodules' )

    configParser.read( configFilePath )

It throw the error:

Exception in thread Thread-1:
Traceback (most recent call last):
  File "/usr/lib/python2.7/threading.py", line 801, in __bootstrap_inner
    self.run()
  File "update.py", line 122, in run
    self.create_backstroke_pulls()
  File "update.py", line 132, in create_backstroke_pulls
    configParser.read( configFilePath )
  File "/usr/lib/python2.7/ConfigParser.py", line 305, in read
    self._read(fp, filename)
  File "/usr/lib/python2.7/ConfigParser.py", line 546, in _read
    raise e
ParsingError: File contains parsing errors: /cygdrive/d/.gitmodules
        [line  2]: '\tpath = .versioning\n'
        [line  3]: '\turl = https://github.com/user/repo\n'

But if I remove the tabs from the .gitmodules file, it works correctly. On Python 3.3 it does work with tabs, only on Python 2.7.13 it is not working with tabs. How can I make it work without removing the tabs?

The tabs are natively put by git when I am adding new submodules, so I definitely not remove them from the original file. I have been thinking I could duplicate the file, while removing the tabs. But is there less costly operation for compatibility with Python?


Related questions:

  1. How can I remove the white characters from configuration file?

Solution

  • A workaround would be to use a io.StringIO, with modified contents, to pass to readfp (which accepts a file handle instead of file name).

    The following code is trying to comply to both Python 2 and Python 3 (even if in python 3, readfp is deprecated, now it's read_file. Anyway that still works). Note that I don't need six package, configparser exists natively in 2 & 3 python versions.

    try:
        import ConfigParser as configparser
    except ImportError:
        import configparser
    
    import io
    try:
        unicode
    except NameError:
        unicode = str  # python 3: no more unicode
    
    r = configparser.RawConfigParser()
    
    with open(configFilePath) as f:
        fakefile = io.StringIO(unicode(f.read().replace("\t","")))
    
    r.readfp(fakefile,filename=configFilePath)
    

    so the parser is "fooled" by reading a fake file with filecontents minus the tabs.