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
3 changes: 2 additions & 1 deletion Doc/library/urllib.request.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1486,7 +1486,8 @@ some point in the future.
.. function:: urlcleanup()

Cleans up temporary files that may have been left behind by previous
calls to :func:`urlretrieve`.
calls to :func:`urlretrieve`. It also resets the default global opener
installed by :func:`install_opener`.


:mod:`!urllib.request` Restrictions
Expand Down
1 change: 1 addition & 0 deletions Lib/profiling/sampling/live_collector/collector.py
Original file line number Diff line number Diff line change
Expand Up @@ -702,6 +702,7 @@ def build_stats_list(self):
def reset_stats(self):
"""Reset all collected statistics."""
self.result.clear()
self.opcode_stats.clear()
self.per_thread_data.clear()
self.thread_ids.clear()
self.view_mode = "ALL"
Expand Down
16 changes: 9 additions & 7 deletions Lib/test/test_capi/test_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -310,13 +310,15 @@ def check_run_interactive(self, run, encode_filename, use_loop=False):
# supported". In this case, run the test without redirecting
# stderr to a temporary file.
self._check_run_interactive(run, encode_filename, use_loop)
else:
with tempfile.TemporaryFile() as tmp:
try:
os.dup2(tmp.fileno(), STDERR_FD)
self._check_run_interactive(run, encode_filename, use_loop)
finally:
os.dup2(stderr_copy, STDERR_FD)
return

with tempfile.TemporaryFile() as tmp:
try:
os.dup2(tmp.fileno(), STDERR_FD)
self._check_run_interactive(run, encode_filename, use_loop)
finally:
os.dup2(stderr_copy, STDERR_FD)
os.close(stderr_copy)

def test_run_interactiveone(self):
# Test PyRun_InteractiveOne()
Expand Down
10 changes: 10 additions & 0 deletions Lib/test/test_fstring.py
Original file line number Diff line number Diff line change
Expand Up @@ -709,6 +709,16 @@ def test_double_braces(self):
["f'{ {{}} }'", # dict in a set
])

def test_double_brace_ast_location_covers_both_source_braces(self):
value = ast.parse('f"a{{"').body[0].value.values[0]
self.assertIsInstance(value, ast.Constant)
self.assertEqual(value.value, "a{")
self.assertEqual(
(value.lineno, value.col_offset, value.end_lineno,
value.end_col_offset),
(1, 2, 1, 5),
)

def test_compile_time_concat(self):
x = 'def'
self.assertEqual('abc' f'## {x}ghi', 'abc## defghi')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ def test_reset_stats(self):
"cumulative_calls": 75,
"total_rec_calls": 0,
}
self.collector.opcode_stats[("test.py", 1, "func")][100] = 5

# Reset
self.collector.reset_stats()
Expand All @@ -107,6 +108,7 @@ def test_reset_stats(self):
self.assertEqual(self.collector.successful_samples, 0)
self.assertEqual(self.collector.failed_samples, 0)
self.assertEqual(len(self.collector.result), 0)
self.assertEqual(len(self.collector.opcode_stats), 0)

def test_increase_refresh_rate(self):
"""Test increasing refresh rate (faster updates)."""
Expand Down
160 changes: 160 additions & 0 deletions Lib/test/test_tokenize.py
Original file line number Diff line number Diff line change
Expand Up @@ -2236,6 +2236,13 @@ def test_number_starting_with_zero(self):
self.assertEqual(tokens, expected_tokens)

class CTokenizeTest(TestCase):
@staticmethod
def _get_tokens(source, *, extra_tokens=False):
return list(tokenize._generate_tokens_from_c_tokenizer(
StringIO(source).readline,
extra_tokens=extra_tokens,
))

def check_tokenize(self, s, expected):
# Format the tokens in s in a table format.
# The ENDMARKER and final NEWLINE are omitted.
Expand Down Expand Up @@ -2266,6 +2273,159 @@ def readline(encoding):
))
self.assertEqual(tokens, expected)

