Exemplo n.º 1
0
 def test_parse_case_insensitive(self):
     config_file = NamedTemporaryFile()
     config_file.write('[Section]\nKEY=VALUE\nKey=Value\n'.encode('utf-8'))
     config_file.seek(0)
     config_parser = VersionsConfigParser()
     config_parser.read(config_file.name)
     self.assertEquals(config_parser.sections(), ['Section'])
     self.assertEquals(config_parser.options('Section'), ['KEY', 'Key'])
     config_file.close()
Exemplo n.º 2
0
 def parse_versions(self, source):
     """
     Parses the source file to return the packages
     with their current versions.
     """
     config = VersionsConfigParser()
     config.read(source)
     try:
         versions = config.items('versions')
     except NoSectionError:
         logger.debug("'versions' section not found in %s." % source)
         return []
     logger.info('- %d versions found in %s.' % (len(versions), source))
     return versions
def cmdline(argv=sys.argv[1:]):
    parser = ArgumentParser(
        description='(Re)indent buildout related files')
    parser.add_argument(
        'sources', nargs='*',
        help='The buildout files to (re)indent')
    format_group = parser.add_argument_group('Formatting')
    format_group.add_argument(
        '--indent', dest='indentation', type=int, default=32,
        help='Spaces used when indenting "key = value" (default: 32)')
    format_group.add_argument(
        '--sorting', dest='sorting', default='', choices=['alpha', 'length'],
        help='Sorting algorithm used on the keys when writing source file '
        '(default: None)')
    verbosity_group = parser.add_argument_group('Verbosity')
    verbosity_group.add_argument(
        '-v', action='count', dest='verbosity', default=1,
        help='Increase verbosity (specify multiple times for more)')
    verbosity_group.add_argument(
        '-q', action='count', dest='quietly', default=0,
        help='Decrease verbosity (specify multiple times for more)')

    if isinstance(argv, string_types):
        argv = argv.split()
    options = parser.parse_args(argv)

    verbose_logs = {0: 100,
                    1: logging.WARNING,
                    2: logging.INFO,
                    3: logging.DEBUG}
    verbosity = min(3, max(0, options.verbosity - options.quietly))
    console = logging.StreamHandler(sys.stdout)
    console.setLevel(verbose_logs[verbosity])
    logger.addHandler(console)

    if not options.sources:
        logger.warning('No files to (re)indent')
        sys.exit(0)

    for source in options.sources:
        config = VersionsConfigParser()
        config_readed = config.read(source)
        if config_readed:
            config.write(source, options.indentation, options.sorting)
            logger.warning('- %s (re)indented at %s spaces.' % (
                source, options.indentation))
        else:
            logger.warning('- %s cannot be read.' % source)

    sys.exit(0)
Exemplo n.º 4
0
 def test_parse_and_write_buildout_conditional_sections(self):
     config_file = NamedTemporaryFile()
     config_file.write('[Section:Condition]\nKey=Value\n'.encode('utf-8'))
     config_file.seek(0)
     config_parser = VersionsConfigParser()
     config_parser.read(config_file.name)
     config_file.seek(0)
     config_parser.write(config_file.name, 24)
     config_file.seek(0)
     self.assertEquals(
         config_file.read().decode('utf-8'),
         '[Section:Condition]\n'
         'Key                     = Value\n')
     config_file.close()
Exemplo n.º 5
0
 def test_parse_and_write_buildout_macros_offset(self):
     config_file = NamedTemporaryFile()
     config_file.write(
         '[Section]\n<  = Macro\n  Template'.encode('utf-8'))
     config_file.seek(0)
     config_parser = VersionsConfigParser()
     config_parser.read(config_file.name)
     config_file.seek(0)
     config_parser.write(config_file.name, 24)
     config_file.seek(0)
     self.assertEquals(
         config_file.read().decode('utf-8'),
         '[Section]\n'
         '<=                        Macro\n'
         '                          Template\n')
     config_file.close()
Exemplo n.º 6
0
 def test_parse_and_write_buildout_operators_multilines(self):
     config_file = NamedTemporaryFile()
     config_file.write(
         '[Section]\nAdd+=Multi\n  Lines'.encode('utf-8'))
     config_file.seek(0)
     config_parser = VersionsConfigParser()
     config_parser.read(config_file.name)
     config_file.seek(0)
     config_parser.write(config_file.name, 24)
     config_file.seek(0)
     self.assertEquals(
         config_file.read().decode('utf-8'),
         '[Section]\n'
         'Add                    += Multi\n'
         '                          Lines\n')
     config_file.close()
