Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion iniparse/ini.py
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,10 @@ class INISection(config.ConfigNamespace):
_defaults: Optional["INISection"] = None
_optionxformvalue: "INIConfig" = None
_optionxformsource: "INIConfig" = None
_compat_skip_empty_lines: Set[str] = set()
# The real set is created per instance in __init__(). The immutable
# class-level value only makes ConfigNamespace.__setattr__ treat the
# name as a member; a mutable set here would be shared by all sections.
_compat_skip_empty_lines: Set[str] = frozenset() # type: ignore[assignment]

def __init__(
self,
Expand All @@ -369,6 +372,7 @@ def __init__(
self._optionxformvalue = optionxformvalue
self._optionxformsource = optionxformsource
self._options = {}
self._compat_skip_empty_lines = set()

_optionxform = _make_xform_property('_optionxform')

Expand Down
53 changes: 53 additions & 0 deletions tests/test_regressions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
"""
:component: python-iniparse
:requirement: RHSS-291606
:polarion-project-id: RHELSS
:polarion-include-skipped: false
:polarion-lookup-method: id
:poolteam: rhel-sst-csi-client-tools
:caseautomation: Automated
:upstream: No
"""

import unittest
from io import StringIO

from iniparse import compat


class TestCompatSkipEmptyLines(unittest.TestCase):
def test_not_shared_between_instances(self):
"""
:id: fce0ac15-8871-4af4-8017-5f37cbc905b0
:title: Empty-line skipping state is not shared between parsers
:description:
Verifies that the per-option "skip empty lines" compatibility
state of one parser is not modified by operations performed
on another, unrelated parser.
:tags: Tier 1
:steps:
1. Parse a multi-line value containing an empty line with parser A.
2. Set an option with the same name in parser B.
3. Set a multi-line value in parser C, then parse a file with
parser D that has a same-named multi-line option.
:expectedresults:
1. Parser A returns the value without the empty line.
2. Parser A still returns the value without the empty line.
3. Parser C still returns its value with the empty line kept.
"""
a = compat.RawConfigParser()
a.readfp(StringIO('[a]\nfoo = line1\n\n line2\n'))
self.assertEqual(a.get('a', 'foo'), 'line1\nline2')

b = compat.RawConfigParser()
b.add_section('b')
b.set('b', 'foo', 'x')
self.assertEqual(a.get('a', 'foo'), 'line1\nline2')

c = compat.RawConfigParser()
c.add_section('c')
c.set('c', 'bar', 'x\n\ny')
d = compat.RawConfigParser()
d.readfp(StringIO('[d]\nbar = 1\n\n 2\n'))
self.assertEqual(c.get('c', 'bar'), 'x\n\ny')
self.assertEqual(d.get('d', 'bar'), '1\n2')
Loading