def test_extra_tokens_relaxes_lexer_errors(self):
cases = [
(
"2sin(x)",
("invalid decimal literal", (1, 1)),
[
(token.NUMBER, "2", (1, 0), (1, 1)),
(token.NAME, "sin", (1, 1), (1, 4)),
(token.OP, "(", (1, 4), (1, 5)),
(token.NAME, "x", (1, 5), (1, 6)),
(token.OP, ")", (1, 6), (1, 7)),
],
),
(
"01234",
(
"leading zeros in decimal integer literals are not permitted; "
"use an 0o prefix for octal integers",
(1, 1),
),
[(token.NUMBER, "01234", (1, 0), (1, 5))],
),
(
")",
("unmatched ')'", (1, 1)),
[(token.OP, ")", (1, 0), (1, 1))],
),
(
"(]",
(
"closing parenthesis ']' does not match opening parenthesis '('",
(1, 2),
),
[
(token.OP, "(", (1, 0), (1, 1)),
(token.OP, "]", (1, 1), (1, 2)),
],
),
(
"a☃b",
("invalid character '☃' (U+2603)", (1, 2)),
[(token.NAME, "a☃b", (1, 0), (1, 3))],
),
]

for source, error, expected in cases:
with self.subTest(source=source):
with self.assertRaises(tokenize.TokenError) as caught:
self._get_tokens(source)
self.assertEqual(caught.exception.args, error)

tokens = self._get_tokens(source, extra_tokens=True)
self.assertEqual(
[(tok.type, tok.string, tok.start, tok.end)
for tok in tokens[:-2]],
expected,
)

def test_extra_tokens_emits_comments_and_real_indent_locations(self):
source = "if x:\n # c\n y\nz\n"
kinds = {token.COMMENT, token.NL, token.INDENT, token.DEDENT}

parser_tokens = self._get_tokens(source)
self.assertEqual(
[(tok.type, tok.string, tok.start, tok.end)
for tok in parser_tokens if tok.type in kinds],
[
(token.INDENT, "", (3, -1), (3, -1)),
(token.DEDENT, "", (4, -1), (4, -1)),
],
)

tolerant_tokens = self._get_tokens(source, extra_tokens=True)
self.assertEqual(
[(tok.type, tok.string, tok.start, tok.end)
for tok in tolerant_tokens if tok.type in kinds],
[
(token.COMMENT, "# c", (2, 2), (2, 5)),
(token.NL, "\n", (2, 5), (2, 6)),
(token.INDENT, " ", (3, 0), (3, 2)),
(token.DEDENT, "", (4, 0), (4, 0)),
],
)

def test_printable_invalid_operator_streams_in_both_modes(self):
for extra_tokens in (False, True):
with self.subTest(extra_tokens=extra_tokens):
first = self._get_tokens(
"1 $ 2",
extra_tokens=extra_tokens,
)[1]
self.assertEqual(
(first.type, first.string, first.start, first.end),
(token.OP, "$", (1, 2), (1, 3)),
)

def test_degraded_fstring_format_spec(self):
tokens = self._get_tokens('f"{1:{2}{{3}}}"')
self.assertEqual(
[(tok.string, tok.start, tok.end)
for tok in tokens if tok.type == token.FSTRING_MIDDLE],
[
("{", (1, 8), (1, 9)),
("3", (1, 10), (1, 11)),
("}", (1, 12), (1, 13)),
],
)

tokens = self._get_tokens('f"{x:{y}}"')
self.assertEqual(
[(tok.string, tok.start, tok.end)
for tok in tokens if tok.type == token.FSTRING_MIDDLE],
[("", (1, 8), (1, 8))],
)

with self.assertRaises(tokenize.TokenError) as caught:
self._get_tokens('f"{1:{2}x}}y"')
self.assertEqual(
caught.exception.args,
("f-string: single '}' is not allowed", (1, 11)),
)

def test_escaped_fstring_brace_has_a_position_gap(self):
tokens = self._get_tokens('f"a{{"', extra_tokens=True)
self.assertEqual(
[(tok.type, tok.string, tok.start, tok.end)
for tok in tokens
if tok.type in {token.FSTRING_MIDDLE, token.FSTRING_END}],
[
(token.FSTRING_MIDDLE, "a{", (1, 2), (1, 4)),
(token.FSTRING_END, '"', (1, 5), (1, 6)),
],
)

def test_tolerant_incompatible_prefix_position_after_non_ascii(self):
with self.assertRaises(tokenize.TokenError) as caught:
self._get_tokens('bé )tf"2 ', extra_tokens=True)
self.assertEqual(
caught.exception.args,
("'f' and 't' prefixes are incompatible", (1, 6)),
)

def test_tolerant_fstring_closer_at_expression_entry_depth(self):
source = "f'1:{]]{}}r}''"
for extra_tokens, position in ((False, (1, 6)), (True, (1, 7))):
with self.subTest(extra_tokens=extra_tokens):
with self.assertRaises(tokenize.TokenError) as caught:
self._get_tokens(source, extra_tokens=extra_tokens)
self.assertEqual(
caught.exception.args,
("f-string: unmatched ']'", position),
)