Exemplo n.º 7
0
 def test_parse_and_write_buildout_operators_offset(self):
     config_file = NamedTemporaryFile()
     config_file.write(
         '[Section]\nAd  +=dition\nSub - = straction'.encode('utf-8'))
     config_file.seek(0)
     config_parser = VersionsConfigParser()
     config_parser.read(config_file.name)
     config_file.seek(0)
     config_parser.write(config_file.name, 24)
     config_file.seek(0)
     self.assertEquals(
         config_file.read().decode('utf-8'),
         '[Section]\n'
         'Ad                     += dition\n'
         'Sub                    -= straction\n')
     config_file.close()
Exemplo n.º 8
0
    def parse_versions(self, source):
        """
        Parses the source file to return the packages
        with their current versions.
        """
        config = VersionsConfigParser()
        has_read = config.read(source)

        if not has_read:
            logger.warning("'%s' cannot be read.", source)
            return []

        try:
            versions = config.items('versions')
        except NoSectionError:
            logger.debug("'versions' section not found in %s.", source)
            return []

        logger.info('- %d versions found in %s.', len(versions), source)

        return versions
Exemplo n.º 9
0
 def test_parse_case_insensitive(self):
     config_file = NamedTemporaryFile()
     config_file.write('[Section]\nKEY=VALUE\nKey=Value\n'.encode('utf-8'))
     config_file.seek(0)
     config_parser = VersionsConfigParser()
     config_parser.read(config_file.name)
     self.assertEquals(config_parser.sections(), ['Section'])
     self.assertEquals(config_parser.options('Section'), ['KEY', 'Key'])
     config_file.close()
Exemplo n.º 10
0
 def test_parse_and_write_buildout_conditional_sections(self):
     config_file = NamedTemporaryFile()
     config_file.write('[Section:Condition]\nKey=Value\n'.encode('utf-8'))
     config_file.seek(0)
     config_parser = VersionsConfigParser()
     config_parser.read(config_file.name)
     config_file.seek(0)
     config_parser.write(config_file.name, 24)
     config_file.seek(0)
     self.assertEquals(
         config_file.read().decode('utf-8'), '[Section:Condition]\n'
         'Key                     = Value\n')
     config_file.close()
Exemplo n.º 11
0
 def test_parse_and_write_buildout_macros_offset(self):
     config_file = NamedTemporaryFile()
     config_file.write('[Section]\n<  = Macro\n  Template'.encode('utf-8'))
     config_file.seek(0)
     config_parser = VersionsConfigParser()
     config_parser.read(config_file.name)
     config_file.seek(0)
     config_parser.write(config_file.name, 24)
     config_file.seek(0)
     self.assertEquals(
         config_file.read().decode('utf-8'), '[Section]\n'
         '<=                        Macro\n'
         '                          Template\n')
     config_file.close()
Exemplo n.º 12
0
 def test_parse_and_write_buildout_operators_multilines(self):
     config_file = NamedTemporaryFile()
     config_file.write('[Section]\nAdd+=Multi\n  Lines'.encode('utf-8'))
     config_file.seek(0)
     config_parser = VersionsConfigParser()
     config_parser.read(config_file.name)
     config_file.seek(0)
     config_parser.write(config_file.name, 24)
     config_file.seek(0)
     self.assertEquals(
         config_file.read().decode('utf-8'), '[Section]\n'
         'Add                    += Multi\n'
         '                          Lines\n')
     config_file.close()
Exemplo n.º 13
0
 def test_parse_and_write_buildout_operators_offset(self):
     config_file = NamedTemporaryFile()
     config_file.write(
         '[Section]\nAd  +=dition\nSub - = straction'.encode('utf-8'))
     config_file.seek(0)
     config_parser = VersionsConfigParser()
     config_parser.read(config_file.name)
     config_file.seek(0)
     config_parser.write(config_file.name, 24)
     config_file.seek(0)
     self.assertEquals(
         config_file.read().decode('utf-8'), '[Section]\n'
         'Ad                     += dition\n'
         'Sub                    -= straction\n')
     config_file.close()
