mirror of
https://github.com/python/cpython.git
synced 2025-08-31 14:07:50 +00:00
Merge branch 'main' of https://github.com/python/cpython
This commit is contained in:
commit
1a137bc320
6 changed files with 61 additions and 14 deletions
|
@ -30,9 +30,8 @@ def initscr():
|
|||
fd=_sys.__stdout__.fileno())
|
||||
stdscr = _curses.initscr()
|
||||
for key, value in _curses.__dict__.items():
|
||||
if key[0:4] == 'ACS_' or key in ('LINES', 'COLS'):
|
||||
if key.startswith('ACS_') or key in ('LINES', 'COLS'):
|
||||
setattr(curses, key, value)
|
||||
|
||||
return stdscr
|
||||
|
||||
# This is a similar wrapper for start_color(), which adds the COLORS and
|
||||
|
@ -41,12 +40,9 @@ def initscr():
|
|||
|
||||
def start_color():
|
||||
import _curses, curses
|
||||
retval = _curses.start_color()
|
||||
if hasattr(_curses, 'COLORS'):
|
||||
curses.COLORS = _curses.COLORS
|
||||
if hasattr(_curses, 'COLOR_PAIRS'):
|
||||
curses.COLOR_PAIRS = _curses.COLOR_PAIRS
|
||||
return retval
|
||||
_curses.start_color()
|
||||
curses.COLORS = _curses.COLORS
|
||||
curses.COLOR_PAIRS = _curses.COLOR_PAIRS
|
||||
|
||||
# Import Python has_key() implementation if _curses doesn't contain has_key()
|
||||
|
||||
|
@ -85,10 +81,11 @@ def wrapper(func, /, *args, **kwds):
|
|||
# Start color, too. Harmless if the terminal doesn't have
|
||||
# color; user can test with has_color() later on. The try/catch
|
||||
# works around a minor bit of over-conscientiousness in the curses
|
||||
# module -- the error return from C start_color() is ignorable.
|
||||
# module -- the error return from C start_color() is ignorable,
|
||||
# unless they are raised by the interpreter due to other issues.
|
||||
try:
|
||||
start_color()
|
||||
except:
|
||||
except _curses.error:
|
||||
pass
|
||||
|
||||
return func(stdscr, *args, **kwds)
|
||||
|
|
|
@ -821,6 +821,17 @@ class AST_Tests(unittest.TestCase):
|
|||
with self.assertRaisesRegex(ValueError, f"identifier field can't represent '{constant}' constant"):
|
||||
compile(expr, "<test>", "eval")
|
||||
|
||||
def test_constant_as_unicode_name(self):
|
||||
constants = [
|
||||
("True", b"Tru\xe1\xb5\x89"),
|
||||
("False", b"Fal\xc5\xbfe"),
|
||||
("None", b"N\xc2\xbane"),
|
||||
]
|
||||
for constant in constants:
|
||||
with self.assertRaisesRegex(ValueError,
|
||||
f"identifier field can't represent '{constant[0]}' constant"):
|
||||
ast.parse(constant[1], mode="eval")
|
||||
|
||||
def test_precedence_enum(self):
|
||||
class _Precedence(enum.IntEnum):
|
||||
"""Precedence table that originated from python grammar."""
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
Raise :exc:`ValueError` when constants ``True``, ``False`` or ``None`` are
|
||||
used as an identifier after NFKC normalization.
|
|
@ -549,6 +549,21 @@ _PyPegen_new_identifier(Parser *p, const char *n)
|
|||
}
|
||||
id = id2;
|
||||
}
|
||||
static const char * const forbidden[] = {
|
||||
"None",
|
||||
"True",
|
||||
"False",
|
||||
NULL
|
||||
};
|
||||
for (int i = 0; forbidden[i] != NULL; i++) {
|
||||
if (_PyUnicode_EqualToASCIIString(id, forbidden[i])) {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"identifier field can't represent '%s' constant",
|
||||
forbidden[i]);
|
||||
Py_DECREF(id);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
PyInterpreterState *interp = _PyInterpreterState_GET();
|
||||
_PyUnicode_InternImmortal(interp, &id);
|
||||
if (_PyArena_AddPyObject(p->arena, id) < 0)
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
[mypy]
|
||||
files =
|
||||
Tools/build/compute-changes.py,
|
||||
Tools/build/generate_sbom.py
|
||||
Tools/build/generate_sbom.py,
|
||||
Tools/build/update_file.py
|
||||
|
||||
pretty = True
|
||||
|
||||
# Make sure Python can still be built
|
||||
|
@ -10,6 +12,8 @@ python_version = 3.10
|
|||
|
||||
# ...And be strict:
|
||||
strict = True
|
||||
strict_bytes = True
|
||||
local_partial_types = True
|
||||
extra_checks = True
|
||||
enable_error_code = ignore-without-code,redundant-expr,truthy-bool,possibly-undefined
|
||||
warn_unreachable = True
|
||||
|
|
|
@ -6,14 +6,27 @@ This avoids wholesale rebuilds when a code (re)generation phase does not
|
|||
actually change the in-tree generated code.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import contextlib
|
||||
import os
|
||||
import os.path
|
||||
import sys
|
||||
|
||||
TYPE_CHECKING = False
|
||||
if TYPE_CHECKING:
|
||||
import typing
|
||||
from collections.abc import Iterator
|
||||
from io import TextIOWrapper
|
||||
|
||||
_Outcome: typing.TypeAlias = typing.Literal['created', 'updated', 'same']
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def updating_file_with_tmpfile(filename, tmpfile=None):
|
||||
def updating_file_with_tmpfile(
|
||||
filename: str,
|
||||
tmpfile: str | None = None,
|
||||
) -> Iterator[tuple[TextIOWrapper, TextIOWrapper]]:
|
||||
"""A context manager for updating a file via a temp file.
|
||||
|
||||
The context manager provides two open files: the source file open
|
||||
|
@ -46,13 +59,18 @@ def updating_file_with_tmpfile(filename, tmpfile=None):
|
|||
update_file_with_tmpfile(filename, tmpfile)
|
||||
|
||||
|
||||
def update_file_with_tmpfile(filename, tmpfile, *, create=False):
|
||||
def update_file_with_tmpfile(
|
||||
filename: str,
|
||||
tmpfile: str,
|
||||
*,
|
||||
create: bool = False,
|
||||
) -> _Outcome:
|
||||
try:
|
||||
targetfile = open(filename, 'rb')
|
||||
except FileNotFoundError:
|
||||
if not create:
|
||||
raise # re-raise
|
||||
outcome = 'created'
|
||||
outcome: _Outcome = 'created'
|
||||
os.replace(tmpfile, filename)
|
||||
else:
|
||||
with targetfile:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue