@@ -936,6 +936,52 @@ def test_clear(self):
936936 self .assertEqual (set (cf .sections ()), set ())
937937 self .assertEqual (set (cf [self .default_section ].keys ()), {'foo' })
938938
939+ def test_section_popitem (self ):
940+ cf = self .fromstring (f"""
941+ [section]
942+ name1 { self .delimiters [0 ]} value1
943+ name2 { self .delimiters [0 ]} value2
944+ name3 { self .delimiters [0 ]} value3
945+ """ , defaults = {"name2" : "<default>" , "name4" : "<default>" })
946+ section = cf ['section' ]
947+ self .assertEqual (section .popitem (), ('name1' , 'value1' ))
948+ self .assertEqual (section .popitem (), ('name2' , 'value2' ))
949+ self .assertEqual (section .popitem (), ('name3' , 'value3' ))
950+ with self .assertRaises (KeyError ):
951+ section .popitem ()
952+ self .assertEqual (dict (section ), {'name2' : '<default>' ,
953+ 'name4' : '<default>' })
954+ default = cf [self .default_section ]
955+ self .assertEqual (default .popitem (), ('name2' , '<default>' ))
956+ self .assertEqual (default .popitem (), ('name4' , '<default>' ))
957+ with self .assertRaises (KeyError ):
958+ default .popitem ()
959+ self .assertEqual (dict (section ), {})
960+ del cf ['section' ]
961+ with self .assertRaises (configparser .NoSectionError ):
962+ section .popitem ()
963+
964+ def test_section_clear (self ):
965+ cf = self .fromstring (f"""
966+ [section1]
967+ name1 { self .delimiters [0 ]} value1
968+ name2 { self .delimiters [0 ]} value2
969+ [section2]
970+ name3 { self .delimiters [0 ]} value3
971+ """ , defaults = {"name2" : "<default>" , "name4" : "<default>" })
972+ section = cf ['section1' ]
973+ section .clear ()
974+ self .assertEqual (dict (section ), {'name2' : '<default>' ,
975+ 'name4' : '<default>' })
976+ self .assertEqual (cf .sections (), ['section1' , 'section2' ])
977+ cf [self .default_section ].clear ()
978+ self .assertEqual (dict (cf [self .default_section ]), {})
979+ self .assertEqual (dict (section ), {})
980+ self .assertEqual (dict (cf ['section2' ]), {'name3' : 'value3' })
981+ del cf ['section1' ]
982+ with self .assertRaises (configparser .NoSectionError ):
983+ section .clear ()
984+
939985 def test_setitem (self ):
940986 cf = self .fromstring (
941987 f"""
@@ -1033,6 +1079,11 @@ def test_interpolation_missing_value(self):
10331079 e .args , ('name' , 'Interpolation Error' , '%(reference)s' , 'reference' )
10341080 )
10351081
1082+ def test_section_clear_does_not_interpolate (self ):
1083+ cf = self .get_interpolation_config ()
1084+ cf ["Interpolation Error" ].clear ()
1085+ self .assertEqual (cf .options ("Interpolation Error" ), [])
1086+
10361087 def test_items (self ):
10371088 self .check_items_config ([
10381089 ('default' , '<default>' ),
@@ -2468,6 +2519,33 @@ def test_option_regex_no_value_does_not_backtrack(self):
24682519 self .assertTrue (parser .has_option ("section" , "x" + " " * 40000 + "y" ))
24692520
24702521
2522+ class MappingComplexityTestCase (unittest .TestCase ):
2523+ """Removing all sections or all options should take linear time."""
2524+
2525+ @support .requires_resource ('cpu' )
2526+ def test_clear_many_sections (self ):
2527+ n = 50000
2528+ parser = configparser .RawConfigParser ()
2529+ parser .read_string ("" .join (f"[{ i } ]\n " for i in range (n )))
2530+ self .assertEqual (len (parser .sections ()), n )
2531+ # A quadratic clear() would copy the names of all remaining
2532+ # sections for every removed section.
2533+ parser .clear ()
2534+ self .assertEqual (parser .sections (), [])
2535+
2536+ @support .requires_resource ('cpu' )
2537+ def test_clear_many_options (self ):
2538+ n = 50000
2539+ parser = configparser .RawConfigParser ({"key" : "value" })
2540+ parser ["section" ] = {str (i ): str (i ) for i in range (n )}
2541+ section = parser ["section" ]
2542+ self .assertEqual (len (section ), n + 1 )
2543+ # A quadratic clear() would copy the whole section merged with
2544+ # the defaults for every removed option.
2545+ section .clear ()
2546+ self .assertEqual (dict (section ), {"key" : "value" })
2547+
2548+
24712549class MiscTestCase (unittest .TestCase ):
24722550 def test__all__ (self ):
24732551 support .check__all__ (
0 commit comments