Exemplo n.º 14
0
 def test_write_section_length_sorting(self):
     config_file = NamedTemporaryFile()
     config_parser = VersionsConfigParser()
     config_parser.add_section('Section')
     config_parser.set('Section', 'Option-multiline', 'Value1\nValue2')
     config_parser.set('Section', 'Option-void', None)
     config_parser.set('Section', 'Option-size', None)
     config_parser.set('Section', 'Option', 'Value')
     config_parser.write_section(config_file, 'Section', 24, 'length')
     config_file.seek(0)
     self.assertEquals(
         config_file.read().decode('utf-8'), '[Section]\n'
         'Option                  = Value\n'
         'Option-size             = \n'
         'Option-void             = \n'
         'Option-multiline        = Value1\n'
         '                          Value2\n')
     config_file.close()
Exemplo n.º 15
0
 def test_write_alpha_sorting(self):
     config_file = NamedTemporaryFile()
     config_parser = VersionsConfigParser()
     config_parser.add_section('Section 1')
     config_parser.add_section('Section 2')
     config_parser.set('Section 1', 'Option', 'Value')
     config_parser.set('Section 1', 'Option-void', None)
     config_parser.set('Section 1', 'Option-add+', 'Value added')
     config_parser.set('Section 2', 'Option-multiline', 'Value1\nValue2')
     config_parser.set('Section 2', '<', 'Value1\nValue2')
     config_parser.write(config_file.name, sorting='alpha')
     config_file.seek(0)
     self.assertEquals(
         config_file.read().decode('utf-8'),
         '[Section 1]\n'
         'Option                          = Value\n'
         'Option-add                     += Value added\n'
         'Option-void                     = \n'
         '\n'
         '[Section 2]\n'
         '<=                                Value1\n'
         '                                  Value2\n'
         'Option-multiline                = Value1\n'
         '                                  Value2\n')
     config_file.close()
Exemplo n.º 16
0
 def test_write_low_indentation(self):
     config_file = NamedTemporaryFile()
     config_parser = VersionsConfigParser()
     config_parser.add_section('Section 1')
     config_parser.add_section('Section 2')
     config_parser.set('Section 1', 'Option', 'Value')
     config_parser.set('Section 1', 'Option-void', None)
     config_parser.set('Section 2', 'Option-multiline', 'Value1\nValue2')
     config_parser.write(config_file.name, 12)
     config_file.seek(0)
     self.assertEquals(
         config_file.read().decode('utf-8'),
         '[Section 1]\n'
         'Option      = Value\n'
         'Option-void = \n'
         '\n'
         '[Section 2]\n'
         'Option-multiline= Value1\n'
         '              Value2\n')
     config_file.close()
Exemplo n.º 17
0
def cmdline(argv=sys.argv[1:]):
    parser = ArgumentParser(description='Find unused pinned eggs')
    parser.add_argument('source',
                        default='versions.cfg',
                        nargs='?',
                        help='The file where versions are pinned '
                        '(default: versions.cfg)')

    filter_group = parser.add_argument_group('Filtering')
    filter_group.add_argument('--eggs',
                              dest='eggs',
                              default='./eggs/',
                              help='The directory where the eggs are located '
                              '(default: ./eggs/)')
    filter_group.add_argument('-e',
                              '--exclude',
                              action='append',
                              dest='excludes',
                              default=[],
                              help='Exclude package when checking updates '
                              '(can be used multiple times)')

    file_group = parser.add_argument_group('File')
    file_group.add_argument('-w',
                            '--write',
                            action='store_true',
                            dest='write',
                            default=False,
                            help='Write the updates in the source file')
    file_group.add_argument(
        '--indent',
        dest='indentation',
        type=int,
        default=-1,
        help='Spaces used when indenting "key = value" (default: auto)')
    file_group.add_argument(
        '--sorting',
        dest='sorting',
        default='',
        choices=['alpha', 'ascii', 'length'],
        help='Sorting algorithm used on the keys when writing source file '
        '(default: None)')

    verbosity_group = parser.add_argument_group('Verbosity')
    verbosity_group.add_argument(
        '-v',
        action='count',
        dest='verbosity',
        default=1,
        help='Increase verbosity (specify multiple times for more)')
    verbosity_group.add_argument(
        '-q',
        action='count',
        dest='quietly',
        default=0,
        help='Decrease verbosity (specify multiple times for more)')

    if isinstance(argv, str):
        argv = argv.split()
    options = parser.parse_args(argv)

    verbose_logs = {
        0: 100,
        1: logging.WARNING,
        2: logging.INFO,
        3: logging.DEBUG
    }
    verbosity = min(3, max(0, options.verbosity - options.quietly))
    console = logging.StreamHandler(sys.stdout)
    console.setLevel(verbose_logs[verbosity])
    logger.addHandler(console)

    source = options.source
    try:
        checker = UnusedVersionsChecker(source, options.eggs, options.excludes)
    except Exception as e:
        sys.exit(str(e))

    if not checker.unused:
        sys.exit(0)

    for package in checker.unused:
        logger.warning('- %s is unused.', package)

    if options.write:
        config = VersionsConfigParser(indentation=options.indentation,
                                      sorting=options.sorting)
        config.read(source)
        for package in checker.unused:
            config.remove_option('versions', package)

        config.write(source)
        logger.info('- %s updated.', source)

    sys.exit(0)
