Question

Just starting in on my Python learning curve, and hitting a snag in porting some code up to Python 2.7. It appears that in Python 2.7 it is no longer possible to perform a deepcopy() on instances of ConfigParser. It also appears that the Python team isn't terribly interested in restoring such a capability:

http://bugs.python.org/issue16058

Can someone propose an elegant solution for manually constructing a deepcopy/duplicate of an instance of ConfigParser?

Many thanks, -Pete

Was it helpful?

Solution 2

Based on @Toenex answer, modified for Python 2.7:

import StringIO
import ConfigParser

# Create a deep copy of the configuration object
config_string = StringIO.StringIO()
base_config.write(config_string)

# We must reset the buffer to make it ready for reading.        
config_string.seek(0)        
new_config = ConfigParser.ConfigParser()
new_config.readfp(config_string)

OTHER TIPS

This is just an example implementation of Jan Vlcinsky answer written in Python 3 (I don't have enough reputation to post this as a comment to Jans answer). Many thanks to Jan for the push in the right direction.

To make a full (deep) copy of base_config into new_config just do the following;

import io
import configparser

config_string = io.StringIO()
base_config.write(config_string)
# We must reset the buffer ready for reading.
config_string.seek(0) 
new_config = configparser.ConfigParser()
new_config.read_file(config_string)

The previous solution doesn't work in all python3 use cases. Specifically if the original parser is using Extended Interpolation the copy may fail to work correctly. Fortunately, the easy solution is to use the pickle module:

def deep_copy(config:configparser.ConfigParser)->configparser.ConfigParser:
    """deep copy config"""
    rep = pickle.dumps(config)
    new_config = pickle.loads(rep)
    return new_config

If you need new independent copy of ConfigParser, then one option is:

  • have original version of ConfigParser
  • serialize the config file into temporary file or StringIO buffer
  • use that tmpfile or StringIO buffer to create new ConfigParser.

And you have it done.

If you are using Python 3 (3.2+) you can use the Mapping Protocol Access to copy (actually deep copy) the sections and options of a source configuration to another ConfigParser object.

You can use read_dict() to copy the state of a configuration parser.

Here is a demo:

import configparser

# the configuration to deep copy:
src_cfg = configparser.ConfigParser()
src_cfg.add_section("Section A")
src_cfg["Section A"]["key1"] = "value1"
src_cfg["Section A"]["key2"] = "value2"

# the destination configuration
dst_cfg = configparser.ConfigParser()
dst_cfg.read_dict(src_cfg)
dst_cfg.add_section("Section B")
dst_cfg["Section B"]["key3"] = "value3"

To display the resulting configuration, you can try:

import io

output = io.StringIO()
dst_cfg.write(output)
print(output.getvalue())

You get:

[Section A]
key1 = value1
key2 = value2

[Section B]
key3 = value3

After reading this article, I am more familiar with config.ini.

Record as follows:

import io
import configparser


def copy_config_demo():
    with io.StringIO() as memory_file:
        memory_file.write(str(test_config_data.__doc__))  # original_config.write(memory_file)
        memory_file.seek(0)
        new_config = configparser.ConfigParser(interpolation=configparser.ExtendedInterpolation())
        new_config.read_file(memory_file)

    # below is just for test
    for section_name, list_item in [(section_name, new_config.items(section_name)) for section_name in new_config.sections()]:
        print('\n[' + section_name + ']')
        for key, value in list_item:
            print(f'{key}: {value}')


def test_config_data():
    """
    [Common]
    home_dir: /Users
    library_dir: /Library
    system_dir: /System
    macports_dir: /opt/local

    [Frameworks]
    Python: >=3.2
    path: ${Common:system_dir}/Library/Frameworks/

    [Arthur]
    name: Carson
    my_dir: ${Common:home_dir}/twosheds
    my_pictures: ${my_dir}/Pictures
    python_dir: ${Frameworks:path}/Python/Versions/${Frameworks:Python}
    """

output:

[Common]
home_dir: /Users
library_dir: /Library
system_dir: /System
macports_dir: /opt/local

[Frameworks]
python: >=3.2
path: /System/Library/Frameworks/

[Arthur]
name: Carson
my_dir: /Users/twosheds
my_pictures: /Users/twosheds/Pictures
python_dir: /System/Library/Frameworks//Python/Versions/>=3.2

hoping it is helpful to you.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top