FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Update some libs & tests to 3.14.7 (#8577) · RustPython/RustPython@435d588 · GitHub

Commit 435d588

Browse files
authored
Update some libs & tests to 3.14.7 (#8577)
* Update some libs and tests to 3.14.7 * test_shlex.py * email
1 parent d53f35f commit 435d588

9 files changed

Lines changed: 349 additions & 8 deletions

File tree

‎Lib/email/utils.py‎

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -317,10 +317,13 @@ def parsedate_to_datetime(data):
317317
if parsed_date_tz is None:
318318
raise ValueError('Invalid date value or format "%s"' % str(data))
319319
*dtuple, tz = parsed_date_tz
320-
if tz is None:
321-
return datetime.datetime(*dtuple[:6])
322-
return datetime.datetime(*dtuple[:6],
323-
tzinfo=datetime.timezone(datetime.timedelta(seconds=tz)))
320+
try:
321+
if tz is None:
322+
return datetime.datetime(*dtuple[:6])
323+
return datetime.datetime(*dtuple[:6],
324+
tzinfo=datetime.timezone(datetime.timedelta(seconds=tz)))
325+
except OverflowError as exc:
326+
raise ValueError('Invalid date value or format "%s"' % str(data)) from exc
324327

325328

326329
def parseaddr(addr, *, strict=True):

‎Lib/html/parser.py‎

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,9 @@ def reset(self):
157157
self.cdata_elem = None
158158
self._support_cdata = True
159159
self._escapable = True
160+
self._pending = []
161+
self._pending_len = 0
162+
self._parse_threshold = 1
160163
super().reset()
161164

162165
def feed(self, data):
@@ -165,11 +168,36 @@ def feed(self, data):
165168
Call this as often as you want, with as little or as much text
166169
as you want (may include '\n').
167170
"""
168-
self.rawdata = self.rawdata + data
169-
self.goahead(0)
171+
# Accumulate new data in a list and only join and parse it once
172+
# enough has piled up. Rescanning an unparsed buffer (e.g. an
173+
# unterminated tag) and concatenating onto it on every call would
174+
# both be quadratic in the input size.
175+
self._pending_len += len(data)
176+
if self._pending_len < self._parse_threshold:
177+
self._pending.append(data)
178+
else:
179+
if not self._pending:
180+
self.rawdata += data
181+
else:
182+
self._pending.append(data)
183+
self.rawdata += ''.join(self._pending)
184+
self._pending.clear()
185+
self._pending_len = 0
186+
n = len(self.rawdata)
187+
self.goahead(0)
188+
if len(self.rawdata) < n:
189+
# Some data was parsed; resume on the next call.
190+
self._parse_threshold = 1
191+
else:
192+
# Nothing was parsed; wait until the buffer doubles.
193+
self._parse_threshold = len(self.rawdata)
170194

171195
def close(self):
172196
"""Handle any buffered data."""
197+
if self._pending:
198+
self.rawdata += ''.join(self._pending)
199+
self._pending.clear()
200+
self._pending_len = 0
173201
self.goahead(1)
174202

175203
__starttag_text = None
@@ -387,9 +415,11 @@ def parse_html_declaration(self, i):
387415
def parse_comment(self, i, report=True):
388416
rawdata = self.rawdata
389417
assert rawdata.startswith('<!--', i), 'unexpected call to parse_comment()'
390-
match = commentclose.search(rawdata, i+4)
418+
# An empty comment is abruptly closed by the first ">" or "->",
419+
# taking priority over a later "-->" or "--!>" close.
420+
match = commentabruptclose.match(rawdata, i+4)
391421
if not match:
392-
match = commentabruptclose.match(rawdata, i+4)
422+
match = commentclose.search(rawdata, i+4)
393423
if not match:
394424
return -1
395425
if report:

‎Lib/test/test_colorsys.py‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ def test_hsv_values(self):
4242
self.assertTripleEqual(hsv, colorsys.rgb_to_hsv(*rgb))
4343
self.assertTripleEqual(rgb, colorsys.hsv_to_rgb(*hsv))
4444

45+
# test 360 phase shift in hue
46+
h, s, v = hsv
47+
self.assertTripleEqual(rgb, colorsys.hsv_to_rgb(h + 1.0, s, v))
48+
4549
def test_hls_roundtrip(self):
4650
for r in frange(0.0, 1.0, 0.2):
4751
for g in frange(0.0, 1.0, 0.2):
@@ -89,6 +93,18 @@ def test_yiq_roundtrip(self):
8993
colorsys.yiq_to_rgb(*colorsys.rgb_to_yiq(*rgb))
9094
)
9195

96+
def test_yiq_to_rgb_clamping(self):
97+
values = [
98+
# rgb, yiq (invalid YIQ values clamped to RGB range)
99+
((1.0, 0.0, 1.0), (0.0, 0.5, 1.0)),
100+
((0.0, 1.0, 0.0), (0.25, -1.0, -1.0)),
101+
((0.0, 0.0, 1.0), (0.0, -1.0, 0.5))
102+
]
103+
104+
for (rgb, yiq) in values:
105+
with self.subTest(rgb=rgb, yiq=yiq):
106+
self.assertTripleEqual(rgb, colorsys.yiq_to_rgb(*yiq))
107+
92108
def test_yiq_values(self):
93109
values = [
94110
# rgb, yiq

‎Lib/test/test_email/test_headerregistry.py‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,14 @@ def test_invalid_date_value(self):
223223
self.assertEqual(len(h.defects), 1)
224224
self.assertIsInstance(h.defects[0], errors.InvalidDateDefect)
225225

226+
def test_out_of_range_date_value(self):
227+
s = 'Mon, 20 Nov 9999999999 12:00:00 +0000'
228+
h = self.make_header('date', s)
229+
self.assertEqual(h, s)
230+
self.assertIsNone(h.datetime)
231+
self.assertEqual(len(h.defects), 1)
232+
self.assertIsInstance(h.defects[0], errors.InvalidDateDefect)
233+
226234
def test_datetime_read_only(self):
227235
h = self.make_header('date', self.datestring)
228236
with self.assertRaises(AttributeError):

‎Lib/test/test_email/test_utils.py‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,15 @@ def test_parsedate_to_datetime_with_invalid_raises_valueerror(self):
7777
with self.subTest(dtstr=dtstr):
7878
self.assertRaises(ValueError, utils.parsedate_to_datetime, dtstr)
7979

80+
def test_parsedate_to_datetime_out_of_range_raises_valueerror(self):
81+
out_of_range_dates = [
82+
'Mon, 20 Nov 9999999999 12:00:00 +0000',
83+
'Mon, 20 Nov 2017 12:00:00 +24000000000000',
84+
]
85+
for dtstr in out_of_range_dates:
86+
with self.subTest(dtstr=dtstr):
87+
self.assertRaises(ValueError, utils.parsedate_to_datetime, dtstr)
88+
8089
class LocaltimeTests(unittest.TestCase):
8190

8291
def test_localtime_is_tz_aware_daylight_true(self):

‎Lib/test/test_getopt.py‎

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,18 @@ def test_getopt(self):
149149
('-a', ''), ('--alpha', '')])
150150
self.assertEqual(args, ['arg1', 'arg2'])
151151

152+
# Allow string for single long argument
153+
opts, args = getopt.getopt(cmdline, 'a::', 'alpha=?')
154+
self.assertEqual(opts, [('-a', '1'), ('--alpha', '2'), ('--alpha', ''),
155+
('-a', ''), ('--alpha', '')])
156+
self.assertEqual(args, ['arg1', 'arg2'])
157+
158+
# Pass everything after -- as args
159+
cmdline = ['-a1', '--alpha=2', '--', '-b', '--beta=5']
160+
opts, args = getopt.getopt(cmdline, 'a:b', ['alpha=', 'beta'])
161+
self.assertEqual(opts, [('-a', '1'), ('--alpha', '2')])
162+
self.assertEqual(args, ['-b', '--beta=5'])
163+
152164
self.assertError(getopt.getopt, cmdline, 'a:b', ['alpha', 'beta'])
153165

154166
def test_gnu_getopt(self):
@@ -191,13 +203,36 @@ def test_gnu_getopt(self):
191203
self.assertEqual(args, ['arg1', '-b', '1', '--alpha', '--beta=2',
192204
'--beta', '3', 'arg2'])
193205

206+
# Allow string for single long argument
207+
opts, args = getopt.gnu_getopt(cmdline, 'ab:', 'alpha')
208+
self.assertEqual(opts, [('-a', '')])
209+
self.assertEqual(args, ['arg1', '-b', '1', '--alpha', '--beta=2',
210+
'--beta', '3', 'arg2'])
211+
212+
# Pass everything after -- as args
213+
cmdline = ['-a1', '--alpha=2', '--', '-b', '--beta=5']
214+
opts, args = getopt.gnu_getopt(cmdline, 'a:b', ['alpha=', 'beta'])
215+
self.assertEqual(opts, [('-a', '1'), ('--alpha', '2')])
216+
self.assertEqual(args, ['-b', '--beta=5'])
217+
218+
# In order arguments
219+
cmdline = ["gamma", "--alpha=3"]
220+
opts, args = getopt.gnu_getopt(cmdline, '-', ["alpha="])
221+
self.assertEqual(opts, [(None, ['gamma']), ('--alpha', '3')])
222+
self.assertEqual(args, [])
223+
224+
194225
def test_issue4629(self):
195226
longopts, shortopts = getopt.getopt(['--help='], '', ['help='])
196227
self.assertEqual(longopts, [('--help', '')])
197228
longopts, shortopts = getopt.getopt(['--help=x'], '', ['help='])
198229
self.assertEqual(longopts, [('--help', 'x')])
199230
self.assertRaises(getopt.GetoptError, getopt.getopt, ['--help='], '', ['help'])
200231

232+
def test_getopt_error_str(self):
233+
error = getopt.GetoptError('option -a not recognized', 'a')
234+
self.assertEqual(str(error), 'option -a not recognized')
235+
201236
def test_libref_examples():
202237
"""
203238
Examples from the Library Reference: Doc/lib/libgetopt.tex

‎Lib/test/test_htmlparser.py‎

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,11 @@ def _run_check(self, source, expected_events,
116116
*, collector=None, convert_charrefs=False):
117117
if collector is None:
118118
collector = self.get_collector(convert_charrefs=convert_charrefs)
119+
if isinstance(source, str):
120+
# Also feed the whole string at once, not just character by
121+
# character (below), to exercise different input buffering.
122+
self._run_check([source], expected_events,
123+
convert_charrefs=convert_charrefs)
119124
parser = collector
120125
for s in source:
121126
parser.feed(s)
@@ -593,6 +598,9 @@ def test_comments(self):
593598
'<!-- <!-- nested --> -->'
594599
'<!--<!-->'
595600
'<!--<!--!>'
601+
# abruptly closed empty comment must not swallow later text
602+
'<!-->x-->'
603+
'<!--->y-->'
596604
)
597605
expected = [('comment', " I'm a valid comment "),
598606
('comment', 'me too!'),
@@ -613,6 +621,8 @@ def test_comments(self):
613621
('comment', ' <!-- nested '), ('data', ' -->'),
614622
('comment', '<!'),
615623
('comment', '<!'),
624+
('comment', ''), ('data', 'x-->'),
625+
('comment', ''), ('data', 'y-->'),
616626
]
617627
self._run_check(html, expected)
618628

@@ -1031,6 +1041,26 @@ def check(source):
10311041
check("<![CDATA[" * 9 * n)
10321042
check("<!doctype" * 35 * n)
10331043

1044+
@support.requires_resource('cpu')
1045+
def test_incremental_no_quadratic_complexity(self):
1046+
# An unterminated construct fed in many small chunks used to take
1047+
# quadratic time, both to rescan and to concatenate the buffer.
1048+
# Now it takes a fraction of a second.
1049+
def check(prefix, chunk, suffix):
1050+
parser = html.parser.HTMLParser()
1051+
parser.feed(prefix)
1052+
for _ in range(200_000):
1053+
parser.feed(chunk)
1054+
parser.feed(suffix)
1055+
parser.close()
1056+
chunk = "a" * 64
1057+
check("<!--", chunk, "-->") # comment
1058+
check("<?", chunk, ">") # processing instruction
1059+
check("<!doctype ", chunk, ">") # doctype
1060+
check("<![CDATA[", chunk, "]]>") # CDATA section
1061+
check("<a href='", chunk, "'>") # start tag
1062+
check("<script>", chunk, "</script>") # RAWTEXT element
1063+
10341064

10351065
class AttributesTestCase(TestCaseBase):
10361066

0 commit comments

Comments
 (0)

Back | FazBrowse Home | New Git URL