Exemplo n.º 18
0
 def test_write_low_indentation(self):
     config_file = NamedTemporaryFile()
     config_parser = VersionsConfigParser()
     config_parser.add_section('Section 1')
     config_parser.add_section('Section 2')
     config_parser.set('Section 1', 'Option', 'Value')
     config_parser.set('Section 1', 'Option-void', None)
     config_parser.set('Section 2', 'Option-multiline', 'Value1\nValue2')
     config_parser.write(config_file.name, 12)
     config_file.seek(0)
     self.assertEquals(
         config_file.read().decode('utf-8'), '[Section 1]\n'
         'Option      = Value\n'
         'Option-void = \n'
         '\n'
         '[Section 2]\n'
         'Option-multiline= Value1\n'
         '              Value2\n')
     config_file.close()
Exemplo n.º 19
0
 def test_write_section_length_sorting(self):
     config_file = NamedTemporaryFile()
     config_parser = VersionsConfigParser()
     config_parser.add_section('Section')
     config_parser.set('Section', 'Option-multiline', 'Value1\nValue2')
     config_parser.set('Section', 'Option-void', None)
     config_parser.set('Section', 'Option-size', None)
     config_parser.set('Section', 'Option', 'Value')
     config_parser.write_section(config_file, 'Section', 24, 'length')
     config_file.seek(0)
     self.assertEquals(
         config_file.read().decode('utf-8'),
         '[Section]\n'
         'Option                  = Value\n'
         'Option-size             = \n'
         'Option-void             = \n'
         'Option-multiline        = Value1\n'
         '                          Value2\n')
     config_file.close()