def test_int(self):

self.check_tokenize('0xff <= 255', """\
Expand Down
3 changes: 3 additions & 0 deletions Makefile.pre.in
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,9 @@ PEGEN_OBJS= \
TOKENIZER_OBJS= \
Parser/lexer/buffer.o \
Parser/lexer/lexer.o \
Parser/lexer/number.o \
Parser/lexer/state.o \
Parser/lexer/string.o \
Parser/tokenizer/file_tokenizer.o \
Parser/tokenizer/readline_tokenizer.o \
Parser/tokenizer/string_tokenizer.o \
Expand All @@ -410,6 +412,7 @@ PEGEN_HEADERS= \
TOKENIZER_HEADERS= \
Parser/lexer/buffer.h \
Parser/lexer/lexer.h \
Parser/lexer/lexer_internal.h \
Parser/lexer/state.h \
Parser/tokenizer/tokenizer.h \
Parser/tokenizer/helpers.h
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fix the live sampling profiler TUI keeping stale aggregated opcode
statistics after a stats reset.
2 changes: 2 additions & 0 deletions PCbuild/_freeze_module.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,8 @@
<ClCompile Include="..\Parser\lexer\buffer.c" />
<ClCompile Include="..\Parser\lexer\state.c" />
<ClCompile Include="..\Parser\lexer\lexer.c" />
<ClCompile Include="..\Parser\lexer\number.c" />
<ClCompile Include="..\Parser\lexer\string.c" />
<ClCompile Include="..\Parser\tokenizer\string_tokenizer.c" />
<ClCompile Include="..\Parser\tokenizer\file_tokenizer.c" />
<ClCompile Include="..\Parser\tokenizer\utf8_tokenizer.c" />
Expand Down
6 changes: 6 additions & 0 deletions PCbuild/_freeze_module.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,12 @@
<ClCompile Include="..\Parser\lexer\lexer.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\Parser\lexer\number.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\Parser\lexer\string.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\Parser\lexer\buffer.c">
<Filter>Source Files</Filter>
</ClCompile>
Expand Down
3 changes: 3 additions & 0 deletions PCbuild/pythoncore.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,7 @@
<ClInclude Include="..\Objects\unicodetype_db.h" />
<ClInclude Include="..\Parser\lexer\state.h" />
<ClInclude Include="..\Parser\lexer\lexer.h" />
<ClInclude Include="..\Parser\lexer\lexer_internal.h" />
<ClInclude Include="..\Parser\lexer\buffer.h" />
<ClInclude Include="..\Parser\tokenizer\helpers.h" />
<ClInclude Include="..\Parser\tokenizer\tokenizer.h" />
Expand Down Expand Up @@ -584,6 +585,8 @@
<ClCompile Include="..\Parser\myreadline.c" />
<ClCompile Include="..\Parser\lexer\state.c" />
<ClCompile Include="..\Parser\lexer\lexer.c" />
<ClCompile Include="..\Parser\lexer\number.c" />
<ClCompile Include="..\Parser\lexer\string.c" />
<ClCompile Include="..\Parser\lexer\buffer.c" />
<ClCompile Include="..\Parser\tokenizer\string_tokenizer.c" />
<ClCompile Include="..\Parser\tokenizer\file_tokenizer.c" />
Expand Down
9 changes: 9 additions & 0 deletions PCbuild/pythoncore.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,9 @@
<ClInclude Include="..\Parser\lexer\state.h">
<Filter>Parser</Filter>
</ClInclude>
<ClInclude Include="..\Parser\lexer\lexer_internal.h">
<Filter>Parser</Filter>
</ClInclude>
<ClInclude Include="..\Parser\lexer\buffer.h">
<Filter>Parser</Filter>
</ClInclude>
Expand Down Expand Up @@ -1331,6 +1334,12 @@
<ClCompile Include="..\Parser\lexer\lexer.c">
<Filter>Parser</Filter>
</ClCompile>
<ClCompile Include="..\Parser\lexer\number.c">
<Filter>Parser</Filter>
</ClCompile>
<ClCompile Include="..\Parser\lexer\string.c">
<Filter>Parser</Filter>
</ClCompile>
<ClCompile Include="..\Parser\lexer\state.c">
<Filter>Parser</Filter>
</ClCompile>
Expand Down
Loading
Loading