Exemplo n.º 20
0
def cmdline(argv=sys.argv[1:]):
    parser = ArgumentParser(description='Check availables updates from a '
                            'version section of a buildout script')
    parser.add_argument('source',
                        default='versions.cfg',
                        nargs='?',
                        help='The file where versions are pinned '
                        '(default: versions.cfg)')
    version_group = parser.add_argument_group('Allowed versions')
    version_group.add_argument(
        '--pre',
        action='store_true',
        dest='prereleases',
        default=False,
        help='Allow pre-releases and development versions '
        '(by default only stable versions are found)')
    version_group.add_argument(
        '-s',
        '--specifier',
        action=StoreSpecifiers,
        dest='specifiers',
        default={},
        help='Describe what versions of a package are acceptable. '
        'Example "package:>=1.0,!=1.3.4.*,< 2.0" '
        '(can be used multiple times)')
    filter_group = parser.add_argument_group('Filtering')
    filter_group.add_argument('-i',
                              '--include',
                              action='append',
                              dest='includes',
                              default=[],
                              help='Include package when checking updates '
                              '(can be used multiple times)')
    filter_group.add_argument('-e',
                              '--exclude',
                              action='append',
                              dest='excludes',
                              default=[],
                              help='Exclude package when checking updates '
                              '(can be used multiple times)')
    file_group = parser.add_argument_group('File')
    file_group.add_argument('-w',
                            '--write',
                            action='store_true',
                            dest='write',
                            default=False,
                            help='Write the updates in the source file')
    file_group.add_argument(
        '--indent',
        dest='indentation',
        type=int,
        default=32,
        help='Spaces used when indenting "key = value" (default: 32)')
    file_group.add_argument(
        '--sorting',
        dest='sorting',
        default='',
        choices=['alpha', 'length'],
        help='Sorting algorithm used on the keys when writing source file '
        '(default: None)')
    network_group = parser.add_argument_group('Network')
    network_group.add_argument(
        '--service-url',
        dest='service_url',
        default='http://pypi.python.org/pypi',
        help='The service to use for checking the packages '
        '(default: http://pypi.python.org/pypi)')
    network_group.add_argument('--timeout',
                               dest='timeout',
                               type=int,
                               default=10,
                               help='Timeout for each request (default: 10s)')
    network_group.add_argument(
        '-t',
        '--threads',
        dest='threads',
        type=int,
        default=10,
        help='Threads used for checking the versions in parallel')
    verbosity_group = parser.add_argument_group('Verbosity')
    verbosity_group.add_argument(
        '-v',
        action='count',
        dest='verbosity',
        default=1,
        help='Increase verbosity (specify multiple times for more)')
    verbosity_group.add_argument(
        '-q',
        action='count',
        dest='quietly',
        default=0,
        help='Decrease verbosity (specify multiple times for more)')

    if isinstance(argv, string_types):
        argv = argv.split()
    options = parser.parse_args(argv)

    verbose_logs = {
        0: 100,
        1: logging.WARNING,
        2: logging.INFO,
        3: logging.DEBUG
    }
    verbosity = min(3, max(0, options.verbosity - options.quietly))
    console = logging.StreamHandler(sys.stdout)
    console.setLevel(verbose_logs[verbosity])
    logger.addHandler(console)

    source = options.source
    try:
        checker = VersionsChecker(source, options.specifiers,
                                  options.prereleases, options.includes,
                                  options.excludes, options.service_url,
                                  options.timeout, options.threads)
    except Exception as e:
        sys.exit(str(e))

    if not checker.updates:
        sys.exit(0)

    logger.warning('[versions]')
    for package, version in checker.updates.items():
        logger.warning('%s= %s' %
                       (package.ljust(options.indentation), version))

    if options.write:
        config = VersionsConfigParser()
        config.read(source)
        if not config.has_section('versions'):
            config.add_section('versions')
        for package, version in checker.updates.items():
            config.set('versions', package, version)

        config.write(source, options.indentation, options.sorting)
        logger.info('- %s updated.' % source)

    sys.exit(0)
def cmdline(argv=sys.argv[1:]):
    parser = ArgumentParser(
        description='Check availables updates from a '
        'version section of a buildout script')
    parser.add_argument(
        'source', default='versions.cfg', nargs='?',
        help='The file where versions are pinned '
        '(default: versions.cfg)')
    version_group = parser.add_argument_group('Allowed versions')
    version_group.add_argument(
        '--pre', action='store_true', dest='prereleases', default=False,
        help='Allow pre-releases and development versions '
        '(by default only stable versions are found)')
    version_group.add_argument(
        '-s', '--specifier', action=StoreSpecifiers,
        dest='specifiers', default={},
        help='Describe what versions of a package are acceptable. '
        'Example "package:>=1.0,!=1.3.4.*,< 2.0" '
        '(can be used multiple times)')
    filter_group = parser.add_argument_group('Filtering')
    filter_group.add_argument(
        '-i', '--include', action='append', dest='includes', default=[],
        help='Include package when checking updates '
        '(can be used multiple times)')
    filter_group.add_argument(
        '-e', '--exclude', action='append', dest='excludes', default=[],
        help='Exclude package when checking updates '
        '(can be used multiple times)')
    file_group = parser.add_argument_group('File')
    file_group.add_argument(
        '-w', '--write', action='store_true', dest='write', default=False,
        help='Write the updates in the source file')
    file_group.add_argument(
        '--indent', dest='indentation', type=int, default=32,
        help='Spaces used when indenting "key = value" (default: 32)')
    file_group.add_argument(
        '--sorting', dest='sorting', default='', choices=['alpha', 'length'],
        help='Sorting algorithm used on the keys when writing source file '
        '(default: None)')
    network_group = parser.add_argument_group('Network')
    network_group.add_argument(
        '--service-url',  dest='service_url',
        default='http://pypi.python.org/pypi',
        help='The service to use for checking the packages '
        '(default: http://pypi.python.org/pypi)')
    network_group.add_argument(
        '--timeout', dest='timeout', type=int, default=10,
        help='Timeout for each request (default: 10s)')
    network_group.add_argument(
        '-t', '--threads', dest='threads', type=int, default=10,
        help='Threads used for checking the versions in parallel')
    verbosity_group = parser.add_argument_group('Verbosity')
    verbosity_group.add_argument(
        '-v', action='count', dest='verbosity', default=1,
        help='Increase verbosity (specify multiple times for more)')
    verbosity_group.add_argument(
        '-q', action='count', dest='quietly', default=0,
        help='Decrease verbosity (specify multiple times for more)')

    if isinstance(argv, string_types):
        argv = argv.split()
    options = parser.parse_args(argv)

    verbose_logs = {0: 100,
                    1: logging.WARNING,
                    2: logging.INFO,
                    3: logging.DEBUG}
    verbosity = min(3, max(0, options.verbosity - options.quietly))
    console = logging.StreamHandler(sys.stdout)
    console.setLevel(verbose_logs[verbosity])
    logger.addHandler(console)

    source = options.source
    try:
        checker = VersionsChecker(
            source,
            options.specifiers, options.prereleases,
            options.includes, options.excludes,
            options.service_url, options.timeout,
            options.threads)
    except Exception as e:
        sys.exit(str(e))

    if not checker.updates:
        sys.exit(0)

    logger.warning('[versions]')
    for package, version in checker.updates.items():
        logger.warning('%s= %s' % (
            package.ljust(options.indentation), version))

    if options.write:
        config = VersionsConfigParser()
        config.read(source)
        if not config.has_section('versions'):
            config.add_section('versions')
        for package, version in checker.updates.items():
            config.set('versions', package, version)

        config.write(source, options.indentation, options.sorting)
        logger.info('- %s updated.' % source)

    sys.exit(0)
def cmdline(argv=sys.argv[1:]):
    parser = ArgumentParser(description='(Re)indent buildout related files')
    parser.add_argument('sources',
                        nargs='*',
                        help='The buildout files to (re)indent')

    format_group = parser.add_argument_group('Formatting')
    format_group.add_argument(
        '--indent',
        dest='indentation',
        type=int,
        default=-1,
        help='Spaces used when indenting "key = value" (default: auto)')
    format_group.add_argument(
        '--sorting',
        dest='sorting',
        default='',
        choices=['alpha', 'ascii', 'length'],
        help='Sorting algorithm used on the keys when writing source file '
        '(default: None)')

    verbosity_group = parser.add_argument_group('Verbosity')
    verbosity_group.add_argument(
        '-v',
        action='count',
        dest='verbosity',
        default=1,
        help='Increase verbosity (specify multiple times for more)')
    verbosity_group.add_argument(
        '-q',
        action='count',
        dest='quietly',
        default=0,
        help='Decrease verbosity (specify multiple times for more)')

    if isinstance(argv, str):
        argv = argv.split()
    options = parser.parse_args(argv)

    verbose_logs = {
        0: 100,
        1: logging.WARNING,
        2: logging.INFO,
        3: logging.DEBUG
    }
    verbosity = min(3, max(0, options.verbosity - options.quietly))
    console = logging.StreamHandler(sys.stdout)
    console.setLevel(verbose_logs[verbosity])
    logger.addHandler(console)

    if not options.sources:
        logger.warning('No files to (re)indent')
        sys.exit(0)

    for source in options.sources:
        config = VersionsConfigParser(indentation=options.indentation,
                                      sorting=options.sorting)
        config_readed = config.read(source)
        if config_readed:
            config.write(source)
            logger.warning('- %s (re)indented at %s spaces.', source,
                           config.indentation)
        else:
            logger.warning('- %s cannot be read.', source)

    sys.exit(0)
Exemplo n.º 23
0
 def test_write_alpha_sorting(self):
     config_file = NamedTemporaryFile()
     config_parser = VersionsConfigParser()
     config_parser.add_section('Section 1')
     config_parser.add_section('Section 2')
     config_parser.set('Section 1', 'Option', 'Value')
     config_parser.set('Section 1', 'Option-void', None)
     config_parser.set('Section 1', 'Option-add+', 'Value added')
     config_parser.set('Section 2', 'Option-multiline', 'Value1\nValue2')
     config_parser.set('Section 2', '<', 'Value1\nValue2')
     config_parser.write(config_file.name, sorting='alpha')
     config_file.seek(0)
     self.assertEquals(
         config_file.read().decode('utf-8'), '[Section 1]\n'
         'Option                          = Value\n'
         'Option-add                     += Value added\n'
         'Option-void                     = \n'
         '\n'
         '[Section 2]\n'
         '<=                                Value1\n'
         '                                  Value2\n'
         'Option-multiline                = Value1\n'
         '                                  Value2\n')
     config_file.close()